OpenTelemetry Logs for C++

Prerequisites

Make sure your exporter is configured before you start instrumenting code. Follow Getting started with OpenTelemetry C++ or set up OTLP Configuration first.

If you are not familiar with logs terminology, read the introduction to OpenTelemetry Logs first.

Overview

OpenTelemetry C++ provides a native Logs API for emitting structured log records. The Logs API integrates with the tracing system to automatically correlate logs with traces.

Configuration

cpp
#include <cstdlib>
#include "opentelemetry/exporters/otlp/otlp_http_log_record_exporter_factory.h"
#include "opentelemetry/exporters/otlp/otlp_http_log_record_exporter_options.h"
#include "opentelemetry/sdk/logs/logger_provider_factory.h"
#include "opentelemetry/sdk/logs/simple_log_record_processor_factory.h"
#include "opentelemetry/logs/provider.h"

namespace otlp = opentelemetry::exporter::otlp;
namespace logs_sdk = opentelemetry::sdk::logs;
namespace logs_api = opentelemetry::logs;

void InitLogger() {
    otlp::OtlpHttpLogRecordExporterOptions opts;
    opts.url = "https://api.uptrace.dev/v1/logs";

    const char* dsn = std::getenv("UPTRACE_DSN");
    opts.http_headers = {{"uptrace-dsn", dsn ? dsn : ""}};

    auto exporter = otlp::OtlpHttpLogRecordExporterFactory::Create(opts);
    auto processor = logs_sdk::SimpleLogRecordProcessorFactory::Create(
        std::move(exporter));

    std::shared_ptr<logs_api::LoggerProvider> provider =
        logs_sdk::LoggerProviderFactory::Create(std::move(processor));
    logs_api::Provider::SetLoggerProvider(provider);
}

Emitting logs

cpp
auto logger = logs_api::Provider::GetLoggerProvider()
    ->GetLogger("myservice", "1.0.0");

logger->EmitLogRecord(
    logs_api::Severity::kInfo,
    "Application started successfully"
);

Severity levels

cpp
logger->EmitLogRecord(logs_api::Severity::kTrace, "Trace message");
logger->EmitLogRecord(logs_api::Severity::kDebug, "Debug message");
logger->EmitLogRecord(logs_api::Severity::kInfo, "Info message");
logger->EmitLogRecord(logs_api::Severity::kWarn, "Warning message");
logger->EmitLogRecord(logs_api::Severity::kError, "Error message");
logger->EmitLogRecord(logs_api::Severity::kFatal, "Fatal message");

Log-trace correlation

When you emit a log within an active trace span, OpenTelemetry automatically includes:

  • trace_id: Links log to the entire distributed trace
  • span_id: Links log to the specific operation
cpp
#include "opentelemetry/trace/provider.h"
#include "opentelemetry/logs/provider.h"

namespace trace_api = opentelemetry::trace;
namespace logs_api = opentelemetry::logs;

void processRequest() {
    auto tracer = trace_api::Provider::GetTracerProvider()->GetTracer("myservice");
    auto logger = logs_api::Provider::GetLoggerProvider()->GetLogger("myservice");

    auto span = tracer->StartSpan("process-request");
    auto scope = tracer->WithActiveSpan(span);

    // Logs are automatically correlated with the span
    logger->EmitLogRecord(logs_api::Severity::kInfo, "Processing request");

    span->End();
}

Complete example

cpp
#include <cstdlib>
#include "opentelemetry/exporters/otlp/otlp_http_log_record_exporter_factory.h"
#include "opentelemetry/exporters/otlp/otlp_http_log_record_exporter_options.h"
#include "opentelemetry/sdk/logs/logger_provider_factory.h"
#include "opentelemetry/sdk/logs/logger_provider.h"
#include "opentelemetry/sdk/logs/simple_log_record_processor_factory.h"
#include "opentelemetry/logs/provider.h"

namespace otlp = opentelemetry::exporter::otlp;
namespace logs_sdk = opentelemetry::sdk::logs;
namespace logs_api = opentelemetry::logs;

void InitLogger() {
    otlp::OtlpHttpLogRecordExporterOptions opts;
    opts.url = "https://api.uptrace.dev/v1/logs";

    const char* dsn = std::getenv("UPTRACE_DSN");
    opts.http_headers = {{"uptrace-dsn", dsn ? dsn : ""}};

    auto exporter = otlp::OtlpHttpLogRecordExporterFactory::Create(opts);
    auto processor = logs_sdk::SimpleLogRecordProcessorFactory::Create(
        std::move(exporter));

    std::shared_ptr<logs_api::LoggerProvider> provider =
        logs_sdk::LoggerProviderFactory::Create(std::move(processor));
    logs_api::Provider::SetLoggerProvider(provider);
}

void CleanupLogger() {
    auto provider = logs_api::Provider::GetLoggerProvider();
    if (provider) {
        static_cast<logs_sdk::LoggerProvider*>(provider.get())->ForceFlush();
    }
    std::shared_ptr<logs_api::LoggerProvider> none;
    logs_api::Provider::SetLoggerProvider(none);
}

int main() {
    InitLogger();

    auto logger = logs_api::Provider::GetLoggerProvider()
        ->GetLogger("myservice", "1.0.0");

    logger->EmitLogRecord(logs_api::Severity::kInfo, "Application started");

    CleanupLogger();
    return 0;
}

What's next?