wip
This commit is contained in:
parent
0a4b32dffe
commit
774ea44af1
9 changed files with 160 additions and 115 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1 +1,2 @@
|
|||
.null-ls_806023_main.py
|
||||
.null-ls_378979_main.py
|
||||
|
|
|
|||
30
justfile
30
justfile
|
|
@ -1,21 +1,41 @@
|
|||
forward_loki:
|
||||
# export KUBECONFIG=kubeconfig.yaml
|
||||
|
||||
|
||||
kind-up:
|
||||
kind create cluster --name grafana
|
||||
kind get kubeconfig --name grafana > kubeconfig.yaml
|
||||
kubectl create namespace meta && kubectl create namespace prod
|
||||
helm repo add grafana https://grafana.github.io/helm-charts && helm repo update
|
||||
|
||||
helm install loki grafana/loki --namespace meta --values loki-values.yaml
|
||||
helm install kps prometheus-community/kube-prometheus-stack --namespace meta -f prometheus-values.yaml
|
||||
helm install grafana grafana/grafana --values grafana-values.yml --namespace meta
|
||||
helm install k8s-monitoring grafana/k8s-monitoring --values ./k8s-monitoring-values.yml -n meta --create-namespace
|
||||
|
||||
kubectl apply -f pyservice.yaml
|
||||
|
||||
kind-down:
|
||||
kind delete cluster --name grafana
|
||||
|
||||
forward-loki:
|
||||
kubectl port-forward --namespace meta svc/loki-gateway 3100:80
|
||||
forward_grafana:
|
||||
|
||||
forward-grafana:
|
||||
#!/bin/bash
|
||||
export POD_NAME=$(kubectl get pods --namespace meta -l "app.kubernetes.io/name=grafana,app.kubernetes.io/instance=grafana" -o jsonpath="{.items[0].metadata.name}")
|
||||
kubectl --namespace meta port-forward $POD_NAME 3000
|
||||
|
||||
forward_alloy_logs:
|
||||
forward-alloy-logs:
|
||||
#!/bin/bash
|
||||
export POD_NAME=$(kubectl get pods --namespace meta -l "app.kubernetes.io/name=alloy-logs,app.kubernetes.io/instance=k8s" -o jsonpath="{.items[0].metadata.name}")
|
||||
kubectl --namespace meta port-forward $POD_NAME 12345
|
||||
|
||||
forward_otel_collector:
|
||||
forward-otel-collector:
|
||||
#!/bin/bash
|
||||
export POD_NAME=$(kubectl get pods --namespace meta -l "app.kubernetes.io/name=otel-collector,app.kubernetes.io/instance=k8s" -o jsonpath="{.items[0].metadata.name}")
|
||||
kubectl --namespace meta port-forward $POD_NAME 4317
|
||||
|
||||
get_inotify_max_user_watches:
|
||||
get-inotify-max-user-watches:
|
||||
#!/bin/bashcat /proc/sys/fs/inotify/max_user_watches
|
||||
|
||||
export POD_NAME=$(kubectl get pods --namespace meta -l "app.kubernetes.io/name=grafana,app.kubernetes.io/instance=grafana" -o jsonpath="{.items[0].metadata.name}")
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ podLogs:
|
|||
trace_id: ${body.trace_id}
|
||||
span_id: ${body.span_id}
|
||||
service_name: ${body.service_name}
|
||||
app: "${kubernetes.labels.app}"
|
||||
structuredMetadata:
|
||||
pod: pod # Set structured metadata "pod" from label "pod"
|
||||
namespaces: []
|
||||
|
|
@ -36,8 +37,8 @@ nodeExporter:
|
|||
enabled: true
|
||||
kube-state-metrics:
|
||||
enabled: true
|
||||
nodeLogs:
|
||||
enabled: true
|
||||
# nodeLogs:
|
||||
# enabled: true
|
||||
kubeletMetrics:
|
||||
enabled: true
|
||||
cAdvisor:
|
||||
|
|
|
|||
20
kubeconfig.yaml
Normal file
20
kubeconfig.yaml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURCVENDQWUyZ0F3SUJBZ0lJYXAwZDdtK0k2bVV3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TlRBMU1qSXlNREk1TkRGYUZ3MHpOVEExTWpBeU1ETTBOREZhTUJVeApFekFSQmdOVkJBTVRDbXQxWW1WeWJtVjBaWE13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLCkFvSUJBUURENXVQVnJEVVFuQkd4bGtKYmdSWm1Xc21yWDgwYlR1R3RIOXZsWFNaTmd3L3NFZy9uK1FXRncrd3oKbGFlbytWNnpFQStjSkVvMVFyVm5kTUFUSjdjUkxra0oyenVpM2pCMVpTRm5lcjZKMXVpRmcyYmN0ZjJ0R29jQQpZbGx1KzVqdmlOamNmcHZhcUFqaFR2SzdzVE1nc1pYTHFlQ3I5ZGoybnVUWG12QlhEVHFtSmJ2MDAyaVJ5UEV6ClNPUENYOG13QUxuVFlteVgyRVlDbU00K3NqNzhQWVoyZ3FqV1VtZGd5Mnl1WjczOGNtc0tEeVNXZlRmcXhEMS8KamRoN2pWbUtwZXZaM1MrVnhkaHdKR0lSbm1oK3NMd3NCQjFhamNwZWY4QVp2U3hwdlJ0YWxIeVgxTCs5SmVJegpKSHptTVJ3U21SRGRnQUZucFIyR3I1YitjQXdIQWdNQkFBR2pXVEJYTUE0R0ExVWREd0VCL3dRRUF3SUNwREFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUIwR0ExVWREZ1FXQkJTd2l0dDRPM2gydGd3L1hFUi8zZ1BXbjRMczd6QVYKQmdOVkhSRUVEakFNZ2dwcmRXSmxjbTVsZEdWek1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQmxhaVNGckttUQpGWFIvQWhKUUZjY3U3L2N3by9HMCtZT0xDbElsZ2tGaHNqMVlhUERkci9FTWxVeWpwMkNNaGYrTjBYUXJyM0wvCnNnMCt1R1J2dzV6VDI0VzhYbXBURjhiTGdtMlo3azMrMWdyVzlVUHVKczVVQzJURWJYWnhXZUtnRkl2Mm56OGoKUWMwVGdqaUtNLzNMaTdlWWQ4QUNZbzlyNnMvMUJXNVlxR01VOWt5ZktlTE1wQy8wMHlPRWJBRHRHRzVEeDFtbApweko2bURwQml5WERNQjE1VUJyVW96SllxUys5Mk1VcUM1WXZHTXpKTm1UMzhpcWY4TzlxMzVNWUJvSWI3WjM1CjM4S0h3MGgwZFhocnB5by8yYW1JRSs0a0lXc2hPWEl2Q0RrVCsyWDVUd1o0RkFmU1htazlNeC9jS1l1VkJ0Y0oKMld3VVFtYXdiWUFiCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
|
||||
server: https://127.0.0.1:42441
|
||||
name: kind-grafana
|
||||
contexts:
|
||||
- context:
|
||||
cluster: kind-grafana
|
||||
user: kind-grafana
|
||||
name: kind-grafana
|
||||
current-context: kind-grafana
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: kind-grafana
|
||||
user:
|
||||
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLVENDQWhHZ0F3SUJBZ0lJRExoYllYczFrcGt3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TlRBMU1qSXlNREk1TkRGYUZ3MHlOakExTWpJeU1ETTBOREZhTUR3eApIekFkQmdOVkJBb1RGbXQxWW1WaFpHMDZZMngxYzNSbGNpMWhaRzFwYm5NeEdUQVhCZ05WQkFNVEVHdDFZbVZ5CmJtVjBaWE10WVdSdGFXNHdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFETVBKZmMKVjY0MElNRXYzVFM5R3pkTS9zMkgvTGEwcWRXdDNlOHY0TlRRUTBKN3EzbldldlpMYmp2TXVJNDQ3czRxRGY3Qgo1VjVpMFY1UUZIREVXWHFOM2h5Mnc0dG1zVVUrQ3R0UCt4QWp0RFlDaC9pT0NrUFA3UEJ1eG5ndm82R2Qyczl3CnF4emd0ZW56UHZ1ekdsMzdaSDN2L0t2bDVoMWVoMXo4OHh5RjNFZUNmN0RGUW44aFFMSStNOUt1d0ZLNXdqcUUKeGRXWlRrbWg4WElIVy8vQVRybHhEZjAra3ZuaUgzNFVVSGZxSnhCUHpDYjNsQk9WMmRpOTlOdWdvcEp2QTZxdQorcXRXRGhqTFR5MFF5WWdYcmE0ZjFVYUpGVGZqS2lXTy9VWm1FcjE4bEd1THd6TVQrRUp6SitSUERRVlo0YVA5CkZNRDQzNE96MmQxMGJjZWpBZ01CQUFHalZqQlVNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUsKQmdnckJnRUZCUWNEQWpBTUJnTlZIUk1CQWY4RUFqQUFNQjhHQTFVZEl3UVlNQmFBRkxDSzIzZzdlSGEyREQ5YwpSSC9lQTlhZmd1enZNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUJSNWZjNVEzNEtiZmZLclVyU3lNMng1STh2CnNUdDhYeTdsOTFoeHd4N1RObXk3ZkUrdUdHSzRWVDlMNnZ4dUw4UHRLbXZNSUtpM0pSbUtTYXVRZXJMeW16bGEKNE42eTQzbStJdTdxRjRwbG1RMUlNL1kzY1JFQTBhcXhwOVhUUVBjRDROeGxFNy81MEhTZ3NZeitNWXVYQUliMgpGYi8xWmRQMkUrWElGam9JbVFtNE1lNkV2ZjlkWW1mdFN1Sm1qOVVtM3h5ZG1jelRsbkdEK051UDZ2T01IS2o5CmJUUlBUUEVCUk5pMGJzck5ycXBLUkQzUno1UWZqcUVaUE9FNVFMTThBRUUzTkQ1SHQrUnVUcmZ3a2lGdlo2SVEKZk42eFFtOWp4VFpRSEx1WFUvZy9UdzFOajlrZDJqSm1HOGFBRkR4OEw0MFJMSXFqUmNtU1F3SS9MOVcvCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
|
||||
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBekR5WDNGZXVOQ0RCTDkwMHZSczNUUDdOaC95MnRLblZyZDN2TCtEVTBFTkNlNnQ1CjFucjJTMjQ3ekxpT09PN09LZzMrd2VWZVl0RmVVQlJ3eEZsNmpkNGN0c09MWnJGRlBncmJUL3NRSTdRMkFvZjQKamdwRHorendic1o0TDZPaG5kclBjS3NjNExYcDh6NzdzeHBkKzJSOTcveXI1ZVlkWG9kYy9QTWNoZHhIZ24rdwp4VUovSVVDeVBqUFNyc0JTdWNJNmhNWFZtVTVKb2ZGeUIxdi93RTY1Y1EzOVBwTDU0aDkrRkZCMzZpY1FUOHdtCjk1UVRsZG5ZdmZUYm9LS1Nid09xcnZxclZnNFl5MDh0RU1tSUY2MnVIOVZHaVJVMzR5b2xqdjFHWmhLOWZKUnIKaThNekUvaENjeWZrVHcwRldlR2ovUlRBK04rRHM5bmRkRzNIb3dJREFRQUJBb0lCQUVia0VXSXVIUTJEQVF0NApJTUl6SERMaGpyM1EvaW9mZVVmc2JRV1ZhTWtSVDVaVm91akxyWW5wTFdDVi91Zk1IRXVFcUJUdFpLR3dRcWhSCk1BTTNlODZhZGlVS0l1ejJReTZSM2lZWTR6VkJiQzNjdkcyeEtuQ1ZzYThCdk4zc1VrRFVub1JoSUpqdkM5R2UKM3diLzgvYzZubXdhckNBVWk4VXYveHJkMTl5dVJuYnRsV1F5UmpPTVh0RHl4bnlIVy8vZnViZVl4dUhBdU9VQgpFZjFOaHc5SXhZaFh1WlJoYTZoUHM1M1FZaS9RSnNkb2w0TmFHcU1LbmkybUZOTGQxUXAvNXdvNmhKanYzeHBZCkdGc3psSVVvbExpMmRWV0pXVEl3UUJiMjlwc1dxN0pVY0FKWGc5NmhSNU5qNHF1cW5kSDY1bURxdDFvL3hrSmUKOUhwWi9VRUNnWUVBNDlyUExRSS9xZEgybjJzK1FKY1ovWFJ6MWpuRjNRNGc2NS8va0EvZlZMODVGRHB6QmozWgp4T2lYRXVqelN3N3NDcGpucmhsRXl4cXFnZU1yakJxL3VhcWRCS1BjTERaNXhLZURLMlVZeXk4MmVFblFZKzFvCm5XVmk0UkZUblpkUXFiY3lXejNrZFo1ZkI0UHQySmhoQTVyS2RRNlEwcHMvdkdId2poTWhXUHNDZ1lFQTVYYncKRW52dnJNYVlVL0lpLzBMdTc2NDlPU0dhWTZhWWhKeHAvbTg3Yis5OFVMVXNWMngwbW8zUnY3QytSYjlYQ1pjMQpndHpDMEduWERSMzlvcHdqZlQrQm1HRkNuSjFCZ0M4OVhtak1nK2tzYTFnZkd4b1hUWnhxMDRNZXhVZHR4eVR5CndxckpTYjh2WUJCMExvOW5oYms3QXQwM29MUStJcTBaRlhuazIza0NnWUI3TUFsaVpCelhTMVR5eTZCVWUxenAKMHRQdHRqNXJUUUF2WThsZnNiVWt0RjIvdWZvR0hkcG13dmtxbUJjeE5WZ1lRcUsvVlpvRDFON3FhazlZNS8xUAovQlg0TkQ4TkNFYTlNM09QT3BFMUNNbUNMeVlqWUc5MjZTR1VYVEcvdWRjNmFua25LMGNnOEFhZ29Zc3QxdlJjClpvdWV6Y2t1bEJEWllIb1YxZkhwa1FLQmdRREtWd3p2WDdaREJvUkFVZDRtZFNFNDNNNUQyS3ZKZjVneUo3TVgKbDRJei9Gd0UxeDJZb1p4WXhRSFdKTVpEdnF2RFcwRG1la0NYZ3gwTkJnc29Ic0wwcU5GZ1N6TnY0d05sUTBLOApRM0ZFU0pMUXZVNEFtZ3MrZHRXRVdiVUNoUy82VVV4MytCMnpHQkZ3aGxITTFNdVdrWFhGMnNnNHYzZWpJRHhrClFhNWJFUUtCZ1FDK05Hbk5vU2lUQTBqUG9XVERwQ3BOekg5OEtJUFBYMUl4STgvWEw1TXJ2ZTNiQndMVDVoeFAKTkh3RHpRL2ZQQUtHL3B4V1cxRmNyVVIrTVFPZlNLbVA0WkVOVVY0NndJek14WlhoR3ppSTNaTktkVzlROXczUworaVcxYnBYMmhzVGU0V3pmZEdnclBzNHdSc1pxNlRGdHJacFdwYzFGRXVXUnROdFNEbmdXN2c9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
|
||||
|
||||
26
logspammer.yaml
Normal file
26
logspammer.yaml
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: logspammer
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: logspammer
|
||||
namespace: prod
|
||||
labels:
|
||||
app: logger
|
||||
service_name: logspammer-service-name
|
||||
spec:
|
||||
restartPolicy: Always
|
||||
containers:
|
||||
- name: logspammer
|
||||
image: busybox:latest
|
||||
command: ["/bin/sh", "-c"]
|
||||
args:
|
||||
- |
|
||||
while true; do
|
||||
echo "$(date -Is) ⚙️ Hello from the Kubernetes logger pod!"
|
||||
sleep 5
|
||||
done
|
||||
---
|
||||
75
main.py
75
main.py
|
|
@ -1,36 +1,42 @@
|
|||
import time
|
||||
import random
|
||||
from flask import Flask
|
||||
from opentelemetry import trace
|
||||
from opentelemetry import trace, metrics
|
||||
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.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.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter
|
||||
import logging
|
||||
from opentelemetry.trace import get_current_span
|
||||
|
||||
# === Resource ===
|
||||
resource = Resource(attributes={"service.name": "my-flask-app"})
|
||||
|
||||
# Configure tracing
|
||||
trace.set_tracer_provider(
|
||||
TracerProvider(resource=Resource.create({"service.name": "my-flask-app"}))
|
||||
)
|
||||
# === Tracing ===
|
||||
trace.set_tracer_provider(TracerProvider(resource=resource))
|
||||
tracer = trace.get_tracer(__name__)
|
||||
span_processor = BatchSpanProcessor(OTLPSpanExporter())
|
||||
trace.get_tracer_provider().add_span_processor(span_processor)
|
||||
# trace_exporter = OTLPSpanExporter(
|
||||
# endpoint="http://otel-collector.meta.svc:4318/v1/traces"
|
||||
# )
|
||||
trace.get_tracer_provider().add_span_processor(BatchSpanProcessor(trace_exporter))
|
||||
|
||||
# === Metrics ===
|
||||
reader = PeriodicExportingMetricReader(
|
||||
OTLPMetricExporter(endpoint="http://otel-collector.meta.svc:4318/v1/metrics")
|
||||
)
|
||||
provider = MeterProvider(resource=resource, metric_readers=[reader])
|
||||
metrics.set_meter_provider(provider)
|
||||
|
||||
|
||||
# Setup logging with trace_id
|
||||
# === 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
|
||||
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
|
||||
|
||||
|
||||
|
|
@ -45,43 +51,22 @@ 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
|
||||
# === 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
|
||||
# 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_trace_id()})
|
||||
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!"
|
||||
return "Hello from / with traces and metrics!"
|
||||
|
||||
|
||||
def fetch_user():
|
||||
|
|
|
|||
|
|
@ -15,11 +15,18 @@ spec:
|
|||
spec:
|
||||
containers:
|
||||
- name: otel-collector
|
||||
image: otel/opentelemetry-collector-contrib:0.81.0
|
||||
image: otel/opentelemetry-collector:latest
|
||||
args: ["--config=/etc/otel/otel-collector-config.yaml"]
|
||||
volumeMounts:
|
||||
- name: otel-config
|
||||
mountPath: /etc/otel
|
||||
ports:
|
||||
- name: prom
|
||||
containerPort: 8889
|
||||
- name: grpc
|
||||
containerPort: 4317
|
||||
- name: http
|
||||
containerPort: 4318
|
||||
volumes:
|
||||
- name: otel-config
|
||||
configMap:
|
||||
|
|
@ -40,19 +47,12 @@ data:
|
|||
http:
|
||||
endpoint: 0.0.0.0:4318
|
||||
|
||||
processors:
|
||||
spanmetrics:
|
||||
dimensions:
|
||||
- name: operation
|
||||
default: unknown
|
||||
metrics_exporter: prometheus
|
||||
aggregation_temporality: "AGGREGATION_TEMPORALITY_CUMULATIVE"
|
||||
|
||||
exporters:
|
||||
otlp:
|
||||
endpoint: tempo:4317
|
||||
tls:
|
||||
insecure: true
|
||||
|
||||
prometheus:
|
||||
endpoint: "0.0.0.0:8889"
|
||||
|
||||
|
|
@ -60,18 +60,20 @@ data:
|
|||
pipelines:
|
||||
traces:
|
||||
receivers: [otlp]
|
||||
processors: [spanmetrics]
|
||||
exporters: [otlp]
|
||||
|
||||
metrics:
|
||||
receivers: []
|
||||
receivers: [otlp]
|
||||
exporters: [prometheus]
|
||||
processors: []
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: otel-collector
|
||||
namespace: meta
|
||||
labels:
|
||||
release: kps # this MUST match the `release:` label used by your Prometheus install
|
||||
app: otel-collector
|
||||
spec:
|
||||
ports:
|
||||
- name: grpc
|
||||
|
|
@ -80,5 +82,23 @@ spec:
|
|||
- name: http
|
||||
port: 4318
|
||||
targetPort: 4318
|
||||
- name: prom
|
||||
port: 8889
|
||||
targetPort: 8889
|
||||
selector:
|
||||
app: otel-collector
|
||||
---
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: otel-collector
|
||||
namespace: meta
|
||||
labels:
|
||||
release: kps # again, must match Prometheus's release label
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: otel-collector
|
||||
endpoints:
|
||||
- port: prom
|
||||
interval: 15s
|
||||
|
|
|
|||
|
|
@ -2,49 +2,42 @@ apiVersion: v1
|
|||
kind: ConfigMap
|
||||
metadata:
|
||||
name: my-python-app
|
||||
namespace: meta
|
||||
namespace: prod
|
||||
data:
|
||||
main.py: |
|
||||
import time
|
||||
import random
|
||||
from flask import Flask
|
||||
from opentelemetry import trace
|
||||
from opentelemetry import trace, metrics
|
||||
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.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
|
||||
SERVICE_NAME = "my-flask-app" # match your OTEL resource name
|
||||
|
||||
# === Resource ===
|
||||
resource = Resource(attributes={"service.name": "my-flask-app"})
|
||||
|
||||
|
||||
trace.set_tracer_provider(
|
||||
TracerProvider(resource=Resource.create({"service.name": "my-flask-app"}))
|
||||
)
|
||||
# === Tracing ===
|
||||
trace.set_tracer_provider(TracerProvider(resource=resource))
|
||||
tracer = trace.get_tracer(__name__)
|
||||
span_processor = BatchSpanProcessor(OTLPSpanExporter())
|
||||
trace.get_tracer_provider().add_span_processor(span_processor)
|
||||
|
||||
|
||||
|
||||
# === 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")
|
||||
record.service_name = SERVICE_NAME
|
||||
else:
|
||||
record.trace_id = None
|
||||
record.span_id = None
|
||||
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", "service_name": "my-flask-app"}'
|
||||
'{"message": "%(message)s", "trace_id": "%(trace_id)s", "span_id": "%(span_id)s"}'
|
||||
)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setFormatter(formatter)
|
||||
|
|
@ -54,43 +47,22 @@ data:
|
|||
logger.setLevel(logging.INFO)
|
||||
logger.addHandler(handler)
|
||||
|
||||
|
||||
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__)
|
||||
|
||||
|
||||
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
|
||||
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_trace_id()})
|
||||
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!"
|
||||
return "Hello from / with traces and metrics!"
|
||||
|
||||
|
||||
def fetch_user():
|
||||
|
|
@ -112,7 +84,7 @@ apiVersion: apps/v1
|
|||
kind: Deployment
|
||||
metadata:
|
||||
name: python-otel
|
||||
namespace: meta
|
||||
namespace: prod
|
||||
labels:
|
||||
app: python-otel
|
||||
spec:
|
||||
|
|
@ -156,7 +128,7 @@ apiVersion: v1
|
|||
kind: Service
|
||||
metadata:
|
||||
name: python-otel
|
||||
namespace: meta
|
||||
namespace: prod
|
||||
spec:
|
||||
selector:
|
||||
app: python-otel
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue