from django.apps import AppConfig import os import logging import multiprocessing from uuid import uuid4 from opentelemetry import trace, metrics from opentelemetry._logs import set_logger_provider from opentelemetry.sdk.resources import Resource, SERVICE_INSTANCE_ID from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter from opentelemetry.sdk.metrics import MeterProvider from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler from opentelemetry.sdk._logs.export import BatchLogRecordProcessor from opentelemetry.exporter.otlp.proto.grpc._log_exporter import OTLPLogExporter from opentelemetry.instrumentation.django import DjangoInstrumentor class TelemetryConfig(AppConfig): name = "telemetry" def ready(self): # Resource Definition resource = Resource.create({ "service.name": "development-kitchen", SERVICE_INSTANCE_ID: str(uuid4()), "worker": os.getpid(), # os.getpid() works outside Gunicorn too }) endpoint = os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT", "http://129.159.229.69:4317") # TRACE SETUP if not isinstance(trace.get_tracer_provider(), TracerProvider): tracer_provider = TracerProvider(resource=resource) span_exporter = OTLPSpanExporter(endpoint=endpoint) tracer_provider.add_span_processor(BatchSpanProcessor(span_exporter)) trace.set_tracer_provider(tracer_provider) # METRIC SETUP if not isinstance(metrics.get_meter_provider(), MeterProvider): metric_reader = PeriodicExportingMetricReader(OTLPMetricExporter(endpoint=endpoint)) meter_provider = MeterProvider(resource=resource, metric_readers=[metric_reader]) metrics.set_meter_provider(meter_provider) # LOGGING SETUP # 1. Create and set the logger provider FIRST logger_provider = LoggerProvider(resource=resource) set_logger_provider(logger_provider) # MUST be set before using LoggingHandler # 2. Add processor and exporter log_exporter = OTLPLogExporter(endpoint=endpoint) logger_provider.add_log_record_processor(BatchLogRecordProcessor(log_exporter)) # 3. Now safely create the handler (uses global logger provider) otel_handler = LoggingHandler(level=logging.INFO) # 4. Attach to Django and root loggers logging.getLogger("django").addHandler(otel_handler) logging.getLogger("django").setLevel(logging.INFO) logging.getLogger().addHandler(otel_handler) logging.getLogger().setLevel(logging.INFO) from opentelemetry.instrumentation.django import DjangoInstrumentor DjangoInstrumentor().instrument() import sys from .utils import PrintLogger # assuming PrintLogger is defined in telemetry/utils.py # Redirect print() and errors to logger so they appear in SigNoz sys.stdout = PrintLogger(logging.INFO) sys.stderr = PrintLogger(logging.ERROR)