@@ -1056,28 +1056,34 @@ def _evaluate( # pylint: disable=too-many-locals,too-many-statements
10561056def _log_events_to_app_insights (
10571057 otel_logger ,
10581058 events : List [Dict [str , Any ]],
1059- attributes : Optional [ Dict [str , Any ]] = None ,
1059+ log_attributes : Dict [str , Any ],
10601060 data_source_item : Optional [Dict [str , Any ]] = None ,
10611061) -> None :
10621062 """
10631063 Log independent events directly to App Insights using OpenTelemetry logging.
10641064 No spans are created - events are sent as pure log records.
10651065
1066- :param connection_string: Azure Application Insights connection string
1067- :type connection_string: str
1066+ :param otel_logger: OpenTelemetry logger instance
1067+ :type otel_logger: Logger
10681068 :param events: List of event data dictionaries to log
10691069 :type events: List[Dict[str, Any]]
1070- :param attributes: Additional attributes to add to each event
1071- :type attributes: Optional[Dict[str, Any]]
1070+ :param log_attributes: Attributes dict to use for each event (already includes extra_attributes if present)
1071+ :type log_attributes: Dict[str, Any]
1072+ :param data_source_item: Data source item containing trace_id, response_id, conversation_id
1073+ :type data_source_item: Optional[Dict[str, Any]]
10721074 """
10731075
10741076 from opentelemetry .sdk ._logs import LogRecord
10751077
10761078 try :
1077- # Get the trace_id
1079+ # Get the trace_id and other context from data source item
10781080 trace_id = None
10791081 response_id = None
10801082 conversation_id = None
1083+ previous_response_id = None
1084+ agent_name = None
1085+ agent_version = None
1086+ agent_id = None
10811087 if data_source_item :
10821088 for key , value in data_source_item .items ():
10831089 if key .endswith ("trace_id" ) and value and isinstance (value , str ):
@@ -1089,20 +1095,23 @@ def _log_events_to_app_insights(
10891095 response_id = value
10901096 elif key .endswith ("conversation_id" ) and value and isinstance (value , str ):
10911097 conversation_id = value
1098+ elif key .endswith ("previous_response_id" ) and value and isinstance (value , str ):
1099+ previous_response_id = value
1100+ elif key .endswith ("agent_name" ) and value and isinstance (value , str ):
1101+ agent_name = value
1102+ elif key .endswith ("agent_version" ) and value and isinstance (value , str ):
1103+ agent_version = value
1104+ elif key .endswith ("agent_id" ) and value and isinstance (value , str ):
1105+ agent_id = value
10921106
10931107 # Log each event as a separate log record
10941108 for i , event_data in enumerate (events ):
10951109 try :
1096- # Prepare log record attributes with specific mappings
1097- log_attributes = {
1098- # Use the public API for custom events
1099- # The KEY is "microsoft.custom_event.name", the VALUE is the event name
1100- "microsoft.custom_event.name" : EVALUATION_EVENT_NAME ,
1101- # These fields are always present and are already strings
1102- "gen_ai.evaluation.name" : event_data .get ("metric" ),
1103- "gen_ai.evaluation.score.value" : event_data .get ("score" ),
1104- "gen_ai.evaluation.score.label" : event_data .get ("label" ),
1105- }
1110+ # Add standard event attributes
1111+ log_attributes ["microsoft.custom_event.name" ] = EVALUATION_EVENT_NAME
1112+ log_attributes ["gen_ai.evaluation.name" ] = event_data .get ("metric" )
1113+ log_attributes ["gen_ai.evaluation.score.value" ] = event_data .get ("score" )
1114+ log_attributes ["gen_ai.evaluation.score.label" ] = event_data .get ("label" )
11061115
11071116 # Optional field that may not always be present
11081117 if "reason" in event_data :
@@ -1132,36 +1141,19 @@ def _log_events_to_app_insights(
11321141 properties ["attack_success_threshold" ]
11331142 )
11341143
1135- # Add additional attributes from AppInsights config if provided
1136- if attributes :
1137- if "run_type" in attributes :
1138- log_attributes ["gen_ai.evaluation.azure_ai_type" ] = str (attributes ["run_type" ])
1139-
1140- if "schedule_type" in attributes :
1141- log_attributes ["gen_ai.evaluation.azure_ai_scheduled" ] = str (attributes ["schedule_type" ])
1142-
1143- if "run_id" in attributes :
1144- log_attributes ["gen_ai.evaluation.run.id" ] = str (attributes ["run_id" ])
1145-
1146- if "response_id" in attributes :
1147- log_attributes ["gen_ai.response.id" ] = str (attributes ["response_id" ])
1148-
1149- if "agent_id" in attributes :
1150- log_attributes ["gen_ai.agent.id" ] = str (attributes ["agent_id" ])
1151-
1152- if "agent_name" in attributes :
1153- log_attributes ["gen_ai.agent.name" ] = str (attributes ["agent_name" ])
1154-
1155- if "agent_version" in attributes :
1156- log_attributes ["gen_ai.agent.version" ] = str (attributes ["agent_version" ])
1157-
1158- if "project_id" in attributes :
1159- log_attributes ["gen_ai.azure_ai_project.id" ] = str (attributes ["project_id" ])
1160-
1144+ # Add response_id and conversation_id from data source if present
11611145 if response_id :
11621146 log_attributes ["gen_ai.response.id" ] = response_id
11631147 if conversation_id :
11641148 log_attributes ["gen_ai.conversation.id" ] = conversation_id
1149+ if previous_response_id :
1150+ log_attributes ["gen_ai.previous.response_id" ] = previous_response_id
1151+ if agent_name :
1152+ log_attributes ["gen_ai.agent.name" ] = agent_name
1153+ if agent_version :
1154+ log_attributes ["gen_ai.agent.version" ] = agent_version
1155+ if agent_id :
1156+ log_attributes ["gen_ai.agent.id" ] = agent_id
11651157
11661158 # Create a LogRecord and emit it
11671159 log_record = LogRecord (
@@ -1203,7 +1195,6 @@ def emit_eval_result_events_to_app_insights(app_insights_config: AppInsightsConf
12031195 return
12041196
12051197 try :
1206- # Extract only the AppInsights config attributes that exist
12071198 # Configure OpenTelemetry logging
12081199 logger_provider = LoggerProvider ()
12091200 _logs .set_logger_provider (logger_provider )
@@ -1216,27 +1207,28 @@ def emit_eval_result_events_to_app_insights(app_insights_config: AppInsightsConf
12161207
12171208 # Create a logger
12181209 otel_logger = _logs .get_logger (__name__ )
1219- app_insights_attributes = {}
1210+
1211+ # Initialize base log attributes with extra_attributes if present, otherwise empty dict
1212+ base_log_attributes = app_insights_config .get ("extra_attributes" , {})
1213+
1214+ # Add AppInsights config attributes with proper semantic convention mappings
12201215 if "run_type" in app_insights_config :
1221- app_insights_attributes [ "run_type " ] = app_insights_config ["run_type" ]
1216+ base_log_attributes [ "gen_ai.evaluation.azure_ai_type " ] = str ( app_insights_config ["run_type" ])
12221217 if "schedule_type" in app_insights_config :
1223- app_insights_attributes [ "schedule_type " ] = app_insights_config ["schedule_type" ]
1218+ base_log_attributes [ "gen_ai.evaluation.azure_ai_scheduled " ] = str ( app_insights_config ["schedule_type" ])
12241219 if "run_id" in app_insights_config :
1225- app_insights_attributes ["run_id" ] = app_insights_config ["run_id" ]
1226- if "agent_id" in app_insights_config :
1227- app_insights_attributes ["agent_id" ] = app_insights_config ["agent_id" ]
1228- if "agent_name" in app_insights_config :
1229- app_insights_attributes ["agent_name" ] = app_insights_config ["agent_name" ]
1230- if "agent_version" in app_insights_config :
1231- app_insights_attributes ["agent_version" ] = app_insights_config ["agent_version" ]
1220+ base_log_attributes ["gen_ai.evaluation.run.id" ] = str (app_insights_config ["run_id" ])
12321221 if "project_id" in app_insights_config :
1233- app_insights_attributes [ "project_id " ] = app_insights_config ["project_id" ]
1222+ base_log_attributes [ "gen_ai.azure_ai_project.id " ] = str ( app_insights_config ["project_id" ])
12341223
12351224 for result in results :
1225+ # Create a copy of base attributes for this result's events
1226+ log_attributes = base_log_attributes .copy ()
1227+
12361228 _log_events_to_app_insights (
12371229 otel_logger = otel_logger ,
12381230 events = result ["results" ],
1239- attributes = app_insights_attributes ,
1231+ log_attributes = log_attributes ,
12401232 data_source_item = result ["datasource_item" ] if "datasource_item" in result else None ,
12411233 )
12421234 # Force flush to ensure events are sent
0 commit comments