Exporters
Send telemetry to the OpenTelemetry Collector to make sure it’s exported correctly. Using the Collector in production environments is a best practice. To visualize your telemetry, export it to a backend such as Jaeger, Zipkin, Prometheus, or a vendor-specific backend.
Available exporters
The registry contains a list of exporters for C++.
Among exporters, OpenTelemetry Protocol (OTLP) exporters are designed with the OpenTelemetry data model in mind, emitting OTel data without any loss of information. Furthermore, many tools that operate on telemetry data support OTLP (such as Prometheus, Jaeger, and most vendors), providing you with a high degree of flexibility when you need it. To learn more about OTLP, see OTLP Specification.
This page covers the main OpenTelemetry C++ exporters and how to set them up.
OTLP
Collector Setup
Note
If you have a OTLP collector or backend already set up, you can skip this section and setup the OTLP exporter dependencies for your application.
To try out and verify your OTLP exporters, you can run the collector in a docker container that writes telemetry directly to the console.
In an empty directory, create a file called collector-config.yaml
with the
following content:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
exporters:
debug:
verbosity: detailed
service:
pipelines:
traces:
receivers: [otlp]
exporters: [debug]
metrics:
receivers: [otlp]
exporters: [debug]
logs:
receivers: [otlp]
exporters: [debug]
Now run the collector in a docker container:
docker run -p 4317:4317 -p 4318:4318 --rm -v $(pwd)/collector-config.yaml:/etc/otelcol/config.yaml otel/opentelemetry-collector
This collector is now able to accept telemetry via OTLP. Later you may want to configure the collector to send your telemetry to your observability backend.
Dependencies
If you want to send telemetry data to an OTLP endpoint (like the OpenTelemetry Collector, Jaeger or Prometheus), you can choose between two different protocols to transport your data:
- HTTP/protobuf
- gRPC
Make sure that you have set the right cmake build variables while building OpenTelemetry C++ from source:
-DWITH_OTLP_GRPC=ON
: To enable building OTLP gRPC exporter.-DWITH_OTLP_HTTP=ON
: To enable building OTLP HTTP exporter.
Usage
Next, configure the exporter to point at an OTLP endpoint in your code.
#include "opentelemetry/exporters/otlp/otlp_http_exporter_factory.h"
#include "opentelemetry/exporters/otlp/otlp_http_exporter_options.h"
#include "opentelemetry/sdk/trace/processor.h"
#include "opentelemetry/sdk/trace/batch_span_processor_factory.h"
#include "opentelemetry/sdk/trace/batch_span_processor_options.h"
#include "opentelemetry/sdk/trace/tracer_provider_factory.h"
#include "opentelemetry/trace/provider.h"
#include "opentelemetry/sdk/trace/tracer_provider.h"
#include "opentelemetry/exporters/otlp/otlp_http_metric_exporter_factory.h"
#include "opentelemetry/exporters/otlp/otlp_http_metric_exporter_options.h"
#include "opentelemetry/metrics/provider.h"
#include "opentelemetry/sdk/metrics/aggregation/default_aggregation.h"
#include "opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader.h"
#include "opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader_factory.h"
#include "opentelemetry/sdk/metrics/meter_context_factory.h"
#include "opentelemetry/sdk/metrics/meter_provider.h"
#include "opentelemetry/sdk/metrics/meter_provider_factory.h"
#include "opentelemetry/exporters/otlp/otlp_http_log_record_exporter_factory.h"
#include "opentelemetry/exporters/otlp/otlp_http_log_record_exporter_options.h"
#include "opentelemetry/logs/provider.h"
#include "opentelemetry/sdk/logs/logger_provider_factory.h"
#include "opentelemetry/sdk/logs/processor.h"
#include "opentelemetry/sdk/logs/simple_log_record_processor_factory.h"
namespace trace_api = opentelemetry::trace;
namespace trace_sdk = opentelemetry::sdk::trace;
namespace metric_sdk = opentelemetry::sdk::metrics;
namespace metrics_api = opentelemetry::metrics;
namespace otlp = opentelemetry::exporter::otlp;
namespace logs_api = opentelemetry::logs;
namespace logs_sdk = opentelemetry::sdk::logs;
void InitTracer()
{
trace_sdk::BatchSpanProcessorOptions bspOpts{};
otlp::OtlpHttpExporterOptions opts;
opts.url = "http://localhost:4318/v1/traces";
auto exporter = otlp::OtlpHttpExporterFactory::Create(opts);
auto processor = trace_sdk::BatchSpanProcessorFactory::Create(std::move(exporter), bspOpts);
std::shared_ptr<trace_api::TracerProvider> provider = trace_sdk::TracerProviderFactory::Create(std::move(processor));
trace_api::Provider::SetTracerProvider(provider);
}
void InitMetrics()
{
otlp::OtlpHttpMetricExporterOptions opts;
opts.url = "http://localhost:4318/v1/metrics";
auto exporter = otlp::OtlpHttpMetricExporterFactory::Create(opts);
metric_sdk::PeriodicExportingMetricReaderOptions reader_options;
reader_options.export_interval_millis = std::chrono::milliseconds(1000);
reader_options.export_timeout_millis = std::chrono::milliseconds(500);
auto reader = metric_sdk::PeriodicExportingMetricReaderFactory::Create(std::move(exporter), reader_options);
auto context = metric_sdk::MeterContextFactory::Create();
context->AddMetricReader(std::move(reader));
auto u_provider = metric_sdk::MeterProviderFactory::Create(std::move(context));
std::shared_ptr<metrics_api::MeterProvider> provider(std::move(u_provider));
metrics_api::Provider::SetMeterProvider(provider);
}
void InitLogger()
{
otlp::OtlpHttpLogRecordExporterOptions opts;
opts.url = "http://localhost:4318/v1/logs";
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);
}
#include "opentelemetry/exporters/otlp/otlp_grpc_exporter_factory.h"
#include "opentelemetry/exporters/otlp/otlp_grpc_exporter_options.h"
#include "opentelemetry/sdk/trace/processor.h"
#include "opentelemetry/sdk/trace/batch_span_processor_factory.h"
#include "opentelemetry/sdk/trace/batch_span_processor_options.h"
#include "opentelemetry/sdk/trace/tracer_provider_factory.h"
#include "opentelemetry/trace/provider.h"
#include "opentelemetry/sdk/trace/tracer_provider.h"
#include "opentelemetry/exporters/otlp/otlp_grpc_metric_exporter_factory.h"
#include "opentelemetry/exporters/otlp/otlp_grpc_metric_exporter_options.h"
#include "opentelemetry/metrics/provider.h"
#include "opentelemetry/sdk/metrics/aggregation/default_aggregation.h"
#include "opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader.h"
#include "opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader_factory.h"
#include "opentelemetry/sdk/metrics/meter_context_factory.h"
#include "opentelemetry/sdk/metrics/meter_provider.h"
#include "opentelemetry/sdk/metrics/meter_provider_factory.h"
#include "opentelemetry/exporters/otlp/otlp_grpc_log_record_exporter_factory.h"
#include "opentelemetry/exporters/otlp/otlp_grpc_log_record_exporter_options.h"
#include "opentelemetry/logs/provider.h"
#include "opentelemetry/sdk/logs/logger_provider_factory.h"
#include "opentelemetry/sdk/logs/processor.h"
#include "opentelemetry/sdk/logs/simple_log_record_processor_factory.h"
namespace trace_api = opentelemetry::trace;
namespace trace_sdk = opentelemetry::sdk::trace;
namespace metric_sdk = opentelemetry::sdk::metrics;
namespace metrics_api = opentelemetry::metrics;
namespace otlp = opentelemetry::exporter::otlp;
namespace logs_api = opentelemetry::logs;
namespace logs_sdk = opentelemetry::sdk::logs;
void InitTracer()
{
trace_sdk::BatchSpanProcessorOptions bspOpts{};
opentelemetry::exporter::otlp::OtlpGrpcExporterOptions opts;
opts.endpoint = "localhost:4317";
opts.use_ssl_credentials = true;
opts.ssl_credentials_cacert_as_string = "ssl-certificate";
auto exporter = otlp::OtlpGrpcExporterFactory::Create(opts);
auto processor = trace_sdk::BatchSpanProcessorFactory::Create(std::move(exporter), bspOpts);
std::shared_ptr<opentelemetry::trace_api::TracerProvider> provider =
trace_sdk::TracerProviderFactory::Create(std::move(processor));
// Set the global trace provider
trace_api::Provider::SetTracerProvider(provider);
}
void InitMetrics()
{
otlp::OtlpGrpcMetricExporterOptions opts;
opts.endpoint = "localhost:4317";
opts.use_ssl_credentials = true;
opts.ssl_credentials_cacert_as_string = "ssl-certificate";
auto exporter = otlp::OtlpGrpcMetricExporterFactory::Create(opts);
metric_sdk::PeriodicExportingMetricReaderOptions reader_options;
reader_options.export_interval_millis = std::chrono::milliseconds(1000);
reader_options.export_timeout_millis = std::chrono::milliseconds(500);
auto reader = metric_sdk::PeriodicExportingMetricReaderFactory::Create(std::move(exporter), reader_options);
auto context = metric_sdk::MeterContextFactory::Create();
context->AddMetricReader(std::move(reader));
auto u_provider = metric_sdk::MeterProviderFactory::Create(std::move(context));
std::shared_ptr<opentelemetry::metrics::MeterProvider> provider(std::move(u_provider));
metrics_api::Provider::SetMeterProvider(provider);
}
void InitLogger()
{
otlp::OtlpGrpcLogRecordExporterOptions opts;
opts.endpoint = "localhost:4317";
opts.use_ssl_credentials = true;
opts.ssl_credentials_cacert_as_string = "ssl-certificate";
auto exporter = otlp::OtlpGrpcLogRecordExporterFactory::Create(opts);
auto processor = logs_sdk::SimpleLogRecordProcessorFactory::Create(std::move(exporter));
nostd::shared_ptr<logs_api::LoggerProvider> provider(
logs_sdk::LoggerProviderFactory::Create(std::move(processor)));
logs_api::Provider::SetLoggerProvider(provider);
}
Console
To debug your instrumentation or see the values locally in development, you can use exporters writing telemetry data to the console (stdout).
While
building OpenTelemetry C++ from source
the OStreamSpanExporter
is included in the build by default.
#include "opentelemetry/exporters/ostream/span_exporter_factory.h"
#include "opentelemetry/sdk/trace/exporter.h"
#include "opentelemetry/sdk/trace/processor.h"
#include "opentelemetry/sdk/trace/simple_processor_factory.h"
#include "opentelemetry/sdk/trace/tracer_provider_factory.h"
#include "opentelemetry/trace/provider.h"
#include "opentelemetry/exporters/ostream/metrics_exporter_factory.h"
#include "opentelemetry/sdk/metrics/meter_provider.h"
#include "opentelemetry/sdk/metrics/meter_provider_factory.h"
#include "opentelemetry/metrics/provider.h"
#include "opentelemetry/exporters/ostream/log_record_exporter_factory.h"
#include "opentelemetry/logs/provider.h"
#include "opentelemetry/sdk/logs/logger_provider_factory.h"
#include "opentelemetry/sdk/logs/processor.h"
#include "opentelemetry/sdk/logs/simple_log_record_processor_factory.h"
namespace trace_api = opentelemetry::trace;
namespace trace_sdk = opentelemetry::sdk::trace;
namespace trace_exporter = opentelemetry::exporter::trace;
namespace metrics_sdk = opentelemetry::sdk::metrics;
namespace metrics_api = opentelemetry::metrics;
namespace metrics_exporter = opentelemetry::exporter::metrics;
namespace logs_api = opentelemetry::logs;
namespace logs_sdk = opentelemetry::sdk::logs;
namespace logs_exporter = opentelemetry::exporter::logs;
void InitTracer()
{
auto exporter = trace_exporter::OStreamSpanExporterFactory::Create();
auto processor = trace_sdk::SimpleSpanProcessorFactory::Create(std::move(exporter));
std::shared_ptr<opentelemetry::trace::TracerProvider> provider = trace_sdk::TracerProviderFactory::Create(std::move(processor));
trace_api::Provider::SetTracerProvider(provider);
}
void InitMetrics()
{
auto exporter = metrics_exporter::OStreamMetricExporterFactory::Create();
auto u_provider = metrics_sdk::MeterProviderFactory::Create();
std::shared_ptr<opentelemetry::metrics::MeterProvider> provider(std::move(u_provider));
auto *p = static_cast<metrics_sdk::MeterProvider *>(u_provider.get());
p->AddMetricReader(std::move(exporter));
metrics_api::Provider::SetMeterProvider(provider);
}
void InitLogger()
{
auto exporter = logs_exporter::OStreamLogRecordExporterFactory::Create();
auto processor = logs_sdk::SimpleLogRecordProcessorFactory::Create(std::move(exporter));
nostd::shared_ptr<logs_api::LoggerProvider> provider(
logs_sdk::LoggerProviderFactory::Create(std::move(processor)));
logs_api::Provider::SetLoggerProvider(provider);
}
Jaeger
Jaeger natively supports OTLP to receive trace data. You can run Jaeger in a docker container with the UI accessible on port 16686 and OTLP enabled on ports 4317 and 4318:
docker run --rm \
-e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
-p 16686:16686 \
-p 4317:4317 \
-p 4318:4318 \
-p 9411:9411 \
jaegertracing/all-in-one:latest
Now following the instruction to setup the OTLP exporters.
Prometheus
To send your metric data to Prometheus, you can either
enable Prometheus’ OTLP Receiver
and use the OTLP exporter or you can use the
PrometheusHttpServer
,
a MetricReader
, that starts an HTTP server that will collect metrics and
serialize to Prometheus text format on request.
Backend Setup
Note
If you have Prometheus or a Prometheus-compatible backend already set up, you can skip this section and setup the Prometheus or OTLP exporter dependencies for your application.
You can run Prometheus in a docker container,
accessible on port 9090
by following these instructions:
Create a file called prometheus.yml
with the following content:
scrape_configs:
- job_name: dice-service
scrape_interval: 5s
static_configs:
- targets: [host.docker.internal:9464]
Run Prometheus in a docker container with the UI accessible on port 9090
:
docker run --rm -v ${PWD}/prometheus.yml:/prometheus/prometheus.yml -p 9090:9090 prom/prometheus --enable-feature=otlp-write-receive
Note
When using Prometheus’ OTLP Receiver, make sure that you set the OTLP endpoint
for metrics in your application to http://localhost:9090/api/v1/otlp
.
Not all docker environments support host.docker.internal
. In some cases you
may need to replace host.docker.internal
with localhost
or the IP address of
your machine.
Dependencies
To send your trace data to Prometheus, make sure that you have set the right cmake build variables while building OpenTelemetry C++ from source:
cmake -DWITH_PROMETHEUS=ON ...
Update your OpenTelemetry configuration to use the Prometheus Exporter:
#include "opentelemetry/exporters/prometheus/exporter_factory.h"
#include "opentelemetry/exporters/prometheus/exporter_options.h"
#include "opentelemetry/metrics/provider.h"
#include "opentelemetry/sdk/metrics/meter_provider.h"
#include "opentelemetry/sdk/metrics/meter_provider_factory.h"
namespace metrics_sdk = opentelemetry::sdk::metrics;
namespace metrics_api = opentelemetry::metrics;
namespace metrics_exporter = opentelemetry::exporter::metrics;
void InitMetrics()
{
metrics_exporter::PrometheusExporterOptions opts;
opts.url = "localhost:9464";
auto prometheus_exporter = metrics_exporter::PrometheusExporterFactory::Create(opts);
auto u_provider = metrics_sdk::MeterProviderFactory::Create();
auto *p = static_cast<metrics_sdk::MeterProvider *>(u_provider.get());
p->AddMetricReader(std::move(prometheus_exporter));
std::shared_ptr<metrics_api::MeterProvider> provider(std::move(u_provider));
metrics_api::Provider::SetMeterProvider(provider);
}
With the above you can access your metrics at http://localhost:9464/metrics. Prometheus or an OpenTelemetry Collector with the Prometheus receiver can scrape the metrics from this endpoint.
Zipkin
Backend Setup
Note
If you have Zipkin or a Zipkin-compatible backend already set up, you can skip this section and setup the Zipkin exporter dependencies for your application.
You can run Zipkin on in a Docker container by executing the following command:
docker run --rm -d -p 9411:9411 --name zipkin openzipkin/zipkin
Dependencies
To send your trace data to Zipkin, make sure that you have set the right cmake build variables while building OpenTelemetry C++ from source:
cmake -DWITH_ZIPKIN=ON ...
Update your OpenTelemetry configuration to use the Zipkin Exporter and to send data to your Zipkin backend:
#include "opentelemetry/exporters/zipkin/zipkin_exporter_factory.h"
#include "opentelemetry/sdk/resource/resource.h"
#include "opentelemetry/sdk/trace/processor.h"
#include "opentelemetry/sdk/trace/simple_processor_factory.h"
#include "opentelemetry/sdk/trace/tracer_provider_factory.h"
#include "opentelemetry/trace/provider.h"
namespace trace = opentelemetry::trace;
namespace trace_sdk = opentelemetry::sdk::trace;
namespace zipkin = opentelemetry::exporter::zipkin;
namespace resource = opentelemetry::sdk::resource;
void InitTracer()
{
zipkin::ZipkinExporterOptions opts;
resource::ResourceAttributes attributes = {{"service.name", "zipkin_demo_service"}};
auto resource = resource::Resource::Create(attributes);
auto exporter = zipkin::ZipkinExporterFactory::Create(opts);
auto processor = trace_sdk::SimpleSpanProcessorFactory::Create(std::move(exporter));
std::shared_ptr<opentelemetry::trace::TracerProvider> provider =
trace_sdk::TracerProviderFactory::Create(std::move(processor), resource);
// Set the global trace provider
trace::Provider::SetTracerProvider(provider);
}
Other available exporters
There are many other exporters available. For a list of available exporters, see the registry.
Finally, you can also write your own exporter. For more information, see the SpanExporter Interface in the API documentation.
Batching span and log records
The OpenTelemetry SDK provides a set of default span and log record processors, that allow you to either emit spans one-by-on (“simple”) or batched. Using batching is recommended, but if you do not want to batch your spans or log records, you can use a simple processor instead as follows:
#include "opentelemetry/exporters/otlp/otlp_http_exporter_factory.h"
#include "opentelemetry/exporters/otlp/otlp_http_exporter_options.h"
#include "opentelemetry/sdk/trace/processor.h"
#include "opentelemetry/sdk/trace/batch_span_processor_factory.h"
#include "opentelemetry/sdk/trace/batch_span_processor_options.h"
opentelemetry::sdk::trace::BatchSpanProcessorOptions options{};
auto exporter = opentelemetry::exporter::otlp::OtlpHttpExporterFactory::Create(opts);
auto processor = opentelemetry::sdk::trace::BatchSpanProcessorFactory::Create(std::move(exporter), options);
#include "opentelemetry/exporters/otlp/otlp_http_exporter_factory.h"
#include "opentelemetry/exporters/otlp/otlp_http_exporter_options.h"
#include "opentelemetry/sdk/trace/processor.h"
#include "opentelemetry/sdk/trace/simple_processor_factory.h"
auto exporter = opentelemetry::exporter::otlp::OtlpHttpExporterFactory::Create(opts);
auto processor = opentelemetry::sdk::trace::SimpleSpanProcessorFactory::Create(std::move(exporter));