@@ -5,39 +5,51 @@ namespace Sentry.Extensions.AI;
55/// <summary>
66/// Listens to FunctionInvokingChatClient's Activity
77/// </summary>
8- internal static class SentryAIActivityListener
8+ internal class SentryAiActivityListener
99{
10- private static volatile IHub Hub = HubAdapter . Instance ;
10+ private static ActivityListener ? Instance ;
1111
1212 /// <summary>
13- /// Sentry's <see cref="ActivityListener"/> to tap into function invocation 's Activity
13+ /// Initializes Sentry's <see cref="ActivityListener"/> to tap into FunctionInvokingChatClient 's Activity
1414 /// </summary>
15- private static readonly ActivityListener FICCListener = new ( )
15+ /// <param name="hub">Optional IHub instance to use. If not provided, HubAdapter.Instance will be used.</param>
16+ public SentryAiActivityListener ( IHub ? hub = null )
1617 {
17- ShouldListenTo = source => source . Name . StartsWith ( SentryAIConstants . SentryActivitySourceName ) ,
18- Sample = ( ref ActivityCreationOptions < ActivityContext > options ) =>
19- SentryAIConstants . FICCActivityNames . Contains ( options . Name ) ?
20- ActivitySamplingResult . AllDataAndRecorded : ActivitySamplingResult . None ,
21- ActivityStarted = activity =>
18+ if ( Instance != null )
2219 {
23- var agentSpan = Hub . StartSpan ( SentryAIConstants . SpanAttributes . InvokeAgentOperation , SentryAIConstants . SpanAttributes . InvokeAgentDescription ) ;
24- activity . SetFused ( SentryAIConstants . SentryFICCSpanAttributeName , agentSpan ) ;
25- } ,
26- ActivityStopped = activity =>
27- {
28- var agentSpan = activity . GetFused < ISpan > ( SentryAIConstants . SentryFICCSpanAttributeName ) ;
29- // Don't pass in OK status in case there was an exception
30- agentSpan ? . Finish ( ) ;
20+ return ;
3121 }
32- } ;
22+
23+ var currHub = hub ?? HubAdapter . Instance ;
24+ Instance = new ActivityListener
25+ {
26+ ShouldListenTo = source => source . Name . StartsWith ( SentryAIConstants . SentryActivitySourceName ) ,
27+ Sample = ( ref ActivityCreationOptions < ActivityContext > options ) =>
28+ SentryAIConstants . FICCActivityNames . Contains ( options . Name )
29+ ? ActivitySamplingResult . AllDataAndRecorded
30+ : ActivitySamplingResult . None ,
31+ ActivityStarted = activity =>
32+ {
33+ var agentSpan = currHub . StartSpan ( SentryAIConstants . SpanAttributes . InvokeAgentOperation ,
34+ SentryAIConstants . SpanAttributes . InvokeAgentDescription ) ;
35+ activity . SetFused ( SentryAIConstants . SentryFICCSpanAttributeName , agentSpan ) ;
36+ } ,
37+ ActivityStopped = activity =>
38+ {
39+ var agentSpan = activity . GetFused < ISpan > ( SentryAIConstants . SentryFICCSpanAttributeName ) ;
40+ // Don't pass in OK status in case there was an exception
41+ agentSpan ? . Finish ( ) ;
42+ }
43+ } ;
44+ ActivitySource . AddActivityListener ( Instance ) ;
45+ }
3346
3447 /// <summary>
35- /// Initializes Sentry's <see cref="ActivityListener"/> to tap into FunctionInvokingChatClient's Activity
48+ /// Dispose the singleton instance (for testing purposes mostly)
3649 /// </summary>
37- /// <param name="hub">Optional IHub instance to use. If not provided, HubAdapter.Instance will be used.</param>
38- internal static void Init ( IHub ? hub = null )
50+ internal static void Dispose ( )
3951 {
40- Hub = hub ?? HubAdapter . Instance ;
41- ActivitySource . AddActivityListener ( FICCListener ) ;
52+ Instance ? . Dispose ( ) ;
53+ Instance = null ;
4254 }
4355}
0 commit comments