learn-grafana/pyservice.yaml
Waylon S. Walker 774ea44af1 wip
2025-05-23 10:24:41 -05:00

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