>_ DevTrendsja

言語

ホーム

言語

セクション

フロントエンド バックエンド モバイル DevOps AI / ML ゲーム開発 ブロックチェーン 組み込み セキュリティ
C-plus-plus

重い依存関係なしで痛苦のないC++高速ロギング

C++でチュートリアルスクリプトより複雑なものを書いたことがある人なら 누구나、ロギングライブラリの選択に直面したことがあるでしょう。標準のstd::coutはシンプルなコンソールユーティリティには便利ですが、I/Oの遅さと便利なフォーマットの欠如により、すぐにボトルネックになります。Boost.Logやlog4cxxのような代替ライブラリは、依存関係が多く、コンパイルに時間がかかり、複雑な設定に圧倒されます。

2014年、開発者のGabriel Melmanがspdlogライブラリを公開しました。このプロジェクトはC++コミュニティで急速に人気となり、現在GitHubでほぼ30,000個の星を獲得しています。

人気の秘密

このライブラリが成功した主な理由は、パフォーマンスと統合のしやすさのバランスです。spdlogはヘッダーオンリー形式で配布されています:単にincludeディレクトリをプロジェクトにコピーし、ヘッダーファイルをインクルードすれば、すぐに使い始められます。アプリケーションのビルドを高速化する必要がある場合、CMakeでプリコンパイルしたり、最も一般的なパッケージマネージャー(apt、brew、vcpkg、conan)からインストールしたりできます。

文字列フォーマッティングはfmtライブラリをベースにしており、これはC++20のstd::formatのベースとなりました。これにより、<<演算子を使った面倒なチェーンが不要になります。アライメント、16進数出力、位置引数も簡単かつ明確に記述できます。

日常開発に便利な機能

ログシンクの組み合わせ

実際には、エラーを色付けされたコンソールに出力しながら、デバッグの詳細をローテーション付きのファイルに書き込む必要がある 경우가よくあります。spdlogでは、複数のシンクを単一のロガーオブジェクトに組み合わせてこの問題を解決します:

#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/basic_file_sink.h"

void setup_logging() {
    auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    console_sink->set_level(spdlog::level::warn);

    auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/app.txt", true);
    file_sink->set_level(spdlog::level::trace);

    spdlog::logger logger("multi_sink", {console_sink, file_sink});
    logger.info("Сообщение зафиксировано только в файле");
    logger.warn("Сообщение попадет и в консоль, и в файл");
}

高負荷タスク向け非同期モード

ネットワークサーバーやゲームエンジンのワーカースレッドでは、直接のディスク書き込みがコード実行を遅延させます。spdlogは非同期で動作できます:バックグラウンドスレッドがリングバッファからメッセージを引き出し、メイン計算を遅らせることなくディスクにフラッシュします。

#include "spdlog/async.h"
#include "spdlog/sinks/basic_file_sink.h"

void async_example() {
    // Очередь на 8192 элемента и 1 фоновый поток
    spdlog::init_thread_pool(8192, 1); 
    
    auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>(
        "async_logger", "logs/async_log.txt"
    );
    
    async_file->info("Запись лога не блокирует текущий поток");
}

エラー追跡用のリングバッファ

このライブラリの興味深い機能は、トレースサポートです。本番環境でログレベルがINFOに設定され、詳細なデバッグが無効になっているとします。SPDLOG_TRACEが有効になると、ライブラリはメモリ内に最後のN個のデバッグメッセージを保存します。障害が発生すると、それらを即座にログファイルにダンプできます。

spdlog::enable_backtrace(32); // Сохраняем последние 32 сообщения в буфер

for (int i = 0; i < 100; ++i) {
    spdlog::debug("Отладочный шаг №{}", i); // Сообщения пока не пишутся в диск
}

// При возникновении ошибки выгружаем накопленный буфер
spdlog::dump_backtrace();

再ビルドなしでログレベルを変更

ログレベルはアプリケーション起動時に環境変数やコマンドライン引数から直接読み取れます:

#include "spdlog/cfg/env.h"

int main(int argc, char* argv[]) {
    spdlog::cfg::load_env_levels();
    spdlog::info("Приложение успешно запущено");
}

バイナリを--log_level=debugフラグで実行すると、即座にデバッグメッセージ出力が有効になります。

パフォーマンスベンチマーク

同期シングルスレッドロガーは、短文字列の処理において毎秒約570万回の呼び出しを処理できます(Intel i7-4770での筆者のテスト)。10個の競合スレッドがある場合、速度は毎秒約160万メッセージを維持します。

オーバーフローポリシー(backpressure)を使用した非同期モードでは、ライブラリは毎秒260万以上の操作を処理します。これらの数値は、最小限のメモリ割り当てと高速な文字列構築によって達成されています。

すぐに使える統合

このライブラリはLinux、Windows、macOS、Android、FreeBSDでサポートされています。パッケージにはsyslog、Windowsイベントログ、Android logcat、Qtテキストウィジェット(QTextEdit)との統合用の готовыеシンクが含まれています。さらに、コードセグメントの実行時間を測定するためのstopwatchと、バイナリデータを16進数形式で出力するユーティリティが含まれています。

spdlogは不必要な複雑さなしでロギングの問題を解決します。小さなユーティリティにはヘッダーファイルをコピーするだけで十分であり、大きなサービスには非同期モード、ファイルローテーション、リアルタイムメッセージフィルタリングが便利です。高速で予測可能なC++ツールが必要な場合は、spdlogをスタックに追加することが最優先事項となるでしょう。

関連プロジェクト