44This module contains processors for OpenTelemetry spans.
55"""
66
7- import copy
8- import threading
97import time
108from threading import Event , Lock , Thread
11- from typing import Any , Dict , List , Optional
9+ from typing import Dict , Optional
1210
1311from opentelemetry .context import Context
1412from opentelemetry .sdk .trace import ReadableSpan , Span , SpanProcessor
1513from opentelemetry .sdk .trace .export import SpanExporter
16- from termcolor import colored
1714
1815import agentops .semconv as semconv
1916from agentops .logging import logger
20- from agentops .sdk . converters import trace_id_to_uuid , uuid_to_int16
17+ from agentops .helpers . dashboard import log_trace_url
2118from agentops .semconv .core import CoreAttributes
2219
2320
@@ -94,14 +91,7 @@ class InternalSpanProcessor(SpanProcessor):
9491 - This processor tries to use the native kind first, then falls back to the attribute
9592 """
9693
97- def __init__ (self , app_url : str = "https://app.agentops.ai" ):
98- """
99- Initialize the PrintSpanProcessor.
100-
101- Args:
102- app_url: The base URL for the AgentOps dashboard.
103- """
104- self .app_url = app_url
94+ _root_span_id : Optional [Span ] = None
10595
10696 def on_start (self , span : Span , parent_context : Optional [Context ] = None ) -> None :
10797 """
@@ -115,31 +105,10 @@ def on_start(self, span: Span, parent_context: Optional[Context] = None) -> None
115105 if not span .context or not span .context .trace_flags .sampled :
116106 return
117107
118- # Get the span kind from the span.kind property or the attributes
119- span_kind = span .kind .name if hasattr (span , "kind" ) else (
120- span .attributes .get (semconv .SpanAttributes .AGENTOPS_SPAN_KIND , "unknown" ) if span .attributes else "unknown"
121- )
122-
123- # Print basic information about the span
124- logger .debug (f"Started span: { span .name } (kind: { span_kind } )" )
125-
126- # Special handling for session spans
127- if span_kind == semconv .SpanKind .SESSION :
128- trace_id = span .context .trace_id
129- # Convert trace_id to hex string if it's not already
130- if isinstance (trace_id , int ):
131- session_url = f"{ self .app_url } /drilldown?session_id={ trace_id_to_uuid (trace_id )} "
132- logger .info (
133- colored (
134- f"\x1b [34mSession started: { session_url } \x1b [0m" ,
135- "light_green" ,
136- )
137- )
138- else :
139- # Print basic information for other span kinds
140- # For native OpenTelemetry SpanKind values (INTERNAL, CLIENT, CONSUMER, etc.),
141- # we'll see the actual kind rather than "unknown"
142- logger .debug (f"Started span: { span .name } (kind: { span_kind } )" )
108+ if not self ._root_span_id :
109+ self ._root_span_id = span .context .span_id
110+ logger .debug (f"[agentops.InternalSpanProcessor] Found root span: { span .name } " )
111+ log_trace_url (span )
143112
144113 def on_end (self , span : ReadableSpan ) -> None :
145114 """
@@ -152,32 +121,13 @@ def on_end(self, span: ReadableSpan) -> None:
152121 if not span .context or not span .context .trace_flags .sampled :
153122 return
154123
155- # Get the span kind from the span.kind property or the attributes
156- span_kind = span .kind .name if hasattr (span , "kind" ) else (
157- span .attributes .get (semconv .SpanAttributes .AGENTOPS_SPAN_KIND , "unknown" ) if span .attributes else "unknown"
158- )
159-
160- # Special handling for session spans
161- if span_kind == semconv .SpanKind .SESSION :
162- trace_id = span .context .trace_id
163- # Convert trace_id to hex string if it's not already
164- if isinstance (trace_id , int ):
165- session_url = f"{ self .app_url } /drilldown?session_id={ trace_id_to_uuid (trace_id )} "
166- logger .info (
167- colored (
168- f"\x1b [34mSession Replay: { session_url } \x1b [0m" ,
169- "blue" ,
170- )
171- )
172- else :
173- # Print basic information for other span kinds
174- # For native OpenTelemetry SpanKind values (INTERNAL, CLIENT, CONSUMER, etc.),
175- # we'll see the actual kind rather than "unknown"
176- logger .debug (f"Ended span: { span .name } (kind: { span_kind } )" )
124+ if self ._root_span_id and (span .context .span_id is self ._root_span_id ):
125+ logger .debug (f"[agentops.InternalSpanProcessor] Ending root span: { span .name } " )
126+ log_trace_url (span )
177127
178128 def shutdown (self ) -> None :
179129 """Shutdown the processor."""
180- pass
130+ self . _root_span_id = None
181131
182132 def force_flush (self , timeout_millis : int = 30000 ) -> bool :
183133 """Force flush the processor."""
0 commit comments