Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Implement distributed tracing with Jaeger and Tempo to track requests across microservices and identify performance bottlenecks. Use when debugging microservices, analyzing request flows, or implementing observability for distributed systems.
.claude/skills/microck-distributed-tracing/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-14 | ✗→✓ | ▲ Improved | 107% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 90% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 423% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 303% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 216% | 0% |
Implement distributed tracing with Jaeger and Tempo for request flow visibility across microservices.
Track requests across distributed systems to understand latency, dependencies, and failure points.
Trace (Request ID: abc123)
↓
Span (frontend) [100ms]
↓
Span (api-gateway) [80ms]
├→ Span (auth-service) [10ms]
└→ Span (user-service) [60ms]
└→ Span (database) [40ms]bash# Deploy Jaeger Operator kubectl create namespace observability kubectl create -f https://github.com/jaegertracing/jaeger-operator/releases/download/v1.51.0/jaeger-operator.yaml -n observability # Deploy Jaeger instance kubectl apply -f - <<EOF apiVersion: jaegertracing.io/v1 kind: Jaeger metadata: name: jaeger namespace: observability spec: strategy: production storage: type: elasticsearch options: es: server-urls: http://elasticsearch:9200 ingress: enabled: true EOF
yamlversion: '3.8' services: jaeger: image: jaegertracing/all-in-one:latest ports: - "5775:5775/udp" - "6831:6831/udp" - "6832:6832/udp" - "5778:5778" - "16686:16686" # UI - "14268:14268" # Collector - "14250:14250" # gRPC - "9411:9411" # Zipkin environment: - COLLECTOR_ZIPKIN_HOST_PORT=:9411
Reference: See references/jaeger-setup.md
pythonfrom opentelemetry import trace from opentelemetry.exporter.jaeger.thrift import JaegerExporter from opentelemetry.sdk.resources import SERVICE_NAME, Resource from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.instrumentation.flask import FlaskInstrumentor from flask import Flask # Initialize tracer resource = Resource(attributes={SERVICE_NAME: "my-service"}) provider = TracerProvider(resource=resource) processor = BatchSpanProcessor(JaegerExporter( agent_host_name="jaeger", agent_port=6831, )) provider.add_span_processor(processor) trace.set_tracer_provider(provider) # Instrument Flask app = Flask(__name__) FlaskInstrumentor().instrument_app(app) @app.route('/api/users') def get_users(): tracer = trace.get_tracer(__name__) with tracer.start_as_current_span("get_users") as span: span.set_attribute("user.count", 100) # Business logic users = fetch_users_from_db() return {"users": users} def fetch_users_from_db(): tracer = trace.get_tracer(__name__) with tracer.start_as_current_span("database_query") as span: span.set_attribute("db.system", "postgresql") span.set_attribute("db.statement", "SELECT * FROM users") # Database query return query_database()
javascriptconst { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); const { BatchSpanProcessor } = require('@opentelemetry/sdk-trace-base'); const { registerInstrumentations } = require('@opentelemetry/instrumentation'); const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http'); const { ExpressInstrumentation } = require('@opentelemetry/instrumentation-express'); // Initialize tracer const provider = new NodeTracerProvider({ resource: { attributes: { 'service.name': 'my-service' } } }); const exporter = new JaegerExporter({ endpoint: 'http://jaeger:14268/api/traces' }); provider.addSpanProcessor(new BatchSpanProcessor(exporter)); provider.register(); // Instrument libraries registerInstrumentations({ instrumentations: [ new HttpInstrumentation(), new ExpressInstrumentation(), ], }); const express = require('express'); const app = express(); app.get('/api/users', async (req, res) => { const tracer = trace.getTracer('my-service'); const span = tracer.startSpan('get_users'); try { const users = await fetchUsers(); span.setAttributes({ 'user.count': users.length }); res.json({ users }); } finally { span.end(); } });
gopackage main import ( "context" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/jaeger" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.4.0" ) func initTracer() (*sdktrace.TracerProvider, error) { exporter, err := jaeger.New(jaeger.WithCollectorEndpoint( jaeger.WithEndpoint("http://jaeger:14268/api/traces"), )) if err != nil { return nil, err } tp := sdktrace.NewTracerProvider( sdktrace.WithBatcher(exporter), sdktrace.WithResource(resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceNameKey.String("my-service"), )), ) otel.SetTracerProvider(tp) return tp, nil } func getUsers(ctx context.Context) ([]User, error) { tracer := otel.Tracer("my-service") ctx, span := tracer.Start(ctx, "get_users") defer span.End() span.SetAttributes(attribute.String("user.filter", "active")) users, err := fetchUsersFromDB(ctx) if err != nil { span.RecordError(err) return nil, err } span.SetAttributes(attribute.Int("user.count", len(users))) return users, nil }
Reference: See references/instrumentation.md
traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
tracestate: congo=t61rcWkgMzEpythonfrom opentelemetry.propagate import inject headers = {} inject(headers) # Injects trace context response = requests.get('http://downstream-service/api', headers=headers)
javascriptconst { propagation } = require('@opentelemetry/api'); const headers = {}; propagation.inject(context.active(), headers); axios.get('http://downstream-service/api', { headers });
yamlapiVersion: v1 kind: ConfigMap metadata: name: tempo-config data: tempo.yaml: | server: http_listen_port: 3200 distributor: receivers: jaeger: protocols: thrift_http: grpc: otlp: protocols: http: grpc: storage: trace: backend: s3 s3: bucket: tempo-traces endpoint: s3.amazonaws.com querier: frontend_worker: frontend_address: tempo-query-frontend:9095 --- apiVersion: apps/v1 kind: Deployment metadata: name: tempo spec: replicas: 1 template: spec: containers: - name: tempo image: grafana/tempo:latest args: - -config.file=/etc/tempo/tempo.yaml volumeMounts: - name: config mountPath: /etc/tempo volumes: - name: config configMap: name: tempo-config
Reference: See assets/jaeger-config.yaml.template
yaml# Sample 1% of traces sampler: type: probabilistic param: 0.01
yaml# Sample max 100 traces per second sampler: type: ratelimiting param: 100
pythonfrom opentelemetry.sdk.trace.sampling import ParentBased, TraceIdRatioBased # Sample based on trace ID (deterministic) sampler = ParentBased(root=TraceIdRatioBased(0.01))
Jaeger Query:
service=my-service
duration > 1sJaeger Query:
service=my-service
error=true
tags.http.status_code >= 500Jaeger automatically generates service dependency graphs showing:
pythonimport logging from opentelemetry import trace logger = logging.getLogger(__name__) def process_request(): span = trace.get_current_span() trace_id = span.get_span_context().trace_id logger.info( "Processing request", extra={"trace_id": format(trace_id, '032x')} )
No traces appearing:
High latency overhead:
references/jaeger-setup.md - Jaeger installationreferences/instrumentation.md - Instrumentation patternsassets/jaeger-config.yaml.template - Jaeger configurationprometheus-configuration - For metricsgrafana-dashboards - For visualizationslo-implementation - For latency SLOs| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | pass→pass | 13,128 | 9,412 | -28% | 1 | 1 | 0% | 2,483 | 4,724 | +90% | 0 | 0 | — |
case-02 | pass→pass | 3,512 | 3,803 | +8% | 1 | 1 | 0% | 681 | 3,559 | +423% | 0 | 0 | — |
case-03 | pass→pass | 4,989 | 4,393 | -12% | 1 | 1 | 0% | 928 | 3,737 | +303% | 0 | 0 | — |
case-04 | pass→pass | 6,574 | 4,440 | -32% | 1 | 1 | 0% | 1,181 | 3,733 | +216% | 0 | 0 | — |
case-05 | pass→pass | 7,971 | 5,538 | -31% | 1 | 1 | 0% | 1,517 | 3,983 | +163% | 0 | 0 | — |
case-06 | pass→pass | 5,149 | 2,594 | -50% | 1 | 1 | 0% | 973 | 3,443 | +254% | 0 | 0 | — |
case-07 | pass→pass | 9,386 | 7,639 | -19% | 1 | 1 | 0% | 1,757 | 4,400 | +150% | 0 | 0 | — |
case-08 | pass→pass | 4,438 | 2,767 | -38% | 1 | 1 | 0% | 766 | 3,350 | +337% | 0 | 0 | — |
case-09 | pass→pass | 4,532 | 2,612 | -42% | 1 | 1 | 0% | 704 | 3,222 | +358% | 0 | 0 | — |
case-18 | pass→pass | 2,737 | 2,410 | -12% | 1 | 1 | 0% | 411 | 3,249 | +691% | 0 | 0 | — |
case-10 | pass→pass | 6,813 | 4,973 | -27% | 1 | 1 | 0% | 1,399 | 3,866 | +176% | 0 | 0 | — |
case-11 | pass→pass | 4,144 | 3,135 | -24% | 1 | 1 | 0% | 690 | 3,512 | +409% | 0 | 0 | — |
case-12 | pass→pass | 4,042 | 2,758 | -32% | 1 | 1 | 0% | 651 | 3,345 | +414% | 0 | 0 | — |
case-13 | pass→pass | 6,482 | 3,029 | -53% | 1 | 1 | 0% | 1,082 | 3,409 | +215% | 0 | 0 | — |
case-14 | fail→pass | 11,137 | 4,771 | -57% | 1 | 1 | 0% | 1,777 | 3,686 | +107% | 0 | 0 | — |
case-15 | pass→pass | 2,895 | 2,071 | -28% | 1 | 1 | 0% | 431 | 3,233 | +650% | 0 | 0 | — |
case-16 | pass→pass | 7,488 | 2,736 | -63% | 1 | 1 | 0% | 1,396 | 3,338 | +139% | 0 | 0 | — |
case-17 | pass→pass | 3,870 | 2,308 | -40% | 1 | 1 | 0% | 690 | 3,319 | +381% | 0 | 0 | — |
case-19 | pass→pass | 7,147 | 5,167 | -28% | 1 | 1 | 0% | 1,219 | 3,869 | +217% | 0 | 0 | — |
case-20 | pass→pass | 7,728 | 5,882 | -24% | 1 | 1 | 0% | 1,524 | 4,095 | +169% | 0 | 0 | — |
case-21 | pass→pass | 8,177 | 5,160 | -37% | 1 | 1 | 0% | 1,443 | 3,810 | +164% | 0 | 0 | — |
case-22 | pass→pass | 13,391 | 11,449 | -15% | 1 | 1 | 0% | 2,472 | 5,278 | +114% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +5 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.