Skip to main content
In this lesson we continue the sample payment application and demonstrate how to instrument both the client-side payment flow and the external charge API using OpenTelemetry. You will learn how spans are created on the client, how to add useful attributes, and how to instrument a Flask service to export server spans to an OTLP endpoint. Overview
  • 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).
Client-side instrumentation (payment.py) This client simulates a payment flow and creates spans plus attributes before calling the downstream charge service.
Key points:
  • 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.
Uninstrumented Flask charge service (initial state) The external service that performs the charge is a minimal Flask app. Below is the uninstrumented version:
Quick local verification Run the uninstrumented service and verify the endpoint responds:
Instrumenting the Flask API with OpenTelemetry To export traces from the Flask API, we will:
  • 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/traces in this example).
  • Start a server span for incoming requests and enrich it with HTTP attributes: http.method, net.peer.ip, and http.path.
Below is a cohesive, instrumented charge.py:
Notes:
  • OTLPSpanExporter(endpoint="http://localhost:4318/v1/traces") sends traces over HTTP to an OTLP-compatible collector or backend.
  • BatchSpanProcessor is recommended in production to improve performance.
  • Setting Resource attributes like service.name and service.version improves 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.
Start the instrumented service and test
If you have a tracing backend (Jaeger, Tempo, or an OpenTelemetry Collector forwarding to a backend), refresh the tracing UI and look for the 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.name and versioning across your services for easier filtering.
  • Prefer BatchSpanProcessor in production and ConsoleSpanExporter while 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.name and service.version.
Common attributes to set on spans
AttributePurposeExample
service.nameIdentify the service producing spanscharge-service
service.versionVersion of the service0.5.0
http.methodHTTP verb of the requestGET
http.pathPath requested/charge
net.peer.ipClient IP address127.0.0.1
userApplication-level user idjohn
account_numberApplication-level account identifier7372349
Summary
  • 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.name and service.version.
Links and References

Watch Video