
このネットワークには、Q&A形式の膨大な数のサイトがあり、カテゴリから質問が寄せられます。
- C ++ロガーを提案しますか? (C ++ロギングフレームワークの提案)
- 最も効率的なスレッドセーフC ++ロガーとは何ですか? (最も効率的なスレッドセーフC ++ロガーとは)
- Cゲームのロギングライブラリ
- 非同期スレッドセーフC ++ロガー? (C ++の非同期スレッドセーフロギング)
人々は自分の経験と知識を共有しますが、そのようなサイトの形式は、応答者の個人的な好みのみを表示できます。 たとえば、パンテイオスは最も生産性の高いロガーの1つと呼ばれることが最も多く、メーカーのテストによれば、100万を超えるログ行を書き込むのに100秒以上かかりますが、最新のハードウェアでは約30秒ですか?
この記事では、近年の最も有名で価値のあるロガーと、比較的若い数人のロガーを25を超える基準で比較します。
やる気
私が知っているほぼすべてのプロジェクトで、遅かれ早かれロギングが登場し、エンジニアは「この問題を解決する方法」を自問しました。誰かがQ&Aサイトを調べ、「Logger Xが近づいてきました。通常のフライトのようです」(1)彼は自分のロガーを書き(2)、誰かが患者であり、彼らの興味の対象についてロガーの群れ全体を研究し、1週間後に別の選択をしました(3)。
この記事は3つのグループすべてを対象としています。
- 最初のグループについては、この記事では「ロガーXが最適です」という推奨事項よりもロガーの広範な比較を示します。
- 2番目のグループの場合、この記事では現在の技術レベルについて説明し、おそらく「既製の方が使いやすい」または「すごい作業がたくさんありますが、もっとうまくいくことができます」という方向にスケールを変えるでしょう。
- 3番目の最も退屈なグループについては、この記事が3週間の研究の少なくとも1つを節約することを願っています。業界全体で、これは驚くべき工数になります。
NBこの記事は非常に膨大ですので、読むことにした場合は、しばらくお待ちください!
ロガーとその主なパラメーター
比較するロガーの選択は面倒で簡単ではありません。いずれにしても「なぜロガーXが考慮されなかったのか?」という疑問が生じます。私が言えることは、ロジックは単純だったということです。
しかし、これらの8人の候補者を比較することでさえ、ドックの喫煙、問題、フォーラムの閲覧、テストの作成、結果の収集に3週間以上かかりました。
何らかの方法で、非常に重要なロガーを見逃した場合-記事を更新できます。 レビューには以下が含まれます。
選択されたロガーの一般的な特性
人。 | 言語 | リフレッシュ | プラット。 | 比較 | |
---|---|---|---|---|---|
パンテイオス | BSD | C ++ | 2010 | Windows * nix、OS-X | VC ++、GCC、Intel、Borland、Comeau、Digital Mars、Metrowerks |
グログ | 3節のBSD | C ++ | 2018年 | Windows * nix、QNX | VC ++、GCC、clang、intel |
log4cpp | LGPL | C ++ | 2017年 | Windows * nix、Solaris | VC ++、GCC、Sun CC、OpenVMS |
P7 | LGPL | C ++、C、C#、Python | 2018年 | Windows * nix | VC ++、GCC、clang、MinGW |
G3log | パブリックドメイン | C ++ 11 | 2018年 | Windows * nix | VC ++、GCC、clang |
Spdlog | MIT | C ++ 11 | 2018年 | Windows、Linux、Solaris、OS-X、Android | VC ++、GCC、Clang |
イージーロギング | MIT | C ++ 11 | 2018年 | Windows、Linux、Solaris、OS-X、Android | VC ++、GCC、Clang、Intel |
Boost.log | ブースト( 1 ) | C ++ | 2016年 | Windows、Linux( 2 ) | VC ++、GCC、Clang( 3 ) |
- 独自のライセンスwww.boost.org/LICENSE_1_0.txt
- www.boost.org/doc/libs/1_62_0/libs/log/doc/html/log/installation.html
- Boostをコンパイルできるプラットフォームおよびコンパイラは他にも多数ありますが、それらは公式にはサポートされておらず、おそらく追加の作業が必要になります。
ドキュメントと依存関係
複雑なプロジェクトのドキュメントの重要性に異議を唱えることは難しく、現代のロガーは単純なプロジェクトと呼ばれることがあり、優れたドキュメントの可用性は、実装とエラーの修正を大幅にスピードアップします。
ドキュメント | 依存関係 | |
---|---|---|
パンテイオス | フル(API +使用) | STLSoft |
グログ | 初歩的、ほとんど欠席 | Google gflags、弱い依存関係( 1 ) |
log4cpp | 生成(Doxygen)(APIのみ) | ブースト、弱い中毒( 1 ) |
P7 | フル(API +使用) | いや |
G3log | 基本(一般的な使用方法) | いや |
Spdlog | 基本(一般的な使用方法) | いいえ、ヘッダーファイルのみ( 2 ) |
イージーロギング | 基本(一般的な使用方法) | いいえ、ヘッダーファイルのみ( 2 ) |
Boost.log | 基本(一般的な使用方法)に加えて、いくつかのクラスとそのメソッドの基本的な説明 | ブースト |
- 弱い依存関係-コードの一部はサードパーティのソリューションに依存しますが、コンパイルを妨げませんが、機能を部分的に制限します。
- ヘッダーファイルのみ-ライブラリは、プログラムの各ソースファイルに含める必要がある1つまたは複数のヘッダーファイルの形式で配布されます; Easyloggingの場合、コンパイル速度は大幅に低下します。 しかし、この状況から抜け出す方法があります-これらのプロジェクトをライブラリの形でコンパイルし、既に接続することですが、これにはプロジェクトの作成にさらに時間がかかります。
ロガータイプ、メモリ消費制御、スレッドセーフ
現在、ロギングへの2つのアプローチが広まっています。
- 同期-ログ(..)関数の呼び出しとファイルへの書き込みは、1つのストリームから同期的に発生します
- 非同期-Log(..)関数の呼び出しは、他のスレッドが書き込み中にメッセージキューのみを更新するため、ユーザーストリームからLog(..)関数を呼び出すのにかかる時間を短縮し、その結果、ユーザーストリームの最大パフォーマンスが達成され、Log呼び出しの遅延が最小化されます(..)関数。
確かに、ロギングライブラリのさまざまなメーカーによって非同期性を理解する微妙な違いがあります。
- タイプ番号1:Log(..)関数の呼び出しはアトミックである必要があると考える人もいるため、ファイル内のログメッセージの順序は00:00-> 00:01-> 00:02のように連続します。
- タイプNo. 2:他の人は、最大のパフォーマンスを達成するために、Log(..)関数呼び出しの原子性を犠牲にして、ファイル内のログメッセージがインターリーブされるという事実に耐えることができると考えています。たとえば、00:00-> 00:05-> 00 :01。
個人的には、非同期ログに関する最初のグループの観点に固執します。混合ログの分析は、特に大きなログファイルであり、単一のログが混合されていないが、数百または数千の要素のロググループである場合、快適とは言えません。
ロガーを非同期にするには、データをバッファに保存し、別のストリームから書き込む必要があるため、非同期ロギングのもう1つの重要な側面はメモリ割り当ての制御です。 そして、ここには重要な些細な問題があります-どのサイズのバッファーが最適であり、ユーザーはこのパラメーターに影響を与えることができますか? テストされたロガーの一部はニーズに合わせて数百メガバイトを割り当てたため、この質問はまったく無駄ではありません。
種類 | メモリ制御 | スレッドセーフ | |
---|---|---|---|
パンテイオス | 同期 | いや | はい |
グログ | 同期 | いや | はい |
log4cpp | 同期 | いや | はい |
P7 | 非同期、(タイプ1)( 2 ) | 正確(1Kbステップ) | はい |
G3log | 非同期、(タイプ2)( 3 ) | いいえ( 5 ) | はい |
Spdlog | 非同期、(タイプ2)( 3 ) | 部分的( 6 ) | はい |
イージーロギング | 同期( 1 ) | いや | いいえ( 4 ) |
Boost.log | 同期、非同期、(タイプ2)( 7 ) | デフォルトなし( 8 ) | はい |
- 非同期モードは実験状態です
- シャッフルされないタイムスタンプとメッセージ
- タイムスタンプとメッセージがシャッフルされる場合があります
- デフォルトでは使用できません。マクロELPP_THREAD_SAFEを有効にする必要があります
- 制御されていないメモリ割り当て、高負荷下では数百メガバイトを割り当てることができる、著者のコメント: kjellkod.wordpress.com/2014/08/16/presenting-g3log-the-next-version-of-the-next-generation-of-the-next-generation-of-loggers
g2logまたはg3logの場合、std ::キューが使用されます。内部的にはstd :: dequeです。 制限はありませんが、std :: vectorよりもはるかにメモリ耐性があります。 内部的に、キューはshared_queue.hpp内でラップされます。
- キューの長さは要素で設定できます。初期形式の要素のサイズは88バイト+テキストメッセージ(30〜160バイト)です。 最適なパフォーマンスを得るには、キューサイズを100万メッセージに設定することをお勧めします。これは、ロギングライブラリのみで120メガバイトから250メガバイトのメモリコストに変換されます。
- メッセージのシーケンスはデフォルトのライブラリでは保証されていません。異なるストリームからログを記録する場合、結果のファイルにタイムスタンプを混在させることができます: 「マルチスレッドアプリケーションでログレコードの順序が弱いのはなぜですか?」ライブラリの作成者は、「unbounded_ordering_queue」 。 ソートが実行される属性「RecordID」
- デフォルトでは、ライブラリは「unbounded_fifo_queue」を使用します。これにより、集中的なロギングでメモリ消費が制御不能に増加します。 追加の構成には「bounded_fifo_queue」を使用できます。 この場合、要素でキューの長さを指定できます。 各項目(図書館用語の記録)は約1KBかかります
プロセス障害処理
プロセス障害の正しい処理(クラッシュ処理)は、非同期ロガーにとって主に重要です。 一部のデータはバッファに保存され、それらが時間通りに保存されない場合、おそらく最も重要なデータが障害の直前に失われます。
転倒を傍受する方法は3つあります。
- 自動、ライブラリ自体はすべてのベクトルを設定し、すべてを単独で行います。このソリューションの大きな欠点は、インターセプトされた信号の不足と、クラッシュダンプファイルまたはフラッシュバッファーを保存するためにクラッシュ自体を処理したいアプリケーションの干渉です。
- 手動-ライブラリは、フォールをインターセプトしてバッファをフラッシュするためのプリミティブを提供し、アプリケーション自体がインターセプターをインストールするタイミングと方法、およびフォールの場合の処理を決定します。
- 落ちて、日常生活の問題
パンテイオス | いや |
---|---|
グログ | 自動、Linuxのみ( 1 ) |
log4cpp | いや |
P7 | 手動および自動( 2 ) |
G3log | 自動、Linuxのみ( 3 ) |
Spdlog | いいえ( 4 ) |
イージーロギング | 自動、Linuxのみ( 5 ) |
Boost.log | いいえ( 6 ) |
- 以下のシグナルがインターセプトされます:SIGSEGV、SIGILL、SIGFPE、SIGABRT、SIGBUS、SIGTERM。
- SIGSEGV、SIGILL、SIGFPE、SIGINT、SIGABRT、SIGBUS、SIGTERM、SIGBUS、PureVirtualCall、VectoredException、Newhandler、InvalidParameterHandler、status_access_、exception_array_bounds_exceeded、exception_datatype_misalignment、exception_flt_divide_by_zero、exception_flt_stack_check、EXCEPTION_ILLEGAL_INSTRUCTION、EXCEPTION_INT_DIVIDE_BY_ZERO、exception_noncontinuable_exception、exception_priv_instruction、EXCEPTION_STACK_OVERFLOW次の信号を傍受
- 次のシグナルがインターセプトされます:SIGSEGV、SIGILL、SIGFPE、SIGABRT、SIGBUS、SIGTERM、ゼロによるDiv、不正なprintf、範囲外、アクセス違反、std :: future_error
- github.com/gabime/spdlog/issues/55-欠陥は2015年に「クローズ」されました。 この方向での作業は予測されていません。
- 以下のシグナルがインターセプトされます:SIGABRT、SIGFPE、SIGILL、SIGSEGV、SIGINT
- 同期モードの場合でも、プロセスに障害が発生するとデータ損失のリスクがあります;非同期モードを使用する場合、データ損失のリスクは非常に高くなります
ロギングスタイルと出力(シンク)
ほとんどのライブラリは、確立された2つのロギングスタイルをサポートしています。
- 可変引数のリストを持つ関数(prinfスタイル)
- 演算子のオーバーロード「<<」
スタイル | 出力(シンク) | |
---|---|---|
パンテイオス | テンプレート+オーバーロード関数
F(A)、F(A、A)、F(A、A、A)、... F(A、<-64->、A) Printf | ファイル、syslog、コンソール、音声、ACE、COMerror、WinEventLog
|
グログ | ログ()<<メッセージ | ファイル、syslog、コンソール |
log4cpp | Printf、Log()<<メッセージ | ファイル、syslog、コンソール、NTログ、IDS / A、OsStream、StringQueue、Win32Debug |
P7( 6 ) | Printf | バイナリファイル、コンソール、syslog、テキストファイル(Linux:UTF8、Windows:UTF-16)ネットワーク(独自のプロトコルとサーバー( 2 ))、null |
G3log | Printf、Log()<<メッセージ | ファイル( 3 ) |
Spdlog | Printf( 4 ) | ファイル、syslog、コンソール |
イージーロギング | Printf( 1 )、Log()<<メッセージ | ファイル、syslog、コンソール |
Boost.log | ログ()<<メッセージ( 5 ) | ファイル、syslog、コンソール、Win32Debug、WinEventLog、IPC |
- 使用された場合、Printfは例外をスローしましたが、これはおそらく一時的な問題です。
- そのサーバーは、最大のパフォーマンスを実現するために使用されます。 このサーバーは無料ですが、残念ながらWindowsのみをサポートしており、明らかにQtに基づいており、作成者にLinuxサポートのリクエストが送信されました。 テスト構成でネットワークを介してログを送信する速度は、CPUのロード時に毎秒約350万でした-13%。 パフォーマンステストについては、次の章で詳しく説明します。
- 公式ディストリビューションには、ファイルローテーションとコンソールをサポートするSinkは含まれていませんが、これらの拡張機能はgithub.com/KjellKod/g3sinksからダウンロードできます
- Printfライブラリ関数の文字列形式は標準形式と互換性がないため、あるロガーを別のロガーに簡単に置き換えることは困難です
- nullptr文字列をロガーへの引数として渡すと、セグメンテーション違反/アクセス違反が発生します
- 最も生産的なシンク:バイナリファイル、Baical
ロガーの初期化
パラメータの初期化または受け渡しは重要なポイントです。 ロガーに柔軟性を追加し、たとえばロギングレベルを変更する場合に再コンパイルの必要性を排除します。
パンテイオス | 手動(コードのみ) |
---|---|
グログ | コマンドライン、マニュアル、環境変数 |
log4cpp | 構成ファイル( 1 )、マニュアル |
P7 | コマンドライン( 2 )、マニュアル |
G3log | 手動(コードのみ) |
Spdlog | 手動(コードのみ) |
イージーロギング | 設定ファイル、コマンドライン、マニュアル |
Boost.log | 構成ファイル( 3 )、手動 |
- ロガーパラメーターの詳細かつ適切に設定された設定は、おそらく最も詳細です。
- 他のすべてのロガーでは、コマンドラインパラメーターを処理するために、int main(int argc、char * argv [])関数から手でロガーに渡す必要があります。 このロガーでは、これらのパラメーターはプログラム/モジュール(dllなど)の任意の部分から自動的にインターセプトできます。
- ライブラリは、構成ファイルを介した構成のための最も基本的なプリミティブのみを提供します 。 この問題のより完全な議論はここで見つけることができます。 そして結論として
有効なエントリは、シンク、フィルタなどを実装するソースコードから派生しているため、構成ファイル形式のエントリの説明を見つけるのは難しいように思えます。 この実装はユーザー定義であってもよいため、明示的な構成フォーマットの説明を提供することは不可能です
フィルタリング設定
最も一般的なフィルタリング手法は、ログレベルによるものです。たとえば、フィルターがERRORレベルに設定されている場合、ERRORより小さいすべて(TRACE、DEBUG、INFO、WARNING ...)はログに記録されません。 この方法は、現時点では必要のない大量の情報をふるいにかけ、CPUとディスク容量を節約するのに非常に便利です。
パンテイオス | いいえ( 1 ) |
---|---|
グログ | コマンドライン、マニュアル、環境変数 |
log4cpp | 構成ファイル( 4 )、手動 |
P7 | ネットワーク経由でリアルタイムでリモートでコマンドライン( 2 )( 3 )、手動 |
G3log | いいえ( 5 ) |
Spdlog | マニュアル |
イージーロギング | マニュアル( 6 ) |
Boost.log | 手動構成ファイル |
- フィルタリングを整理するには、フロントエンドを開発する必要があります
- データがネットワーク経由で送信される場合にのみサポートされます;ローカルファイルに書き込む場合、サーバーは詳細レベルにアクセスできません。
- グローバルレベルに加えて、各モジュールのレベルを設定できます。
- 各ロガーの階層的なロギングとレベルの個別設定
- デフォルトでは無効になっており、マクロG3_DYNAMIC_LOGGINGによって有効になっています。その後、すべてのロガーのレベルを手動で設定できます。 パフォーマンスが大幅に低下します。
- 製造元によってサポートが発表されましたが、機能させることはできませんでした。使用中に機能が開発中または放棄されたようです。
Unicodeサポート
テストのこの部分は最も悲しいものの1つでした。2016年、このような有名なライブラリでのUnicodeサポートは「 公式ではない 」レベルのままです。
ライブラリは重要なアプリケーションデータ(ユーザー名、ファイルパス、ドメイン名)を保存するために必要であり、既存のもののほとんどは、データが些細な文字に収まらない場合、これを許可しません。
パンテイオス | UTF-16( 1 )( 4 )、UTF-8 |
---|---|
グログ | いや |
log4cpp | いや |
P7 | Windows-UTF-16、* nix-UTF-8、UTF-32 |
G3log | いや |
Spdlog | いや |
イージーロギング | Windows Utf-16( 2 )、Utf-8( 3 ) |
Boost.log | 部分的にUTF-8( 5 ) |
- 結果のログファイルにUnicodeトークンがなく、ビューアでのエンコーディングを自分で選択する必要があることを除いて、ほぼ完璧です。
- サポートは要求されていますが、実装されていません。Unicode文字はログファイルに含まれていません。
- START_EASYLOGGINGPPマクロはUnicodeをサポートしていません
- UTF-16など、ANSI文字列を1つのメッセージに結合することはできません
- Unicodeサポートは、Boost.Localeライブラリを使用して実行され、UTF-8 / 16/32およびその他の国のロケールのさまざまな形式に対する印象的な幅広いサポートが提供されますが、残念ながら、UTF-8ファイル形式でのみ初期化関数を使用してBoost.Logを動作させることができました同期ロガー「logging :: add_file_log」、他のすべての試行は失敗し、Unicode文字はファイルに到達しませんでした。おそらく、この機能を動作させるのに十分な時間です
ロガーへのアクセス
現代の図書館では、「誰がロガーを所有しているのか」という疑問が舞台裏に残っており、ほとんどの場合、LOG(ERROR)<< "My message"と書くことができ、図書館がすべてを処理します。 この単純さは、グローバル変数を使用して実現されます。 グローバル変数を使用するという倫理を舞台裏で残しますが、これは特別な場合ですが、単純なアプリケーションの場合にグローバル変数を使用する単純さは、多くの動的または静的モジュールで構成される複雑なアプリケーションの開発者に背を向けます。
ロガーにアクセスする別のオプションは、自分でオブジェクトを作成し、そのライフサイクルを制御することです。
最後のオプションはハイブリッドで、ロガーオブジェクトは手動モードで作成され、動的モジュールを含むプロセス全体に共通するグローバル変数(レジストリ)または共有メモリが使用されます。
パンテイオス | グローバル変数、自動初期化 |
---|---|
グログ | グローバル変数、自動初期化 |
log4cpp | グローバル変数、自動および手動の初期化 |
P7 | 共有メモリ、手動初期化 |
G3log | グローバル変数、自動および手動の初期化 |
Spdlog | グローバル変数、手動初期化 |
イージーロギング | グローバル変数、自動初期化 |
Boost.log | グローバル変数、自動および手動の初期化 |
ファイルの回転
パンテイオス | いや |
---|---|
グログ | 大きさ |
log4cpp | サイズ( 2 ) |
P7 | 時間、サイズ( 1 )( 2 ) |
G3log | サイズ、デフォルトでは使用不可( 1 ) |
Spdlog | サイズ、時間(日)( 1 ) |
イージーロギング | 大きさ |
Boost.log | 時間、サイズ( 1 )( 2 ) |
- 名前の各ファイルには日付と時刻が含まれています。
- オプション「最大。 ファイル数」は、最後のファイルのうちN個だけを保存することを許可します
時間精度
この記事で説明するロガーの多くは、高い生産性を念頭に置いて設計されており、毎秒数百万メッセージの可能性があります。 しかし、高速に加えて、正確で高解像度のタイムスタンプが必要です。 ログファイルに同じタイムスタンプを持つ数十または数百のメッセージがある場合、これは実行時間に関する情報の一部がすでに失われていることを意味します。
パンテイオス | Windows:10ミリ秒( 1 )、カスタムバックエンドは精度の向上に役立ちます
Linux:理論。 最小値1ns、ハードウェア依存 |
---|---|
グログ | Windows:10ms( 1 )
Linux:理論。 最小値1ns、ハードウェア依存 |
log4cpp | Windows:10ms( 1 )
Linux:理論。 最小値1ns、ハードウェア依存 |
P7 | Windows:100ns
Linux:理論。 最小値1ns、ハードウェア依存 |
G3log | Windows:1ms
Linux:1us |
Spdlog | Windows:1ms
Linux:理論。 最小値1ns、ハードウェア依存 |
イージーロギング | Windows:1ms
Linux:1us |
Boost.log | Windows:10ms( 1 )
Linux:理論。 最小値1ns、ハードウェア依存 |
- 1ミリ秒の粒度を取得できる場合もありますが、多くの場合、クォンタムは10ミリ秒です。
性能
この記事のリストにあるロガーの多くは、パフォーマンスが最優先事項の1つであると主張しています。
私はこの声明を真剣に受け止め、一連のテストを実施しました。
- デフォルト設定
- メモリの均等使用の条件で
- シングルストリームモード
- マルチスレッドモードで
各テストでは、時間を測定し、100万のメッセージをファイルに保存するためにロガーがCPUを消費します。 3つの測定が実行され、平均指標が計算されます。
テストは、デバッグ(最適化が無効)およびリリース(O2最適化)アセンブリでも実施されました。 テストでは、次の構成が使用されました。
- ウィンドウ7x64(6.1.7601 Service Pack 1ビルド7601)
- Visual Studio 2015、アップデート2
- RAM:16Gb(DDR3-1600 / PC3-12800)
- CPU:Intel Core i7-870
- HDD:Samsung EVO SSD 850 256GB(SATA3)
テストを実際の使用に近づけるために、各メッセージログに次の情報が保存されました。
- メッセージ番号
- ソースファイル名
- コード行番号
- ソース関数名
- ロガー/モジュール名
- レベル(エラー、警告、...)
- 時間
- 現在のスレッドのID(スレッドID)
- CPUコア番号
- テキストメッセージ
各ロガーに対して実行されたコード(コンパイルにはC ++ 11サポートが必要です):
ソーステキスト
#include <stdio.h> #include <atomic> #include <thread> #include <vector> //Include specific logger headers #include "Logger headers ..." using namespace std; using namespace std::chrono; //Use this macro to switch on multi-threading mode //#define MULTI_THREAD int main(int argc, char* argv[]) { //Logger initialization //.. unsigned int thread_count = 4; unsigned int howmany = 1'000'000; vector<thread> threads; auto start = system_clock::now(); #if !defined(MULTI_THREAD) for(unsigned int i=0; i < howmany; i++) { //Has to be customized for every logger LOG(INFO) << " Message + all required information, #" << i; } #else howmany /= thread_count; for (int t = 0; t < thread_count; ++t) { threads.push_back(std::thread([&] { for(unsigned int i=0; i < howmany; i++) { //Has to be customized for every logger LOG(INFO) << " Message + all required information, #" << i; } })); } for(auto &t:threads) { t.join(); }; howmany *= thread_count; #endif auto delta = system_clock::now() - start; auto delta_d = duration_cast<duration<double>> (delta).count(); LOG(INFO) << "Time = " << (double)howmany / delta_d << " per second, total time = " << delta_d; //Logger uninitialization if necessary return 0; }
シングルスレッド
1つのストリームでファイルごとに100万のメッセージを保存する必要があります。フィルタリングは無効になり、ファイルのローテーションは無効になります。 ランタイムおよび平均CPU使用率が測定されます。
デバッグする
時間(ミリ秒) | デバッグする
CPU(%) | リリース
時間(ミリ秒) | リリース
CPU(%) | |
---|---|---|---|---|
パンテイオス | 140 300 | 13% | 28,400 | 13% |
グログ | 52,500 | 13% | 8 270 | 13% |
log4cpp | 130 570 | 13% | 13 806 | 13% |
P7( 1 )( 2 )( 6 ) | 520 | 14% | 100 | 14% |
G3log( 1 )( 3 ) | 102 990 | 38% | 3 660 | 37% |
Spdlog( 1 )( 4 ) | 64,250 | 13% | 869 | 13% |
Spdlog( 1 )( 5 ) | 65,660 | 13% | 885 | 13% |
イージーロギング | 271,060 | 13% | 9 100 | 13% |
Boost.Log( 1 )( 7 ) | 2 310 200 | 17% | 44,300 | 9% |
Boost.Log( 1 )( 8 ) | 649,480 | 25% | 12 680 | 25% |
- 非同期ロギング
- オプション "/P7.Pool=1024"でコンパイル-使用可能なメモリの合計量は1メガバイトです。
- ほとんどの場合、ロガーはバッファーにデータを追加し、アプリケーションを終了すると記録が行われるため、測定は合成と見なすことができます。この作業には、ログ時間を1桁、ログを1秒、データを10秒保存する時間を超える時間がかかります。
- ロガーが約250メガバイトのメモリを消費している間に、製造元が推奨する条件 "spdlog :: set_async_mode(1048576)"でログを記録する
- 「spdlog :: set_async_mode(4096)」というメモリ消費量が等しい条件下でのロギング-この場合、ロガーには4k要素のバッファがあり、各要素は約250バイトを占有し、最終的には約1メガバイトのメモリ消費になります。
- 録音は、UTF-16形式のテキストのバイナリファイルで実行されました。
- メモリ消費が等しい条件(asynchronous_sink + text_file_backend + bounded_ordering_queue + block_on_overflow)でログインすると、キューの長さは1024要素であり、各要素は約1100バイトかかり、最終的には1 MBを少し超えるメモリ消費を与えます。
- 総合テスト。 最も快適な状態、デフォルトのロガー構成(asynchronous_sink + text_file_backend + unbounded_fifo_queue)でのロギング。 メモリ消費に制限はありません。到着順にメッセージをソートすることはありません。 メモリ消費は1.8GBに固定されました。
4スレッド
4つのスレッドでファイルごとに合計100万のメッセージを保存する必要があります。フィルタリングは無効になり、ファイルのローテーションは無効になります。
ランタイムおよび平均CPU使用率が測定されます。
デバッグする
時間(ミリ秒) | デバッグする
CPU(%) | リリース
時間(ミリ秒) | リリース
CPU(%) | |
---|---|---|---|---|
パンテイオス | 10 600 | 48% | 9 500 | 48% |
グログ | 30,200 | 93% | 5,900 | 93% |
log4cpp | 149,600 | 18% | 16 900 | 19% |
P7( 1 )( 2 )( 6 ) | 790 | 19% | 230 | 19% |
G3log( 1 )( 3 ) | 39,700 | 75% | 2,300 | 75% |
Spdlog( 1 )( 4 ) | 11 510 | 13% | 270 | 25% |
Spdlog( 1 )( 5 ) | 73,240 | 25% | 4,653 | 25% |
イージーロギング | 328 230 | 19% | 8 575 | 25% |
Boost.Log( 1 )( 7 ) | 2 645 120 | 14% | 48,290 | 14% |
Boost.Log( 1 )( 8 ) | 655,470 | 65% | 13 560 | 65% |
- 非同期ロギング
- オプション "/P7.Pool=1024"でコンパイル-使用可能なメモリの合計量は1メガバイトです。
- ほとんどの場合、ロガーはバッファーにデータを追加し、アプリケーションを終了すると記録が行われるため、測定は合成と見なすことができます。この作業には、ログ時間を1桁、ログを1秒、データを10秒保存する時間を超える時間がかかります。
- ロガーが約250メガバイトのメモリを消費している間に、製造元が推奨する条件 "spdlog :: set_async_mode(1048576)"でログを記録する
- 「spdlog :: set_async_mode(4096)」というメモリ消費量が等しい条件下でのロギング-この場合、ロガーには4k要素のバッファがあり、各要素は約250バイトを占有し、最終的には約1メガバイトのメモリ消費になります。
- 録音は、UTF-16形式のテキストのバイナリファイルで実行されました。
- メモリ消費が等しい条件(asynchronous_sink + text_file_backend + bounded_ordering_queue + block_on_overflow)でログインすると、キューの長さは1024要素であり、各要素は約1100バイトかかり、最終的には1 MBを少し超えるメモリ消費を与えます。
- 総合テスト。 最も快適な状態、デフォルトのロガー構成(asynchronous_sink + text_file_backend + unbounded_fifo_queue)でのロギング。 メモリ消費に制限はありません。到着順にメッセージをソートすることはありません。 メモリ消費は1.8GBに固定されました。
フィルタリング
ロガーは100万のメッセージを処理し、それらをフィルタリングする必要があります。 最終ファイルに届くメッセージは1つではありません。
実行時間が測定されます。
デバッグする
1スレッド、時間(ms) | デバッグする
4スレッド、時間(ms) | リリース
1スレッド、時間(ms) | リリース
4スレッド、時間(ms) | |
---|---|---|---|---|
パンテイオス( 1 ) | - | - | - | - |
グログ | 55 520 | 28,240 | 6 840 | 4,790 |
log4cpp | 200 | 70 | 80 | 45 |
P7 | 84 | 102 | 23 | 42 |
G3log | 5 530 | 1950 | 24 | 9 |
Spdlog | 269 | 134 | 6 | 32 |
イージーロギング( 2 ) | - | - | - | - |
Boost.log | 26,407 | 8 554 | 699 | 389 |
- フィルタリングはデフォルトでは使用できません
- フィルタリングを機能させることができませんでした
パフォーマンスの概要
多くのロガーのパフォーマンスは非常に良いレベルでした。
残念ながら、P7を除くほとんどすべてのロガーには、デバッグビルドとリリースビルドの間に大きなパフォーマンスギャップがあり、比率が74に達することがあります(Spdlog:65660/885)。 これにより、ロギングの遅延が増加するため、プロジェクトのデバッグが複雑になる可能性があります。
アプリケーションにロギングライブラリを実装する開発者は、ニーズに合わせて250メガバイトのメモリを割り当てたり、CPUの75%以上を消費したりしないため、実行されるテストはある意味で合成と呼ばれます。
通常、インテグレーターはライブラリーを非表示にし、特に小さな組み込みシステムの場合は、最小限のハードウェア要件で作業を行いたいと考えています。
したがって、1%のCPUと1MBに相当するが十分な量のメモリを使用して書き込むことができるメッセージログの数を判断するために、各ロガーの最適なインジケータを再計算しました( メモリ消費量が等しいテスト )
計算式:
((10000 ms /テスト時間(ms))* 1 000 000メッセージ)/テストでのCPU使用率
1%CPU使用時の1秒あたりのメッセージ | |
---|---|
P7 | 714,285メッセージ(1,000,000 *(1000/100 ms)/ 14%) |
Spdlog | 86 918件の投稿(1,000,000 *(1000/885ミリ秒)/ 13%) |
グログ | 9 301メッセージ(1,000,000 *(1000/8270 ms)/ 13%) |
イージーロギング | 8,453メッセージ(1,000,000 *(1,000 / 9,100ミリ秒)/ 13%) |
G3log | 7 384メッセージ(1,000,000 *(1000/3660ミリ秒)/ 37%) |
log4cpp | 5 571メッセージ(1,000,000 *(1000/13806 ms)/ 13%) |
パンテイオス | 2,708メッセージ(1,000,000 *(1000 / 28,400ミリ秒)/ 13%) |
Boost.log | 2 508メッセージ(1,000,000 *(1000/44300 ms)/ 9%) |
結論
パンテイオス
このライブラリはかなり複雑な印象を与えました。一方で著者はプロジェクトに徹底的かつ思慮深くアプローチしましたが、一方では機能、ドキュメントの良いレビュー、他方で生産性は低くなりますが(著者は反対の(1)を指摘していますが)、ファイルのローテーションやその他の些細なことの欠如は全体的な印象を大きく損ないます。
したがって、ライブラリの利点:
- タイプセーフなテンプレートベースの呼び出し
- 優れた完全なドキュメント
- Unicodeをサポートする数少ないロガーの1つですが、いくつかの制限があります。
- 低メモリ消費
- サポートされている多数のシンク
- サポートされている多数のコンパイラ
短所:
- 開発は中止されたようです
- ロガーとシンク(ファイル、ネットワークなど)のコンパイラー段階での静的バインディング
- 強力なコンピューター上での間接的な結果でさえ、信じられないほど長いコンパイル-バイナリファイルのサイズ
- レビューされたすべてのロガーの中で最も低いパフォーマンス指標の1つ
- コード内のロガー構成のみ(構成ファイル、コマンドラインのサポートなし...)
- ファイルローテーションのサポートなし
- 同期実行、つまり すべてのSink遅延(たとえば、ファイルへの書き込み)は、コードの速度に影響します。
- 同じメッセージ内でUnicode文字列とANSI文字列を組み合わせる方法はありません
- 高い入場しきい値(非常に習得が難しく、紛らわしい)
- 信じられないほど効率的で、他のすべての深刻なC ++診断ログライブラリよりも大幅に(最大2桁) 高速ですwww.pantheios.org/essentials.html
NB:ライブラリは、比較されるすべての中で最大かつ最も複雑なライブラリの1つであるため、その機能の多くが考慮されていない可能性が高いです。
グログ
ライブラリの機能はかなり貧弱で、パフォーマンスもありませんが、このライブラリは、「父」を大きく成長させた他の多くのプロジェクトに影響を与えました。 これだけがすでに著者のカルマで太っている。
ライブラリの利点:
- ライブラリの理解と保守が簡単
- プロセス障害のサポート
- コマンドライン経由で設定する機能
- 低メモリ消費
短所:
- 非常に弱いドキュメント
- プロセスクラッシュの弱いサポート-限られた数のシグナル、Linuxのみ
- 高いメッセージフィルタリングのオーバーヘッド
- デバッグおよびリリースコードのパフォーマンスの複数のギャップ(最大9回)
- 同期実行、つまり すべてのSink遅延(たとえば、ファイルへの書き込み)は、コードの速度に影響します。
- アクティブな開発が一時停止しました
- Unicodeサポートなし
- タイムスタンプの精度が不十分です
- マルチスレッドテストでCPU消費量が最も高く、1つのスレッドと比較してロガーのパフォーマンスが非常に低い
log4cpp
別の名誉あるロガーは非常に良い印象を与えました。大きな失望はなく、知名度の高いプロモーションはありません。約束は果たされません。
ライブラリの利点:
- 生成されたドキュメント
- サポートされている多数のシンク
- 低メモリ消費
- 構成ファイルのサポート
- 優れたメッセージフィルタリングパフォーマンス
短所:
- 同期実行、つまり すべてのSink遅延(たとえば、ファイルへの書き込み)は、コードの速度に影響します。
- Unicodeサポートなし
- デバッグおよびリリースコードのパフォーマンスの複数のギャップ(最大10倍)
- 低い生産性(最後から2番目の場所)
- 行サイズは1024文字を超えてはいけません-そうでなければアサートします
- ログファイルへのパスが存在しない場合、例外がスローされます。
P7
この記事で説明したものの中で最も珍しいロガーの1つであるこのパッケージには、ロガーだけでなく、ネットワーク経由でメッセージを受信し、ログファイルを表示し、フィルタリング、エクスポート、冗長レベルをリモートで制御するためのサーバー、および他の多くの機能が含まれます。 プロジェクトはネットワークと正確なメモリ管理に焦点を合わせていたため、SpdLogの場合と同様に、範囲はパフォーマンスと組み込みデバイスで使用する機能を対象としていました。
また、Sink = FileBinまたはSink = Baicalを使用する場合、プロジェクトはネットワーク経由で受信、表示、フィルタリングなどを行うための無料ソフトウェアを提供することにも注意してください。
ソフトウェア。

