in src/WebJobs.Script.WebHost/Diagnostics/SystemLogger.cs [58:182]
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (!IsEnabled(logLevel) || _isUserFunction || FunctionInvoker.CurrentScope == FunctionInvocationScope.User)
{
return;
}
// Enumerate all the state values once, capturing the values we'll use below - last one wins.
string stateSourceValue = null;
string stateFunctionName = null;
string stateEventName = null;
string stateActivityId = null;
string diagnosticEventErrorCode = null;
bool isDiagnosticEvent = false;
if (state is IEnumerable<KeyValuePair<string, object>> stateProps)
{
foreach (var kvp in stateProps)
{
if (string.Equals(kvp.Key, ScriptConstants.LogPropertySourceKey, StringComparison.OrdinalIgnoreCase))
{
stateSourceValue = kvp.Value?.ToString();
}
else if (string.Equals(kvp.Key, ScriptConstants.DiagnosticEventKey, StringComparison.OrdinalIgnoreCase))
{
isDiagnosticEvent = true;
}
else if (string.Equals(kvp.Key, ScriptConstants.ErrorCodeKey, StringComparison.OrdinalIgnoreCase))
{
diagnosticEventErrorCode = kvp.Value?.ToString();
}
else if (string.Equals(kvp.Key, ScriptConstants.LogPropertyIsUserLogKey, StringComparison.OrdinalIgnoreCase))
{
if ((bool)kvp.Value)
{
return;
}
}
else if (Utility.IsFunctionName(kvp))
{
stateFunctionName = kvp.Value?.ToString();
}
else if (string.Equals(kvp.Key, ScriptConstants.LogPropertyEventNameKey, StringComparison.OrdinalIgnoreCase))
{
stateEventName = kvp.Value?.ToString();
}
else if (string.Equals(kvp.Key, ScriptConstants.LogPropertyActivityIdKey, StringComparison.OrdinalIgnoreCase))
{
stateActivityId = kvp.Value?.ToString();
}
}
}
// Propagate special exceptions through the EventManager.
string source = _categoryName ?? stateSourceValue;
if (exception is FunctionIndexingException && _eventManager != null)
{
_eventManager.Publish(new FunctionIndexingEvent(nameof(FunctionIndexingException), source, exception));
}
// If we don't have a message, there's nothing to log.
string formattedMessage = formatter?.Invoke(state, exception);
if (string.IsNullOrEmpty(formattedMessage))
{
return;
}
var scopeProps = _scopeProvider.GetScopeDictionaryOrNull();
string functionName = _functionName ?? stateFunctionName ?? string.Empty;
if (string.IsNullOrEmpty(functionName) && scopeProps?.Count > 0)
{
if (Utility.TryGetFunctionName(scopeProps, out string scopeFunctionName))
{
functionName = scopeFunctionName;
}
}
string invocationId = string.Empty;
object scopeValue = null;
string scopeActivityId = null;
if (scopeProps != null)
{
if (scopeProps.TryGetValue(ScriptConstants.LogPropertyFunctionInvocationIdKey, out scopeValue) && scopeValue != null)
{
invocationId = scopeValue.ToString();
}
// For Http function invocations we want to stamp invocation logs with
// the request ID for easy correlation with incoming Http request logs.
if (scopeProps.TryGetValue(ScriptConstants.AzureFunctionsRequestIdKey, out scopeValue))
{
scopeActivityId = scopeValue as string;
}
}
// Apply standard event properties.
// Note: we must be sure to default any null values to empty string
// otherwise the ETW event will fail to be persisted (silently).
string eventName = !string.IsNullOrEmpty(eventId.Name) ? eventId.Name : stateEventName ?? string.Empty;
eventName = isDiagnosticEvent ? $"DiagnosticEvent-{diagnosticEventErrorCode}" : eventName;
string activityId = stateActivityId ?? scopeActivityId ?? string.Empty;
var options = _appServiceOptions;
string subscriptionId = options.SubscriptionId ?? string.Empty;
string appName = options.AppName ?? string.Empty;
string runtimeSiteName = options.RuntimeSiteName ?? string.Empty;
string slotName = options.SlotName ?? string.Empty;
string innerExceptionType = string.Empty;
string innerExceptionMessage = string.Empty;
string details = string.Empty;
if (exception != null)
{
// Populate details from the exception.
if (string.IsNullOrEmpty(functionName) && exception is FunctionException fex)
{
functionName = string.IsNullOrEmpty(fex.MethodName) ? string.Empty : fex.MethodName.Replace("Host.Functions.", string.Empty);
}
(innerExceptionType, innerExceptionMessage, details) = exception.GetExceptionDetails();
formattedMessage = Sanitizer.Sanitize(formattedMessage);
innerExceptionMessage = innerExceptionMessage ?? string.Empty;
}
_eventGenerator.LogFunctionTraceEvent(logLevel, subscriptionId, appName, functionName, eventName, source, details, formattedMessage, innerExceptionType, innerExceptionMessage, invocationId, _hostInstanceId, activityId, runtimeSiteName, slotName, DateTime.UtcNow);
}