OpenTelemetry
Automatic distributed tracing and metrics with OTEL.
Available in Phase 1b. This feature ships with the sidecar daemon and wrapper SDKs. Phase 1a (Rust crate only) users access this via the core engine directly.
OpenTelemetry
CoreSDK automatically creates OTEL spans for every request, attaches auth and policy outcomes as span attributes, and propagates trace context across service boundaries.
Configuration
let engine = Engine::from_env().await?;
// Set via env vars:
// OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
// CORESDK_SERVICE_NAME=orders-service# Python: set env vars — sidecar handles OTLP export
# OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
# CORESDK_SERVICE_NAME=orders-service
from coresdk.tracing.decorator import trace
@app.get("/products")
@trace(intent="list-products")
async def list_products(request: Request):
...// Phase 2 — Go SDK not yet available
sdk, err := sdk.New(sdk.Config{
Tenant: "acme",
OtelEndpoint: "http://localhost:4317", // OTLP gRPC
OtelServiceName: "orders-service",
OtelSampleRate: 1.0, // 0.0–1.0
})// Phase 2 — TypeScript SDK not yet available
const sdk = new CoreSDK({
tenant: "acme",
otelEndpoint: "http://localhost:4317", // OTLP gRPC
otelServiceName: "orders-service",
otelSampleRate: 1.0, // 0.0–1.0
});What gets traced
Every request span includes:
| Attribute | Example |
|---|---|
coresdk.tenant_id | acme |
coresdk.user_id | usr_2xK9 |
coresdk.user_role | member |
coresdk.auth.method | jwt |
coresdk.auth.result | allowed |
coresdk.policy.action | orders:read |
coresdk.policy.result | allowed |
coresdk.policy.latency_us | 45 |
http.method | GET |
http.route | /api/orders |
http.status_code | 200 |
Live trace viewer
core trace tail --tenant acme
# stream live traces to terminal
core trace tail --tenant acme --filter 'policy.result=denied'
# filter to denied requests onlyCustom spans
use coresdk_engine::telemetry::span;
async fn process_order(order: Order, user: &User) {
let _span = span!("process_order",
order.id = %order.id,
user.id = %user.id,
);
// span automatically ends when _span drops
do_work(&order).await;
}from coresdk.tracing.decorator import trace
@trace(intent="process-order")
async def process_order(order: Order, user: User):
# span automatically created and ended by the decorator
await do_work(order)import "github.com/coresdk/sdk/telemetry"
func processOrder(ctx context.Context, order Order, user User) error {
ctx, span := telemetry.Start(ctx, "process_order",
telemetry.Attr("order.id", order.ID),
telemetry.Attr("user.id", user.ID),
)
defer span.End()
// span automatically ends when deferred
return doWork(ctx, &order)
}import { span } from "@coresdk/sdk/telemetry";
async function processOrder(order: Order, user: User): Promise<void> {
await span("process_order", { "order.id": order.id, "user.id": user.id }, async () => {
// span automatically ends when callback resolves
await doWork(order);
});
}Baggage propagation
CoreSDK automatically propagates user and tenant context as OTEL baggage across service boundaries.
Downstream services using CoreSDK will have the same user_id and tenant_id in their spans.
Metrics
CoreSDK exports the following OTEL metrics:
| Metric | Type | Description |
|---|---|---|
coresdk.auth.requests | Counter | Auth requests by result (allowed/denied) |
coresdk.auth.latency | Histogram | JWT verification latency |
coresdk.policy.requests | Counter | Policy evaluations by action + result |
coresdk.policy.latency | Histogram | Rego evaluation latency |
coresdk.errors | Counter | Errors by type |
CloudEvents envelope
Phase note. Ships Phase 2.
CoreSDK can wrap OTel events in a CloudEvents metadata envelope before exporting. This enables interoperability with event-driven systems (Kafka, EventBridge, Knative Eventing, Azure Event Grid) that expect CloudEvents format.
let engine = Engine::from_env().await?;
// cloud_events configuration via coresdk-sidecar.yaml# Phase 2 — configure via sidecar YAML
# cloud_events:
# enabled: true
# source: https://orders.acme.com// Phase 2 — Go SDK not yet available
sdk, err := coresdk.New(coresdk.Config{
Tenant: "acme",
CloudEvents: true,
CloudEventsSource: "https://orders.acme.com",
})// Phase 2 — TypeScript SDK not yet available
const sdk = new CoreSDK({
tenant: "acme",
cloudEvents: true,
cloudEventsSource: "https://orders.acme.com",
});Each exported OTel log event is wrapped in a CloudEvents envelope:
{
"specversion": "1.0",
"type": "io.coresdk.policy.decision",
"source": "https://orders.acme.com",
"id": "01HX7KQMB4NWE9P6T2JS0RY3ZV",
"time": "2026-03-19T14:35:00Z",
"datacontenttype": "application/json",
"data": {
"tenant_id": "acme",
"user_id": "usr_2xK9",
"action": "orders:read",
"result": "allowed",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}CloudEvents wrapping applies to log events only — traces and metrics continue to export via OTLP in standard format.
Export targets
CoreSDK works with any OTLP-compatible backend:
// Jaeger
.otel_endpoint("http://jaeger:4317")
// Grafana Tempo
.otel_endpoint("http://tempo:4317")
// Datadog (via OTLP)
.otel_endpoint("http://datadog-agent:4317")
// CoreSDK Cloud
.otel_endpoint("https://otel.coresdk.dev")
.otel_api_key("sdk_...")# Set OTEL_EXPORTER_OTLP_ENDPOINT to route to any OTLP-compatible backend:
# Jaeger
# OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger:4317
# Grafana Tempo
# OTEL_EXPORTER_OTLP_ENDPOINT=http://tempo:4317
# Datadog (via OTLP)
# OTEL_EXPORTER_OTLP_ENDPOINT=http://datadog-agent:4317
# CoreSDK Cloud
# OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.coresdk.dev// Jaeger
sdk.New(sdk.Config{Tenant: "acme", OtelEndpoint: "http://jaeger:4317"})
// Grafana Tempo
sdk.New(sdk.Config{Tenant: "acme", OtelEndpoint: "http://tempo:4317"})
// Datadog (via OTLP)
sdk.New(sdk.Config{Tenant: "acme", OtelEndpoint: "http://datadog-agent:4317"})
// CoreSDK Cloud
sdk.New(sdk.Config{
Tenant: "acme",
OtelEndpoint: "https://otel.coresdk.dev",
OtelApiKey: "sdk_...",
})// Jaeger
new CoreSDK({ tenant: "acme", otelEndpoint: "http://jaeger:4317" })
// Grafana Tempo
new CoreSDK({ tenant: "acme", otelEndpoint: "http://tempo:4317" })
// Datadog (via OTLP)
new CoreSDK({ tenant: "acme", otelEndpoint: "http://datadog-agent:4317" })
// CoreSDK Cloud
new CoreSDK({
tenant: "acme",
otelEndpoint: "https://otel.coresdk.dev",
otelApiKey: "sdk_...",
})