100 lines
4.7 KiB
Python
100 lines
4.7 KiB
Python
import os
|
|
|
|
from opentelemetry import metrics, trace
|
|
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
|
|
from opentelemetry.exporter.prometheus import PrometheusMetricReader
|
|
from opentelemetry.sdk.metrics import MeterProvider
|
|
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
|
|
from opentelemetry.sdk.trace import Tracer, TracerProvider
|
|
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
from prometheus_client import start_http_server
|
|
|
|
|
|
def initialize_trace(app=None, name=None) -> Tracer:
|
|
# Resource can be required for some backends, e.g. Jaeger or Prometheus
|
|
# If resource wouldn't be set - traces wouldn't appear in Jaeger.
|
|
# The 'name' value is the name shown in Jaeger.
|
|
resource = Resource(
|
|
attributes={
|
|
SERVICE_NAME: (name if name else os.environ.get("APPLICATION_NAME", "Python App"))
|
|
}
|
|
)
|
|
#
|
|
# 1. Tracing (Jaeger) configuration
|
|
# ----------------------------------
|
|
#
|
|
# Configure the OTLP exporter (or HTTP exporter the same way)
|
|
# the recommended configuration is via environment variables. The mandatory ones:
|
|
# OTEL_EXPORTER_OTLP_ENDPOINT: "http://jaeger:4317"
|
|
# OTEL_EXPORTER_OTLP_INSECURE: "true"
|
|
# for more see here: https://opentelemetry-python.readthedocs.io/en/latest/exporter/otlp/otlp.html
|
|
# alternatively these values can be provided as input values to OTLPSpanExporter() constructor.
|
|
#
|
|
# otlp_exporter = OTLPSpanExporter()
|
|
# or provide endpoint explicitly, as
|
|
otlp_exporter = OTLPSpanExporter(endpoint="http://jaeger:4317")
|
|
#
|
|
# Initialize the tracer provider. This is abstract API call.
|
|
# The actual implementation is given by the included dependency
|
|
# The opentelemetry default is the OTLP trace provider.
|
|
provider = TracerProvider(resource=resource)
|
|
# Add the exporters to the batch span processor
|
|
span_processor = BatchSpanProcessor(otlp_exporter)
|
|
provider.add_span_processor(span_processor)
|
|
# Sets the global default tracer provider
|
|
trace.set_tracer_provider(provider)
|
|
#
|
|
|
|
# logging.info(' * Instrumenting application..... ')
|
|
# if Flask, then use:
|
|
# FlaskInstrumentor().instrument_app(flask_app)
|
|
# if FastAPI, then use
|
|
# FastAPIInstrumentor.instrument_app(app)
|
|
|
|
#
|
|
# Python Flask is now automatically instrumented to export details of each REST endpoint call.
|
|
# For Django based app, use 'opentelemetry-instrumentation-django' import instead. see here:
|
|
# https://opentelemetry-python.readthedocs.io/en/latest/examples/django/README.html for example
|
|
#
|
|
# If the used library has no instrumentation support in opentelemetry.io, then the trace
|
|
# can be started manually. In this code,
|
|
# 'trace' should be global shared variable, initialized once per application (see tracing.py)
|
|
# 'tracer' can be shared global or local variable, application can use multiple uniquely
|
|
# named tracers, Jaeger will group the generated traces by the name of the tracer
|
|
# that was used to start the Span. See this example code:
|
|
#
|
|
# tracer = trace.get_tracer(name)
|
|
#
|
|
# @app.route("/server_request")
|
|
# def server_request():
|
|
# with tracer.start_as_current_span(
|
|
# "server_request",
|
|
# context=extract(request.headers),
|
|
# kind=trace.SpanKind.SERVER,
|
|
# attributes=collect_request_attributes(request.environ),
|
|
# ):
|
|
# # do the work here, like logging.info something and return response
|
|
# logging.info(request.args.get("param"))
|
|
# return "served"
|
|
#
|
|
# Note:
|
|
# the otlp code looks for HTTP header named 'traceparent' that, if present, should contain
|
|
# the otlp parent span identification, and the span created here will be made a child
|
|
# of that parent span, indicating visually the progression of requests via different services
|
|
# for as long as the current span is provided in the traceparent header to next service.
|
|
|
|
# 2. Metrics (Prometheus) configuration
|
|
# -------------------------------------
|
|
#
|
|
# Start Prometheus client
|
|
start_http_server(port=9464, addr="localhost")
|
|
# Initialize PrometheusMetricReader which pulls metrics from the SDK
|
|
# on-demand to respond to scrape requests (unlike Jaeger, which worls with push model - application
|
|
# pushes traces when those become available to Jaeger's collector. Prometheus works with pull model
|
|
# where it periodically polls pre-configured and/or discovered endpoints for metrics.
|
|
reader = PrometheusMetricReader()
|
|
provider = MeterProvider(resource=resource, metric_readers=[reader])
|
|
metrics.set_meter_provider(provider)
|
|
|
|
return trace.get_tracer(name)
|