- Install dependencies:
npm install- Build TypeScript:
npm run buildMake sure Elasticsearch APM Server is running and accessible at http://localhost:8200 (or set OTEL_EXPORTER_OTLP_ENDPOINT).
Run the example:
npm startOr run directly with ts-node:
npm run devAfter running, traces are sent to Elasticsearch. To view them:
-
Kibana UI: Navigate to
http://localhost:5601/app/apm/traces - Elasticsearch API: Query traces by traceId:
curl -X GET "localhost:9200/apm-*/_search?q=trace.id:<traceId>"The traceId is printed in the console output when the example runs.
Set the OTLP endpoint via environment variable:
OTEL_EXPORTER_OTLP_ENDPOINT=http://your-elasticsearch:8200 npm startimport { withTracing, withTracingAsync } from './src/tracing';
// Synchronous function
const tracedFn = withTracing(function myFunction(x: number, y: number) {
return x + y;
});
// Async function
const tracedAsyncFn = withTracingAsync(async function myAsyncFunction(x: number, y: number) {
await someAsyncOperation();
return x * y;
});To group multiple traces together that are part of the same conversation or session:
import { withTracing, setConversationId } from './src/tracing';
const tracedFn = withTracing(function handleUserRequest(userId: string, sessionId: string) {
// Set conversation ID to group all traces for this user session
setConversationId(`user_${userId}_session_${sessionId}`);
// All spans created in this function and its children will have this gen_ai.conversation.id
// ... rest of function
});The gen_ai.conversation.id attribute allows you to filter and group traces in the AIQA server by conversation, making it easier to analyze multi-step interactions or user sessions. See the OpenTelemetry GenAI Events specification for more details.
To link traces across different services or agents, you can extract and propagate trace IDs:
import { getTraceId, getSpanId } from './src/tracing';
// Get the current trace ID and span ID
const traceId = getTraceId(); // Returns hex string (32 chars) or undefined
const spanId = getSpanId(); // Returns hex string (16 chars) or undefined
// Pass these to another service (e.g., in HTTP headers, message queue, etc.)import { createSpanFromTraceId, trace, context } from './src/tracing';
import { trace as otelTrace } from '@opentelemetry/api';
// Continue a trace from another service/agent
// traceId and parentSpanId come from the other service
const span = createSpanFromTraceId(
traceId,
parentSpanId,
"service_b_operation"
);
context.with(otelTrace.setSpan(context.active(), span), () => {
// Your code here - this span will be linked to the original trace
span.end();
});For HTTP requests, use the built-in context propagation:
import { injectTraceContext, extractTraceContext } from './src/tracing';
import { trace, context } from '@opentelemetry/api';
import axios from 'axios';
// In the sending service:
const headers: Record<string, string> = {};
injectTraceContext(headers); // Adds trace context to headers
const response = await axios.get("http://other-service/api", { headers });
// In the receiving service:
// Extract context from incoming request headers
const ctx = extractTraceContext(request.headers);
// Use the context to create a span
const span = tracer.startSpan("operation", {}, ctx);
context.with(trace.setSpan(ctx, span), () => {
// Your code here
span.end();
});