OpenTelemetry (OTel) is a set of APIs, libraries, and agents to capture distributed traces and metrics from your app. It’s a Cloud Native Computing Foundation (CNCF) project that was started to create a unified solution for service and app performance monitoring.

The OpenTelemetry project has published strong specifications for the three main pillars of observability: logs, traces, and metrics. These schemas are supported by all tools and services that support interacting with OpenTelemetry. Axiom supports OpenTelemetry natively on an API level, allowing you to connect any existing OpenTelemetry shipper, library, or tool to Axiom for sending data.

OpenTelemetry-compatible events flow into Axiom, where they’re organized into datasets for easy segmentation. Users can create a dataset to receive OpenTelemetry data and obtain an API token for ingestion. Axiom provides comprehensive observability through browsing, querying, dashboards, and alerting of OpenTelemetry data.

OTel traces and OTel logs support are already live. Axiom will soon support OpenTelemetry Metrics (OTel Metrics).

OpenTelemetry componentCurrently supported
TracesYes
LogsYes
MetricsNo (coming soon)

OpenTelemetry Collector

Configuring the OpenTelemetry collector is as simple as creating an HTTP exporter that sends data to the Axiom API together with headers to set the dataset and API token:

exporters:
  otlphttp:
    compression: gzip
    endpoint: https://api.axiom.co
    headers:
      authorization: Bearer <YOUR_API_TOKEN>
      x-axiom-dataset: <YOUR_DATASET>

service:
  pipelines:
    traces:
      receivers:
        - otlp
      processors:
        - memory_limiter
        - batch
      exporters:
        - otlphttp

When using the OTLP/HTTP endpoint for traces and logs, the following endpoint URLs should be used in your SDK exporter OTel configuration.

  • Traces: https://api.axiom.co/v1/traces
  • Logs: https://api.axiom.co/v1/logs

OpenTelemetry for Go

The example below configures a Go app using the OpenTelemetry SDK for Go to send OpenTelemetry data to Axiom.

package main

import (
   "context" // For managing request-scoped values, cancellation signals, and deadlines.
   "crypto/tls" // For configuring TLS options, like certificates.

   // OpenTelemetry imports for setting up tracing and exporting telemetry data.
   "go.opentelemetry.io/otel" // Core OpenTelemetry APIs for managing tracers.
   "go.opentelemetry.io/otel/attribute" // For creating and managing trace attributes.
   "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" // HTTP trace exporter for OpenTelemetry Protocol (OTLP).
   "go.opentelemetry.io/otel/propagation" // For managing context propagation formats.
   "go.opentelemetry.io/otel/sdk/resource" // For defining resources that describe an entity producing telemetry.
   "go.opentelemetry.io/otel/sdk/trace" // For configuring tracing, like sampling and processors.
   semconv "go.opentelemetry.io/otel/semconv/v1.24.0" // Semantic conventions for resource attributes.
)

const (
   serviceName           = "axiom-go-otel" // Name of the service for tracing.
   serviceVersion        = "0.1.0" // Version of the service.
   otlpEndpoint          = "api.axiom.co" // OTLP collector endpoint.
   bearerToken           = "Bearer $API_TOKEN" // Authorization token.
   deploymentEnvironment = "production" // Deployment environment.
)

func SetupTracer() (func(context.Context) error, error) {
   ctx := context.Background()
   return InstallExportPipeline(ctx) // Setup and return the export pipeline for telemetry data.
}

func Resource() *resource.Resource {
   // Defines resource with service name, version, and environment.
   return resource.NewWithAttributes(
       semconv.SchemaURL,
       semconv.ServiceNameKey.String(serviceName),
       semconv.ServiceVersionKey.String(serviceVersion),
       attribute.String("environment", deploymentEnvironment),
   )
}

func InstallExportPipeline(ctx context.Context) (func(context.Context) error, error) {
   // Sets up OTLP HTTP exporter with endpoint, headers, and TLS config.
   exporter, err := otlptracehttp.New(ctx,
       otlptracehttp.WithEndpoint(otlpEndpoint),
       otlptracehttp.WithHeaders(map[string]string{
           "Authorization":   bearerToken,
           "X-AXIOM-DATASET": "$DATASET_NAME",
       }),
       otlptracehttp.WithTLSClientConfig(&tls.Config{}),
   )
   if err != nil {
       return nil, err
   }

   // Configures the tracer provider with the exporter and resource.
   tracerProvider := trace.NewTracerProvider(
       trace.WithBatcher(exporter),
       trace.WithResource(Resource()),
   )
   otel.SetTracerProvider(tracerProvider)

   // Sets global propagator to W3C Trace Context and Baggage.
   otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
       propagation.TraceContext{},
       propagation.Baggage{},
   ))

   return tracerProvider.Shutdown, nil // Returns a function to shut down the tracer provider.
}

