2#ifndef LOGIT_CPP_HEADER_LOGIT_CPP_LOGIT_LOGGERS_OTLPHTTPLOGGER_HPP_INCLUDED
3#define LOGIT_CPP_HEADER_LOGIT_CPP_LOGIT_LOGGERS_OTLPHTTPLOGGER_HPP_INCLUDED
9# error "OtlpHttpLogger requires LOGIT_WITH_OTLP=1 and the optional kurlyk dependency. Enable LOGIT_WITH_OTLP in CMake."
19#ifndef KURLYK_WEBSOCKET_SUPPORT
20# define KURLYK_WEBSOCKET_SUPPORT 0
22#ifndef KURLYK_HTTP_SUPPORT
23# define KURLYK_HTTP_SUPPORT 1
29#include <condition_variable>
43 std::condition_variable
cv;
61 std::string
host =
"http://localhost:4318";
62 std::string
path =
"/v1/logs";
88 m_config.max_in_flight_requests = 1;
90 m_client.set_content_type(
"application/json");
95#if !defined(LOGIT_HAS_ZLIB)
96 throw std::runtime_error(
"OtlpHttpLogger: gzip compression requested but LOGIT_WITH_GZIP is not enabled");
100#if !defined(LOGIT_HAS_ZSTD)
101 throw std::runtime_error(
"OtlpHttpLogger: zstd compression requested but LOGIT_WITH_ZSTD is not enabled");
106 m_worker = std::thread(&OtlpHttpLogger::worker_loop, this);
121 void log(
const LogRecord& record,
const std::string& message)
override {
135 std::vector<OtlpLogItem> batch;
136 batch.push_back(item);
146 std::unique_lock<std::mutex> lock(
m_state->mutex);
158 lifecycle_lock.unlock();
159 m_state->space_cv.wait(lock, [
this]() {
163 lifecycle_lock.lock();
173 m_state->queue.push_back(item);
186 std::unique_lock<std::mutex> lock(
m_state->mutex);
187 m_state->cv.wait(lock, [
this]() {
209 return std::string();
267 return m_state->failed_exports.load();
286 std::vector<OtlpLogItem> batch;
290 std::unique_lock<std::mutex> lock(
m_state->mutex);
295 const bool can_submit =
296 !m_state->queue.empty() &&
297 m_state->http_in_flight < m_config.max_in_flight_requests;
299 const bool can_stop_now =
301 (m_config.cancel_on_shutdown ||
302 (m_state->queue.empty() && m_state->http_in_flight == 0));
304 return can_submit || can_stop_now;
321 batch.push_back(
m_state->queue.front());
325 m_state->space_cv.notify_all();
328 if (!batch.empty()) {
340 if (chunks.empty()) {
344 kurlyk::Headers headers;
345 headers.emplace(
"Content-Type",
"application/json");
347 auto weak_state = std::weak_ptr<OtlpHttpLoggerState>(
m_state);
349 for (
auto& chunk : chunks) {
350 std::string post_content;
351 kurlyk::Headers chunk_headers = headers;
357 m_state->failed_exports.fetch_add(1);
358 post_content = std::move(chunk);
360 chunk_headers.emplace(
"Content-Encoding",
"gzip");
366 m_state->failed_exports.fetch_add(1);
367 post_content = std::move(chunk);
369 chunk_headers.emplace(
"Content-Encoding",
"zstd");
372 post_content = std::move(chunk);
376 std::unique_lock<std::mutex> lock(
m_state->mutex);
377 m_state->cv.wait(lock, [
this]() {
383 m_state->failed_exports.fetch_add(1);
390 bool submitted =
false;
394 m_config.
path, {}, chunk_headers, std::move(post_content),
395 [weak_state](kurlyk::HttpResponsePtr response) {
396 auto state = weak_state.lock();
401 std::lock_guard<std::mutex> lock(state->mutex);
402 if (!response || response->status_code < 200 || response->status_code >= 300) {
403 state->failed_exports.fetch_add(1);
405 if (state->http_in_flight > 0) {
406 --state->http_in_flight;
408 state->cv.notify_all();
416 std::lock_guard<std::mutex> lock(state->mutex);
417 state->failed_exports.fetch_add(1);
418 if (state->http_in_flight > 0) {
419 --state->http_in_flight;
421 state->cv.notify_all();
429 std::lock_guard<std::mutex> lifecycle_lock(m_lifecycle_mutex);
430 std::lock_guard<std::mutex> lock(m_state->mutex);
431 if (m_state->stopping) {
434 m_state->stopping =
true;
437 m_dropped.fetch_add(m_state->queue.size());
438 m_state->queue.clear();
439 m_state->space_cv.notify_all();
445 m_client.cancel_requests();
450 m_state->cv.notify_all();
451 m_state->space_cv.notify_all();
453 if (m_worker.joinable()) {
459 m_client.wait_requests();
468 return m_last_log_ts.load();
474 const int64_t last = get_last_log_ts();
479 return now > last ? now - last : 0;
486 const uint64_t max_value =
static_cast<uint64_t
>((std::numeric_limits<int64_t>::max)());
487 return value > max_value ? (std::numeric_limits<int64_t>::max)() :
static_cast<int64_t
>(value);
Shared gzip/zstd compression helpers used by OTLP and MDBX backends.
Defines the interface for loggers used in the logging system.
Compression algorithm selected for OTLP/HTTP payloads.
Defines OTLP/HTTP JSON serialization helpers for logs.
Splits oversized OTLP log batches into multiple JSON payload chunks.
Optional buffered snapshot access returns empty results by default.
Exports logs to an OTLP/HTTP endpoint using kurlyk.
std::thread m_worker
Export worker thread.
kurlyk::HttpClient m_client
HTTP client used for OTLP export.
int64_t get_int_param(const LoggerParam ¶m) const override
Retrieves an integer parameter from the logger.
OtlpHttpLogger(const OtlpHttpLogger &)=delete
uint64_t dropped_count() const
Returns number of dropped records.
void wait() override
Waits until queued and in-flight exports finish.
double get_float_param(const LoggerParam ¶m) const override
Retrieves a floating-point parameter from the logger.
OtlpHttpLogger()
Constructs OTLP HTTP logger with default configuration.
Config m_config
Export configuration.
void log(const LogRecord &record, const std::string &message) override
Queues or exports a log message.
LogLevel get_log_level() const override
Gets minimal log level for this logger.
std::mutex m_lifecycle_mutex
Serializes log() with shutdown.
OtlpHttpLogger & operator=(const OtlpHttpLogger &)=delete
int64_t get_time_since_last_log() const
Returns elapsed time since last log.
std::atomic< int64_t > m_last_log_ts
void submit_batch_async(const std::vector< OtlpLogItem > &batch)
Submits one batch asynchronously, splitting into payload chunks.
std::atomic< int > m_log_level
std::string get_string_param(const LoggerParam ¶m) const override
Retrieves a string parameter from the logger.
void worker_loop()
Worker thread loop.
uint64_t failed_export_count() const
Returns number of failed export attempts.
~OtlpHttpLogger() override
Stops worker and cancels pending HTTP requests.
int64_t get_last_log_ts() const
Returns last log timestamp.
OtlpHttpLogger(const Config &config)
Constructs OTLP HTTP logger with custom configuration.
std::atomic< uint64_t > m_dropped
void set_log_level(LogLevel level) override
Sets minimal log level for this logger.
void stop()
Stops worker and cancels pending requests.
std::shared_ptr< OtlpHttpLoggerState > m_state
static int64_t counter_to_int64(uint64_t value)
Converts unsigned counter value to int64_t with saturation.
void shutdown() override
Stops the OTLP worker after draining queued exports.
#define LOGIT_CURRENT_TIMESTAMP_MS()
Macro to get the current timestamp in milliseconds.
bool compress_string_gzip(const std::string &input, std::string &output, int level)
Compress a string with gzip.
bool compress_string_zstd(const std::string &input, std::string &output, int level)
Compress a string with zstd.
The primary namespace for the LogIt++ library.
OtlpCompression
Compression algorithm used for an OTLP/HTTP request payload.
@ LOG_LVL_TRACE
Trace level logging.
std::vector< std::string > build_otlp_logs_json_payload_chunks(const std::vector< OtlpLogItem > &batch, const OtlpJsonFormatConfig &format, std::size_t max_payload_bytes)
Builds OTLP JSON payload chunks from a batch, splitting when a chunk would exceed max_payload_bytes.
OtlpRecordSnapshot make_otlp_record_snapshot(const LogRecord &record)
Creates an owned snapshot from a LogRecord.
LoggerParam
Enumeration for different logger parameters that can be retrieved.
@ TimeSinceLastLog
The time elapsed since the last log in seconds.
@ LastLogTimestamp
The timestamp of the last log.
@ DroppedLogCount
Number of log records dropped by the backend.
@ FailedExportCount
Number of failed export attempts reported by the backend.
Stores log metadata and content.
const int64_t timestamp_ms
Timestamp in milliseconds.
std::condition_variable space_cv
std::condition_variable cv
std::deque< OtlpLogItem > queue
std::atomic< uint64_t > failed_exports
std::size_t http_in_flight
std::size_t max_in_flight_requests
OtlpCompression compression
OtlpJsonFormatConfig format
std::size_t max_payload_bytes
std::size_t max_queue_size
std::size_t max_batch_size
Owns one formatted log message and its structured metadata.
OtlpRecordSnapshot record
Structured log metadata snapshot.
std::string message
Formatted message body.