1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
#!/usr/bin/env python3
"""
Tracing Demo - Backend Service
Final service in the chain that returns data.
Simulates database queries and demonstrates end-to-end tracing.
"""
from flask import Flask, jsonify
import os
import logging
import time
from datetime import datetime
# OpenTelemetry imports for distributed tracing
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from opentelemetry.sdk.resources import Resource
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Initialize OpenTelemetry tracing with resource attributes
# These attributes identify this service in traces
resource = Resource(attributes={
"service.name": "backend",
"service.namespace": "tracing-demo",
"service.version": "1.0.0",
"deployment.environment": "production"
})
provider = TracerProvider(resource=resource)
# Configure OTLP exporter to send traces to Alloy
otlp_exporter = OTLPSpanExporter(
endpoint=os.getenv('OTEL_EXPORTER_OTLP_ENDPOINT',
'http://alloy.monitoring.svc.cluster.local:4317'),
insecure=True
)
# Batch spans for efficient export
processor = BatchSpanProcessor(otlp_exporter)
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)
# Get tracer for manual instrumentation
tracer = trace.get_tracer(__name__)
# Create Flask application
app = Flask(__name__)
# Auto-instrument Flask
# Auto-instrument Flask to create spans for HTTP requests
# Exclude health check endpoint to reduce tracing noise
FlaskInstrumentor().instrument_app(app, excluded_urls="/health")
@app.route('/')
def index():
"""
Health check and service information endpoint.
Returns service metadata.
"""
return jsonify({
"service": "backend",
"version": "1.0.0",
"message": "Tracing demo backend service"
})
@app.route('/health')
def health():
"""
Kubernetes health check endpoint.
Used by readiness and liveness probes.
"""
return jsonify({"status": "healthy"}), 200
@app.route('/api/data', methods=['GET'])
def get_data():
"""
Return data endpoint that simulates a database query.
Creates custom spans to track query execution.
This is the final service in the trace chain.
"""
# Create a custom span for the database query simulation
with tracer.start_as_current_span("backend-get-data") as span:
# Add custom attributes to the span
span.set_attribute("backend.handler", "get_data")
# Simulate database query delay
query_time = 0.1
time.sleep(query_time)
# Record query duration in span
span.set_attribute("backend.query.duration_ms", query_time * 1000)
span.set_attribute("backend.query.type", "simulated_database_query")
# Prepare response data
data = {
"service": "backend",
"data": {
"id": 12345,
"value": "Sample data from backend service",
"timestamp": datetime.utcnow().isoformat(),
"query_time_ms": query_time * 1000
}
}
logger.info(f"Returning data: {data['data']['id']}")
return jsonify(data), 200
if __name__ == '__main__':
logger.info("Starting backend service on port 5002")
logger.info(f"OTLP endpoint: {os.getenv('OTEL_EXPORTER_OTLP_ENDPOINT', 'default')}")
app.run(host='0.0.0.0', port=5002, debug=False)
|