中文档
BqLog は、「Honor of Kings」などのプロジェクトで使用される軽量で高性能のロギング システムであり、導入に成功し、スムーズに実行されています。
Windows 64ビット
MacOS
Linux
iOS
Android(X86_64、arm64-v8a、armeabi-v7a)
Unix(FreeBSDのテストに合格)
C++
ジャワ
コトリン
C#
既存のオープンソース ロギング ライブラリと比較して、BqLog はパフォーマンスに大きな利点をもたらします (ベンチマークを参照)。サーバーやクライアントだけでなく、モバイルデバイスとの高い互換性も備えています。
メモリ消費量が低いため、10 スレッドと 20,000,000 ログ エントリのベンチマーク ケースでは、BqLog 自体のメモリ消費量は 1 MB 未満です。
高性能、高圧縮のリアルタイム ログ形式を提供します。
Unreal に提供される一般的なタイプのサポートにより、ゲーム エンジン ( Unity
、 Unreal
) で通常使用できます。
UTF-8
、 UTF-16
、 UTF-32
の文字と文字列に加え、 bool、float、double、さまざまな長さと型の整数などの一般的なパラメータ型をサポート
C++20
format specifications
をサポート
非同期ログは、データ損失を回避するクラッシュ レビューをサポートします (XLog からインスピレーションを受けています)
サイズが非常に小さく、Android コンパイル後の動的ライブラリはわずか約 200k です。
Java および C# では追加のヒープ割り当てが生成されないため、実行時に継続的に新しいオブジェクトが作成されることが回避されます。
標準の C 言語ライブラリとプラットフォーム API にのみ依存し、Android のANDROID_STL = none
モードでコンパイルできます。
C++11
以降のコンパイル標準をサポートし、-Wall -Wextra -pedantic -Werror の厳格な要件に基づいてコンパイルできます。
コンパイル モジュールはCMake
に基づいており、さまざまなプラットフォーム用のコンパイル スクリプトを提供するため、使いやすくなっています。
カスタムパラメータタイプをサポート
コードの提案に非常にフレンドリー
BqLog が速い理由 - 高性能リアルタイム圧縮ログ形式
BqLog が高速な理由 - 高同時実行リング バッファ
BqLog をプロジェクトに統合する
簡単なデモ
アーキテクチャの概要
メインプロセスAPIの使用手順
1-ログオブジェクトの作成
2-ログオブジェクトの取得
3 - メッセージのログ記録
4-その他のAPI
同期および非同期ロギング
1. 非同期ロギングのスレッドセーフ
アペンダーの概要
1. コンソールアペンダー
2.TextFileAppender
3. CompressedFileAppender (強く推奨)
4.RawFileAppender
設定手順
1. 完全な例
2. 詳細説明
バイナリ形式アペンダーのオフライン デコード
組み立て説明書
1. ライブラリの構築
2. デモのビルドと実行
3. 自動テスト実行手順
4. ベンチマーク実行手順
高度な使用法のトピック
1. ヒープ割り当てなし
2. カテゴリサポート付きのログオブジェクト
3. プログラム異常終了時のデータ保護
4. NDK と ANDROID_STL = none について
5. カスタムパラメータタイプ
6. Unreal Engine での BqLog の使用
ベンチマーク
1. ベンチマークの説明
2. BqLog C++ ベンチマーク コード
3.BqLog Java ベンチマーク コード
4. Log4j ベンチマーク コード
5. ベンチマーク結果
BqLog は、さまざまな形でプロジェクトに統合できます。 C++ の場合、動的ライブラリ、静的ライブラリ、およびソース ファイルがサポートされます。 Java および C# の場合、ラッパー ソース コードを含む動的ライブラリをサポートします。 BqLog を含める方法は次のとおりです。
コード リポジトリには、/dist/dynamic_lib/ にあるプリコンパイルされたダイナミック ライブラリ ファイルが含まれています。ライブラリ ファイルを使用して BqLog をプロジェクトに統合するには、次のことを行う必要があります。
プラットフォームに対応するダイナミック ライブラリ ファイルを選択し、プロジェクトのビルド システムに追加します。
/dist/dynamic_lib/include ディレクトリをプロジェクトにコピーし、インクルード ディレクトリ リストに追加します。 (XCode の .framework ライブラリを使用している場合は、.framework ファイルにヘッダー ファイルが既に含まれているため、この手順をスキップできます)。
コード リポジトリには、/dist/static_lib/ にあるプリコンパイルされた静的ライブラリ ファイルが含まれています。ライブラリ ファイルを使用して BqLog をプロジェクトに統合するには、次のことを行う必要があります。
プラットフォームに対応する静的ライブラリ ファイルを選択し、プロジェクトのビルド システムに追加します。
/dist/static_lib/include ディレクトリをプロジェクトにコピーし、インクルード ディレクトリ リストに追加します。 (XCode の .framework ライブラリを使用している場合は、.framework ファイルにヘッダー ファイルが既に含まれているため、この手順をスキップできます)。
BqLog は、コンパイルのためにプロジェクトにソース コードを直接組み込むこともサポートしています。ソース コードを使用して BqLog を統合するには、次の手順に従います。
/src ディレクトリをソース コード参照としてプロジェクトにコピーします。
/include ディレクトリをプロジェクトにコピーし、インクルード ディレクトリ リストに追加します。
Visual Studio で Windows バージョンをコンパイルする場合は、コンパイル オプションに /Zc:__cplusplus を追加して、現在の C++ コンパイラの標準サポートが正しく決定されるようにします。
Android の NDK のソース コードを使用する場合の重要な考慮事項については、「4. NDK と ANDROID_STL = none について」を参照してください。
C# では、ネイティブ ダイナミック ライブラリと C# ラッパーを介して BqLog を使用でき、Mono、Microsoft CLR、および Unity エンジンをサポートします。 Unity は Mono モードと IL2CPP モードの両方と互換性があります。 C# で BqLog を使用するには、次の手順に従います。
/dist/dynamic_lib/ からプラットフォームに対応するダイナミック ライブラリ ファイルを選択し、プロジェクトに追加します (Unity の場合は、「Unity のインポートとプラグインの構成」を参照してください)。
ソース コード ファイルを /wrapper/csharp/src からプロジェクトにコピーします。
Java では、ネイティブ ダイナミック ライブラリと Java ラッパーを介して BqLog を使用でき、一般的な JVM 環境と Android をサポートします。 BqLog を JVM に統合するには、次の手順に従います。
/dist/dynamic_lib/ からプラットフォームに対応するダイナミック ライブラリ ファイルを選択し、プロジェクトに追加します。
ソース コード ファイルを /wrapper/java/src からプロジェクトにコピーします。
(オプション) NDK から BqLog を呼び出す場合は、/dist/dynamic_lib/include ディレクトリをプロジェクトにコピーし、インクルード ディレクトリ リストに追加します。
次のコードは、1000 を超えるログをコンソール (Android の場合は ADB Logcat) に出力します。
#定義されている場合(WIN32) #include#endif#include #include int main() { #if defined(WIN32) // Windows コマンドラインを UTF-8 に切り替えます。これは、BqLog が表示の問題を回避するためにすべての最終テキストを UTF-8 エンコードで出力するためです。 SetConsoleOutputCP(CP_UTF8); SetConsoleCP(CP_UTF8); #endif // この文字列はログ構成です。ここでは、appender_0 という名前の 1 つのアペンダー (出力ターゲット) を備えたロガーを構成し、コンソールに出力します。 std::string config = R"( # このアペンダーの出力ターゲットはコンソールです appenders_config.appender_0.type=console # このアペンダーはタイムスタンプにローカル時間を使用します appenders_config.appender_0.time_zone=default local time # このアペンダーはこれら 6 つのレベルのログを出力します(間にスペースは入れません) appenders_config.appender_0.levels=[verbose,debug,info,warning,error,fatal] )"; bq::log log = bq::log::create_log("my_first_log", config); // 構成を使用してログ オブジェクトを作成 for(int i = 0; i < 1024; ++i) { log.info("これは情報テスト ログです。形式文字列は UTF-8、param int:{}、param bool :{}、param string8:{}、param string16:{}、param string32:{} , param float:{}", i, true, "utf8-string", u"utf16-string", U"utf32-string", 4.3464f); log.error(U"これはエラー テスト ログです。形式文字列は UTF-32 です"); bq::log::force_flush_all_logs(); // BqLog はデフォルトで非同期出力になります。プログラムを終了する前にログが確実に表示されるようにするには、出力を一度強制的にフラッシュして同期します。 0を返します。 }
System.Text を使用する;System を使用する;public class Demon_main { public static void Main(string[] args) { Console.OutputEncoding = エンコーディング.UTF8; Console.InputEncoding = エンコーディング.UTF8; string config = @" # このアペンダーの出力ターゲットはコンソールです appenders_config.appender_0.type=console # このアペンダーはタイムスタンプにローカル時間を使用します ppenders_config.appender_0.time_zone=default local time # このアペンダーはこれら 6 つのレベルのログを出力します (スペースは含まれません)間) appenders_config.appender_0.levels=[verbose,debug,info,warning,error,fatal] "; bq.log log = bq.log.create_log("my_first_log", config); // (int i = 0; i < 1024; ++i) の構成を使用してログ オブジェクトを作成します { log.info("これは情報テスト ログです。形式文字列は UTF-16、param int:{}、param bool :{}、param string:{}、param float:{}", i, true, "文字列テキスト", 4.3464f); } bq.log.force_flush_all_logs(); Console.ReadKey(); }}
public class Demon_main { public static void main(String[] args) { // TODO 自動生成メソッド スタブ String config = """ # このアペンダーの出力ターゲットはコンソールです appenders_config.appender_0.type=console # このアペンダーは現地時間を使用しますタイムスタンプの場合 appenders_config.appender_0.time_zone=default local time # このアペンダーは、これら 6 つのレベルのログを出力します (間にスペースはありません) appenders_config.appender_0.levels=[verbose,debug,info,warning,error,fatal] """; bq.log log = bq.log.create_log("my_first_log", config); // (int i = 0; i < 1024; ++i) の設定を使用してログ オブジェクトを作成します { log.info("これは情報テスト ログです。形式文字列は UTF-16、param int:{}、param bool :{}、param string:{}、param float:{}", i, true, 「文字列テキスト」、4.3464f); bq.log.force_flush_all_logs(); } }
上の図は、BqLog の基本構造を明確に示しています。図の右側は BqLog ライブラリの内部実装で、左側はプログラムとコードです。プログラムは、提供されたラッパー (さまざまな言語のオブジェクト指向 API) を使用して BqLog を呼び出すことができます。この図では、2 つのログが作成されています。1 つは「Log A」、もう 1 つは「Log B」という名前です。各ログは 1 つ以上のアペンダーにアタッチされます。 Appender は、ログ内容の出力対象として理解できます。これは、コンソール (Android の ADB Logcat ログ)、テキスト ファイル、または圧縮ログ ファイルや通常のバイナリ ログ形式ファイルなどの特殊な形式の場合もあります。
同じプロセス内で、異なる言語のラッパーが同じ Log オブジェクトにアクセスできます。たとえば、Log A という名前の Log オブジェクトが Java で作成された場合、C++ 側から Log A という名前でアクセスして使用することもできます。
Android システム上で実行される Unity 開発のゲームなどの極端なケースでは、同じアプリ内に Java、Kotlin、C#、および C++ 言語が含まれる可能性があります。これらはすべて同じ Log オブジェクトを共有できます。 create_log を使用して Java 側でログを作成し、get_log_by_name を使用して他の言語でログにアクセスできます。
注: 次の API は、bq::log (または bq.log) クラスで宣言されます。スペースを節約するために、C++ API のみをリストします。 Java と C# の API は同一であるため、ここでは繰り返しません。
C++ では、 bq::string
BqLog ライブラリの UTF-8 文字列タイプです。 char 、 std::string
、 std::string_view
などの C スタイルの文字列を渡すこともでき、これらは自動的かつ暗黙的に変換されます。
ログ オブジェクトは、create_log 静的関数を使用して作成できます。その宣言は次のとおりです。
//C++ API ////// ログ オブジェクトを作成します /// /// ログ名が空の文字列の場合、bqLog は自動的にユニークなログ名。ログ名がすでに存在する場合は、以前に存在していたログ オブジェクトが返され、以前の設定が新しい設定で上書きされます。 /// ログ設定文字列 ///ログ オブジェクトの作成が失敗した場合、その is_valid() メソッドは false を返します static log create_log(const bq::string& log_name, const bq::string& config_content);
このコードは、ログ オブジェクトの名前と構成文字列を渡してログ オブジェクトを作成します。ログ構成は構成手順で参照できます。注意すべき重要なポイントをいくつか示します。
C# か Java かに関係なく、返されるログ オブジェクトが null になることはありません。ただし、構成エラーまたはその他の理由により、無効なログ オブジェクトが作成される可能性があります。したがって、 is_valid() 関数を使用して、返されたオブジェクトを確認する必要があります。無効なオブジェクトに対して操作を実行すると、プログラムがクラッシュする可能性があります。
空の文字列がログ名として渡された場合、bqLog は「AutoBqLog_1」などの一意のログ名を自動的に生成します。
同じ名前の既存のログ オブジェクトに対して create_log を呼び出しても、新しいログ オブジェクトは作成されませんが、以前の構成が新しい構成で上書きされます。ただし、一部のパラメータはこのプロセスでは変更できません。詳細については、「設定手順」を参照してください。
NDK で使用する場合 (「4. NDK および ANDROID_STL = none について」を参照) を除き、他の状況ではこの API を使用してログ オブジェクトをグローバル変数または静的変数で直接初期化できます。
ログ オブジェクトがすでに別の場所で作成されている場合は、get_log_by_name 関数を使用して、作成されたログ オブジェクトを直接取得できます。
//C++ API ////// 名前でログ オブジェクトを取得します /// /// 検索するログ オブジェクトの名前 ///ログ オブジェクト。特定の名前のログ オブジェクトが見つからなかった場合、その is_valid() メソッドは false を返します。 static log get_log_by_name(const bq::string& log_name);
この関数を使用して、グローバル変数または静的関数のログ オブジェクトを初期化することもできます。ただし、指定した名前のログ オブジェクトがすでに存在していることを確認する必要があることに注意してください。それ以外の場合、返されたログ オブジェクトは使用できなくなり、その is_valid() メソッドは false を返します。
///コア ログ関数には 6 つのログ レベルがあります: ///詳細、デバッグ、情報、警告、エラー、致命的 templatebq::enable_if_t ::value, bool>verbose(const STR& log_content) const; テンプレート<タイプ名 STR、タイプ名...引数> bq::enable_if_t ::value, bool>verbose(const STR& log_format_content, const Args&... args) const; テンプレート<タイプ名 STR> bq::enable_if_t ::value, bool> debug(const STR& log_content) const; テンプレート<タイプ名 STR、タイプ名...引数> bq::enable_if_t ::value, bool> debug(const STR& log_format_content, const Args&... args) const; テンプレート<タイプ名 STR> bq::enable_if_t ::value, bool> info(const STR& log_content) const; テンプレート<タイプ名 STR、タイプ名...引数> bq::enable_if_t ::value, bool> info(const STR& log_format_content, const Args&... args) const; テンプレート<タイプ名 STR> bq::enable_if_t ::value, bool> warning(const STR& log_content) const; テンプレート<タイプ名 STR、タイプ名...引数> bq::enable_if_t ::value, bool> warning(const STR& log_format_content, const Args&... args) const; テンプレート<タイプ名 STR> bq::enable_if_t ::value, bool> error(const STR& log_content) const; テンプレート<タイプ名 STR、タイプ名...引数> bq::enable_if_t ::value, bool> error(const STR& log_format_content, const Args&... args) const; テンプレート<タイプ名 STR> bq::enable_if_t ::value, bool> Fatal(const STR& log_content) const; テンプレート<タイプ名 STR、タイプ名...引数> bq::enable_if_t ::value, bool> Fatal(const STR& log_format_content, const Args&... args) const;
メッセージをログに記録するときは、次の 3 つの重要な点に注意してください。
ご覧のとおり、ログは Android と同様に、冗長、デバッグ、情報、警告、エラー、致命的な 6 つのレベルに分かれています。それらの重要性は順次増加します。コンソールに出力すると、異なる色で表示されます。
STR パラメータは printf の最初のパラメータに似ており、次のようなさまざまな一般的な文字列タイプを使用できます。
Javaのjava.lang.String
C#の文字列
C++ の C スタイル文字列およびstd::string
のさまざまなエンコーディング ( char*
、 char16_t*
、 char32_t*
、 wchar_t*
、 std::string
、 std::u8string
、 std::u16string
、 std::u32string
、 std::wstring
、 std::string_view
、 std::u16string_view
、 std::u32string_view
、 std::wstring_view
、さらにはカスタム文字列タイプ(「カスタム パラメータ タイプ」で参照できます)
STR パラメータの後にさまざまなパラメータを追加できます。これらのパラメーターは、C++20 の std::format と同様のルールに従って、STR 内の指定された場所にフォーマットされます (位置引数と日時フォーマットがサポートされていない点を除く)。たとえば、単一の {} の使用はパラメータのデフォルトの書式設定を表し、{:.2f} は浮動小数点数の書式設定の精度を指定します。手動で文字列を連結するのではなく、フォーマットされたパラメータを使用してログを出力するようにしてください。このアプローチは、パフォーマンスと圧縮形式のストレージにとって最適です。
現在サポートされているパラメータのタイプは次のとおりです。
Null ポインター (null として出力)
ポインタ(0xで始まる16進数のアドレスとして出力)
ブール
半角文字(char)
全角文字(char16_t、wchar_t、C#のchar、Javaのchar)
4バイト文字(char32_tまたはwchar_t)
8ビット整数
8ビット符号なし整数
16ビット整数
16ビット符号なし整数
32ビット整数
32 ビット符号なし整数
64ビット整数
64 ビット符号なし整数
32 ビット浮動小数点数
64 ビット浮動小数点数
C++ のその他の不明な POD タイプ (サイズは 1、2、4、または 8 バイトに制限され、それぞれ int8、int16、int32、および int64 として扱われます)
文字列 (STR パラメータで説明されているすべての文字列タイプを含む)
C# および Java の任意のクラスまたはオブジェクト (ToString() 文字列を出力)
カスタム パラメータ タイプ(「カスタム パラメータ タイプ」で詳しく説明)
特定のタスクを実行できる、一般的に使用される API が他にもあります。 API の詳細な説明については、bq_log/bq_log.h、および Java および C# の bq.log クラスを参照してください。強調表示する必要があるいくつかの主要な API を次に示します。
////// BqLog を初期化しません。プログラムが存在する前にこの関数を呼び出してください。 /// static void uninit();
プログラムを終了する前、または BqLog を使用する自己実装ダイナミック ライブラリをアンインストールする前にuninit()
を実行することをお勧めします。実行しないと、特定の状況下で終了時にプログラムが停止する可能性があります。
////// bqLog が非同期の場合、プログラムのクラッシュにより、バッファ内のログがディスクに保存されなくなる可能性があります。 /// この機能が有効になっている場合、bqLog はクラッシュ時にバッファ内のログの強制フラッシュを実行しようとします。ただし、 /// この機能は成功を保証するものではなく、POSIX システムのみをサポートします。 /// static void enable_auto_crash_handle();
詳細については、「プログラム異常終了時のデータ保護」を参照してください。
////// すべてのログ オブジェクトのバッファを同期的にフラッシュし、 /// 呼び出し後にバッファ内のすべてのデータが処理されるようにします。 /// static void Force_flush_all_logs(); ////// このログ オブジェクトのバッファを同期的にフラッシュし、 /// 呼び出し後にバッファ内のすべてのデータが処理されるようにします。 /// voidforce_flush();
bqLog はデフォルトで非同期ログを使用するため、すべてのログをすぐに同期して出力したい場合があります。このような場合は、force_flush()を強制的に呼び出す必要があります。
////// コンソール ログ メッセージが出力されるたびに呼び出されるコールバックを登録します。 /// これは、外部システムがコンソールのログ出力を監視するために使用できます。 /// /// static void register_console_callback(bq::type_func_ptr_console_callback callback); ////// コンソール コールバックの登録を解除します。 /// /// static void unregister_console_callback(bq::type_func_ptr_console_callback callback);
ConsoleAppender の出力は、コンソールまたは Android 上の ADB Logcat ログに送られますが、これはすべての状況をカバーしているわけではありません。たとえば、カスタム ゲーム エンジンやカスタム IDE では、コンソール ログ出力ごとにコールバック関数を呼び出すメカニズムが提供されます。これにより、プログラム内の任意の場所でコンソール ログを再処理して出力できます。
追加の注意:デッドロックが発生しやすいため、コンソール コールバック内で同期された BQ ログを出力しないでください。
////// コンソール アペンダ バッファを有効または無効にします。 /// ラッパーは C# 仮想マシンと Java 仮想マシンの両方で実行でき、ネイティブ スレッドからコールバックを直接呼び出したくないため、 /// このオプションを有効にできます。このようにして、すべてのコンソール出力は、フェッチされるまでバッファーに保存されます。 /// /// ///static void set_console_buffer_enable(bool Enable); /// /// スレッドセーフな方法でコンソール アペンダ バッファからログ エントリを取得して削除します。 /// コンソール アペンダ バッファが空でない場合、このログ エントリに対して on_console_callback 関数が呼び出されます。 /// コールバック関数内で同期した BQ ログを出力しないようにしてください。 /// /// コンソール アペンダ バッファが空でない場合にフェッチされたログ エントリに対して呼び出されるコールバック関数 ///コンソール アペンダ バッファが空ではないため、ログ エントリがフェッチされます。それ以外の場合は False が返されます。 static bool fetch_and_remove_console_buffer(bq::type_func_ptr_console_callback on_console_callback);
コンソール コールバックを介してコンソール出力をインターセプトするだけでなく、コンソール ログ出力をアクティブに取得することもできます。場合によっては、コールバックがどのスレッドから送信されるかわからないため、コンソール ログ出力がコールバック経由で送信されることを望まない場合があります (たとえば、一部の C# 仮想マシンまたは JVM では、コンソールのログ出力時に VM がガベージ コレクションを実行している可能性があります)。コールバックが呼び出され、ハングまたはクラッシュが発生する可能性があります)。
ここで使用される方法には、 set_console_buffer_enable
を通じてコンソール バッファを有効にすることが含まれます。これにより、 fetch_and_remove_console_buffer
積極的に呼び出して取得するまで、すべてのコンソール ログ出力がメモリに保存されます。したがって、この方法を使用する場合は、メモリが解放されないように、ログをすぐに取得してクリアすることを忘れないでください。
追加の注意:デッドロックが発生しやすいため、コンソール コールバック内で同期された BQ ログを出力しないでください。
追加の注意: IL2CPP 環境でこのコードを使用している場合は、on_console_callback が静的で安全ではないとしてマークされ、[MonoPInvokeCallback(typeof(type_console_callback))] 属性で修飾されていることを確認してください。
////// ログ構成を変更しますが、buffer_size などの一部のフィールドは変更できません。 /// /// ///bool replace_config(const bq::string& config_content);
場合によっては、プログラム内のログの構成を変更したい場合があります。ログ オブジェクトを再作成して設定を上書きするだけでなく (ログ オブジェクトの作成を参照)、リセット インターフェイスを使用することもできます。ただし、すべての構成項目をこの方法で変更できるわけではないことに注意してください。詳細については、設定手順を参照してください。
////// 特定のアペンダーを一時的に無効または有効にします。 /// /// /// void set_appenders_enable(const bq::string& appender_name, bool Enable) ;
デフォルトでは、構成内のアペンダーはアクティブですが、ここでは一時的に無効にして再度有効にするメカニズムが提供されています。
////// スナップショットが設定されている場合にのみ機能します。 /// スナップショット バッファをテキストにデコードします。 /// /// 各ログのタイムスタンプが GMT 時間であるか現地時間であるか ///デコードされたスナップショット バッファ bq::string take_snapshot(bool use_gmt_time) const;
場合によっては、特定の特殊機能ではログの最後の部分を出力する必要がありますが、これはスナップショット機能を使用して行うことができます。この機能を有効にするには、まずログ構成でスナップショットをアクティブ化し、最大バッファ サイズをバイト単位で設定する必要があります。さらに、スナップショットに対してフィルタリングするログ レベルとカテゴリを指定する必要があります (オプション)。詳細な構成については、「スナップショット構成」を参照してください。スナップショットが必要な場合、take_snapshot() を呼び出すと、スナップショット バッファに保存されている最新のログ エントリを含むフォーマットされた文字列が返されます。 C++ では、型はbq::string
であり、暗黙的にstd::string
に変換できます。
namespace bq{ namespace tools { //これは、バイナリ ログ形式をデコードするためのユーティリティ クラスです。 //これを使用するには、まず log_decoder オブジェクトを作成し、 //次にその decode 関数を呼び出してデコードします。 //呼び出しが成功するたびに、 // get_last_decoded_log_entry() を使用してデコードされた結果を取得できます。 //各呼び出しは 1 つのログ エントリをデコードします。 構造体 log_decoder { プライベート: bq::string デコードテキスト_; bq::appender_decode_result result_ = bq::appender_decode_result::success; uint32_t ハンドル_ = 0; public: ////// log_decoder オブジェクトを作成します。各 log_decoder オブジェクトはバイナリ ログ ファイルに対応します。 /// /// バイナリ ログ ファイルのパスは、相対パスまたは絶対パスです。 log_decoder(const bq::string& log_file_path); ~log_decoder(); ////// ログ エントリをデコードします。この関数の各呼び出しは 1 つのログ エントリのみをデコードします /// ///デコード結果、appender_decode_result::eof はログ ファイル全体がデコードされたことを意味します bq::appender_decode_result decode(); ////// 最後のデコード結果を取得します /// ///bq::appender_decode_result get_last_decode_result() const; /// /// 最後のデコード ログ エントリの内容を取得します /// ///const bq::string& get_last_decoded_log_entry() const; }; } }
CompressedFileAppenderやRawFileAppenderなどのバイナリ型Appenderが実行時に出力するログファイルをデコードできるユーティリティクラスです。
これを使用するには、まず log_decoder オブジェクトを作成します。その後、decode() 関数を呼び出すたびに、1 つのログ エントリが順番にデコードされます。返された結果が bq::appender_decode_result::success の場合は、 get_last_decoded_log_entry() を呼び出して、最後にデコードされたログ エントリのフォーマットされたテキスト コンテンツを取得できます。結果が bq::appender_decode_result::eof の場合、すべてのログが完全に読み取られたことを意味します。
BqLog では、thread_mode 設定を通じてログ オブジェクトが同期か非同期かを構成できます。これら 2 つのモードの主な違いは次のとおりです。
同期ロギング | 非同期ロギング | |
---|---|---|
行動 | ロギング関数を呼び出した後、ログは対応するアペンダーにすぐに書き込まれます。 | ロギング関数を呼び出した後、ログはすぐには書き込まれません。代わりに、定期的な処理のためにワーカー スレッドに渡されます。 |
パフォーマンス | ログを書き込むスレッドは、ロギング関数から戻る前に、対応するアペンダーにログが書き込まれるまでブロックして待機する必要があるため、低。 | 高。ログを書き込むスレッドは実際の出力を待つ必要がなく、ログ記録後すぐに戻ることができるためです。 |
スレッドの安全性 | 高ですが、ログ機能の実行中にログパラメータが変更されないことが必要です。 | 高ですが、ログ機能の実行中にログパラメータが変更されないことが必要です。 |
非同期ログについてよくある誤解は、非同期ログはスレッドセーフではないというもので、ワーカー スレッドがログを処理するまでにパラメータが再利用されるのではないかとユーザーが懸念しています。例えば:
{ const char str_array[5] = {'T', 'E', 'S', 'T', '�'}; const char* str_ptr = str_array; log_obj.info("これはテスト パラメータです: {}, {}", str_array, str_ptr); }
上記の例では、 str_array
はスタックに格納されており、スコープが終了すると、そのメモリは有効でなくなります。ユーザーは、非同期ログが使用されている場合、ワーカー スレッドがログを処理するまでに、 str_array
とstr_ptr
無効な変数になるのではないかと心配するかもしれません。
ただし、BqLog はinfo
関数の実行中にすべてのパラメータの内容を内部のring_buffer
にコピーするため、このような状況は発生しません。 info
関数が戻ると、 str_array
やstr_ptr
などの外部変数は必要なくなります。さらに、 ring_buffer
const char*
ポインタ アドレスを格納せず、常に文字列全体を格納します。
実際の潜在的な問題は、次のシナリオで発生します。
静的 std::string global_str = "hello world"; // これは複数のスレッドによって変更されるグローバル変数です。void thread_a() { log_obj.info("これはテスト パラメータです: {}", global_str); }
info
関数の実行中にglobal_str
の内容が変更されると、未定義の動作が発生する可能性があります。 BqLog はクラッシュを防ぐために最善を尽くしますが、最終出力の正確性は保証できません。
Appenderはログの出力対象を表します。 bqLog のアペンダーの概念は、基本的に Log4j の概念と同じです。現在、bqLog は次のタイプのアペンダーを提供しています。
この Appender の出力ターゲットは、Android の ADB および iOS 上の対応するコンソールを含むコンソールです。テキストのエンコードはUTF-8です。
このアペンダーは、ログ ファイルを UTF-8 テキスト形式で直接出力します。
このアペンダーは、圧縮形式でログ ファイルを出力します。これは、 highly recommended format by bqLog
です。すべてのアペンダーの中で最高のパフォーマンスを持ち、最小の出力ファイルを生成します。ただし、最終ファイルはデコードする必要があります。デコードは実行時デコードまたはオフラインデコードで行うことができます。
このアペンダーは、バイナリ ログの内容をメモリからファイルに直接出力します。 TextFileAppender よりもパフォーマンスが高くなりますが、より多くのストレージ容量を消費します。最終ファイルはデコードする必要があります。デコードは実行時デコードまたはオフライン デコードで行うことができます。この Appender の使用は推奨されません。
以下は、さまざまなアペンダーの包括的な比較です。
名前 | 出力対象 | 直接読み取り可能 | 出力性能 | 出力サイズ |
---|---|---|---|---|
コンソールアペンダー | コンソール | ✔ | 低い | - |
TextFileAppender | ファイル | ✔ | 低い | 大きい |
CompressedFileAppender | ファイル | ✘ | 高い | 小さい |
RawFileAppender | ファイル | ✘ | 中くらい | 大きい |
構成とは、create_log 関数とreset_config 関数の構成文字列を指します。この文字列はプロパティ ファイル形式を使用し、# コメントをサポートします (ただし、コメントの場合は # で新しい行を始めることを忘れないでください)。
以下に完全な例を示します。
# この設定では、2 つの異なるファイルに出力する 2 つの TextFileAppender を含む、合計 5 つのアペンダーを持つログ オブジェクトをセットアップします。# 最初のアペンダーの名前は appender_0 で、そのタイプは ConsoleAppenderappenders_config.appender_0.type=console# appender_0 のタイム ゾーンは次のとおりです。システムのローカル時間appenders_config.appender_0.time_zone=default local time# appender_0 は 6 レベルすべてのログを出力します (注: ログ レベル間にスペースがあってはなりません。そうしないと解析に失敗します)appenders_config.appender_0.levels=[verbose,debug ,info,warning,error,fatal]# 2 番目のアペンダーの名前は appender_1 で、そのタイプは TextFileAppenderappenders_config.appender_1.type=text_file# appender_1 のタイムゾーンは GMT、つまり UTC+0appenders_config.appender_1.time_zone=gmt# appender_1 のみレベル情報以上のログを出力します。その他は無視されますappenders_config.appender_1.levels=[info,warning,error,fatal]# appender_1 のパスはプログラムの相対 bqLog ディレクトリにあり、ファイル名はnormal で始まり、その後に続きます。日付と .log 拡張子# iOS では /var/mobile/Containers/Data/Application/[APP]/Library/Caches/bqLog# Android では [android.content.Context] に保存されます.getExternalFilesDir()]/bqLogappenders_config.appender_1.file_name=bqLog/normal# 最大ファイル サイズは 10,000,000 バイトです。超過した場合、新しいファイルが作成されますappenders_config.appender_1.max_file_size=10000000# 10 日より古いファイルはクリーンアップされますappenders_config.appender_1.expire_time_days=10# 出力の合計サイズが 100,000,000 バイトを超える場合、ファイルは最初からクリーンアップされますoldappenders_config.appender_1.capacity_limit=100000000# 3 番目のアペンダーは appender_2 という名前で、そのタイプは TextFileAppenderappenders_config.appender_2.type=text_file# appender_2 はすべてのレベルのログを出力しますappenders_config.appender_2.levels=[all]# appender_2 のパスはプログラムの相対 bqLog ディレクトリ。ファイル名は new_normal で始まり、日付と .log 拡張子が続きます。appenders_config.appender_2.file_name=bqLog/new_normal# このオプションは Android でのみ有効で、内部ストレージ ディレクトリ ([android] にログを保存します) .content.Context.getFilesDir()]/bqLogappenders_config.appender_2.is_in_sandbox=true# 4 番目のアペンダーは appender_3 という名前で、そのタイプは CompressedFileAppenderappenders_config.appender_3.type=compressed_file# appender_3 はすべてのレベルのログを出力しますappenders_config.appender_3.levels=[all ]# appender_3 のパスはプログラムの絶対パス ~/bqLog ディレクトリにあり、ファイル名は compress_log で始まり、日付と .logcompr 拡張子が続きますappenders_config.appender_3.file_name=~/bqLog/compress_log# 5 番目のアペンダーの名前は次のとおりです。 appender_4 とそのタイプは RawFileAppenderappenders_config.appender_4.type=raw_file# appender_4 はデフォルトで無効になっており、後で set_appenders_enableappenders_config.appender_4.enable=false を使用して有効にできます# appender_4 はすべてのレベルのログを出力しますappenders_config.appender_4.levels=[all]# パスappender_4 のファイルはプログラムの相対 bqLog ディレクトリにあり、ファイル名は raw_log で始まり、その後に日付と .lograw 拡張子が続きますappenders_config.appender_4.file_name=bqLog/raw_log# ログは、カテゴリが ModuleA、ModuleB で始まる場合にのみ処理されます。 SystemC、それ以外の場合はすべて無視されます (カテゴリの概念については、後ほど高度な使用法のトピックで詳しく説明します)appenders_config.appender_4.categories_mask=[ModuleA,ModuleB.SystemC]# 非同期バッファの合計サイズは 65535 バイトです。具体的な意味については後述しますlog.buffer_size=65535# ログの信頼性レベルは正常です。具体的な意味については後で説明しますlog.reliable_level=normal# ログは、カテゴリが次の 3 つのワイルドカードに一致する場合にのみ処理され、それ以外の場合はすべて無視されます (カテゴリの概念については、後の高度な使用法のトピックで詳しく説明します)log.categories_mask= [*default,ModuleA,ModuleB.SystemC]# これは非同期ログです。非同期ログは最もパフォーマンスが高く推奨されるログです typelog.thread_mode=async# ログ レベルがエラーまたは致命的である場合、各ログ エントリにコール スタック情報を含めますlog.print_stack_levels=[error,fatal]# スナップショット機能を有効にします。スナップショット キャッシュ サイズは 64Ksnapshot .buffer_size=65536# 情報レベルとエラー レベルを持つログのみがスナップショットに記録されますnapshot.levels=[info,error]# カテゴリが ModuleA、ModuleB.SystemC で始まるログのみがスナップショットに記録され、それ以外の場合は無視されますスナップショット.categories_mask=[モジュールA.システムA.クラスA,モジュールB]
appenders_config
、アペンダーの構成のセットです。 appenders_config
に続く最初のパラメータはアペンダの名前であり、同じ名前を持つすべてのアペンダは同じ設定を共有します。
名前 | 必須 | 設定可能な値 | デフォルト | ConsoleAppender に適用可能 | TextFileAppender に適用可能 | CompressedFileAppender に適用可能 | RawFileAppender に適用可能 |
---|---|---|---|---|---|---|---|
タイプ | ✔ | コンソール、テキストファイル、圧縮ファイル、生ファイル | ✔ | ✔ | ✔ | ✔ | |
有効にする | ✘ | アペンダーがデフォルトで有効になっているかどうか | 真実 | ✔ | ✔ | ✔ | ✔ |
レベル | ✘ | ログレベルの配列 | [全て] | ✔ | ✔ | ✔ | ✔ |
タイムゾーン | ✘ | gmt またはその他の文字列 | 現地時間 | ✔ | ✔ | ✔ | ✔ |
ファイル名 | ✔ | 相対パスまたは絶対パス | ✘ | ✔ | ✔ | ✔ | |
サンドボックス内です | ✘ | 真、偽 | 間違い | ✘ | ✔ | ✔ | ✔ |
最大ファイルサイズ | ✘ | 正の整数または 0 | 0 | ✘ | ✔ | ✔ | ✔ |
期限切れ_時間_日 | ✘ | 正の整数または 0 | 0 | ✘ | ✔ | ✔ | ✔ |
容量_制限 | ✘ | 正の整数または 0 | 0 | ✘ | ✔ | ✔ | ✔ |
カテゴリマスク | ✘ | []で囲まれた文字列の配列 | 空の | ✔ | ✔ | ✔ | ✔ |
アペンダーのタイプを指定します。
console
: ConsoleAppender を表します
text_file
: TextFileAppender を表します
compressed_file
: CompressedFileAppender を表します
raw_file
: RawFileAppender を表します
デフォルトはtrue
です。 false
に設定すると、アペンダーはデフォルトで無効になり、後でset_appenders_enable
使用して有効にできます。
[]
で囲まれた配列。verbose 、 debug
、 info
、 warning
、 error
、 fatal
、またはすべてのレベルを受け入れる[all]
のverbose
の組み合わせが含まれます。注: レベル間にスペースを含めないでください。スペースを含めると、解析が失敗します。
ログのタイムゾーンを指定します。 gmt
グリニッジ標準時 (UTC+0) を表し、他の文字列を指定するか空のままにすると、ローカル タイム ゾーンが使用されます。タイムゾーンは次の 2 つのことに影響します。
フォーマットされたテキスト ログのタイムスタンプ (ConsoleAppender および TextFileAppender に適用)
指定したタイムゾーンで午前 0 時を超えると、新しいログ ファイルが作成されます (TextFileAppender、CompressedFileAppender、および RawFileAppender に適用されます)。
ファイルを保存するためのパスとファイル名のプレフィックス。パスは絶対パス (Android および iOS では推奨されません) または相対パスにすることができます。最終的な出力ファイル名は、このパスと名前の後に、日付、ファイル番号、アペンダーの拡張子が続きます。
Android でのみ意味があります:
true
: ファイルは内部ストレージ ディレクトリ (android.content.Context.getFilesDir()) に保存されます。利用できない場合は、外部ストレージ ディレクトリ (android.content.Context.getExternalFilesDir()) に保存されます。それも利用できない場合は、キャッシュ ディレクトリ (android.content.Context.getCacheDir()) に保存されます。
false
: ファイルはデフォルトで外部ストレージ ディレクトリに保存されます。利用できない場合は、内部ストレージ ディレクトリに保存されます。それも利用できない場合は、キャッシュ ディレクトリに保存されます。
最大ファイル サイズ (バイト単位)。保存されたファイルがこのサイズを超えると、新しいログ ファイルが作成され、ファイル番号が順番に増加します。 0
この機能を無効にします。
ファイルを保持する最大日数。これより古いファイルは自動的に削除されます。 0
この機能を無効にします。
このアペンダーによって出力ディレクトリに出力されるファイルの最大合計サイズ。この制限を超えると、ファイルは古いものから順に、合計サイズが制限内に収まるまで削除されます。 0
この機能を無効にします。
ログ オブジェクトがカテゴリをサポートするログ オブジェクトである場合、これを使用してカテゴリのツリー状リストをフィルタリングできます。配列が空でない場合、この機能はアクティブになります。たとえば、 [*default,ModuleA,ModuleB.SystemC]
、デフォルト カテゴリのログを意味します。