- Client: A small script (
payment.py) that creates spans and attributes for a payment flow. - Server: A minimal Flask app (
charge.py) that receives a /charge request. We’ll first show the uninstrumented service, then the instrumented version that exports traces via OTLP. - Goal: Have both client and server produce spans that are searchable in a tracing backend (Jaeger, Tempo, or any OpenTelemetry-compatible backend).
trace.get_tracer(...)creates a tracer instance used to start spans.trace.get_current_span()accesses the active span to set attributes (user, account number, bank).- Helper functions use the tracer decorator to create child spans for validation and charging.
- Configure a TracerProvider and set resource attributes (
service.name,service.version). - Attach a span processor (BatchSpanProcessor) and an OTLP exporter pointing at an OTLP HTTP endpoint (
http://localhost:4318/v1/tracesin this example). - Start a server span for incoming requests and enrich it with HTTP attributes:
http.method,net.peer.ip, andhttp.path.
charge.py:
OTLPSpanExporter(endpoint="http://localhost:4318/v1/traces")sends traces over HTTP to an OTLP-compatible collector or backend.BatchSpanProcessoris recommended in production to improve performance.- Setting
Resourceattributes likeservice.nameandservice.versionimproves trace filtering and service identification in a backend.
Make sure an OTLP-compatible collector (or backend) is reachable at the OTLP endpoint you configured (here,
http://localhost:4318/v1/traces). If you want console output only for quick testing, you can swap OTLPSpanExporter for ConsoleSpanExporter.charge-service traces. The server spans should contain the attributes we set: http.method, net.peer.ip, and http.path.
Best practices and tips
- Use consistent
service.nameand versioning across your services for easier filtering. - Prefer
BatchSpanProcessorin production andConsoleSpanExporterwhile developing locally. - Enrich spans with HTTP and network attributes (method, path, client IP) so you can search and correlate traces easily.
- Reuse the tracer provider and exporter configuration pattern across services; only change
service.nameandservice.version.
| Attribute | Purpose | Example |
|---|---|---|
service.name | Identify the service producing spans | charge-service |
service.version | Version of the service | 0.5.0 |
http.method | HTTP verb of the request | GET |
http.path | Path requested | /charge |
net.peer.ip | Client IP address | 127.0.0.1 |
user | Application-level user id | john |
account_number | Application-level account identifier | 7372349 |
- The client (
payment.py) demonstrates creating spans and adding attributes to describe a payment workflow. - The Flask service (
charge.py) is instrumented to create server spans and enrich them with HTTP attributes for better observability. - You can reuse the tracer provider, exporter, span processor, and resource configuration across services—only update
service.nameandservice.version.