Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d4019c3
structured logger formatter prototype
maryamariyan Apr 15, 2020
e62739b
add ref to Linq + add public apis
maryamariyan Apr 15, 2020
ae48df1
New APIs for Structured Log Formatting
maryamariyan May 12, 2020
968496c
Apply review feedback
maryamariyan May 14, 2020
55ea183
nit cleanup
maryamariyan May 14, 2020
d2e0808
- messages can color vars in messages (Compact)
maryamariyan May 15, 2020
cf38d82
TODO
maryamariyan May 15, 2020
515bde6
Rename to XConsoleLog...
maryamariyan May 15, 2020
6b5de1e
FormatterNames const not instance properties
maryamariyan May 15, 2020
c9d0939
add AddCompact and other helpers
maryamariyan May 15, 2020
27ddec2
Rename AddCompactFormatter for short?
maryamariyan May 15, 2020
a558275
Revert "Rename AddCompactFormatter for short?"
maryamariyan May 21, 2020
f58aa1f
Add back deprecated APIs
maryamariyan May 21, 2020
94e5c18
exception messaging in compact remains single line
maryamariyan May 21, 2020
9c3345e
cleanup
maryamariyan May 26, 2020
e441d04
rename default to colored
maryamariyan May 26, 2020
3cc92ed
deprecate ConsoleLoggerFormat
maryamariyan May 26, 2020
d72c6f9
minor rename
maryamariyan May 26, 2020
b7085b5
Rename back to default formatter
maryamariyan May 27, 2020
12223c4
triple slash comments on new helpers
maryamariyan May 28, 2020
af1bc5c
slight impl fixup
maryamariyan May 28, 2020
6ab5aa9
ConsoleLoggerProvider: keep ctor not deprecate
maryamariyan May 28, 2020
85d50b2
Added triple slash comments
maryamariyan May 28, 2020
ff39ae1
corner cases
maryamariyan May 29, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
TODO
- make custom autoselect when just AddLogFormatter
- make API renames: ConsoleLogFormatterX
- const string on XFormatter.Name rather than getter
- overall perf check
- perf on compact and json (just for demo now)
  • Loading branch information
maryamariyan committed May 29, 2020
commit cf38d82e9bde7683e3c52ed203812235a008873e
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ public ConsoleLoggerProvider(Microsoft.Extensions.Options.IOptionsMonitor<Micros
public void Dispose() { }
public void SetScopeProvider(Microsoft.Extensions.Logging.IExternalScopeProvider scopeProvider) { }
}
public readonly partial struct ConsoleMessage
{
public readonly System.ConsoleColor? Background;
public readonly string Content;
public readonly System.ConsoleColor? Foreground;
public ConsoleMessage(string message, System.ConsoleColor? background = default(System.ConsoleColor?), System.ConsoleColor? foreground = default(System.ConsoleColor?)) { throw null; }
}
public partial class DefaultLogFormatter : Microsoft.Extensions.Logging.Console.ILogFormatter, System.IDisposable
{
public DefaultLogFormatter(Microsoft.Extensions.Options.IOptionsMonitor<Microsoft.Extensions.Logging.Console.DefaultLogFormatterOptions> options) { }
Expand Down Expand Up @@ -96,15 +103,9 @@ public JsonLogFormatterOptions() { }
}
public readonly partial struct LogMessageEntry
{
public readonly System.ConsoleColor? LevelBackground;
public readonly System.ConsoleColor? LevelForeground;
public readonly string LevelString;
public readonly bool LogAsError;
public readonly string Message;
public readonly System.ConsoleColor? MessageColor;
public readonly string TimeStamp;
public readonly System.Action<Microsoft.Extensions.Logging.Console.IConsole> WriteCallback;
public LogMessageEntry(string message, string timeStamp = null, string levelString = null, System.ConsoleColor? levelBackground = default(System.ConsoleColor?), System.ConsoleColor? levelForeground = default(System.ConsoleColor?), System.ConsoleColor? messageColor = default(System.ConsoleColor?), bool logAsError = false, System.Action<Microsoft.Extensions.Logging.Console.IConsole> writeCallback = null) { throw null; }
public readonly Microsoft.Extensions.Logging.Console.ConsoleMessage[] Messages;
public LogMessageEntry(Microsoft.Extensions.Logging.Console.ConsoleMessage[] messages, bool logAsError = false) { throw null; }
}
public partial class SystemdLogFormatter : Microsoft.Extensions.Logging.Console.ILogFormatter, System.IDisposable
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,14 @@ public virtual void EnqueueMessage(LogMessageEntry message)
}

// for testing
internal virtual void WriteMessage(LogMessageEntry message)
internal virtual void WriteMessage(LogMessageEntry entry)
{
var console = message.LogAsError ? ErrorConsole : Console;
// is giving user control on this thread over how long the output thread takes to write to console - something to consider
message.WriteCallback(console);
var console = entry.LogAsError ? ErrorConsole : Console;
foreach (var message in entry.Messages)
{
console.Write(message.Content, message.Background, message.Foreground);
}
console.Flush();
}