OpenTelemetry for Ruby

To send traces to an OpenTelemetry Collector using the OTLP over HTTP in Ruby, use the opentelemetry-exporter-otlp-http gem provided by the OpenTelemetry project.

require 'opentelemetry/sdk'
require 'opentelemetry/exporter/otlp'
require 'opentelemetry/instrumentation/all'

OpenTelemetry::SDK.configure do |c|
  c.service_name = 'ruby-traces' # Set your service name

  c.use_all # or specify individual instrumentation you need

  c.add_span_processor(
    OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
      OpenTelemetry::Exporter::OTLP::Exporter.new(
        endpoint: 'https://api.axiom.co/v1/traces',
        headers: {
          'Authorization' => 'Bearer API_TOKEN',
          'X-AXIOM-DATASET' => 'DATASET'
        }
      )
    )
  )
end

OpenTelemetry for Java

Here is a basic configuration for a Java app that sends traces to an OpenTelemetry Collector using OTLP over HTTP using the OpenTelemetry Java SDK:

package com.example;

import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;

import java.util.concurrent.TimeUnit;

public class OtelConfiguration {
    // OpenTelemetry configuration
    private static final String SERVICE_NAME = "SERVICE_NAME";
    private static final String SERVICE_VERSION = "SERVICE_VERSION";
    private static final String OTLP_ENDPOINT = "https://api.axiom.co/v1/traces";
    private static final String BEARER_TOKEN = "Bearer API_TOKEN";
    private static final String AXIOM_DATASET = "DATASET";

    public static OpenTelemetry initializeOpenTelemetry() {
        // Create a Resource with service name and version
        Resource resource = Resource.getDefault()
                .merge(Resource.create(Attributes.of(
                        AttributeKey.stringKey("service.name"), SERVICE_NAME,
                        AttributeKey.stringKey("service.version"), SERVICE_VERSION
                )));

        // Create an OTLP/HTTP span exporter
        OtlpHttpSpanExporter spanExporter = OtlpHttpSpanExporter.builder()
                .setEndpoint(OTLP_ENDPOINT)
                .addHeader("Authorization", BEARER_TOKEN)
                .addHeader("X-Axiom-Dataset", AXIOM_DATASET)
                .build();

        // Create a BatchSpanProcessor with the OTLP/HTTP exporter
        SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder()
                .addSpanProcessor(BatchSpanProcessor.builder(spanExporter)
                        .setScheduleDelay(100, TimeUnit.MILLISECONDS)
                        .build())
                .setResource(resource)
                .build();

        // Build and register the OpenTelemetry SDK
        OpenTelemetrySdk openTelemetry = OpenTelemetrySdk.builder()
                .setTracerProvider(sdkTracerProvider)
                .buildAndRegisterGlobal();

        // Add a shutdown hook to properly close the SDK
        Runtime.getRuntime().addShutdownHook(new Thread(sdkTracerProvider::close));

        return openTelemetry;
    }
}

OpenTelemetry for .NET

You can send traces to Axiom using the OpenTelemetry .NET SDK by configuring an OTLP HTTP exporter in your .NET app. Here is a simple example:

using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using System;
using System.Diagnostics;
using System.Reflection;

// Class to configure OpenTelemetry tracing
public static class TracingConfiguration
{
    // Declares an ActivitySource for creating tracing activities
    private static readonly ActivitySource ActivitySource = new("MyCustomActivitySource");

    // Configures OpenTelemetry with custom settings and instrumentation
    public static void ConfigureOpenTelemetry()
    {
        // Retrieve the service name and version from the executing assembly metadata
        var serviceName = Assembly.GetExecutingAssembly().GetName().Name ?? "UnknownService";
        var serviceVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "UnknownVersion";

        // Setting up the tracer provider with various configurations
        Sdk.CreateTracerProviderBuilder()
            .SetResourceBuilder(
                // Set resource attributes including service name and version
                ResourceBuilder.CreateDefault().AddService(serviceName, serviceVersion: serviceVersion)
                .AddAttributes(new[] { new KeyValuePair<string, object>("environment", "development") }) // Additional attributes
                .AddTelemetrySdk() // Add telemetry SDK information to the traces
                .AddEnvironmentVariableDetector()) // Detect resource attributes from environment variables
            .AddSource(ActivitySource.Name) // Add the ActivitySource defined above
            .AddAspNetCoreInstrumentation() // Add automatic instrumentation for ASP.NET Core
            .AddHttpClientInstrumentation() // Add automatic instrumentation for HttpClient requests
            .AddOtlpExporter(options => // Configure the OTLP exporter
            {
                options.Endpoint = new Uri("https://api.axiom.co/v1/traces"); // Set the endpoint for the exporter
                options.Protocol = OpenTelemetry.Exporter.OtlpExportProtocol.HttpProtobuf; // Set the protocol
                options.Headers = "Authorization=Bearer API_TOKEN, X-Axiom-Dataset=DATASET"; // Update API token and dataset
            })
            .Build(); // Build the tracer provider
    }

