Skip to content

Commit 33a68d0

Browse files
Reduce generic specialized code in console formatters (#101474)
Move code that doesn't need to be generic to a non-generic method. Reduces the size of the Stage 2 goldilocks app by 1.4% since these methods are rather large (especially the `JsonConsoleFormatter` one) and we have many specializations.
1 parent 6cd329b commit 33a68d0

File tree

3 files changed

+36
-23
lines changed

3 files changed

+36
-23
lines changed

src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,16 @@ public override void Write<TState>(in LogEntry<TState> logEntry, IExternalScopeP
3232
{
3333
return;
3434
}
35-
LogLevel logLevel = logEntry.LogLevel;
36-
string category = logEntry.Category;
37-
int eventId = logEntry.EventId.Id;
38-
Exception? exception = logEntry.Exception;
35+
36+
// We extract most of the work into a non-generic method to save code size. If this was left in the generic
37+
// method, we'd get generic specialization for all TState parameters, but that's unnecessary.
38+
WriteInternal(scopeProvider, textWriter, message, logEntry.LogLevel, logEntry.Category, logEntry.EventId.Id, logEntry.Exception,
39+
logEntry.State != null, logEntry.State?.ToString(), logEntry.State as IReadOnlyCollection<KeyValuePair<string, object>>);
40+
}
41+
42+
private void WriteInternal(IExternalScopeProvider? scopeProvider, TextWriter textWriter, string message, LogLevel logLevel,
43+
string category, int eventId, Exception? exception, bool hasState, string? stateMessage, IReadOnlyCollection<KeyValuePair<string, object>>? stateProperties)
44+
{
3945
const int DefaultBufferSize = 1024;
4046
using (var output = new PooledByteBufferWriter(DefaultBufferSize))
4147
{
@@ -48,21 +54,21 @@ public override void Write<TState>(in LogEntry<TState> logEntry, IExternalScopeP
4854
DateTimeOffset dateTimeOffset = FormatterOptions.UseUtcTimestamp ? DateTimeOffset.UtcNow : DateTimeOffset.Now;
4955
writer.WriteString("Timestamp", dateTimeOffset.ToString(timestampFormat));
5056
}
51-
writer.WriteNumber(nameof(logEntry.EventId), eventId);
52-
writer.WriteString(nameof(logEntry.LogLevel), GetLogLevelString(logLevel));
53-
writer.WriteString(nameof(logEntry.Category), category);
57+
writer.WriteNumber(nameof(LogEntry<object>.EventId), eventId);
58+
writer.WriteString(nameof(LogEntry<object>.LogLevel), GetLogLevelString(logLevel));
59+
writer.WriteString(nameof(LogEntry<object>.Category), category);
5460
writer.WriteString("Message", message);
5561

5662
if (exception != null)
5763
{
5864
writer.WriteString(nameof(Exception), exception.ToString());
5965
}
6066

61-
if (logEntry.State != null)
67+
if (hasState)
6268
{
63-
writer.WriteStartObject(nameof(logEntry.State));
64-
writer.WriteString("Message", logEntry.State.ToString());
65-
if (logEntry.State is IReadOnlyCollection<KeyValuePair<string, object>> stateProperties)
69+
writer.WriteStartObject(nameof(LogEntry<object>.State));
70+
writer.WriteString("Message", stateMessage);
71+
if (stateProperties != null)
6672
{
6773
foreach (KeyValuePair<string, object> item in stateProperties)
6874
{

src/libraries/Microsoft.Extensions.Logging.Console/src/SimpleConsoleFormatter.cs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,15 @@ public override void Write<TState>(in LogEntry<TState> logEntry, IExternalScopeP
5151
{
5252
return;
5353
}
54-
LogLevel logLevel = logEntry.LogLevel;
54+
55+
// We extract most of the work into a non-generic method to save code size. If this was left in the generic
56+
// method, we'd get generic specialization for all TState parameters, but that's unnecessary.
57+
WriteInternal(scopeProvider, textWriter, message, logEntry.LogLevel, logEntry.EventId.Id, logEntry.Exception, logEntry.Category);
58+
}
59+
60+
private void WriteInternal(IExternalScopeProvider? scopeProvider, TextWriter textWriter, string message, LogLevel logLevel,
61+
int eventId, Exception? exception, string category)
62+
{
5563
ConsoleColors logLevelColors = GetLogLevelConsoleColors(logLevel);
5664
string logLevelString = GetLogLevelString(logLevel);
5765

@@ -70,22 +78,16 @@ public override void Write<TState>(in LogEntry<TState> logEntry, IExternalScopeP
7078
{
7179
textWriter.WriteColoredMessage(logLevelString, logLevelColors.Background, logLevelColors.Foreground);
7280
}
73-
CreateDefaultLogMessage(textWriter, logEntry, message, scopeProvider);
74-
}
7581

76-
private void CreateDefaultLogMessage<TState>(TextWriter textWriter, in LogEntry<TState> logEntry, string message, IExternalScopeProvider? scopeProvider)
77-
{
7882
bool singleLine = FormatterOptions.SingleLine;
79-
int eventId = logEntry.EventId.Id;
80-
Exception? exception = logEntry.Exception;
8183

8284
// Example:
8385
// info: ConsoleApp.Program[10]
8486
// Request received
8587

8688
// category and event id
8789
textWriter.Write(LoglevelPadding);
88-
textWriter.Write(logEntry.Category);
90+
textWriter.Write(category);
8991
textWriter.Write('[');
9092

9193
#if NETCOREAPP

src/libraries/Microsoft.Extensions.Logging.Console/src/SystemdConsoleFormatter.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,15 @@ public override void Write<TState>(in LogEntry<TState> logEntry, IExternalScopeP
4141
{
4242
return;
4343
}
44-
LogLevel logLevel = logEntry.LogLevel;
45-
string category = logEntry.Category;
46-
int eventId = logEntry.EventId.Id;
47-
Exception? exception = logEntry.Exception;
44+
45+
// We extract most of the work into a non-generic method to save code size. If this was left in the generic
46+
// method, we'd get generic specialization for all TState parameters, but that's unnecessary.
47+
WriteInternal(scopeProvider, textWriter, message, logEntry.LogLevel, logEntry.Category, logEntry.EventId.Id, logEntry.Exception);
48+
}
49+
50+
private void WriteInternal(IExternalScopeProvider? scopeProvider, TextWriter textWriter, string message, LogLevel logLevel, string category,
51+
int eventId, Exception? exception)
52+
{
4853
// systemd reads messages from standard out line-by-line in a '<pri>message' format.
4954
// newline characters are treated as message delimiters, so we must replace them.
5055
// Messages longer than the journal LineMax setting (default: 48KB) are cropped.

0 commit comments

Comments
 (0)