private void ProcessLogQueue()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ internal class CompactLogFormatter : ILogFormatter, IDisposable
// ConsoleColor does not have a value to specify the 'Default' color
private readonly ConsoleColor? DefaultConsoleColor = null;

[ThreadStatic]
private static StringBuilder _logBuilder;

static CompactLogFormatter()
{
var logLevelString = GetLogLevelString(LogLevel.Information);
Expand Down Expand Up @@ -69,41 +66,36 @@ public LogMessageEntry Format(LogLevel logLevel, string logName, int eventId, st

private LogMessageEntry FormatHelper<TState>(LogLevel logLevel, string logName, int eventId, string message, Exception exception, IExternalScopeProvider scopeProvider, TState scope)
{
List<Message> msgs = new List<Message>();
// todo fix later:
var logBuilder = _logBuilder;
_logBuilder = null;

if (logBuilder == null)
{
logBuilder = new StringBuilder();
}

// Example:
// INFO: ConsoleApp.Program[10]
// Request received
var messages = new List<ConsoleMessage>();

var logLevelColors = GetLogLevelConsoleColors(logLevel);
var logLevelString = GetLogLevelString(logLevel);
// category and event id
logBuilder.Append(_loglevelPadding);
logBuilder.Append(logName);
logBuilder.Append("[");
logBuilder.Append(eventId);
logBuilder.Append("]");
// logBuilder.AppendLine("]");

msgs.Add(new Message($"{logName}[{eventId}] ", null, null));
string timestamp = null;
var timestampFormat = FormatterOptions.TimestampFormat;
if (timestampFormat != null)
{
var dateTime = GetCurrentDateTime();
timestamp = dateTime.ToString(timestampFormat);
}
if (timestamp != null)
{
messages.Add(new ConsoleMessage(timestamp + " ", null, null));
}
if (logLevelString != null)
{
messages.Add(new ConsoleMessage(logLevelString,logLevelColors.Background, logLevelColors.Foreground));
}

messages.Add(new ConsoleMessage($"{logName}[{eventId}] ", null, null));
string originalFormat = null;
int count = 0;

if (scope != null)
{
logBuilder.Append(_messagePadding);
if (scope is IReadOnlyList<KeyValuePair<string, object>> kvpsx)
{
var strings = new List<KeyValuePair<string, object>>();
logBuilder.Append(" -> ");
foreach (var kvp in kvpsx)
{
if (kvp.Key.Contains("{OriginalFormat}"))
Expand All @@ -112,10 +104,7 @@ private LogMessageEntry FormatHelper<TState>(LogLevel logLevel, string logName,
}
else
{
//count++;
strings.Add(kvp);
logBuilder.Append(kvp.Value.ToString());
logBuilder.Append(", ");
}
}
int prevIndex = 0;
Expand All @@ -129,13 +118,10 @@ private LogMessageEntry FormatHelper<TState>(LogLevel logLevel, string logName,
if (curIndex != -1)
{
var curString = originalFormat.Substring(prevIndex, curIndex - prevIndex);
msgs.Add(new Message(curString, null, null));
msgs.Add(new Message(strings.ElementAt(count).Value.ToString(), null, ConsoleColor.Cyan));
messages.Add(new ConsoleMessage(curString, null, null));
messages.Add(new ConsoleMessage(strings.ElementAt(count).Value.ToString(), null, ConsoleColor.Cyan));
prevIndex += curIndex + strings.ElementAt(count).Key.Length + 2;
count++;
//strings.Add(kvp.Value.ToString());
logBuilder.Append(kvp.Value.ToString());
logBuilder.Append(", ");
}
}
}
Expand All @@ -144,7 +130,6 @@ private LogMessageEntry FormatHelper<TState>(LogLevel logLevel, string logName,
else if (scope is IReadOnlyList<KeyValuePair<string, string>> kvps)
{
var strings = new List<KeyValuePair<string, string>>();
logBuilder.Append(" -> ");
foreach (var kvp in kvps)
{
if (kvp.Key.Contains("{OriginalFormat}"))
Expand All @@ -153,10 +138,7 @@ private LogMessageEntry FormatHelper<TState>(LogLevel logLevel, string logName,
}
else
{
//count++;
strings.Add(kvp);
logBuilder.Append(kvp.Value);
logBuilder.Append(", ");
}
}
int prevIndex = 0;
Expand All @@ -170,142 +152,46 @@ private LogMessageEntry FormatHelper<TState>(LogLevel logLevel, string logName,
if (curIndex != -1)
{
var curString = originalFormat.Substring(prevIndex, curIndex - prevIndex);
msgs.Add(new Message(curString, null, null));
msgs.Add(new Message(strings.ElementAt(count).Value, null, ConsoleColor.Cyan));
messages.Add(new ConsoleMessage(curString, null, null));
messages.Add(new ConsoleMessage(strings.ElementAt(count).Value, null, ConsoleColor.Cyan));
prevIndex += curIndex + strings.ElementAt(count).Key.Length + 2;
count++;
logBuilder.Append(kvp.Value);
logBuilder.Append(", ");
}
}
}
}
}
else
{
logBuilder.Append("-> ");
logBuilder.Append(scope.ToString());
}
}

if (!string.IsNullOrEmpty(message))
{
// message
logBuilder.Append(_messagePadding);

var len = logBuilder.Length;
logBuilder.AppendLine(message);
if (originalFormat == null)
{
msgs.Add(new Message(message, null, null));
messages.Add(new ConsoleMessage(message, null, null));
}
else if (count == 0)
{
msgs.Add(new Message(originalFormat, null, null));
messages.Add(new ConsoleMessage(originalFormat, null, null));
}
}

// scope information
msgs.Add(new Message(" ", null, null));
GetScopeInformation(logBuilder, scopeProvider, msgs);
messages.Add(new ConsoleMessage(" ", null, null));
GetScopeInformation(scopeProvider, messages);

// Example:
// System.InvalidOperationException
// at Namespace.Class.Function() in File:line X
if (exception != null)
{
// exception message
logBuilder.Append(exception.ToString());
msgs.Add(new Message(" ", null, null));
msgs.Add(new Message(exception.ToString(), null, null));
// logBuilder.AppendLine(exception.ToString());
}

string timestamp = null;
var timestampFormat = FormatterOptions.TimestampFormat;
if (timestampFormat != null)
{
var dateTime = GetCurrentDateTime();
timestamp = dateTime.ToString(timestampFormat);
messages.Add(new ConsoleMessage(" ", null, null));
messages.Add(new ConsoleMessage(exception.ToString(), null, null));
// TODO: confirm exception message all in one line?
}

var formattedMessage = logBuilder.ToString();
logBuilder.Clear();
if (logBuilder.Capacity > 1024)
{
logBuilder.Capacity = 1024;
}
_logBuilder = logBuilder;

return new LogMessageEntry(
message: formattedMessage,
timeStamp: timestamp,
levelString: logLevelString,
levelBackground: logLevelColors.Background,
levelForeground: logLevelColors.Foreground,
messageColor: DefaultConsoleColor,
logAsError: logLevel >= FormatterOptions.LogToStandardErrorThreshold,
writeCallback : console =>
{
if (timestamp != null || logLevelString != null)
{
console.Write("[", null, null);

if (timestamp != null)
{
console.Write(timestamp, null, null);
console.Write(" ", null, null);
}
if (logLevelString != null)
{
console.Write(logLevelString, logLevelColors.Background, logLevelColors.Foreground);
console.Write("", null, null);
}
console.Write("] ", null, null);
}

if (msgs.Count > 0)
{
foreach (var item in msgs)
{
console.Write(item.Content, item.Background, item.Foreground);
}
}

//console.Write(formattedMessage, DefaultConsoleColor, DefaultConsoleColor);
console.WriteLine(string.Empty, DefaultConsoleColor, DefaultConsoleColor);
console.Flush();
}
messages: messages.ToArray(),
logAsError: logLevel >= FormatterOptions.LogToStandardErrorThreshold
);
}

internal struct LogEntry
{
internal LogEntry(Action<IConsole> action, Message[] messages, bool logAsError)
{
Messages = messages;
WriteCallback = action;
LogAsError = logAsError;
}

internal Message[] Messages;
internal Action<IConsole> WriteCallback;
internal bool LogAsError;
}

internal struct Message
{
internal Message(string message, ConsoleColor? background, ConsoleColor? foreground)
{
Content = message;
Background = background;
Foreground = foreground;
}
internal string Content;
internal ConsoleColor? Background;
internal ConsoleColor? Foreground;
}

private DateTime GetCurrentDateTime()
{
return FormatterOptions.UseUtcTimestamp ? DateTime.UtcNow : DateTime.Now;
Expand Down Expand Up @@ -360,34 +246,17 @@ private ConsoleColors GetLogLevelConsoleColors(LogLevel logLevel)
}
}