ライブラリの利点:
- 完全なドキュメント
- 高性能+タイムスタンプの高精度、最も近い競合他社SpdLogとの大きなギャップ
- Unicodeサポート
- メモリ消費を完全に制御
- 非同期-Log関数の呼び出しはデータの記録とは無関係であるため、関数の呼び出しの遅延は平準化されます。
- (「グローバル」変数の代わりに)共有メモリを使用してロガーとシンクにアクセスします。これにより、C#やCなど、ライブラリがサポートする他の言語で記述された動的モジュールからでも、プロセスコードの任意の部分からロガーにアクセスできます
- キットには、C、C#、Pythonのラッパーが含まれています
- ログに加えて、ライブラリはリアルタイムの記録と監視をサポートしています。
テレメトリー
- 各デバイス、プロセス、またはモジュールのログレベルを(ネットワークを介して)リモートで制御し、テレメトリカウンターを有効/無効にする機能
- 考慮されるすべてのロガーの中で、パフォーマンスの面で最小のプロセッサ要件があります
- 複数の言語で利用でき、アプリケーションの異なる部分がC#、C ++、Cで記述されている場合、すべて同じロガーを使用できます。
- 独自のテキストシンクを簡単に接続
- シンクの幅広い選択
- Baicalサーバーのカーネルはオープンソースプロジェクトであり、Windows、Linux 32/64でコンパイルできます。
短所:
- 複数のスレッドからロガーを集中的に使用すると、ロガーのパフォーマンスが低下します(2.3倍)(ログメッセージとタイムスタンプのシーケンスに対する支払い)
- バイナリデータ用の独自のシンクの設計は複雑です
- ログメッセージのシリアル化により、すべてのプロセッサコアを均等にロードすることはできません
G3log
G2Logの相続人は、Glogを再考した結果でした。 著者は、主に生産性を追求し、この主題に関する非常に活発な教育研究を行っています( 1 )( 2 )。 残念ながら、パフォーマンステストは総合的なものであることが判明し、結果は予想からはほど遠いものでした。
ライブラリの利点:
- 良好なろ過率
- 残念ながらLinuxでのみ、プロセスクラッシュ(情報が利用可能な場合のスタックトレース生成)の処理
- 全体的に満足できるドキュメント
- 非同期-Log関数の呼び出しはデータの記録とは無関係であるため、関数の呼び出しの遅延は平準化されます。
短所:
- Unicodeサポートなし
- CPU消費量が多い一方で、パフォーマンスが弱い
- ほとんどの場合、ロガーはバッファにデータを追加し、アプリケーションを終了すると記録が行われ、この作業はロギング時間よりも桁違いに長いため、パフォーマンス測定は合成と見なすことができます。
- 完全な非同期-タイムスタンプとメッセージをグループにまとめて、または一度に1つずつ集中的にログを記録できます
- 無制御のメモリ割り当ては数百メガバイトに達し、場合によっては大量のログが記録されるギガバイトに達します。
- コードのみによるロガー構成
- タイムスタンプの精度が不十分です
- デバッグおよびリリースコードのパフォーマンスの複数のギャップ(最大30回)
- 高いCPU消費
- C ++ 11以降をサポートするコンパイラ
- kjellkod.wordpress.com/2014/08/16/presenting-g3log-the-next-version-of-the-next-generation-of-loggers
- kjellkod.wordpress.com/2015/06/30/the-worlds-fastest-logger-vs-g3log
Spdlog
パフォーマンスに目を向けて作成された別のロガーは、残念ながら、数百メガバイトのRAMを使用しないと良好なパフォーマンスが得られません。 機能は他の多くのロガーの標準であり、主な重点は速度です。
ライブラリの利点:
- 全体的に満足できるドキュメント
- CPUは要求していません
- 非同期-Log関数の呼び出しはデータの記録とは無関係であるため、関数の呼び出しの遅延は平準化されます。
- メモリ消費の部分的な制御
- ヘルパーマクロの素敵なセット
- スピード、総合順位で2位、しかし1位の遅れは巨大です
短所:
- プロセス障害処理なし
- Printfライブラリ関数の文字列形式は、標準形式と互換性がないため、1つのロガーを別のロガーに簡単に置き換えることは難しく、実際には片方向チケットです
- 完全な非同期-タイムスタンプとメッセージをグループにまとめて、または一度に1つずつ混合して、結果のファイルに集中的にログを記録できます
- 最適なパフォーマンスを実現するには、約250〜300メガバイトのRAMを消費しますが、メモリ容量が減少すると、パフォーマンスは約18倍低下します。
- Unicodeサポートなし
- プロジェクトの各ファイルにこれらのファイルを含めるとコンパイルが大幅に遅くなるため、ヘッダーファイルのみをマイナスと見なします。プリコンパイル済みヘッダーを使用できます。
- コード内のロガー構成のみ
- 特に達成されたパフォーマンス(1ミリ秒のタイムスタンプ解像度で毎秒数十万から数十万のメッセージ)を考慮すると、タイムスタンプの精度は不十分です。
- C ++ 11以降をサポートするコンパイラ
- デバッグおよびリリースコードのパフォーマンスの複数のギャップ(最大74回)
イージーロギング
ロガーは、唯一のヘッダーファイル(約6700行のコード)である「軽量」を目指しました。 他の多くのロガーの機能は標準です。
ライブラリの利点:
- 全体的に満足できるドキュメント
- CPUは要求していません
- 中程度のメモリ消費
- ヘルパーマクロの素敵なセット
- 設定ファイル、コマンドラインのサポート
- 多数のサポート対象プラットフォームを宣言しました
短所:
- 同期実行、つまり すべてのSink遅延(たとえば、ファイルへの書き込み)は、コードの速度に影響します。
- 低性能
- フィルタリングを取得できませんでした。おそらくオプションが開発中です
- Unicodeサポートは要求されますが、実際にはUnicode文字はファイルに到達せず、途中で失われます
- プロジェクトの各ファイルにヘッダーファイルを含めるとコンパイルが大幅に遅くなるため、マイナスと見なされるヘッダーファイルのみがプリコンパイル済みヘッダーを使用できます。
- タイムスタンプの精度が不十分です
- C ++ 11以降をサポートするコンパイラ
- デバッグおよびリリースコードのパフォーマンスの複数のギャップ(最大40回)
- デフォルトで無効になっている特別なマクロ(ELPP_THREAD_SAFE)でスレッドセーフを有効にする必要があります
Boost.log
機能性、シンプルさ、生産性に目を向けたロガーは、このような優先順位と目標を著者が追求しています: モチベーション。
このプロジェクトはほぼ9年間開発されており、Boostなどの大規模プロジェクトに存在しています。
ライブラリの利点:
- 同期および非同期ロギングのサポート(Log関数の呼び出しはデータ記録とは無関係であるため、関数の呼び出しの遅延は平準化されます)
- 基本的なニーズをカバーする十分なドキュメント
- ログエントリの属性(ストリーム番号、ソースファイル、カウンターなど)
- シンクごとのフォーマットがサポートされています
- フィルタリングに述語を使用する機能
- サポートされている多数のシンクを宣言しました
- Unicodeサポート
- 構成ファイルのサポート
短所:
- この記事で紹介した最も複雑でわかりにくいロギングライブラリの1つ。 完全に複雑なマクロとテンプレートの混合で構築されています。 ほとんどの時間は研究に費やされました。 「フードの下で」勉強するのにさらに多くの時間が費やされました。それがおそらく、たった一人が主な参加者の一人である理由です。
- 考慮されるすべてのロガーの中で最も低いパフォーマンス
- コードのセクションを実行するときのセグメンテーション違反/アクセス違反
char *pStr = nullptr; //…. BOOST_LOG_SEV(lg, trace) << pStr;
- タイムスタンプの精度は不十分ですが、そのようなパフォーマンスではそれほど重要ではありません(1期間に最大12個のメッセージ)
- デバッグおよびリリースコードのパフォーマンスに複数のギャップ(最大54倍)があるため、デバッグモードでは実行時間が完全に受け入れられなくなることに注意する必要があります(ログ記録に数十分)
- Unicodeサポートは十分にテストされた機能の印象を与えません(非同期ログの固定サイズのソートとFIFOを使用してファイルを入力することはできませんでした)
- 同期ロガーでもバッファデータの保存が重要であるという事実を考慮すると、プロセスエラーの処理はありません。重要なデータを失う重大なリスクがあります。
- ログエントリの属性は簡単ではありません。たとえば、元の関数の名前、ファイル、行番号などです。 属性の作成も簡単な作業ではありません。
- そのユーティリティを使用した複雑なコンパイルが、コンパイルされたバイナリも提供されていることに注意する必要があります、問題はすべてのBoostに共通です
- プロジェクトにライブラリを含めると、コンパイルとリンクが大幅に遅くなります(プリコンパイル済みヘッダーを使用している場合でも)
- ライブラリコードのすべてのセクションは例外生成でカバーされますが、独自のインターセプターをインストールすることができます。これにより、各呼び出しでロガーからの例外をキャッチしたくないユーザーの不便を軽減します。
まとめ
注意!
著者の主観的な意見。
- Pantheios — , , ,
- Glog — , , . — , .
- Log4cpp — , - ( , ) , /.
- P7 — , embedded . , , , ( home ). – , . , ( Sink ) (5-7)
- G3Log, SpdLog — , , –
- Easylogging — , ,
- Boost.Log — , , - , , nullptr . , - .
ご清聴ありがとうございました。この記事が、現代のロガーの現実についての一般的なアイデアの作成に役立つことを願っています。