2020from google .adk .models .llm_response import LlmResponse
2121from google .adk .tools import BaseTool
2222from opentelemetry import trace
23- from opentelemetry .sdk .trace import _Span
23+ from opentelemetry .context import get_value
24+ from opentelemetry .sdk .trace import Span , _Span
2425
2526from veadk .tracing .telemetry .attributes .attributes import ATTRIBUTES
2627from veadk .tracing .telemetry .attributes .extractors .types import (
2728 ExtractorResponse ,
2829 LLMAttributesParams ,
2930 ToolAttributesParams ,
3031)
31- from veadk .tracing .telemetry .exporters .inmemory_exporter import (
32- _INMEMORY_EXPORTER_INSTANCE ,
33- )
3432from veadk .utils .logger import get_logger
3533
3634logger = get_logger (__name__ )
3735
3836
39- def upload_metrics (
37+ def _upload_metrics (
4038 invocation_context : InvocationContext ,
39+ event_id : str ,
4140 llm_request : LlmRequest ,
4241 llm_response : LlmResponse ,
4342) -> None :
@@ -48,11 +47,13 @@ def upload_metrics(
4847 for tracer in tracers :
4948 for exporter in getattr (tracer , "exporters" , []):
5049 if getattr (exporter , "meter_uploader" , None ):
51- exporter .meter_uploader .record (llm_request , llm_response )
50+ exporter .meter_uploader .record (
51+ invocation_context , event_id , llm_request , llm_response
52+ )
5253
5354
5455def _set_agent_input_attribute (
55- span : _Span , invocation_context : InvocationContext
56+ span : Span , invocation_context : InvocationContext
5657) -> None :
5758 # We only save the original user input as the agent input
5859 # hence once the `agent.input` has been set, we don't overwrite it
@@ -106,7 +107,7 @@ def _set_agent_input_attribute(
106107 )
107108
108109
109- def _set_agent_output_attribute (span : _Span , llm_response : LlmResponse ) -> None :
110+ def _set_agent_output_attribute (span : Span , llm_response : LlmResponse ) -> None :
110111 content = llm_response .content
111112 if content and content .parts :
112113 for idx , part in enumerate (content .parts ):
@@ -126,67 +127,64 @@ def set_common_attributes_on_model_span(
126127 current_span : _Span ,
127128 ** kwargs ,
128129) -> None :
129- if current_span .context :
130- current_span_id = current_span .context .trace_id
131- else :
132- logger .warning (
133- "Current span context is missing, failed to get `trace_id` to set common attributes."
134- )
135- return
136-
130+ common_attributes = ATTRIBUTES .get ("common" , {})
137131 try :
138- spans = _INMEMORY_EXPORTER_INSTANCE .processor .spans # type: ignore
139-
140- spans_in_current_trace = [
141- span
142- for span in spans
143- if span .context and span .context .trace_id == current_span_id
144- ]
145-
146- common_attributes = ATTRIBUTES .get ("common" , {})
147- for span in spans_in_current_trace :
148- if span .is_recording ():
149- if span .name .startswith ("invocation" ):
150- span .set_attribute ("gen_ai.operation.name" , "chain" )
151- _set_agent_input_attribute (span , invocation_context )
152- _set_agent_output_attribute (span , llm_response )
153- elif span .name .startswith ("agent_run" ):
154- span .set_attribute ("gen_ai.operation.name" , "agent" )
155- _set_agent_input_attribute (span , invocation_context )
156- _set_agent_output_attribute (span , llm_response )
157- for attr_name , attr_extractor in common_attributes .items ():
158- value = attr_extractor (** kwargs )
159- span .set_attribute (attr_name , value )
132+ invocation_span : Span = get_value ("invocation_span_instance" ) # type: ignore
133+ agent_run_span : Span = get_value ("agent_run_span_instance" ) # type: ignore
134+
135+ if invocation_span and invocation_span .name .startswith ("invocation" ):
136+ _set_agent_input_attribute (invocation_span , invocation_context )
137+ _set_agent_output_attribute (invocation_span , llm_response )
138+ for attr_name , attr_extractor in common_attributes .items ():
139+ value = attr_extractor (** kwargs )
140+ invocation_span .set_attribute (attr_name , value )
141+
142+ # Calculate the token usage for the whole invocation span
143+ current_step_token_usage = (
144+ llm_response .usage_metadata .total_token_count
145+ if llm_response .usage_metadata
146+ and llm_response .usage_metadata .total_token_count
147+ else 0
148+ )
149+ prev_total_token_usage = (
150+ invocation_span .attributes ["gen_ai.usage.total_tokens" ]
151+ if invocation_span .attributes
152+ else 0
153+ )
154+ accumulated_total_token_usage = (
155+ current_step_token_usage + int (prev_total_token_usage ) # type: ignore
156+ ) # we can ignore this warning, cause we manually set the attribute to int before
157+ invocation_span .set_attribute (
158+ "gen_ai.usage.total_tokens" , accumulated_total_token_usage
159+ )
160+
161+ if agent_run_span and agent_run_span .name .startswith ("agent_run" ):
162+ _set_agent_input_attribute (agent_run_span , invocation_context )
163+ _set_agent_output_attribute (agent_run_span , llm_response )
164+ for attr_name , attr_extractor in common_attributes .items ():
165+ value = attr_extractor (** kwargs )
166+ agent_run_span .set_attribute (attr_name , value )
167+
168+ for attr_name , attr_extractor in common_attributes .items ():
169+ value = attr_extractor (** kwargs )
170+ current_span .set_attribute (attr_name , value )
160171 except Exception as e :
161172 logger .error (f"Failed to set common attributes for spans: { e } " )
162173
163174
164175def set_common_attributes_on_tool_span (current_span : _Span ) -> None :
165- # find parent span (generally a llm span)
166- if not current_span .context :
167- logger .warning (
168- f"Get tool span's context failed. Skip setting common attributes for span { current_span .name } "
169- )
170- return
171-
172- if not current_span .parent :
173- logger .warning (
174- f"Get tool span's parent failed. Skip setting common attributes for span { current_span .name } "
175- )
176- return
177-
178- parent_span_id = current_span .parent .span_id
179- for span in _INMEMORY_EXPORTER_INSTANCE .processor .spans : # type: ignore
180- if span .context .span_id == parent_span_id :
181- common_attributes = ATTRIBUTES .get ("common" , {})
182- for attr_name in common_attributes .keys ():
183- if hasattr (span .attributes , attr_name ):
184- current_span .set_attribute (attr_name , span .attributes [attr_name ])
185- else :
186- logger .error (f"Parent span does not have attribute { attr_name } " )
176+ common_attributes = ATTRIBUTES .get ("common" , {})
187177
178+ invocation_span : Span = get_value ("invocation_span_instance" ) # type: ignore
188179
189- def trace_send_data (): ...
180+ for attr_name in common_attributes .keys ():
181+ if (
182+ invocation_span
183+ and invocation_span .name .startswith ("invocation" )
184+ and invocation_span .attributes
185+ and attr_name in invocation_span .attributes
186+ ):
187+ current_span .set_attribute (attr_name , invocation_span .attributes [attr_name ])
190188
191189
192190def trace_tool_call (
@@ -212,7 +210,7 @@ def trace_call_llm(
212210 llm_request : LlmRequest ,
213211 llm_response : LlmResponse ,
214212) -> None :
215- span = trace .get_current_span ()
213+ span : Span = trace .get_current_span () # type: ignore
216214
217215 from veadk .agent import Agent
218216
@@ -234,6 +232,7 @@ def trace_call_llm(
234232 span .context .trace_state .get ("call_type" , "" )
235233 if (
236234 hasattr (span , "context" )
235+ and span .context
237236 and hasattr (span .context , "trace_state" )
238237 and hasattr (span .context .trace_state , "get" )
239238 )
@@ -253,4 +252,8 @@ def trace_call_llm(
253252 response : ExtractorResponse = attr_extractor (params )
254253 ExtractorResponse .update_span (span , attr_name , response )
255254
256- upload_metrics (invocation_context , llm_request , llm_response )
255+ _upload_metrics (invocation_context , event_id , llm_request , llm_response )
256+
257+
258+ # Do not modify this function
259+ def trace_send_data (): ...
0 commit comments