// Copyright (c) Microsoft. All rights reserved. using System; using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.Extensions.Logging; namespace Microsoft.SemanticKernel.Connectors.FunctionCalling; [ExcludeFromCodeCoverage] internal static partial class FunctionCallsProcessorLoggingExtensions { /// /// Action to log the . /// private static readonly Action s_logFunctionChoiceBehaviorConfiguration = LoggerMessage.Define( logLevel: LogLevel.Debug, eventId: 0, "Function choice behavior configuration: Choice:{Choice}, AutoInvoke:{AutoInvoke}, AllowConcurrentInvocation:{AllowConcurrentInvocation}, AllowParallelCalls:{AllowParallelCalls} Functions:{Functions}"); /// /// Action to log function calls. /// private static readonly Action s_logFunctionCalls = LoggerMessage.Define( logLevel: LogLevel.Debug, eventId: 0, "Function calls: {Calls}"); /// /// Action to log auto function invocation filter context. /// private static readonly Action s_logAutoFunctionInvocationFilterContext = LoggerMessage.Define( logLevel: LogLevel.Debug, eventId: 0, "Auto function invocation filter context: Name:{Name}, Id:{Id}, IsStreaming:{IsStreaming} FunctionSequenceIndex:{FunctionSequenceIndex}, RequestSequenceIndex:{RequestSequenceIndex}, FunctionCount:{FunctionCount}"); /// /// Action to log auto function invocation filter termination. /// private static readonly Action s_logAutoFunctionInvocationFilterTermination = LoggerMessage.Define( logLevel: LogLevel.Debug, eventId: 0, "Auto function invocation filter requested termination: Name:{Name}, Id:{Id}"); /// /// Logs . /// public static void LogFunctionChoiceBehaviorConfiguration(this ILogger logger, FunctionChoiceBehaviorConfiguration configuration) { if (logger.IsEnabled(LogLevel.Debug)) { var functionsLog = (configuration.Functions != null && configuration.Functions.Any()) ? string.Join(", ", configuration.Functions.Select(f => FunctionName.ToFullyQualifiedName(f.Name, f.PluginName))) : "None (Function calling is disabled)"; s_logFunctionChoiceBehaviorConfiguration( logger, configuration.Choice.Label, configuration.AutoInvoke, configuration.Options.AllowConcurrentInvocation, configuration.Options.AllowParallelCalls, functionsLog, null); } } /// /// Logs function calls. /// public static void LogFunctionCalls(this ILogger logger, FunctionCallContent[] functionCalls) { if (logger.IsEnabled(LogLevel.Debug)) { s_logFunctionCalls( logger, string.Join(", ", functionCalls.Select(call => $"{FunctionName.ToFullyQualifiedName(call.FunctionName, call.PluginName)} [Id: {call.Id}]")), null ); } } /// /// Logs the . /// public static void LogAutoFunctionInvocationFilterContext(this ILogger logger, AutoFunctionInvocationContext context) { if (logger.IsEnabled(LogLevel.Debug)) { var fqn = FunctionName.ToFullyQualifiedName(context.Function.Name, context.Function.PluginName); s_logAutoFunctionInvocationFilterContext( logger, fqn, context.ToolCallId, context.IsStreaming, context.FunctionSequenceIndex, context.RequestSequenceIndex, context.FunctionCount, null); } } /// /// Logs the auto function invocation process termination. /// public static void LogAutoFunctionInvocationProcessTermination(this ILogger logger, AutoFunctionInvocationContext context) { if (logger.IsEnabled(LogLevel.Debug)) { var fqn = FunctionName.ToFullyQualifiedName(context.Function.Name, context.Function.PluginName); s_logAutoFunctionInvocationFilterTermination(logger, fqn, context.ToolCallId, null); } } /// /// Logs function call request failure. /// public static void LogFunctionCallRequestFailure(this ILogger logger, FunctionCallContent functionCall, string error) { if (logger.IsEnabled(LogLevel.Debug)) { var fqn = FunctionName.ToFullyQualifiedName(functionCall.FunctionName, functionCall.PluginName); logger.LogDebug("Function call request failed: Name:{Name}, Id:{Id}", fqn, functionCall.Id); } // Log error at trace level only because it may contain sensitive information. if (logger.IsEnabled(LogLevel.Trace)) { var fqn = FunctionName.ToFullyQualifiedName(functionCall.FunctionName, functionCall.PluginName); logger.LogTrace("Function call request failed: Name:{Name}, Id:{Id}, Error:{Error}", fqn, functionCall.Id, error); } } [LoggerMessage(EventId = 0, Level = LogLevel.Debug, Message = "The maximum limit of {MaxNumberOfAutoInvocations} auto invocations per user request has been reached. Auto invocation is now disabled.")] public static partial void LogMaximumNumberOfAutoInvocationsPerUserRequestReached(this ILogger logger, int maxNumberOfAutoInvocations); [LoggerMessage(EventId = 0, Level = LogLevel.Debug, Message = "The maximum limit of {MaxNumberOfInflightAutoInvocations} in-flight auto invocations has been reached. Auto invocation is now disabled.")] public static partial void LogMaximumNumberOfInFlightAutoInvocationsReached(this ILogger logger, int maxNumberOfInflightAutoInvocations); }