/// <summary> /// Creates a log entry, actually a log info instance, fill the properties of that log info, and then passes it to the associated logger provider. /// <para>WARNING: It's easier to use the ILogger extension methods than this method, since it requires a lot of parameters, so calling it could be a very complicated action.</para> /// </summary> void ILogger.Log <TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func <TState, Exception, string> formatter) { if ((this as ILogger).IsEnabled(logLevel)) { LogEntry entry = new LogEntry { Category = Category, Level = logLevel, // well, the passed default formatter function does not takes the exception into account // SEE: https://github.com/aspnet/Extensions/blob/master/src/Logging/Logging.Abstractions/src/LoggerExtensions.cs Text = exception?.Message ?? state.ToString(), // formatter(state, exception) Exception = exception, EventId = eventId, State = state }; // well, you never know what it really is if (state is string s) { entry.StateText = s; } // in case we have to do with a message template, lets get the keys and values (for Structured Logging providers) // SEE: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging#log-message-template // SEE: https://softwareengineering.stackexchange.com/questions/312197/benefits-of-structured-logging-vs-basic-logging else if (state is IEnumerable <KeyValuePair <string, object> > stateProps) { entry.StateProperties = stateProps.ToDictionary(x => x.Key, x => x.Value); } // gather info about scope(s), if any if (Provider.ScopeProvider is not null) { Provider.ScopeProvider.ForEachScope((value, loggingProps) => { entry.Scopes ??= new List <LogScopeInfo>(); LogScopeInfo Scope = new LogScopeInfo(); entry.Scopes.Add(Scope); if (value is string s) { Scope.Text = s; } else if (value is IEnumerable <KeyValuePair <string, object> > props) { Scope.Properties = props.ToDictionary(x => x.Key, x => x.Value); } }, state); } Provider.WriteLog(entry); } }
/// <summary> Формирование строки из элемента лога и запись в файл </summary> private void WriteLogFile() { if (!_queue.TryDequeue(out LogEntry log)) { return; } var sb = new StringBuilder(); sb.Append(Pad(log.TimeStampUtc.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss.ff"), _lengths["Time"])); sb.Append(Pad(log.HostName, _lengths["Host"])); sb.Append(Pad(log.UserName, _lengths["User"])); sb.Append(Pad(log.Level.ToString(), _lengths["Level"])); sb.Append(Pad(log.EventId.ToString(), _lengths["EventId"])); sb.Append(Pad(log.Category, _lengths["Category"])); string s = string.Empty; if (log.Scopes != null && log.Scopes.Count > 0) { LogScopeInfo scopeInfo = log.Scopes.Last(); if (!string.IsNullOrWhiteSpace(scopeInfo.Text)) { s = scopeInfo.Text; } } sb.Append(Pad(s, _lengths["Scope"])); string text = log.Text; //Пример сохранения свойств //if (log.StateProperties != null && log.StateProperties.Count > 0) //{ // text = text + " Properties = " + JsonConvert.SerializeObject(log.StateProperties); //} if (!string.IsNullOrWhiteSpace(text)) { sb.Append(text.Replace("\r\n", " ").Replace("\r", " ").Replace("\n", " ")); } sb.AppendLine(); WriteLine(sb.ToString()); }