private void GetScopeInformation(StringBuilder stringBuilder, IExternalScopeProvider scopeProvider, List<Message> msgs)
private void GetScopeInformation(IExternalScopeProvider scopeProvider, List<ConsoleMessage> messages)
{
if (FormatterOptions.IncludeScopes && scopeProvider != null)
{
var initialLength = stringBuilder.Length;

scopeProvider.ForEachScope((scope, state) =>
{
var (builder, paddAt, messages) = state;
var padd = paddAt == builder.Length;
if (padd)
{
//messages.Add(new Message(_messagePadding, null, null));
builder.Append(_messagePadding);
}
messages.Add(new Message("=> ", null, null));
messages.Add(new Message(scope.ToString(), null, ConsoleColor.DarkGray));
messages.Add(new Message(" ", null, null));
builder.Append("=> ");
builder.Append(scope);
builder.Append(" ");

}, (stringBuilder, initialLength, msgs));
state.Add(new ConsoleMessage("=> ", null, null));
state.Add(new ConsoleMessage(scope.ToString(), null, ConsoleColor.DarkGray));
state.Add(new ConsoleMessage(" ", null, null));

if (stringBuilder.Length > initialLength)
{
// stringBuilder.AppendLine();
}
}, messages);
}
}

Expand Down
Loading