    // Method to start a new tracing activity with an optional activity kind
    public static Activity? StartActivity(string activityName, ActivityKind kind = ActivityKind.Internal)
    {
        // Starts and returns a new activity if sampling allows it, otherwise returns null
        return ActivitySource.StartActivity(activityName, kind);
    }
}

OpenTelemetry for Python

You can send traces to Axiom using the OpenTelemetry Python SDK by configuring an OTLP HTTP exporter in your Python app. Here is a simple example:

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.sdk.resources import Resource, SERVICE_NAME
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter

# Define the service name resource for the tracer.
resource = Resource(attributes={
    SERVICE_NAME: "NAME_OF_SERVICE" # Replace `NAME_OF_SERVICE` with the name of the service you want to trace.
})

# Create a TracerProvider with the defined resource for creating tracers.
provider = TracerProvider(resource=resource)

# Configure the OTLP/HTTP Span Exporter with Axiom headers and endpoint. Replace `API_TOKEN` with your Axiom API key, and replace `DATASET_NAME` with the name of the Axiom dataset where you want to send data.
otlp_exporter = OTLPSpanExporter(
    endpoint="https://api.axiom.co/v1/traces",
    headers={
        "Authorization": "Bearer API_TOKEN",
        "X-Axiom-Dataset": "DATASET_NAME"
    }
)

# Create a BatchSpanProcessor with the OTLP exporter to batch and send trace spans.
processor = BatchSpanProcessor(otlp_exporter)
provider.add_span_processor(processor)

# Set the TracerProvider as the global tracer provider.
trace.set_tracer_provider(provider)

# Define a tracer for external use in different parts of the app.
service1_tracer = trace.get_tracer("service1")

OpenTelemetry for Node

You can send traces to Axiom using the OpenTelemetry Node SDK by configuring an OTLP HTTP exporter in your Node app. Here is a simple example:

const opentelemetry = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-proto');
const { BatchSpanProcessor } = require('@opentelemetry/sdk-trace-base');
const { Resource } = require('@opentelemetry/resources');
const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions');

// Initialize OTLP trace exporter with the URL and headers for the Axiom API
const traceExporter = new OTLPTraceExporter({
  url: 'https://api.axiom.co/v1/traces', // Axiom API endpoint for trace data
  headers: {
    'Authorization': 'Bearer $API_TOKEN', // Replace $API_TOKEN with your actual API token
    'X-Axiom-Dataset': '$DATASET' // Replace $DATASET with your dataset
  },
});

// Define the resource attributes, in this case, setting the service name for the traces
const resource = new Resource({
  [SemanticResourceAttributes.SERVICE_NAME]: 'node traces', // Name for the tracing service
});

// Create a NodeSDK instance with the configured span processor, resource, and auto-instrumentations
const sdk = new opentelemetry.NodeSDK({
  spanProcessor: new BatchSpanProcessor(traceExporter), // Use BatchSpanProcessor for batching and sending traces
  resource: resource, // Attach the defined resource to provide additional context
  instrumentations: [getNodeAutoInstrumentations()], // Automatically instrument common Node.js modules
});

// Start the OpenTelemetry SDK
sdk.start();

OpenTelemetry for Cloudflare Workers

Configure OpenTelemetry in Cloudflare Workers to send telemetry data to Axiom using the OTel CF Worker package. Here is an example exporter configuration:

// index.ts
import { trace } from '@opentelemetry/api';
import { instrument, ResolveConfigFn } from '@microlabs/otel-cf-workers';

export interface Env {
  AXIOM_API_TOKEN: string,
  AXIOM_DATASET: string
}

const handler = {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    await fetch('https://cloudflare.com');
    const greeting = "Welcome to Axiom Cloudflare instrumentation";
    trace.getActiveSpan()?.setAttribute('greeting', greeting);
    ctx.waitUntil(fetch('https://workers.dev'));
    return new Response(`${greeting}!`);
  },
};

const config: ResolveConfigFn = (env: Env, _trigger) => {
  return {
    exporter: {
      url: 'https://api.axiom.co/v1/traces',
      headers: {
        'Authorization': `Bearer ${env.AXIOM_API_TOKEN}`,
        'X-Axiom-Dataset': `${env.AXIOM_DATASET}`
      },
    },
    service: { name: 'axiom-cloudflare-workers' },
  };
};

export default instrument(handler, config);

Additional resources

For further guidance on integrating OpenTelemetry with Axiom, explore the following guides: