1importlogging 2importthreading 3fromdatetimeimportUTC,datetime 4 5fromopentelemetryimporttrace 6fromopentelemetry.traceimportformat_span_id,format_trace_id 7 8from.coreimportObserverMode 9from.otelimportget_observer_span_processor101112classObserverLogHandler(logging.Handler):13"""Custom logging handler that captures logs during active traces when observer is enabled."""1415def__init__(self,level=logging.NOTSET):16super().__init__(level)17self._logs_lock=threading.Lock()18self._trace_logs={}# trace_id -> list of log records1920defemit(self,record):21"""Emit a log record if we're in an active observer trace."""22try:23# Get the current span to determine if we're in an active trace24current_span=trace.get_current_span()25ifnotcurrent_spanornotcurrent_span.get_span_context().is_valid:26return2728# Get trace and span IDs29trace_id=f"0x{format_trace_id(current_span.get_span_context().trace_id)}"30span_id=f"0x{format_span_id(current_span.get_span_context().span_id)}"3132# Check if observer is recording this trace33processor=get_observer_span_processor()34ifnotprocessor:35return3637# Check if we should record logs for this trace38withprocessor._traces_lock:39iftrace_idnotinprocessor._traces:40return4142trace_info=processor._traces[trace_id]43# Only capture logs in PERSIST mode44iftrace_info["mode"]!=ObserverMode.PERSIST.value:45return4647# Store the formatted message with span context48log_entry={49"message":self.format(record),50"level":record.levelname,51"span_id":span_id,52"timestamp":datetime.fromtimestamp(record.created,tz=UTC),53}5455withself._logs_lock:56iftrace_idnotinself._trace_logs:57self._trace_logs[trace_id]=[]58self._trace_logs[trace_id].append(log_entry)5960# Limit logs per trace to prevent memory issues61iflen(self._trace_logs[trace_id])>1000:62self._trace_logs[trace_id]=self._trace_logs[trace_id][-500:]6364exceptException:65# Don't let logging errors break the application66pass6768defpop_logs_for_trace(self,trace_id):69"""Get and remove all logs for a specific trace in one operation."""70withself._logs_lock:71returnself._trace_logs.pop(trace_id,[]).copy()727374# Global instance of the log handler75observer_log_handler=ObserverLogHandler()