137 lines
3.9 KiB
YAML
137 lines
3.9 KiB
YAML
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: my-python-app
|
|
namespace: prod
|
|
data:
|
|
main.py: |
|
|
import time
|
|
import random
|
|
from flask import Flask
|
|
from opentelemetry import trace, metrics
|
|
from opentelemetry.sdk.trace import TracerProvider
|
|
from opentelemetry.sdk.metrics import MeterProvider
|
|
from opentelemetry.sdk.resources import Resource
|
|
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
|
|
from opentelemetry.instrumentation.flask import FlaskInstrumentor
|
|
import logging
|
|
from opentelemetry.trace import get_current_span
|
|
|
|
# === Resource ===
|
|
resource = Resource(attributes={"service.name": "my-flask-app"})
|
|
|
|
# === Tracing ===
|
|
trace.set_tracer_provider(TracerProvider(resource=resource))
|
|
tracer = trace.get_tracer(__name__)
|
|
|
|
|
|
# === Logging with trace ID ===
|
|
class TraceIdFilter(logging.Filter):
|
|
def filter(self, record):
|
|
span = trace.get_current_span()
|
|
ctx = span.get_span_context()
|
|
record.trace_id = format(ctx.trace_id, "032x") if ctx.trace_id != 0 else None
|
|
record.span_id = format(ctx.span_id, "016x") if ctx.span_id != 0 else 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)
|
|
|
|
# === Flask App ===
|
|
app = Flask(__name__)
|
|
FlaskInstrumentor().instrument_app(app) # auto-instruments metrics + traces
|
|
|
|
|
|
@app.route("/")
|
|
def root():
|
|
with tracer.start_as_current_span("handle_homepage"):
|
|
logger.info(
|
|
"handling request",
|
|
extra={"trace_id": get_current_span().get_span_context().trace_id},
|
|
)
|
|
time.sleep(random.random() * 0.05) # simulate request parsing
|
|
fetch_user()
|
|
calculate_recommendations()
|
|
return "Hello from / with traces and metrics!"
|
|
|
|
|
|
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)
|
|
---
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: python-otel
|
|
namespace: prod
|
|
labels:
|
|
app: python-otel
|
|
spec:
|
|
replicas: 1
|
|
selector:
|
|
matchLabels:
|
|
app: python-otel
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: python-otel
|
|
spec:
|
|
containers:
|
|
- name: python
|
|
image: python
|
|
command: ["/bin/sh", "-c"]
|
|
args:
|
|
- |
|
|
python -m venv .venv && \
|
|
.venv/bin/python -m pip install --upgrade pip && \
|
|
.venv/bin/python -m pip install \
|
|
opentelemetry-sdk \
|
|
opentelemetry-exporter-otlp \
|
|
opentelemetry-instrumentation-flask \
|
|
flask && \
|
|
.venv/bin/python /app/main.py
|
|
volumeMounts:
|
|
- name: app-code
|
|
mountPath: /app
|
|
env:
|
|
- name: OTEL_EXPORTER_OTLP_ENDPOINT
|
|
value: http://otel-collector.meta.svc:4318
|
|
- name: OTEL_EXPORTER_OTLP_INSECURE
|
|
value: "true"
|
|
volumes:
|
|
- name: app-code
|
|
configMap:
|
|
name: my-python-app
|
|
---
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: python-otel
|
|
namespace: prod
|
|
spec:
|
|
selector:
|
|
app: python-otel
|
|
ports:
|
|
- port: 80
|
|
targetPort: 5000
|