How to setup HTTP Requests Tracing using Opentelemetry SDK
Last updated: August 20, 2025
Overview
This document defines how to use the OpenTelemetry SDK in software applications for HTTP API request instrumentation.
The primary objective is to ensure comprehensive API observability by consistently capturing key attributes in OpenTelemetry spans whenever an HTTP request is processed.
Intended Audience
This guide is written for application developers who are responsible for implementing observability in their services. The tracing should be applied inside REST controllers or HTTP request handlers, where the incoming request and outgoing response are available.
By following this specification, developers ensure that every API request is enriched with standardized span attributes for request/response details, headers, network information, and service metadata.
Runtime Characteristics
The OpenTelemetry SDK is asynchronous in nature:
When attributes are added to spans, they are buffered in memory.
Exporting to the configured backend (Astra Traffic Collector) happens asynchronously.
This means instrumentation does not block the main request flow and does not add significant latency to API handling.
Developers should note:
The actual cost of creating spans is lightweight and non-blocking.
Exporting traces depends on the chosen exporter, but the SDK ensures that spans are sent out of band.
If the exporter backend is unavailable, spans are dropped rather than blocking the API handler.
Prerequisites
Astra Traffic Collector is installed and accessible
Opentelemetry SDK integration should be created and keep the
sensorIDhandy
Tracing Selection Criteria
Only successful HTTP requests should be selected for tracing. This ensures that trace data reflects valid service interactions, rather than clutter from failed requests.
Include:
Status codes in the 2xx range (e.g.,
200,201)Status codes in the 3xx range (e.g.,
301,302)
Exclude:
Status codes in the 4xx range (client errors)
Status codes in the 5xx range (server errors)
Resource Attributes
Resource attributes describe the service or application emitting telemetry data. These attributes are set once at the resource level (not per span).
Attribute Name | Type | Description | Example |
| string | Version of the deployed sensor agent |
|
Required Span Attributes
Each span must include a consistent set of attributes. These attributes provide details about the request, network, headers, and bodies.
1. HTTP Request Metadata
Attribute Name | Type | Description | Example |
| string | integration ID aka |
|
| string | HTTP method used |
|
| string | Request scheme |
|
| string | HTTP protocol version |
|
| string | Hostname or domain |
|
| string | URL path including query string |
|
| int | Response HTTP status code |
|
2. Network Information
Attribute Name | Type | Description | Example |
| string | Client IP address or unique identifier |
|
3. Headers and Body
Attribute Name | Type | Description | Example Value |
| string | JSON string of request headers |
|
| string | JSON string of response headers |
|
| string | Raw request body |
|
| string | Raw response body |
|
Example: Tracing For A Sample HTTP Request
Let's consider an example cURL request and how that request is mapped to otel span attributes for easy understanding
HTTP Request cURL:
curl -X POST 'https://api.example.com/users?source=mobile' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' \
-H 'User-Agent: MyApp/1.0' \
--data-raw '{
"name": "John Doe",
"email": "john.doe@example.com",
"age": 30,
"preferences": {
"theme": "dark",
"notifications": true
}
}'
#Following cURL response is assumed with 200OK status
{
"id": 12345,
"name": "John Doe",
"email": "john.doe@example.com",
"created_at": "2023-12-01T10:30:00Z",
"status": "active"
}Corresponding Span Attributes
import (
"encoding/json"
"log"
)
reqBody := `<root>
<name>Example</name>
<mail>val@yopmail.com</mail>
<age>30</age>
<addresses>
<address city="Anytown1">
<street>123 Main St</street>
</address>
<address city="Anytown2">
<street>124 Main St</street>
</address>
</addresses>
</root>`
respBody := "{\"email\":\"val@yopmail.com\",\"arr\":[1,2,3,4]}"
// Example request headers map
requestHeaders := map[string]string{
"host": "localhost:8080",
"content-type": "application/xml",
"accept": "application/json",
"user-agent": "curl/7.68.0",
"accept-encoding": "gzip, deflate, br",
"authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
}
// Example response headers map
responseHeaders := map[string]string{
"content-type": "application/json",
"content-length": "152",
"x-request-id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"strict-transport-security": "max-age=31536000; includeSubDomains",
"cache-control": "no-cache, no-store, must-revalidate",
}
// Convert request headers to JSON string
requestHeadersJSON, err := json.Marshal(requestHeaders)
if err != nil {
log.Fatalf("Failed to marshal request headers: %v", err)
}
// Convert response headers to JSON string
responseHeadersJSON, err := json.Marshal(responseHeaders)
if err != nil {
log.Fatalf("Failed to marshal response headers: %v", err)
}
// Set span attributes
span.SetAttributes(
attribute.String("sensor.id", "17062dc8-6cd6-4951-9b21-5f40c85b0e71"), // Unique identifier for the sensor
attribute.String("http.method", "GET"), //http methods like: GET/POST/PUT/PATCH
attribute.String("http.scheme", "https"), //url scheme like: http/https
attribute.String("http.flavor", "2.0"), //scheme flavor: 1.0/1.1/2.0
attribute.String("http.host", "localhost"), //host or main domain name: api.mycompany.com
attribute.String("http.target", "/stage-test-client1?param1=10"), //url target. Everything after domain name in this fashion: https://api.mydomain.com/<this_is_url_target_including_prefix_/>
attribute.String("net.sock.peer.addr", "127.0.0.1"), //IP address of incoming request. Or else, any unique identifier of client
attribute.Int("http.status_code", 200), //http status code like: 200/404/500/etc
attribute.String("http.request.headers", string(requestHeadersJSON)), //jsonified string of request header/value map
attribute.String("http.response.headers", string(responseHeadersJSON)), //jsonified string of response header/value map
attribute.String("http.request.body", reqBody), //stringified request body
attribute.String("http.response.body", respBody),//stringified response body
)//Requires Java 8+
String reqBody = "<root>\n" +
" <name>Example</name>\n" +
" <mail>val@yopmail.com</mail>\n" +
" <age>30</age>\n" +
" <addresses>\n" +
" <address city=\"Anytown1\">\n" +
" <street>123 Main St</street>\n" +
" </address>\n" +
" <address city=\"Anytown2\">\n" +
" <street>124 Main St</street>\n" +
" </address>\n" +
" </addresses>\n" +
"</root>";
String respBody = "{\"email\":\"val@yopmail.com\",\"arr\":[1,2,3,4]}";
// Request and response headers
Map<String, String> requestHeaders = new HashMap<>();
requestHeaders.put("host", "localhost");
requestHeaders.put("content-type", "application/xml");
requestHeaders.put("accept", "application/json");
requestHeaders.put("authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...");
Map<String, String> responseHeaders = new HashMap<>();
responseHeaders.put("content-type", "application/json");
responseHeaders.put("content-length", "152");
responseHeaders.put("x-request-id", "a1b2c3d4-e5f6-7890-abcd-ef1234567890");
// Convert headers to JSON strings
ObjectMapper objectMapper = new ObjectMapper();
String requestHeadersJson = objectMapper.writeValueAsString(requestHeaders);
String responseHeadersJson = objectMapper.writeValueAsString(responseHeaders);
// Set span attributes
Span span = tracer.spanBuilder("http-request").startSpan();
try (Scope scope = span.makeCurrent()) {
// HTTP Request Metadata
span.setAttribute("sensor.id", "17062dc8-6cd6-4951-9b21-5f40c85b0e71"); // Unique identifier for the sensor
span.setAttribute("http.method", "GET"); // HTTP methods like: GET/POST/PUT/PATCH
span.setAttribute("http.scheme", "https"); // URL scheme like: http/https
span.setAttribute("http.flavor", "2.0"); // Scheme flavor: 1.0/1.1/2.0
span.setAttribute("http.host", "localhost"); // Host or main domain name: api.mycompany.com
span.setAttribute("http.target", "/stage-test-client1?param1=10"); // URL target (path + query)
span.setAttribute("net.sock.peer.addr", "127.0.0.1"); // IP address of incoming request
span.setAttribute("http.status_code", 200); // HTTP status code: 200/404/500/etc
// Headers (as JSON strings)
span.setAttribute("http.request.headers", requestHeadersJson);
span.setAttribute("http.response.headers", responseHeadersJson);
// Request and response bodies
span.setAttribute("http.request.body", reqBody);
span.setAttribute("http.response.body", respBody);
// Perform your actual HTTP request logic here
} finally {
span.end();
}string reqBody = @"<root>
<name>Example</name>
<mail>val@yopmail.com</mail>
<age>30</age>
<addresses>
<address city=""Anytown1"">
<street>123 Main St</street>
</address>
<address city=""Anytown2"">
<street>124 Main St</street>
</address>
</addresses>
</root>";
string respBody = "{\"email\":\"val@yopmail.com\",\"arr\":[1,2,3,4]}";
// Request and response headers
var requestHeaders = new Dictionary<string, string>
{
{ "host", "localhost" },
{ "content-type", "application/xml" },
{ "accept", "application/json" },
{ "authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }
};
var responseHeaders = new Dictionary<string, string>
{
{ "content-type", "application/json" },
{ "content-length", "152" },
{ "x-request-id", "a1b2c3d4-e5f6-7890-abcd-ef1234567890" }
};
// Convert headers to JSON strings
string requestHeadersJson = JsonSerializer.Serialize(requestHeaders);
string responseHeadersJson = JsonSerializer.Serialize(responseHeaders);
using var activity = MyActivitySource.StartActivity("http-request");
if (activity != null)
{
// HTTP Request Metadata
activity.SetTag("sensor.id", "17062dc8-6cd6-4951-9b21-5f40c85b0e71"); // Unique identifier for the sensor
activity.SetTag("http.method", "GET"); // HTTP methods like: GET/POST/PUT/PATCH
activity.SetTag("http.scheme", "https"); // URL scheme like: http/https
activity.SetTag("http.flavor", "2.0"); // Scheme flavor: 1.0/1.1/2.0
activity.SetTag("http.host", "localhost"); // Host or main domain name: api.mycompany.com
activity.SetTag("http.target", "/stage-test-client1?param1=10"); // URL target (path + query)
activity.SetTag("net.sock.peer.addr", "127.0.0.1"); // IP address of incoming request
activity.SetTag("http.status_code", 200); // HTTP status code: 200/404/500/etc
// Headers (as JSON strings)
activity.SetTag("http.request.headers", requestHeadersJson);
activity.SetTag("http.response.headers", responseHeadersJson);
// Request and response bodies
activity.SetTag("http.request.body", reqBody);
activity.SetTag("http.response.body", respBody);
// Perform your actual HTTP request logic here
}const { trace } = require('@opentelemetry/api');
const { URL } = require('url');
// Get tracer
const tracer = trace.getTracer('com.example.YourApplicationName');
const reqBody = `<root>
<name>Example</name>
<mail>val@yopmail.com</mail>
<age>30</age>
<addresses>
<address city="Anytown1">
<street>123 Main St</street>
</address>
<address city="Anytown2">
<street>124 Main St</street>
</address>
</addresses>
</root>`;
const respBody = '{"email":"val@yopmail.com","arr":[1,2,3,4]}';
// Request and response headers
const requestHeaders = {
"host": "localhost",
"content-type": "application/xml",
"accept": "application/json",
"authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
};
const responseHeaders = {
"content-type": "application/json",
"content-length": "152",
"x-request-id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
};
// Convert headers to JSON strings
const requestHeadersJson = JSON.stringify(requestHeaders);
const responseHeadersJson = JSON.stringify(responseHeaders);
// Create and configure span
const span = tracer.startSpan('http-request');
try {
// HTTP Request Metadata
span.setAttributes({
'sensor.id': '17062dc8-6cd6-4951-9b21-5f40c85b0e71', // Unique identifier for the sensor
'http.method': 'GET', // HTTP methods like: GET/POST/PUT/PATCH
'http.scheme': 'https', // URL scheme like: http/https
'http.flavor': '2.0', // Scheme flavor: 1.0/1.1/2.0
'http.host': 'localhost', // Host or main domain name: api.mycompany.com
'http.target': '/stage-test-client1?param1=10', // URL target (path + query)
'net.sock.peer.addr': '127.0.0.1', // IP address of incoming request
'http.status_code': 200, // HTTP status code: 200/404/500/etc
// Headers (as JSON strings)
'http.request.headers': requestHeadersJson,
'http.response.headers': responseHeadersJson,
// Request and response bodies
'http.request.body': reqBody,
'http.response.body': respBody
});
// Perform your actual HTTP request logic here
// ...
} finally {
span.end();
}import json
from opentelemetry import trace
from opentelemetry.trace import Status, StatusCode
# Get tracer
tracer = trace.get_tracer(__name__)
req_body = """<root>
<name>Example</name>
<mail>val@yopmail.com</mail>
<age>30</age>
<addresses>
<address city="Anytown1">
<street>123 Main St</street>
</address>
<address city="Anytown2">
<street>124 Main St</street>
</address>
</addresses>
</root>"""
resp_body = '{"email":"val@yopmail.com","arr":[1,2,3,4]}'
# Request and response headers
request_headers = {
"host": "localhost",
"content-type": "application/xml",
"accept": "application/json",
"authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
response_headers = {
"content-type": "application/json",
"content-length": "152",
"x-request-id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
# Convert headers to JSON strings
request_headers_json = json.dumps(request_headers, separators=(',', ':'))
response_headers_json = json.dumps(response_headers, separators=(',', ':'))
# Create and configure span
with tracer.start_as_current_span("http-request") as span:
# HTTP Request Metadata
span.set_attribute("sensor.id", "17062dc8-6cd6-4951-9b21-5f40c85b0e71") # Unique identifier for the sensor
span.set_attribute("http.method", "GET") # HTTP methods like: GET/POST/PUT/PATCH
span.set_attribute("http.scheme", "https") # URL scheme like: http/https
span.set_attribute("http.flavor", "2.0") # Scheme flavor: 1.0/1.1/2.0
span.set_attribute("http.host", "localhost") # Host or main domain name: api.mycompany.com
span.set_attribute("http.target", "/stage-test-client1?param1=10") # URL target (path + query)
span.set_attribute("net.sock.peer.addr", "127.0.0.1") # IP address of incoming request
span.set_attribute("http.status_code", 200) # HTTP status code: 200/404/500/etc
# Headers (as JSON strings)
span.set_attribute("http.request.headers", request_headers_json)
span.set_attribute("http.response.headers", response_headers_json)
# Request and response bodies
span.set_attribute("http.request.body", req_body)
span.set_attribute("http.response.body", resp_body)
# Perform your actual HTTP request logic here
# ...
# Set span status
span.set_status(Status(StatusCode.OK))Complete code example (including initializing otel sdk and sending the span)
Replace the following variable in the code piece
Variable | Description | Example Value |
| grpc endpoint of Astra Traffic Collector. Provide the endpoint address without scheme |
|
| integration ID aka |
|
package main
import (
"context"
"encoding/json"
"log"
"time"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/resource"
"go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
)
// Global configuration
var (
OtelEndpoint = "astra-traffic-collector:4317"
SensorID = "17062dc8-6cd6-4951-9b21-5f40c85b0e71"
SensorVersion = "1.0.0"
ServiceName = "astra-otel-sdk"
)
func initTracer() (*trace.TracerProvider, error) {
// Create resource with required attributes
res := resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String(ServiceName),
attribute.String("sensor.version", SensorVersion),
)
// Create OTLP exporter
exporter, err := otlptracegrpc.New(context.Background(),
otlptracegrpc.WithEndpoint(OtelEndpoint),
otlptracegrpc.WithInsecure(),
)
if err != nil {
return nil, err
}
// Create tracer provider
tp := trace.NewTracerProvider(
trace.WithBatcher(exporter),
trace.WithResource(res),
)
// Set global tracer provider
otel.SetTracerProvider(tp)
return tp, nil
}
func createSampleSpan() {
tracer := otel.Tracer("user-api-service")
// Sample request/response data
requestBody := `{
"name": "John Doe",
"email": "john.doe@example.com",
"age": 30,
"preferences": {
"theme": "dark",
"notifications": true
}
}`
responseBody := `{
"id": 12345,
"name": "John Doe",
"email": "john.doe@example.com",
"created_at": "2023-12-01T10:30:00Z",
"status": "active"
}`
// Request headers
requestHeaders := map[string]string{
"host": "api.example.com",
"content-type": "application/json",
"accept": "application/json",
"authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user-agent": "MyApp/1.0",
}
// Response headers
responseHeaders := map[string]string{
"content-type": "application/json",
"content-length": "156",
"x-request-id": "req-123456789",
"cache-control": "no-cache",
}
// Convert headers to JSON
requestHeadersJSON, err := json.Marshal(requestHeaders)
if err != nil {
log.Printf("Failed to marshal request headers: %v", err)
return
}
responseHeadersJSON, err := json.Marshal(responseHeaders)
if err != nil {
log.Printf("Failed to marshal response headers: %v", err)
return
}
// Create span
ctx, span := tracer.Start(context.Background(), "http-request")
defer span.End()
// Set all required span attributes
span.SetAttributes(
// HTTP Request Metadata
attribute.String("sensor.id", SensorID),
attribute.String("http.method", "POST"),
attribute.String("http.scheme", "https"),
attribute.String("http.flavor", "1.1"),
attribute.String("http.host", "api.example.com"),
attribute.String("http.target", "/users?source=mobile"),
attribute.Int("http.status_code", 200),
// Network Information
attribute.String("net.sock.peer.addr", "192.168.1.100"),
// Headers and Body
attribute.String("http.request.headers", string(requestHeadersJSON)),
attribute.String("http.response.headers", string(responseHeadersJSON)),
attribute.String("http.request.body", requestBody),
attribute.String("http.response.body", responseBody),
)
log.Printf("Created span with ID: %s", span.SpanContext().SpanID().String())
// Simulate some processing time
time.Sleep(100 * time.Millisecond)
}
func main() {
// Initialize tracer
tp, err := initTracer()
if err != nil {
log.Fatalf("Failed to initialize tracer: %v", err)
}
defer func() {
if err := tp.Shutdown(context.Background()); err != nil {
log.Printf("Error shutting down tracer provider: %v", err)
}
}()
// Create and send sample span
createSampleSpan()
// Wait a bit for export
time.Sleep(2 * time.Second)
log.Println("Sample span sent successfully")
}import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
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 io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
public class OtelTracingExample {
// Global configuration
private static final String OTEL_ENDPOINT = "astra-traffic-collector:4317";
private static final String SENSOR_ID = "17062dc8-6cd6-4951-9b21-5f40c85b0e71";
private static final String SENSOR_VERSION = "1.0.0";
private static final String SERVICE_NAME = "user-api-service";
private static OpenTelemetry openTelemetry;
private static ObjectMapper objectMapper = new ObjectMapper();
public static void initTracer() {
// Create resource with required attributes
Resource resource = Resource.getDefault()
.merge(Resource.create(Attributes.builder()
.put(ResourceAttributes.SERVICE_NAME, SERVICE_NAME)
.put(AttributeKey.stringKey("sensor.version"), SENSOR_VERSION)
.build()));
// Create OTLP exporter
OtlpGrpcSpanExporter spanExporter = OtlpGrpcSpanExporter.builder()
.setEndpoint(OTEL_ENDPOINT)
.build();
// Create tracer provider
SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder()
.setResource(resource)
.addSpanProcessor(BatchSpanProcessor.builder(spanExporter).build())
.build();
// Build OpenTelemetry SDK
openTelemetry = OpenTelemetrySdk.builder()
.setTracerProvider(sdkTracerProvider)
.buildAndRegisterGlobal();
}
public static void createSampleSpan() {
Tracer tracer = openTelemetry.getTracer("user-api-service");
// Sample request/response data
String requestBody = "{\n" +
" \"name\": \"John Doe\",\n" +
" \"email\": \"john.doe@example.com\",\n" +
" \"age\": 30,\n" +
" \"preferences\": {\n" +
" \"theme\": \"dark\",\n" +
" \"notifications\": true\n" +
" }\n" +
"}";
String responseBody = "{\n" +
" \"id\": 12345,\n" +
" \"name\": \"John Doe\",\n" +
" \"email\": \"john.doe@example.com\",\n" +
" \"created_at\": \"2023-12-01T10:30:00Z\",\n" +
" \"status\": \"active\"\n" +
"}";
// Request headers
Map<String, String> requestHeaders = new HashMap<>();
requestHeaders.put("host", "api.example.com");
requestHeaders.put("content-type", "application/json");
requestHeaders.put("accept", "application/json");
requestHeaders.put("authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...");
requestHeaders.put("user-agent", "MyApp/1.0");
// Response headers
Map<String, String> responseHeaders = new HashMap<>();
responseHeaders.put("content-type", "application/json");
responseHeaders.put("content-length", "156");
responseHeaders.put("x-request-id", "req-123456789");
responseHeaders.put("cache-control", "no-cache");
try {
// Convert headers to JSON
String requestHeadersJson = objectMapper.writeValueAsString(requestHeaders);
String responseHeadersJson = objectMapper.writeValueAsString(responseHeaders);
// Create span
Span span = tracer.spanBuilder("http-request").startSpan();
try {
// Set all required span attributes
span.setAttribute("sensor.id", SENSOR_ID);
span.setAttribute("http.method", "POST");
span.setAttribute("http.scheme", "https");
span.setAttribute("http.flavor", "1.1");
span.setAttribute("http.host", "api.example.com");
span.setAttribute("http.target", "/users?source=mobile");
span.setAttribute("http.status_code", 200);
span.setAttribute("net.sock.peer.addr", "192.168.1.100");
span.setAttribute("http.request.headers", requestHeadersJson);
span.setAttribute("http.response.headers", responseHeadersJson);
span.setAttribute("http.request.body", requestBody);
span.setAttribute("http.response.body", responseBody);
System.out.println("Created span with ID: " + span.getSpanContext().getSpanId());
// Simulate some processing time
Thread.sleep(100);
} finally {
span.end();
}
} catch (Exception e) {
System.err.println("Error creating span: " + e.getMessage());
}
}
public static void main(String[] args) {
try {
// Initialize tracer
initTracer();
// Create and send sample span
createSampleSpan();
// Wait a bit for export
Thread.sleep(2000);
System.out.println("Sample span sent successfully");
// Shutdown
GlobalOpenTelemetry.get().close();
} catch (Exception e) {
System.err.println("Error in main: " + e.getMessage());
}
}
}using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using OpenTelemetry;
using OpenTelemetry.Exporter;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
namespace OtelTracingExample
{
public static class OtelConfig
{
public const string OtelEndpoint = "astra-traffic-collector:4317";
public const string SensorID = "17062dc8-6cd6-4951-9b21-5f40c85b0e71";
public const string SensorVersion = "1.0.0";
public const string ServiceName = "user-api-service";
}
public static class Instrumentation
{
public static readonly ActivitySource ActivitySource = new ActivitySource("user-api-service");
}
public static class Program
{
private static TracerProvider tracerProvider;
public static void InitTracer()
{
// Create tracer provider with resource attributes
tracerProvider = Sdk.CreateTracerProviderBuilder()
.SetResourceBuilder(ResourceBuilder.CreateDefault()
.AddService(OtelConfig.ServiceName)
.AddAttributes(new KeyValuePair<string, object>[]
{
new("sensor.version", OtelConfig.SensorVersion)
}))
.AddSource("user-api-service")
.AddOtlpExporter(options =>
{
options.Endpoint = new Uri(OtelConfig.OtelEndpoint);
options.Protocol = OtlpExportProtocol.Grpc;
})
.Build();
}
public static void CreateSampleSpan()
{
// Sample request/response data
string requestBody = @"{
""name"": ""John Doe"",
""email"": ""john.doe@example.com"",
""age"": 30,
""preferences"": {
""theme"": ""dark"",
""notifications"": true
}
}";
string responseBody = @"{
""id"": 12345,
""name"": ""John Doe"",
""email"": ""john.doe@example.com"",
""created_at"": ""2023-12-01T10:30:00Z"",
""status"": ""active""
}";
// Request headers
var requestHeaders = new Dictionary<string, string>
{
{ "host", "api.example.com" },
{ "content-type", "application/json" },
{ "accept", "application/json" },
{ "authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." },
{ "user-agent", "MyApp/1.0" }
};
// Response headers
var responseHeaders = new Dictionary<string, string>
{
{ "content-type", "application/json" },
{ "content-length", "156" },
{ "x-request-id", "req-123456789" },
{ "cache-control", "no-cache" }
};
// Convert headers to JSON
string requestHeadersJson = JsonSerializer.Serialize(requestHeaders);
string responseHeadersJson = JsonSerializer.Serialize(responseHeaders);
// Create span
using var activity = Instrumentation.ActivitySource.StartActivity("http-request");
if (activity != null)
{
// Set all required span attributes
activity.SetTag("sensor.id", SensorID);
activity.SetTag("http.method", "POST");
activity.SetTag("http.scheme", "https");
activity.SetTag("http.flavor", "1.1");
activity.SetTag("http.host", "api.example.com");
activity.SetTag("http.target", "/users?source=mobile");
activity.SetTag("http.status_code", 200);
activity.SetTag("net.sock.peer.addr", "192.168.1.100");
activity.SetTag("http.request.headers", requestHeadersJson);
activity.SetTag("http.response.headers", responseHeadersJson);
activity.SetTag("http.request.body", requestBody);
activity.SetTag("http.response.body", responseBody);
Console.WriteLine($"Created span with ID: {activity.Id}");
// Simulate some processing time
Thread.Sleep(100);
}
}
public static async Task Main(string[] args)
{
try
{
// Initialize tracer
InitTracer();
// Create and send sample span
CreateSampleSpan();
// Wait a bit for export
await Task.Delay(2000);
Console.WriteLine("Sample span sent successfully");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
finally
{
// Shutdown
tracerProvider?.Dispose();
Instrumentation.ActivitySource?.Dispose();
}
}
}
}const { NodeSDK } = require('@opentelemetry/sdk-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-otlp-grpc');
const { Resource } = require('@opentelemetry/resources');
const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions');
const { trace } = require('@opentelemetry/api');
// Global configuration
const OTEL_ENDPOINT = 'astra-traffic-collector:4317';
const SENSOR_ID = '17062dc8-6cd6-4951-9b21-5f40c85b0e71'
const SENSOR_VERSION = '1.0.0';
const SERVICE_NAME = 'user-api-service';
let sdk;
function initTracer() {
// Initialize OpenTelemetry SDK
sdk = new NodeSDK({
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: SERVICE_NAME,
'sensor.version': SENSOR_VERSION
}),
traceExporter: new OTLPTraceExporter({
url: OTEL_ENDPOINT
})
});
// Start the SDK
sdk.start();
console.log('OpenTelemetry initialized successfully');
}
function createSampleSpan() {
const tracer = trace.getTracer('user-api-service');
// Sample request/response data
const requestBody = `{
"name": "John Doe",
"email": "john.doe@example.com",
"age": 30,
"preferences": {
"theme": "dark",
"notifications": true
}
}`;
const responseBody = `{
"id": 12345,
"name": "John Doe",
"email": "john.doe@example.com",
"created_at": "2023-12-01T10:30:00Z",
"status": "active"
}`;
// Request headers
const requestHeaders = {
"host": "api.example.com",
"content-type": "application/json",
"accept": "application/json",
"authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user-agent": "MyApp/1.0"
};
// Response headers
const responseHeaders = {
"content-type": "application/json",
"content-length": "156",
"x-request-id": "req-123456789",
"cache-control": "no-cache"
};
// Convert headers to JSON
const requestHeadersJson = JSON.stringify(requestHeaders);
const responseHeadersJson = JSON.stringify(responseHeaders);
// Create span
const span = tracer.startSpan('http-request');
try {
// Set all required span attributes
span.setAttributes({
'sensor.id': '17062dc8-6cd6-4951-9b21-5f40c85b0e71',
'http.method': 'POST',
'http.scheme': 'https',
'http.flavor': '1.1',
'http.host': 'api.example.com',
'http.target': '/users?source=mobile',
'http.status_code': 200,
'net.sock.peer.addr': '192.168.1.100',
'http.request.headers': requestHeadersJson,
'http.response.headers': responseHeadersJson,
'http.request.body': requestBody,
'http.response.body': responseBody
});
console.log(`Created span with trace ID: ${span.spanContext().traceId}`);
// Simulate some processing time
setTimeout(() => {}, 100);
} finally {
span.end();
}
}
async function main() {
try {
// Initialize tracer
initTracer();
// Create and send sample span
createSampleSpan();
// Wait a bit for export
await new Promise(resolve => setTimeout(resolve, 2000));
console.log('Sample span sent successfully');
} catch (error) {
console.error('Error:', error.message);
} finally {
// Shutdown
if (sdk) {
await sdk.shutdown();
}
}
}
// Required dependencies in package.json:
/*
{
"dependencies": {
"@opentelemetry/api": "^1.4.0",
"@opentelemetry/sdk-node": "^0.39.0",
"@opentelemetry/exporter-otlp-grpc": "^0.39.0",
"@opentelemetry/semantic-conventions": "^1.12.0"
}
}
*/
main().catch(console.error);import json
import time
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource
from opentelemetry.trace import Status, StatusCode
# Global configuration
OTEL_ENDPOINT = "astra-traffic-collector:4317"
SENSOR_ID = "17062dc8-6cd6-4951-9b21-5f40c85b0e71"
SENSOR_VERSION = "1.0.0"
SERVICE_NAME = "user-api-service"
def init_tracer():
"""Initialize OpenTelemetry tracer with proper configuration."""
# Create resource with required attributes
resource = Resource.create({
"service.name": SERVICE_NAME,
"sensor.version": SENSOR_VERSION
})
# Set tracer provider
trace.set_tracer_provider(TracerProvider(resource=resource))
# Configure OTLP exporter
otlp_exporter = OTLPSpanExporter(endpoint=OTEL_ENDPOINT)
span_processor = BatchSpanProcessor(otlp_exporter)
trace.get_tracer_provider().add_span_processor(span_processor)
print("OpenTelemetry initialized successfully")
def create_sample_span():
"""Create a sample span with all required attributes."""
tracer = trace.get_tracer("user-api-service")
# Sample request/response data
request_body = """{
"name": "John Doe",
"email": "john.doe@example.com",
"age": 30,
"preferences": {
"theme": "dark",
"notifications": true
}
}"""
response_body = """{
"id": 12345,
"name": "John Doe",
"email": "john.doe@example.com",
"created_at": "2023-12-01T10:30:00Z",
"status": "active"
}"""
# Request headers
request_headers = {
"host": "api.example.com",
"content-type": "application/json",
"accept": "application/json",
"authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user-agent": "MyApp/1.0"
}
# Response headers
response_headers = {
"content-type": "application/json",
"content-length": "156",
"x-request-id": "req-123456789",
"cache-control": "no-cache"
}
# Convert headers to JSON strings
try:
request_headers_json = json.dumps(request_headers, separators=(',', ':'))
response_headers_json = json.dumps(response_headers, separators=(',', ':'))
except Exception as e:
print(f"Error converting headers to JSON: {e}")
return
# Create span with all required attributes
with tracer.start_as_current_span("http-request") as span:
# Set all required span attributes
span.set_attribute("sensor.id", SENSOR_ID)
span.set_attribute("http.method", "POST")
span.set_attribute("http.scheme", "https")
span.set_attribute("http.flavor", "1.1")
span.set_attribute("http.host", "api.example.com")
span.set_attribute("http.target", "/users?source=mobile")
span.set_attribute("http.status_code", 200)
span.set_attribute("net.sock.peer.addr", "192.168.1.100")
span.set_attribute("http.request.headers", request_headers_json)
span.set_attribute("http.response.headers", response_headers_json)
span.set_attribute("http.request.body", request_body)
span.set_attribute("http.response.body", response_body)
print(f"Created span with trace ID: {span.get_span_context().trace_id}")
# Simulate some processing time
time.sleep(0.1)
# Set span status
span.set_status(Status(StatusCode.OK))
def main():
"""Main function to run the example."""
try:
# Initialize tracer
init_tracer()
# Create and send sample span
create_sample_span()
# Wait a bit for export
time.sleep(2)
print("Sample span sent successfully")
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
main()Implementation Notes
Define global configuration variables:
var ( OtelEndpoint = "astra-traffic-collector:4317" SensorID = "17062dc8-6cd6-4951-9b21-5f40c85b0e71" SensorVersion = "1.0.0" ServiceName = "astra-otel-sdk" )public class OtelConfig { // Global configuration variables public static final String OTEL_ENDPOINT = "astra-traffic-collector:4317"; private static final String SENSOR_ID = "17062dc8-6cd6-4951-9b21-5f40c85b0e71"; public static final String SENSOR_VERSION = "1.0.0"; // Other configuration values can be added here }public static class OtelConfig { // Global configuration variables public const string OtelEndpoint = "astra-traffic-collector:4317"; public const string SensorID = "17062dc8-6cd6-4951-9b21-5f40c85b0e71"; public const string SensorVersion = "1.0.0"; // Other configuration values can be added here }// otel-config.js class OtelConfig { static get OTEL_ENDPOINT() { return process.env.OTEL_ENDPOINT || 'astra-traffic-collector:4317'; } static get SENSOR_ID() { return process.env.SENSOR_ID || '17062dc8-6cd6-4951-9b21-5f40c85b0e71'; } static get SERVICE_NAME() { return process.env.SERVICE_NAME || 'your-service-name'; } } module.exports = { OtelConfig };# otel_config.py import os class OtelConfig: """Global configuration for OpenTelemetry settings""" OTEL_ENDPOINT = os.getenv("OTEL_ENDPOINT", "astra-traffic-collector:4317") SENSOR_ID = os.getenv("SENSOR_ID","17062dc8-6cd6-4951-9b21-5f40c85b0e71") SENSOR_VERSION = os.getenv("SENSOR_VERSION", "1.0.0") SERVICE_NAME = os.getenv("SERVICE_NAME", "your-service-name")Set resource attributes at tracer initialization:
res := resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceNameKey.String("your-service-name"), attribute.String("sensor.version", SensorVersion), )// Initialize OpenTelemetry Resource resource = Resource.getDefault() .merge(Resource.create(Attributes.builder() .put("service.name", "your-service-name") .put("sensor.version", OtelConfig.SENSOR_VERSION) .build())); SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() .setResource(resource) .addSpanProcessor(BatchSpanProcessor.builder(OtlpGrpcSpanExporter.builder() .setEndpoint(OtelConfig.OTEL_ENDPOINT) .build()).build()) .build(); OpenTelemetrySdk openTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .buildAndRegisterGlobal(); Tracer tracer = openTelemetry.getTracer("com.example.YourApplicationName");using OpenTelemetry; using OpenTelemetry.Resources; using OpenTelemetry.Trace; using Microsoft.Extensions.DependencyInjection; // For ASP.NET Core application in Startup.cs or Program.cs public void ConfigureServices(IServiceCollection services) { services.AddOpenTelemetry() .WithTracing(builder => builder .SetResourceBuilder(ResourceBuilder.CreateDefault() .AddService("your-service-name") .AddAttributes(new KeyValuePair<string, object>[] { new("sensor.version", OtelConfig.SensorVersion) })) .AddAspNetCoreInstrumentation() .AddHttpClientInstrumentation() .AddOtlpExporter(options => { options.Endpoint = new Uri(OtelConfig.OtelEndpoint); }) ); } // For a non-ASP.NET Core application, you can initialize the provider directly: static TracerProvider CreateTracerProvider() { return Sdk.CreateTracerProviderBuilder() .SetResourceBuilder(ResourceBuilder.CreateDefault() .AddService("your-service-name") .AddAttributes(new KeyValuePair<string, object>[] { new("sensor.version", OtelConfig.SensorVersion) })) .AddSource("your-application-name") .AddOtlpExporter(options => { options.Endpoint = new Uri(OtelConfig.OtelEndpoint); }) .Build(); }const { NodeSDK } = require('@opentelemetry/sdk-node'); const { OTLPTraceExporter } = require('@opentelemetry/exporter-otlp-http'); const { Resource } = require('@opentelemetry/resources'); const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions'); const { OtelConfig } = require('./otel-config'); // Initialize OpenTelemetry const sdk = new NodeSDK({ resource: new Resource({ [SemanticResourceAttributes.SERVICE_NAME]: OtelConfig.SERVICE_NAME, 'sensor.version': OtelConfig.SENSOR_VERSION }), traceExporter: new OTLPTraceExporter({ url: OtelConfig.OTEL_ENDPOINT }) }); // Initialize the SDK sdk.start(); // Get tracer after initialization const { trace } = require('@opentelemetry/api'); const tracer = trace.getTracer('com.example.YourApplicationName'); module.exports = { tracer };from opentelemetry import trace from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter from opentelemetry.sdk.resources import Resource from otel_config import OtelConfig # Initialize OpenTelemetry resource = Resource.create({ "service.name": OtelConfig.SERVICE_NAME, "sensor.version": OtelConfig.SENSOR_VERSION }) trace.set_tracer_provider(TracerProvider(resource=resource)) # Configure OTLP exporter otlp_exporter = OTLPSpanExporter(endpoint=OtelConfig.OTEL_ENDPOINT) span_processor = BatchSpanProcessor(otlp_exporter) trace.get_tracer_provider().add_span_processor(span_processor) # Get tracer tracer = trace.get_tracer("com.example.YourApplicationName")Ensure span attributes include all required metadata.
Redact sensitive values (tokens, passwords, API keys) from headers and bodies.
Best Practices
Maintain consistent resource attributes across services.
Apply redaction or masking for sensitive values.
Limit body capture for large payloads to avoid performance overhead.
Use span attributes to align with OpenTelemetry Semantic Conventions where applicable.