LogIt++
Header-only, macro-first C++ logging library
Loading...
Searching...
No Matches
example_logit_mdbx_logger.cpp
Go to the documentation of this file.
1
4
5// #define LOGIT_BASE_PATH "E:\\_repoz\\log-it-cpp" <- set via CMake
6
7#include <logit.hpp>
8
9#ifdef LOGIT_WITH_MDBX
10
11#include <chrono>
12#include <cstdio>
13#include <ctime>
14#include <iomanip>
15#include <iostream>
16#include <sstream>
17#include <vector>
18
19namespace {
20
21std::string make_db_path() {
22 std::ostringstream os;
23 os << logit::get_exec_dir() << "/example_mdbx_logger_" << LOGIT_CURRENT_TIMESTAMP_MS() << ".mdbx";
24 return os.str();
25}
26
27void cleanup_db(const std::string& path) {
28 std::remove(path.c_str());
29 std::remove((path + "-lck").c_str());
30}
31
32} // namespace
33
34int main() {
35 const std::string db_path = make_db_path();
36 cleanup_db(db_path);
37
38 std::cout << "MdbxLogger example starting, db=" << db_path << std::endl;
39
40 // ------------------------------------------------------------------
41 // 1. Configure and add the MDBX backend
42 // ------------------------------------------------------------------
43 logit::MdbxLogger::Config mdbx_config;
44 mdbx_config.path = db_path;
45 mdbx_config.app_name = "example-mdbx";
46 mdbx_config.async = true;
47 mdbx_config.max_queue_size = 256;
48 mdbx_config.max_batch_size = 32;
49 mdbx_config.large_payload_threshold = 256;
50 mdbx_config.store_large_payloads_separately = true;
51
52 // Optional: capture write errors instead of writing to stderr
53 mdbx_config.on_error = [](const std::string& msg) {
54 std::cerr << "[MdbxLogger error callback] " << msg << std::endl;
55 };
56
57 // Add a console logger for live observation (optional).
59
60 // Add to the registry as a regular backend so standard LOGIT_* macros
61 // write both to MDBX and to the console logger above.
64 (mdbx_config),
66 ("[%l] %v"));
67
68 // The MDBX logger is now the last added backend; its index is:
69 const int mdbx_index = static_cast<int>(logit::Logger::get_instance().logger_count()) - 1;
70
71 // ------------------------------------------------------------------
72 // 2. Log messages via standard macros
73 // ------------------------------------------------------------------
74 LOGIT_INFO("Application started");
75 LOGIT_WARN("Disk usage is above 80%%");
76
77 {
78 LOGIT_SCOPE_INFO("process_batch");
79 LOGIT_INFO("Processing 42 items");
80 LOGIT_DEBUG("Detail: item id=7, status=pending");
81
82 // This message is larger than large_payload_threshold and will spill
83 // into the separate log_payloads table with a preview kept inline.
84 std::string big;
85 big.reserve(512);
86 for (int i = 0; i < 50; ++i) {
87 big += "chunk-" + std::to_string(i) + " ";
88 }
89 LOGIT_INFO(big);
90 }
91
92 LOGIT_ERROR("Connection timeout to upstream-3");
93 LOGIT_FATAL("Critical: unable to recover transaction state");
94
95 // Wait until the async queue is flushed.
96 LOGIT_WAIT();
97
98 // ------------------------------------------------------------------
99 // 3. Read through the common ILogReader API, then use MDBX-only extras
100 // ------------------------------------------------------------------
101 LOGIT_WITH_LOGGER_AS(mdbx_index, logit::MdbxLogger, mdbx) {
102 // Session metadata
103 auto session_opt = mdbx->read_session(mdbx->session_id());
104 if (session_opt) {
105 std::cout << "\n--- Session ---" << std::endl;
106 std::cout << " app_name: " << session_opt->app_name << std::endl;
107 std::cout << " process_id: " << session_opt->process_id << std::endl;
108 std::cout << " started_ms: " << session_opt->start_time_ms << std::endl;
109 std::cout << " schema_ver: " << session_opt->schema_version << std::endl;
110 }
111
112 // The LOGIT_READ_* macros work with both MemoryLogger and MdbxLogger.
113 // All records in a wide time window (last 24 hours).
114 const int64_t now_ms = LOGIT_CURRENT_TIMESTAMP_MS();
115 auto all_records = LOGIT_READ_RANGE(
116 mdbx_index,
117 now_ms - 24LL * 60 * 60 * 1000,
118 now_ms + 1,
119 0);
120
121 std::cout << "\n--- All records (" << all_records.size() << ") ---" << std::endl;
122 for (const auto& r : all_records) {
123 std::cout << " [" << logit::to_string(r.level) << "] "
124 << r.timestamp_ms << " seq=" << r.sequence
125 << " msg=\"" << r.message << "\"";
126 if (r.payload_id != 0) {
127 std::cout << " [payload_id=" << r.payload_id << "]";
128 }
129 std::cout << std::endl;
130 }
131
132 // Level-based client-side filter
133 std::cout << "\n--- Records with level >= WARN ---" << std::endl;
134 for (const auto& r : all_records) {
135 if (static_cast<int>(r.level) >= static_cast<int>(logit::LogLevel::LOG_LVL_WARN)) {
136 std::cout << " [" << logit::to_string(r.level) << "] "
137 << r.timestamp_ms << " " << r.message << std::endl;
138 }
139 }
140
141 // Spilled payloads (decompressed transparently)
142 std::cout << "\n--- Spilled payloads ---" << std::endl;
143 for (const auto& r : all_records) {
144 if (r.payload_id != 0) {
145 auto data_opt = mdbx->read_payload_data(r.payload_id);
146 if (data_opt) {
147 std::cout << " payload_id=" << r.payload_id
148 << " size=" << data_opt->size()
149 << " preview=\"" << r.message << "\""
150 << std::endl;
151 } else {
152 std::cout << " payload_id=" << r.payload_id << " FAILED to read/decompress"
153 << std::endl;
154 }
155 }
156 }
157
158 // Query by today's local midnight
159 try {
160 auto now_local = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
161 std::tm* tm_now = std::localtime(&now_local);
162 std::tm tm_midnight = *tm_now;
163 tm_midnight.tm_hour = 0;
164 tm_midnight.tm_min = 0;
165 tm_midnight.tm_sec = 0;
166 std::time_t midnight_t = std::mktime(&tm_midnight);
167
168 auto today_ms = std::chrono::milliseconds(static_cast<int64_t>(midnight_t) * 1000);
169 auto tomorrow_ms = today_ms + std::chrono::hours(24);
170
171 auto day_records = LOGIT_READ_RANGE(
172 mdbx_index,
173 today_ms.count(),
174 tomorrow_ms.count(),
175 0);
176
177 std::cout << "\n--- Records for today (" << day_records.size() << ") ---" << std::endl;
178 for (const auto& r : day_records) {
179 std::cout << " [" << logit::to_string(r.level) << "] "
180 << r.timestamp_ms << " " << r.message << std::endl;
181 }
182 } catch (const std::exception& e) {
183 std::cerr << "Date query example skipped: " << e.what() << std::endl;
184 }
185
186 // read_recent: last 100 records in ascending order, through ILogReader.
187 auto recent = LOGIT_READ_RECENT_ASC(mdbx_index, 100, 0);
188 std::cout << "\n--- LOGIT_READ_RECENT_ASC(100) (" << recent.size() << ") ---" << std::endl;
189 for (const auto& r : recent) {
190 std::cout << " [" << logit::to_string(r.level) << "] "
191 << r.timestamp_ms << " " << r.message << std::endl;
192 }
193
194 // Live subscription: the LOGIT_* callback macros also work with both
195 // MemoryLogger and MdbxLogger.
196 std::vector<logit::LogRecordSnapshot> live_updates;
197 const uint64_t cb_id = LOGIT_ADD_LOG_CALLBACK(
198 mdbx_index,
199 ([&live_updates](const logit::LogRecordSnapshot& v) {
200 live_updates.push_back(v);
201 }));
202
203 LOGIT_INFO("Live event 1 via callback");
204 LOGIT_INFO("Live event 2 via callback");
205 LOGIT_WAIT();
206
207 std::cout << "\n--- Live updates received (" << live_updates.size()
208 << ") ---" << std::endl;
209 for (const auto& r : live_updates) {
210 std::cout << " [" << logit::to_string(r.level) << "] "
211 << r.message << std::endl;
212 }
213
214 if (LOGIT_REMOVE_LOG_CALLBACK(mdbx_index, cb_id)) {
215 std::cout << "Callback removed" << std::endl;
216 }
217
218 LOGIT_INFO("Event after unsubscribe");
219 LOGIT_WAIT();
220 std::cout << "Live updates after unsubscribe: " << live_updates.size()
221 << std::endl;
222
223 // Statistics
224 std::cout << "\n--- Statistics ---" << std::endl;
225 std::cout << " dropped: " << mdbx->dropped_count() << std::endl;
226 std::cout << " failed_writes: " << mdbx->failed_export_count() << std::endl;
227 } else {
228 std::cerr << "MDBX logger not found at index " << mdbx_index << std::endl;
230 cleanup_db(db_path);
231 return 1;
232 }
233
234 // ------------------------------------------------------------------
235 // 5. Graceful shutdown and cleanup
236 // ------------------------------------------------------------------
238
239 // After shutdown the session end_time_ms is persisted.
240 LOGIT_WITH_LOGGER_AS(mdbx_index, logit::MdbxLogger, mdbx) {
241 auto session_opt = mdbx->read_session(mdbx->session_id());
242 if (session_opt) {
243 std::cout << " session end_ms: " << session_opt->end_time_ms << std::endl;
244 }
245 }
246
247 cleanup_db(db_path);
248 std::cout << "\nMdbxLogger example completed." << std::endl;
249 return 0;
250}
251
252#else
253
254#include <iostream>
255
256int main() {
257 std::cout << "MdbxLogger example requires LOGIT_WITH_MDBX=ON." << std::endl;
258 return 0;
259}
260
261#endif
static Logger & get_instance()
Retrieves singleton instance of Logger.
Definition Logger.hpp:53
std::size_t logger_count() const
Returns the number of registered logger strategies.
Definition Logger.hpp:507
Stores formatted logs in MDBX tables with optional async batching.
A simple log formatter that formats log messages based on a user-defined pattern.
#define LOGIT_CURRENT_TIMESTAMP_MS()
Macro to get the current timestamp in milliseconds.
Definition config.hpp:84
#define LOGIT_ADD_CONSOLE_DEFAULT()
Macro for adding the default console logger.
#define LOGIT_WAIT()
Macro for waiting for all asynchronous loggers to finish processing.
#define LOGIT_WITH_LOGGER_AS(logger_index, logger_type, var_name)
Executes a code block when the logger backend has the requested type.
#define LOGIT_ERROR(...)
#define LOGIT_INFO(...)
#define LOGIT_DEBUG(...)
#define LOGIT_SHUTDOWN()
Macro for shutting down logger system.
#define LOGIT_WARN(...)
#define LOGIT_FATAL(...)
#define LOGIT_ADD_LOG_CALLBACK(logger_index, callback)
Registers a callback to receive newly written log records.
#define LOGIT_READ_RECENT_ASC(logger_index, limit, period_ms)
Reads recent records in ascending order (oldest first).
#define LOGIT_REMOVE_LOG_CALLBACK(logger_index, callback_id)
Unregisters a previously added log callback.
#define LOGIT_SCOPE_INFO(phase)
#define LOGIT_ADD_LOGGER(logger_type, logger_args, formatter_type, formatter_args)
Macro for adding a logger with a specific formatter.
#define LOGIT_READ_RANGE(logger_index, from_ms, to_ms, limit)
Reads a time-range of records from a backend that supports ILogReader.
Unified umbrella header for the LogIt++ library.
std::string to_string(LogLevel level, int mode=0)
Convert LogLevel to a std::string representation.
Definition enums.hpp:109
@ LOG_LVL_WARN
Warning level logging.
std::string get_exec_dir()
Retrieves the directory of the executable file.
Common owning snapshot of a stored log record.
Configuration for the MDBX logger backend.
bool store_large_payloads_separately
Store large messages in log_payloads.
std::size_t max_batch_size
Maximum records per write transaction.
std::size_t max_queue_size
Maximum async queue size; 0 means unlimited.
std::function< void(const std::string &)> on_error
Optional callback invoked on initialization and write errors instead of stderr.
std::string path
MDBX environment path.
bool async
Queue records and write them from a worker thread.
std::size_t large_payload_threshold
Spill messages larger than this.
std::string app_name
Optional application name stored in session metadata.