中文文档
BqLog adalah sistem logging ringan dan berkinerja tinggi yang digunakan dalam proyek seperti "Honor of Kings", dan telah berhasil diterapkan serta berjalan dengan lancar.
jendela 64bit
macOS
Linux
iOS
Android (X86_64, arm64-v8a, armeabi-v7a)
Unix (Lulus tes di FreeBSD)
C++
Jawa
Kotlin
C#
Dibandingkan dengan pustaka logging sumber terbuka yang sudah ada, BqLog menawarkan keunggulan performa yang signifikan (lihat Tolok Ukur). Ini tidak hanya cocok untuk server dan klien tetapi juga sangat kompatibel dengan perangkat seluler.
Dengan konsumsi memori yang rendah, dalam kasus Benchmark 10 thread dan 20.000.000 entri log, BqLog sendiri mengonsumsi kurang dari 1 MB memori.
Menyediakan format log real-time berkinerja tinggi dan kompresi tinggi
Dapat digunakan secara normal di mesin game ( Unity
, Unreal
), dengan dukungan untuk tipe umum yang disediakan untuk Unreal.
Mendukung karakter dan string UTF-8
, UTF-16
, UTF-32
, serta tipe parameter umum seperti bool, float, double, dan berbagai panjang dan tipe bilangan bulat
Mendukung format specifications
C++20
Logging asinkron mendukung tinjauan kerusakan untuk menghindari kehilangan data (terinspirasi oleh XLog)
Ukurannya sangat kecil, dengan perpustakaan dinamis hanya sekitar 200 ribu setelah kompilasi Android
Tidak menghasilkan alokasi heap tambahan di Java dan C#, menghindari pembuatan objek baru secara konstan selama runtime
Hanya bergantung pada pustaka bahasa C standar dan API platform, dan dapat dikompilasi dalam mode ANDROID_STL = none
Android
Mendukung C++11
dan standar kompilasi yang lebih baru, dan dapat dikompilasi berdasarkan persyaratan ketat -Wall -Wextra -pedantic -Werror
Modul kompilasi didasarkan pada CMake
dan menyediakan skrip kompilasi untuk berbagai platform, sehingga mudah digunakan
Mendukung jenis parameter khusus
Sangat ramah terhadap saran kode
Mengapa BqLog begitu cepat - Format Log Terkompresi Waktu Nyata Berkinerja Tinggi
Mengapa BqLog begitu cepat - Ring Buffer Konkurensi Tinggi
Mengintegrasikan BqLog ke dalam Proyek Anda
Demo Sederhana
Ikhtisar Arsitektur
Petunjuk Penggunaan API Proses Utama
1-Membuat Objek Log
2-Mengambil Objek Log
3-Mencatat Pesan
4-API lainnya
Logging Sinkron dan Asinkron
1. Keamanan thread pada logging asinkron
Pengantar Appender
1. KonsolPenambahan
2. Penambah File Teks
3. CompressedFileAppender (Sangat Direkomendasikan)
4.Penambahan File Mentah
Petunjuk Konfigurasi
1. Contoh Lengkap
2. Penjelasan Mendetail
Decoding Offline dari Penambah Format Biner
Petunjuk Pembuatan
1. Pembangunan Perpustakaan
2. Demo Bangun dan Jalankan
3. Petunjuk Uji Coba Otomatis
4. Petunjuk Jalankan Tolok Ukur
Topik Penggunaan Tingkat Lanjut
1. Tidak Ada Alokasi Tumpukan
2. Mencatat Objek dengan Dukungan Kategori
3. Perlindungan Data pada Program Keluar Tidak Normal
4. Tentang NDK dan ANDROID_STL = tidak ada
5. Jenis Parameter Khusus
6. Menggunakan BqLog di Unreal Engine
Tolok ukur
1. Deskripsi Tolok Ukur
2. Kode Tolok Ukur BqLog C++
3. Kode Tolok Ukur Java BqLog
4. Kode Tolok Ukur Log4j
5. Hasil Tolok Ukur
BqLog dapat diintegrasikan ke dalam proyek Anda dalam berbagai bentuk. Untuk C++, ini mendukung perpustakaan dinamis, perpustakaan statis, dan file sumber. Untuk Java dan C#, ini mendukung perpustakaan dinamis dengan kode sumber wrapper. Di bawah ini adalah metode untuk memasukkan BqLog:
Repositori kode mencakup file perpustakaan dinamis yang telah dikompilasi yang terletak di /dist/dynamic_lib/. Untuk mengintegrasikan BqLog ke dalam proyek Anda menggunakan file perpustakaan, Anda perlu melakukan hal berikut:
Pilih file perpustakaan dinamis yang sesuai dengan platform Anda dan tambahkan ke sistem pembangunan proyek Anda.
Salin direktori /dist/dynamic_lib/include ke proyek Anda dan tambahkan ke daftar direktori include. (Jika Anda menggunakan pustaka .framework XCode, Anda dapat melewati langkah ini karena file .framework sudah menyertakan file header).
Repositori kode mencakup file perpustakaan statis yang telah dikompilasi yang terletak di /dist/static_lib/. Untuk mengintegrasikan BqLog ke dalam proyek Anda menggunakan file perpustakaan, Anda perlu melakukan hal berikut:
Pilih file perpustakaan statis yang sesuai dengan platform Anda dan tambahkan ke sistem pembangunan proyek Anda.
Salin direktori /dist/static_lib/include ke proyek Anda dan tambahkan ke daftar direktori include. (Jika Anda menggunakan pustaka .framework XCode, Anda dapat melewati langkah ini karena file .framework sudah menyertakan file header).
BqLog juga mendukung penyertaan langsung kode sumber ke dalam proyek Anda untuk kompilasi. Untuk mengintegrasikan BqLog menggunakan kode sumber, ikuti langkah-langkah berikut:
Salin direktori /src ke proyek Anda sebagai referensi kode sumber.
Salin direktori /include ke proyek Anda dan tambahkan ke daftar direktori include.
Jika mengkompilasi versi Windows di Visual Studio, tambahkan /Zc:__cplusplus ke opsi kompilasi untuk memastikan dukungan standar kompiler C++ saat ini ditentukan dengan benar.
Jika menggunakan source code di NDK Android, silakan merujuk ke 4. Tentang NDK dan ANDROID_STL = none untuk pertimbangan penting.
Di C#, BqLog dapat digunakan melalui perpustakaan dinamis asli dan C# Wrapper, mendukung mesin Mono, Microsoft CLR, dan Unity. Unity kompatibel dengan mode Mono dan IL2CPP. Untuk menggunakan BqLog di C#, ikuti langkah-langkah berikut:
Pilih file perpustakaan dinamis yang sesuai dengan platform Anda dari /dist/dynamic_lib/ dan tambahkan ke proyek Anda (untuk Unity, lihat Impor Unity dan konfigurasikan plug-in).
Salin file kode sumber dari /wrapper/csharp/src ke proyek Anda.
Di Java, BqLog dapat digunakan melalui perpustakaan dinamis asli dan Java Wrapper, mendukung lingkungan JVM umum dan Android. Untuk mengintegrasikan BqLog ke JVM, ikuti langkah-langkah berikut:
Pilih file perpustakaan dinamis yang sesuai dengan platform Anda dari /dist/dynamic_lib/ dan tambahkan ke proyek Anda.
Salin file kode sumber dari /wrapper/java/src ke proyek Anda.
(Opsional) Salin direktori /dist/dynamic_lib/include ke proyek Anda dan tambahkan ke daftar direktori include jika Anda ingin memanggil BqLog dari NDK.
Kode berikut akan menampilkan lebih dari 1000 log ke konsol Anda (atau ADB Logcat jika di Android)
#jika ditentukan (WIN32) #include#endif#include #include int main() { #jika ditentukan(WIN32) // Alihkan baris perintah Windows ke UTF-8 karena BqLog mengeluarkan semua teks akhir dalam pengkodean UTF-8 untuk menghindari masalah tampilan SetConsoleOutputCP(CP_UTF8); SetConsoleCP(CP_UTF8); #endif // String ini adalah konfigurasi log. Di sini ia mengonfigurasi logger dengan satu appender (target keluaran) bernama appender_0, yang menghasilkan keluaran ke konsol. std::string config = R"( # Target keluaran appender ini adalah konsol appenders_config.appender_0.type=console # Appender ini menggunakan waktu lokal untuk stempel waktu appenders_config.appender_0.time_zone=default waktu lokal # Appender ini mengeluarkan log dari 6 level ini (tanpa spasi di antaranya) appenders_config.appender_0.levels=[verbose,debug,info,warning,error,fatal] )"; bq::log log = bq::log::create_log("my_first_log", config); // Membuat objek log menggunakan konfigurasi for(int i = 0; i < 1024; ++i) { log.info("Ini adalah log pengujian info, format stringnya adalah 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"Ini adalah log pengujian kesalahan, format stringnya adalah UTF-32"); bq::log::force_flush_all_logs(); // BqLog defaultnya adalah keluaran asinkron. Untuk memastikan log terlihat sebelum program keluar, paksa flush untuk menyinkronkan output satu kali. kembali 0; }
menggunakan Sistem.Teks;menggunakan Sistem;kelas publik demo_main { public static void Main(string[] args) { Konsol.OutputEncoding = Pengkodean.UTF8; Konsol.InputEncoding = Pengkodean.UTF8; string config = @" # Target keluaran appender ini adalah konsol appenders_config.appender_0.type=console # Appender ini menggunakan waktu lokal untuk stempel waktu ppenders_config.appender_0.time_zone=default waktu lokal # Appender ini mengeluarkan log dari 6 level ini (tidak ada spasi di dalamnya antara) appenders_config.appender_0.levels=[verbose,debug,info,peringatan,kesalahan,fatal] "; bq.log log = bq.log.create_log("my_first_log", config); // Buat objek log menggunakan konfigurasi for (int i = 0; i < 1024; ++i) { log.info("Ini adalah log pengujian info, format stringnya adalah UTF-16, param int:{}, param bool :{}, param string:{}, param float:{}", i, true, " Teks String", 4.3464f); } bq.log.force_flush_all_logs(); Konsol.ReadKey(); }}
public class demo_main { public static void main(String[] args) { // TODO Metode yang dibuat secara otomatis stub String config = """ # Target keluaran appender ini adalah konsol appenders_config.appender_0.type=console # Appender ini menggunakan waktu lokal untuk stempel waktu appenders_config.appender_0.time_zone=waktu lokal default # Appender ini mengeluarkan log dari 6 level ini (tanpa spasi di antaranya) appenders_config.appender_0.levels=[verbose,debug,info,warning,error,fatal] """; bq.log log = bq.log.create_log("my_first_log", config); // Membuat objek log menggunakan konfigurasi for (int i = 0; i < 1024; ++i) { log.info("Ini adalah log pengujian info, format stringnya adalah UTF-16, param int:{}, param bool :{}, param string:{}, param float:{}", i, true, "Teks String", 4.3464f); } bq.log.force_flush_all_logs(); } }
Diagram di atas dengan jelas menggambarkan struktur dasar BqLog. Di sisi kanan diagram adalah implementasi internal perpustakaan BqLog, sedangkan di sisi kiri adalah program dan kode Anda. Program Anda dapat memanggil BqLog menggunakan pembungkus yang disediakan (API berorientasi objek untuk berbagai bahasa). Dalam diagram, dua Log dibuat: satu bernama "Log A" dan yang lainnya bernama "Log B." Setiap Log dilampirkan ke satu atau lebih Appender. Appender dapat dipahami sebagai target keluaran konten log. Ini bisa berupa konsol (log ADB Logcat untuk Android), file teks, atau bahkan format khusus seperti file log terkompresi atau file format log biner biasa.
Dalam proses yang sama, pembungkus untuk bahasa berbeda dapat mengakses objek Log yang sama. Misalnya, jika objek Log bernama Log A dibuat di Java, objek tersebut juga dapat diakses dan digunakan dari sisi C++ dengan nama Log A.
Dalam kasus ekstrem, seperti game yang dikembangkan Unity yang berjalan di sistem Android, Anda mungkin melibatkan bahasa Java, Kotlin, C#, dan C++ dalam aplikasi yang sama. Mereka semua dapat berbagi objek Log yang sama. Anda dapat membuat Log di sisi Java menggunakan create_log, lalu mengaksesnya dalam bahasa lain menggunakan get_log_by_name.
Catatan: API berikut dideklarasikan di kelas bq::log (atau bq.log). Untuk menghemat ruang, hanya C++ API yang dicantumkan. API di Java dan C# identik dan tidak akan terulang di sini.
Di C++, bq::string
adalah tipe string UTF-8 di perpustakaan BqLog. Anda juga dapat meneruskan string gaya c seperti char atau std::string
atau std::string_view
, yang akan dikonversi secara otomatis dan implisit.
Objek log dapat dibuat menggunakan fungsi statis create_log. Deklarasinya adalah sebagai berikut:
//C++ API ////// Membuat objek log /// /// Jika nama log adalah string kosong, bqLog akan secara otomatis memberi Anda a nama log yang unik. Jika nama log sudah ada, maka akan mengembalikan objek log yang sudah ada sebelumnya dan menimpa konfigurasi sebelumnya dengan konfigurasi baru. /// String konfigurasi log ///Objek log, jika pembuatan gagal, metode is_valid() akan mengembalikan false log statis create_log(const bq::string& log_name, const bq::string& config_content);
Kode ini membuat objek log dengan memasukkan nama objek log dan string konfigurasi. Konfigurasi log dapat direferensikan dalam Petunjuk Konfigurasi. Berikut adalah beberapa poin penting yang perlu diperhatikan:
Terlepas dari apakah itu C# atau Java, objek log yang dikembalikan tidak akan pernah bernilai null. Namun, karena kesalahan konfigurasi atau alasan lain, objek log yang tidak valid mungkin dibuat. Oleh karena itu, Anda harus menggunakan fungsi is_valid() untuk memeriksa objek yang dikembalikan. Melakukan operasi pada objek yang tidak valid dapat menyebabkan program terhenti.
Jika string kosong diteruskan sebagai nama log, bqLog akan secara otomatis menghasilkan nama log unik, seperti "AutoBqLog_1."
Memanggil create_log pada objek log yang sudah ada dengan nama yang sama tidak akan membuat objek log baru tetapi akan menimpa konfigurasi sebelumnya dengan yang baru. Namun, beberapa parameter tidak dapat diubah dalam proses ini; lihat Petunjuk Konfigurasi untuk detailnya.
Kecuali saat menggunakan di NDK (lihat 4. Tentang NDK dan ANDROID_STL = none), Anda dapat menginisialisasi objek log secara langsung dalam variabel global atau statis menggunakan API ini dalam situasi lain.
Jika objek log telah dibuat di tempat lain, Anda bisa mendapatkan objek log yang dibuat secara langsung menggunakan fungsi get_log_by_name.
//C++ API ////// Dapatkan objek log berdasarkan namanya /// /// Nama objek log yang ingin Anda temukan ///Objek log, jika objek log dengan nama tertentu tidak ditemukan, metode is_valid() akan mengembalikan false static log get_log_by_name(const bq::string& log_name);
Anda juga dapat menggunakan fungsi ini untuk menginisialisasi objek log dalam variabel global atau fungsi statis. Namun, perhatikan bahwa Anda harus memastikan objek log dengan nama yang ditentukan sudah ada. Jika tidak, objek log yang dikembalikan tidak akan dapat digunakan, dan metode is_valid()-nya akan menghasilkan false.
///Fungsi log inti, ada 6 level log: ///verbose, debug, info, peringatan, kesalahan, templat fatalbq::enable_if_t ::value, bool> verbose(const STR& log_content) const; templat bq::enable_if_t ::value, bool> verbose(const STR& log_format_content, const Args&... args) const; templat bq::enable_if_t ::nilai, bool> debug(const STR& log_content) const; templat bq::enable_if_t ::value, bool> debug(const STR& log_format_content, const Args&... args) const; templat bq::enable_if_t ::value, bool> info(const STR& log_content) const; templat bq::enable_if_t ::value, bool> info(const STR& log_format_content, const Args&... args) const; templat bq::enable_if_t ::value, bool> peringatan(const STR& log_content) const; templat bq::enable_if_t ::value, bool> peringatan(const STR& log_format_content, const Args&... args) const; templat bq::enable_if_t ::value, bool> error(const STR& log_content) const; templat bq::enable_if_t ::value, bool> error(const STR& log_format_content, const Args&... args) const; templat bq::enable_if_t ::nilai, bool> fatal(const STR& log_content) const; templat bq::enable_if_t ::value, bool> fatal(const STR& log_format_content, const Args&... args) const;
Saat mencatat pesan, perhatikan tiga poin utama:
Seperti yang Anda lihat, log kami dibagi menjadi enam level: verbose, debug, info, peringatan, kesalahan, dan fatal, konsisten dengan Android. Pentingnya mereka meningkat secara berurutan. Saat dikeluarkan ke konsol, mereka akan muncul dalam warna berbeda.
Parameter STR mirip dengan parameter pertama printf dan dapat berupa berbagai tipe string yang umum, termasuk:
Java.lang.String di Java
string C#
Berbagai pengkodean string gaya C C++ dan 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
dan bahkan tipe string khusus, yang dapat Anda rujuk ke inCustom Parameter Types )
Anda dapat menambahkan berbagai parameter setelah parameter STR. Parameter ini akan diformat ke tempat yang ditentukan di STR, mengikuti aturan yang mirip dengan std::format C++20 (kecuali kurangnya dukungan untuk argumen posisi dan format tanggal dan waktu). Misalnya, penggunaan {} tunggal mewakili pemformatan default sebuah parameter, dan {:.2f} menetapkan presisi untuk memformat angka floating-point. Cobalah untuk menggunakan parameter yang diformat untuk mengeluarkan log daripada menggabungkan string secara manual. Pendekatan ini optimal untuk kinerja dan penyimpanan format terkompresi.
Jenis parameter yang didukung saat ini meliputi:
Pointer nol (keluaran sebagai nol)
Pointer (keluaran sebagai alamat heksadesimal dimulai dengan 0x)
bodoh
Karakter byte tunggal (char)
Karakter byte ganda (char16_t, wchar_t, char C#, char Java)
Karakter empat byte (char32_t atau wchar_t)
bilangan bulat 8-bit
Bilangan bulat 8-bit yang tidak ditandatangani
bilangan bulat 16-bit
Bilangan bulat 16-bit yang tidak ditandatangani
bilangan bulat 32-bit
Bilangan bulat 32-bit yang tidak ditandatangani
bilangan bulat 64-bit
Bilangan bulat 64-bit yang tidak ditandatangani
Angka floating-point 32-bit
Angka floating-point 64-bit
Tipe POD lain yang tidak diketahui di C++ (terbatas pada ukuran 1, 2, 4, atau 8 byte, masing-masing diperlakukan sebagai int8, int16, int32, dan int64)
String, termasuk semua tipe string yang disebutkan dalam Parameter STR
Kelas atau objek apa pun di C# dan Java (mengeluarkan string ToString())
Tipe parameter kustom, seperti yang dirinci dalam Tipe Parameter Kustom
Ada API tambahan yang umum digunakan yang dapat menyelesaikan tugas tertentu. Untuk deskripsi API mendetail, lihat bq_log/bq_log.h, serta kelas bq.log di Java dan C#. Berikut beberapa API utama yang perlu disorot:
////// Hapus inisialisasi BqLog, harap aktifkan fungsi ini sebelum program Anda ada. /// statis batal unit();
Disarankan untuk menjalankan uninit()
sebelum keluar dari program atau menghapus instalasi pustaka dinamis yang diterapkan sendiri yang menggunakan BqLog, jika tidak, program mungkin macet saat keluar dalam kondisi tertentu.
////// Jika bqLog tidak sinkron, crash pada program dapat menyebabkan log di buffer tidak disimpan ke disk. /// Jika fitur ini diaktifkan, bqLog akan mencoba melakukan pembersihan paksa log di buffer jika terjadi kerusakan. Namun, /// fungsi ini tidak menjamin kesuksesan, dan hanya mendukung sistem POSIX. /// statis batal aktifkan_auto_crash_handle();
Untuk pengenalan mendetail, lihatPerlindungan Data pada Program Keluar Tidak Normal
////// Hapus buffer semua objek log secara bersamaan /// untuk memastikan bahwa semua data dalam buffer diproses setelah panggilan. /// kekosongan statis force_flush_all_logs(); ////// Hapus buffer objek log ini secara sinkron /// untuk memastikan bahwa semua data dalam buffer diproses setelah panggilan. /// batal force_flush();
Karena bqLog menggunakan logging asinkron secara default, ada kalanya Anda mungkin ingin segera menyinkronkan dan mengeluarkan semua log. Dalam kasus seperti itu, Anda perlu memanggil paksa force_flush().
////// Daftarkan panggilan balik yang akan dipanggil setiap kali pesan log konsol dikeluarkan. /// Ini dapat digunakan oleh sistem eksternal untuk memantau keluaran log konsol. /// /// static void register_console_callback(bq::type_func_ptr_console_callback panggilan balik); /// /// Membatalkan pendaftaran panggilan balik konsol. /// /// static void unregister_console_callback(bq::type_func_ptr_console_callback panggilan balik);
Output dariConsoleAppender masuk ke konsol atau log ADB Logcat di Android, namun ini mungkin tidak mencakup semua situasi. Misalnya, di mesin game khusus atau IDE khusus, mekanisme disediakan untuk memanggil fungsi panggilan balik untuk setiap keluaran log konsol. Hal ini memungkinkan Anda memproses ulang dan mengeluarkan log konsol di mana pun dalam program Anda.
Perhatian Tambahan: Jangan menampilkan log BQ tersinkronisasi apa pun dalam panggilan balik konsol karena dapat dengan mudah menyebabkan kebuntuan.
////// Mengaktifkan atau menonaktifkan buffer penambahan konsol. /// Karena wrapper kita dapat berjalan di mesin virtual C# dan Java, dan kita tidak ingin langsung memanggil callback dari thread asli, /// kita dapat mengaktifkan opsi ini. Dengan cara ini, semua keluaran konsol akan disimpan di buffer sampai kita mengambilnya. /// /// /// static void set_console_buffer_enable(bool aktifkan); /// /// Ambil dan hapus entri log dari buffer penambah konsol dengan cara yang aman untuk thread. /// Jika buffer penambahan konsol tidak kosong, fungsi on_console_callback akan dipanggil untuk entri log ini. /// Harap pastikan untuk tidak menampilkan log BQ yang disinkronkan dalam fungsi panggilan balik. /// /// Fungsi panggilan balik yang akan dipanggil untuk entri log yang diambil jika buffer penambahan konsol tidak kosong ///True jika buffer konsol appender tidak kosong dan entri log diambil; jika tidak, False dikembalikan. static bool Fetch_and_remove_console_buffer(bq::type_func_ptr_console_callback on_console_callback);
Selain mencegat keluaran konsol melalui callback konsol, Anda dapat secara aktif mengambil keluaran log konsol. Terkadang, kita mungkin tidak ingin keluaran log konsol datang melalui panggilan balik karena Anda tidak tahu dari thread mana panggilan balik itu berasal (misalnya, di beberapa mesin virtual C#, atau JVM, VM mungkin melakukan pengumpulan sampah saat konsol panggilan balik dipanggil, yang berpotensi menyebabkan hang atau crash).
Metode yang digunakan di sini melibatkan pengaktifan buffer konsol melalui set_console_buffer_enable
. Hal ini menyebabkan setiap keluaran log konsol disimpan dalam memori hingga kita secara aktif memanggil fetch_and_remove_console_buffer
untuk mengambilnya. Oleh karena itu, jika Anda memilih untuk menggunakan metode ini, ingatlah untuk segera mengambil dan menghapus log untuk menghindari memori yang belum dirilis.
Perhatian Tambahan: Jangan menampilkan log BQ tersinkronisasi apa pun dalam panggilan balik konsol karena dapat dengan mudah menyebabkan kebuntuan.
Perhatian Tambahan: Jika Anda menggunakan kode ini di lingkungan IL2CPP, pastikan bahwa on_console_callback ditandai sebagai statis tidak aman dan dihiasi dengan atribut [MonoPInvokeCallback(typeof(type_console_callback))].
////// Memodifikasi konfigurasi log, namun beberapa kolom, seperti buffer_size, tidak dapat diubah. /// /// ///bool reset_config(const bq::string& config_content);
Terkadang Anda mungkin ingin mengubah konfigurasi log dalam program Anda. Selain membuat ulang objek log untuk menimpa konfigurasi (Lihat Membuat Objek Log), Anda juga dapat menggunakan antarmuka reset. Namun perlu diingat bahwa tidak semua item konfigurasi dapat dimodifikasi dengan cara ini. Untuk detailnya, lihat Petunjuk Konfigurasi
////// Menonaktifkan atau mengaktifkan Appender tertentu untuk sementara. /// /// /// void set_appenders_enable(const bq::string& appender_name, bool aktifkan) ;
Secara default, Appenders dalam konfigurasi aktif, tetapi mekanisme disediakan di sini untuk menonaktifkan sementara dan mengaktifkannya kembali.
////// Hanya berfungsi ketika snapshot dikonfigurasi. /// Ini akan memecahkan kode buffer snapshot menjadi teks. /// /// apakah stempel waktu setiap log adalah waktu GMT atau waktu lokal /// buffer snapshot yang didekode bq::string take_snapshot(bool use_gmt_time) const;
Terkadang, fitur khusus tertentu memerlukan keluaran bagian terakhir log, yang dapat dilakukan menggunakan fitur snapshot. Untuk mengaktifkan fitur ini, Anda harus terlebih dahulu mengaktifkan snapshot di konfigurasi log dan mengatur ukuran buffer maksimum, dalam byte. Selain itu, Anda perlu menentukan tingkat log dan kategori yang akan difilter untuk snapshot (opsional). Untuk konfigurasi mendetail, silakan merujuk ke Konfigurasi Snapshot. Ketika snapshot diperlukan, pemanggilan take_snapshot() akan mengembalikan string yang diformat yang berisi entri log terbaru yang disimpan dalam buffer snapshot. Dalam C++, tipenya adalah bq::string
, yang secara implisit dapat dikonversi menjadi std::string
.
namespace bq{ namespace tools {//Ini adalah kelas utilitas untuk mendekode format log biner. //Untuk menggunakannya, pertama-tama buat objek log_decoder, //lalu panggil fungsi decode untuk melakukan decode. //Setelah setiap panggilan berhasil, //Anda dapat menggunakan get_last_decoded_log_entry() untuk mengambil hasil dekode. //Setiap panggilan menerjemahkan satu entri log. struct log_decoder { pribadi: bq::string decode_text_; bq::appender_decode_result result_ = bq::appender_decode_result::sukses; uint32_t menangani_ = 0; public: ////// Membuat objek log_decoder, dengan setiap objek log_decoder berhubungan dengan file log biner. /// /// jalur file log biner, dapat berupa jalur relatif atau jalur absolut log_decoder(const bq::string& log_file_path); ~log_decoder(); ////// Dekode entri log. setiap panggilan fungsi ini hanya akan mendekode 1 entri log /// /// hasil dekode, appender_decode_result::eof berarti seluruh file log telah didekode bq::appender_decode_result decode(); ////// dapatkan hasil decode terakhir /// ///bq::appender_decode_result get_last_decode_result() const; /// /// dapatkan konten entri log dekode terakhir /// ///const bq::string& get_last_decoded_log_entry() const; }; } }
Ini adalah kelas utilitas yang dapat memecahkan kode keluaran file log oleh Appender tipe biner saat runtime, seperti CompressedFileAppender dan RawFileAppender。
Untuk menggunakannya, pertama-tama buat objek log_decoder. Kemudian, setiap kali Anda memanggil fungsi decode(), fungsi tersebut akan mendekode satu entri log secara berurutan. Jika hasil yang dikembalikan adalah bq::appender_decode_result::success, Anda dapat memanggil get_last_decoded_log_entry() untuk mendapatkan konten teks yang diformat dari entri log terakhir yang didekodekan. Jika hasilnya bq::appender_decode_result::eof, berarti semua log sudah terbaca seluruhnya.
BqLog memungkinkan Anda mengonfigurasi apakah objek log sinkron atau asinkron melalui pengaturan thread_mode. Perbedaan utama antara kedua mode ini adalah sebagai berikut:
Pencatatan Log Sinkron | Pencatatan Asinkron | |
---|---|---|
Perilaku | Setelah memanggil fungsi logging, log segera ditulis ke appender yang sesuai. | Setelah memanggil fungsi logging, log tidak langsung ditulis; sebaliknya, ia diserahkan ke thread pekerja untuk diproses secara berkala. |
Pertunjukan | Rendah, karena thread yang menulis log perlu diblokir dan menunggu log ditulis ke appender yang sesuai sebelum kembali dari fungsi logging. | Tinggi, karena thread yang menulis log tidak perlu menunggu keluaran aktual dan dapat kembali segera setelah logging. |
Keamanan Benang | Tinggi, tetapi mengharuskan parameter log tidak diubah selama pelaksanaan fungsi logging. | Tinggi, tetapi mengharuskan parameter log tidak diubah selama pelaksanaan fungsi logging. |
Kesalahpahaman umum tentang logging asinkron adalah bahwa logging ini kurang aman bagi thread, karena pengguna khawatir bahwa parameter dapat diperoleh kembali pada saat thread pekerja memproses log. Misalnya:
{ const char str_array[5] = {'T', 'E', 'S', 'T', '�'}; const char* str_ptr = str_array; log_obj.info("Ini adalah parameter pengujian: {}, {}", str_array, str_ptr); }
Dalam contoh di atas, str_array
disimpan di tumpukan, dan setelah cakupannya keluar, memorinya tidak lagi valid. Pengguna mungkin khawatir jika logging asinkron digunakan, pada saat thread pekerja memproses log, str_array
dan str_ptr
akan menjadi variabel yang tidak valid.
Namun, situasi seperti ini tidak akan terjadi karena BqLog menyalin semua konten parameter ke ring_buffer
internalnya selama eksekusi fungsi info
. Setelah fungsi info
kembali, variabel eksternal seperti str_array
atau str_ptr
tidak lagi diperlukan. Selain itu, ring_buffer
tidak akan menyimpan alamat penunjuk const char*
tetapi akan selalu menyimpan seluruh string.
Potensi masalah sebenarnya muncul dalam skenario berikut:
static std::string global_str = "halo dunia"; // Ini adalah variabel global yang dimodifikasi oleh beberapa thread.void thread_a() { log_obj.info("Ini adalah parameter pengujian: {}", global_str); }
Jika konten global_str
berubah selama eksekusi fungsi info
, hal ini dapat menyebabkan perilaku tidak terdefinisi. BqLog akan melakukan yang terbaik untuk mencegah crash, namun kebenaran hasil akhir tidak dapat dijamin.
Appender mewakili target keluaran log. Konsep Appenders di bqLog pada dasarnya sama dengan di Log4j. Saat ini, bqLog menyediakan jenis Appender berikut:
Target keluaran Appender ini adalah konsol, termasuk ADB Android dan konsol terkait di iOS. Pengkodean teks adalah UTF-8.
Appender ini mengeluarkan file log secara langsung dalam format teks UTF-8.
Appender ini mengeluarkan file log dalam format terkompresi, yang merupakan highly recommended format by bqLog
. Ini memiliki kinerja tertinggi di antara semua Appender dan menghasilkan file output terkecil. Namun, file terakhir perlu didekodekan. Decoding dapat dilakukan saat decoding runtime, atau decoding offline。
Appender ini mengeluarkan konten log biner dari memori langsung ke file. Kinerjanya lebih tinggi dibandingkan TextFileAppender, namun mengkonsumsi lebih banyak ruang penyimpanan. File terakhir perlu didekodekan. Decoding dapat dilakukan saat decoding runtime, atau decoding offline. Appender ini tidak disarankan untuk digunakan.
Di bawah ini adalah perbandingan komprehensif dari berbagai Appender:
Nama | Sasaran Keluaran | Dapat Dibaca Langsung | Kinerja Keluaran | Ukuran Keluaran |
---|---|---|---|---|
ConsoleAppender | Menghibur | ✔ | Rendah | - |
TextFileAppender | Mengajukan | ✔ | Rendah | Besar |
Appender File Terkompresi | Mengajukan | ✘ | Tinggi | Kecil |
Penambah File Mentah | Mengajukan | ✘ | Sedang | Besar |
Konfigurasi mengacu pada string konfigurasi di fungsi create_log dan reset_config. String ini menggunakan format file properti dan mendukung # komentar (tapi ingat untuk memulai baris baru dengan # untuk komentar).
Di bawah ini adalah contoh lengkapnya:
# Konfigurasi ini menyiapkan objek log dengan total 5 Appender, termasuk dua TextFileAppender yang menghasilkan dua file berbeda.# Appender pertama bernama appender_0 dan tipenya adalah ConsoleAppenderappenders_config.appender_0.type=console# Zona waktu untuk appender_0 adalah timeappenders_config.appender_0.time_zone=waktu lokal default sistem# appender_0 akan menampilkan semua 6 level log (catatan: tidak boleh ada spasi di antara level log, atau akan gagal diurai)appenders_config.appender_0.levels=[verbose,debug ,info,warning,error,fatal]# Appender kedua bernama appender_1 dan tipenya adalah TextFileAppenderappenders_config.appender_1.type=text_file# Zona waktu untuk appender_1 adalah GMT, yaitu UTC+0appenders_config.appender_1.time_zone=gmt# appender_1 saja mengeluarkan log dari info level ke atas, yang lain akan diabaikanappenders_config.appender_1.levels=[info,warning,error,fatal]# Jalur untuk appender_1 akan berada di direktori relatif bqLog program, dengan nama file dimulai dengan normal, diikuti oleh tanggal dan ekstensi .log# Di iOS, akan disimpan di /var/mobile/Containers/Data/Application/[APP]/Library/Caches/bqLog# Di Android, akan disimpan di [android.content.Context .getExternalFilesDir()]/bqLogappenders_config.appender_1.file_name=bqLog/normal# Ukuran file maksimum adalah 10.000.000 byte; jika terlampaui, file baru akan dibuatappenders_config.appender_1.max_file_size=10000000# File yang lebih tua dari sepuluh hari akan dibersihkanappenders_config.appender_1.expire_time_days=10# Jika total ukuran output melebihi 100,000,000 byte, file akan dibersihkan mulai dari tertuaappenders_config.appender_1.capacity_limit=100000000# Appender ketiga bernama appender_2 dan tipenya adalah TextFileAppenderappenders_config.appender_2.type=text_file# appender_2 akan menampilkan semua level logsappenders_config.appender_2.levels=[all]# Jalur untuk appender_2 akan berada di direktori bqLog relatif program, dengan nama file dimulai dengan new_normal, diikuti dengan tanggal dan .log extensionappenders_config.appender_2.file_name=bqLog/new_normal# Opsi ini hanya efektif di Android, menyimpan log di direktori penyimpanan internal, yaitu [android .content.Context.getFilesDir()]/bqLogappenders_config.appender_2.is_in_sandbox=true# Appender keempat bernama appender_3 dan tipenya adalah CompressedFileAppenderappenders_config.appender_3.type=compressed_file# appender_3 akan menampilkan semua level logsappenders_config.appender_3.levels=[all ]# Jalur untuk appender_3 akan berada di jalur absolut ~/bqLog direktori program, dengan nama file dimulai dengan kompres_log, diikuti dengan tanggal dan .logcompr extensionappenders_config.appender_3.file_name=~/bqLog/compress_log# Appender kelima diberi nama appender_4 dan tipenya adalah RawFileAppenderappenders_config.appender_4.type=raw_file# appender_4 dinonaktifkan secara default dan dapat diaktifkan nanti menggunakan set_appenders_enableappenders_config.appender_4.enable=false# appender_4 akan menampilkan semua level logsappenders_config.appender_4.levels=[all]# Jalur untuk appender_4 akan berada di direktori relatif bqLog program, dengan nama file dimulai dengan raw_log, diikuti dengan tanggal dan .lograw extensionappenders_config.appender_4.file_name=bqLog/raw_log# Log hanya akan diproses jika kategorinya dimulai dengan ModuleA, ModuleB. SystemC, jika tidak semua akan diabaikan (konsep Kategori dijelaskan secara rinci dalam topik penggunaan lanjutan nanti)appenders_config.appender_4.categories_mask=[ModuleA,ModuleB.SystemC]# Total ukuran buffer asinkron adalah 65535 byte; arti spesifiknya dijelaskan nantilog.buffer_size=65535# Tingkat keandalan log adalah normal; arti spesifiknya dijelaskan nantilog.reliable_level=normal# Log hanya akan diproses jika kategorinya cocok dengan tiga wildcard berikut, jika tidak semua akan diabaikan (konsep Kategori dijelaskan secara rinci dalam topik penggunaan lanjutan nanti)log.categories_mask= [*default,ModuleA,ModuleB.SystemC]# Ini adalah log asinkron; log asinkron adalah log yang berkinerja tertinggi dan direkomendasikan typelog.thread_mode=async# Jika level log error atau fatal, sertakan informasi tumpukan panggilan dengan setiap entri log.print_stack_levels=[error,fatal]# Aktifkan fungsionalitas snapshot, ukuran cache snapshot adalah 64Ksnapshot .buffer_size=65536# Hanya log dengan info dan tingkat kesalahan yang akan dicatat dalam snapshotsnapshot.levels=[info,error]# Hanya log yang kategorinya dimulai dengan ModuleA, ModuleB.SystemC yang akan dicatat dalam snapshot, jika tidak log tersebut akan diabaikansnapshot .categories_mask=[ModuleA.SystemA.ClassA,ModuleB]
appenders_config
adalah sekumpulan konfigurasi untuk Appenders. Parameter pertama setelah appenders_config
adalah nama Appender, dan semua Appender dengan nama yang sama memiliki konfigurasi yang sama.
Nama | Diperlukan | Nilai yang Dapat Dikonfigurasi | Bawaan | Berlaku untuk ConsoleAppender | Berlaku untuk TextFileAppender | Berlaku untuk CompressedFileAppender | Berlaku untuk RawFileAppender |
---|---|---|---|---|---|---|---|
jenis | ✔ | konsol, file_teks, file_terkompresi, file_mentah | ✔ | ✔ | ✔ | ✔ | |
memungkinkan | ✘ | Apakah Appender diaktifkan secara default | BENAR | ✔ | ✔ | ✔ | ✔ |
tingkat | ✘ | Array level log | [semua] | ✔ | ✔ | ✔ | ✔ |
zona_waktu | ✘ | gmt atau string lainnya | Waktu setempat | ✔ | ✔ | ✔ | ✔ |
nama_file | ✔ | Jalur relatif atau absolut | ✘ | ✔ | ✔ | ✔ | |
is_in_sandbox | ✘ | benar, salah | PALSU | ✘ | ✔ | ✔ | ✔ |
ukuran_file_maks | ✘ | Bilangan bulat positif atau 0 | 0 | ✘ | ✔ | ✔ | ✔ |
kadaluarsa_waktu_hari | ✘ | Bilangan bulat positif atau 0 | 0 | ✘ | ✔ | ✔ | ✔ |
kapasitas_batas | ✘ | Bilangan bulat positif atau 0 | 0 | ✘ | ✔ | ✔ | ✔ |
kategori_mask | ✘ | Array string yang diapit [] | Kosong | ✔ | ✔ | ✔ | ✔ |
Menentukan jenis Appender.
console
: Mewakili ConsoleAppender
text_file
: Mewakili TextFileAppender
compressed_file
: Mewakili CompressedFileAppender
raw_file
: Mewakili RawFileAppender
Defaultnya adalah true
. Jika disetel ke false
, Appender akan dinonaktifkan secara default dan dapat diaktifkan nanti menggunakan set_appenders_enable
.
Array yang diapit []
, berisi kombinasi verbose
, debug
, info
, warning
, error
, fatal
, atau [all]
untuk menerima semua level. Catatan: Jangan sertakan spasi antar level, jika tidak maka akan gagal diuraikan.
Menentukan zona waktu log. gmt
mewakili Greenwich Mean Time (UTC+0), dan string lainnya atau membiarkannya kosong akan menggunakan zona waktu lokal. Zona waktu mempengaruhi dua hal:
Stempel waktu log teks yang diformat (berlaku untuk ConsoleAppender dan TextFileAppender)
File log baru akan dibuat ketika tengah malam terlewati dalam zona waktu yang ditentukan (berlaku untuk TextFileAppender, CompressedFileAppender, dan RawFileAppender).
Awalan jalur dan nama file untuk menyimpan file. Jalurnya bisa bersifat absolut (tidak disarankan untuk Android dan iOS) atau relatif. Nama file keluaran akhir adalah jalur dan nama ini, diikuti dengan tanggal, nomor file, dan ekstensi Appender.
Hanya bermakna di Android:
true
: File disimpan di direktori Penyimpanan Internal (android.content.Context.getFilesDir()). Jika tidak tersedia, file tersebut disimpan di direktori Penyimpanan Eksternal (android.content.Context.getExternalFilesDir()). Jika itu juga tidak tersedia, mereka disimpan di direktori Cache (android.content.Context.getCacheDir()).
false
: File disimpan di direktori Penyimpanan Eksternal secara default. Jika tidak tersedia, disimpan di direktori Penyimpanan Internal. Jika itu juga tidak tersedia, maka disimpan di direktori Cache.
Ukuran file maksimum dalam byte. Ketika file yang disimpan melebihi ukuran ini, file log baru dibuat, dengan nomor file bertambah secara berurutan. 0
menonaktifkan fitur ini.
Jumlah hari maksimum untuk menyimpan file. File yang lebih lama dari ini akan dihapus secara otomatis. 0
menonaktifkan fitur ini.
Ukuran total maksimum file yang dihasilkan oleh Appender ini di direktori keluaran. Jika batas ini terlampaui, file akan dihapus mulai dari yang terlama hingga ukuran totalnya sesuai batas. 0
menonaktifkan fitur ini.
Jika objek log adalah objek Log yang mendukung kategori, ini dapat digunakan untuk memfilter daftar kategori yang mirip pohon. Jika array tidak kosong, fitur ini aktif. Misalnya, [*default,ModuleA,ModuleB.SystemC]
berarti log dengan kategori default