public void Log <TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func <TState, Exception, string> formatter) { if (!IsEnabled(logLevel)) { return; } var stateValues = state as IEnumerable <KeyValuePair <string, object> >; string formattedMessage = formatter?.Invoke(state, exception); // If we don't have a message, there's nothing to log. if (string.IsNullOrEmpty(formattedMessage)) { return; } bool isSystemTrace = Utility.GetStateBoolValue(stateValues, ScriptConstants.LogPropertyIsSystemLogKey); if (isSystemTrace) { // System traces are not logged to files. return; } bool isPrimaryHostTrace = Utility.GetStateBoolValue(stateValues, ScriptConstants.LogPropertyPrimaryHostKey); if (isPrimaryHostTrace && !_isPrimary()) { return; } if (exception != null) { if (exception is FunctionInvocationException || exception is AggregateException) { // we want to minimize the stack traces for function invocation // failures, so we drill into the very inner exception, which will // be the script error Exception actualException = exception; while (actualException.InnerException != null) { actualException = actualException.InnerException; } formattedMessage += $"{Environment.NewLine}{actualException.Message}"; } else { formattedMessage += $"{Environment.NewLine}{exception.ToFormattedString()}"; } } formattedMessage = FormatLine(stateValues, logLevel, formattedMessage); try { _fileWriter.AppendLine(formattedMessage); // flush errors immediately if (logLevel == LogLevel.Error || exception != null) { _fileWriter.Flush(); } } catch (Exception) { // Make sure the Logger doesn't throw if there are Exceptions (disk full, etc). } }