100 lines
2.9 KiB
Python
100 lines
2.9 KiB
Python
import time
|
|
import random
|
|
from flask import Flask
|
|
from opentelemetry import trace
|
|
from opentelemetry.sdk.trace import TracerProvider
|
|
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
|
from opentelemetry.instrumentation.flask import FlaskInstrumentor
|
|
from opentelemetry.sdk.resources import Resource
|
|
import logging
|
|
from opentelemetry.trace import get_current_span
|
|
|
|
|
|
# Configure tracing
|
|
trace.set_tracer_provider(
|
|
TracerProvider(resource=Resource.create({"service.name": "my-flask-app"}))
|
|
)
|
|
tracer = trace.get_tracer(__name__)
|
|
span_processor = BatchSpanProcessor(OTLPSpanExporter())
|
|
trace.get_tracer_provider().add_span_processor(span_processor)
|
|
|
|
|
|
# Setup logging with trace_id
|
|
class TraceIdFilter(logging.Filter):
|
|
def filter(self, record):
|
|
span = trace.get_current_span()
|
|
ctx = span.get_span_context()
|
|
if ctx.trace_id != 0:
|
|
record.trace_id = format(ctx.trace_id, "032x")
|
|
record.span_id = format(ctx.span_id, "016x")
|
|
else:
|
|
record.trace_id = None
|
|
record.span_id = None
|
|
return True
|
|
|
|
|
|
formatter = logging.Formatter(
|
|
'{"message": "%(message)s", "trace_id": "%(trace_id)s", "span_id": "%(span_id)s"}'
|
|
)
|
|
handler = logging.StreamHandler()
|
|
handler.setFormatter(formatter)
|
|
handler.addFilter(TraceIdFilter())
|
|
|
|
logger = logging.getLogger("myapp")
|
|
logger.setLevel(logging.INFO)
|
|
logger.addHandler(handler)
|
|
|
|
# Setup Tracer
|
|
resource = Resource(
|
|
attributes={
|
|
"service.name": "python-otel-demo-app", # 👈 choose any name you like
|
|
}
|
|
)
|
|
trace.set_tracer_provider(TracerProvider(resource=resource))
|
|
tracer = trace.get_tracer(__name__)
|
|
|
|
# Configure OTLP HTTP exporter
|
|
otlp_exporter = OTLPSpanExporter(
|
|
endpoint="http://otel-collector.meta.svc:4318/v1/traces",
|
|
# insecure=True,
|
|
)
|
|
span_processor = BatchSpanProcessor(otlp_exporter)
|
|
trace.get_tracer_provider().add_span_processor(span_processor)
|
|
|
|
# Flask App
|
|
app = Flask(__name__)
|
|
FlaskInstrumentor().instrument_app(app)
|
|
|
|
|
|
def get_trace_id():
|
|
span = get_current_span()
|
|
if span:
|
|
return span.get_span_context().trace_id
|
|
return None
|
|
|
|
|
|
@app.route("/")
|
|
def root():
|
|
with tracer.start_as_current_span("handle_homepage"):
|
|
logger.info("handling request", extra={"trace_id": get_trace_id()})
|
|
time.sleep(random.random() * 0.05) # simulate request parsing
|
|
fetch_user()
|
|
calculate_recommendations()
|
|
return "Hello from / with traces!"
|
|
|
|
|
|
def fetch_user():
|
|
with tracer.start_as_current_span("fetch_user"):
|
|
time.sleep(random.random() * 0.1) # simulate DB query
|
|
|
|
|
|
def calculate_recommendations():
|
|
with tracer.start_as_current_span("calculate_recommendations"):
|
|
for i in range(2):
|
|
with tracer.start_as_current_span(f"score_item_{i}"):
|
|
time.sleep(random.random())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
app.run(host="0.0.0.0", port=5000)
|