Skip to content

Commit b021b63

Browse files
authored
Logs: Scopes, State, & FormattedMessage follow-up (#1883)
* Code review, unit tests, and performance tweaks for logging changes. * Fixed up ConsoleLogRecordExporter for renames. * CHANGELOG update.
1 parent 41a3371 commit b021b63

File tree

8 files changed

+311
-123
lines changed

8 files changed

+311
-123
lines changed

src/OpenTelemetry.Exporter.Console/ConsoleLogRecordExporter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ public override ExportResult Export(in Batch<LogRecord> batch)
4040
this.WriteLine($"{"LogRecord.CategoryName:".PadRight(RightPaddingLength)}{logRecord.CategoryName}");
4141
this.WriteLine($"{"LogRecord.LogLevel:".PadRight(RightPaddingLength)}{logRecord.LogLevel}");
4242
this.WriteLine($"{"LogRecord.TraceFlags:".PadRight(RightPaddingLength)}{logRecord.TraceFlags}");
43-
if (logRecord.Message != null)
43+
if (logRecord.FormattedMessage != null)
4444
{
45-
this.WriteLine($"{"LogRecord.Message:".PadRight(RightPaddingLength)}{logRecord.Message}");
45+
this.WriteLine($"{"LogRecord.FormattedMessage:".PadRight(RightPaddingLength)}{logRecord.FormattedMessage}");
4646
}
4747

4848
if (logRecord.State != null)

src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
OpenTelemetry.Logs.LogRecord.ForEachScope<TState>(System.Action<object, TState> callback, TState state) -> void
2-
OpenTelemetry.Logs.LogRecord.Message.get -> string
2+
OpenTelemetry.Logs.LogRecord.FormattedMessage.get -> string
33
OpenTelemetry.Logs.LogRecord.StateValues.get -> System.Collections.Generic.IReadOnlyList<System.Collections.Generic.KeyValuePair<string, object>>
4-
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.IncludeMessage.get -> bool
5-
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.IncludeMessage.set -> void
4+
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.IncludeFormattedMessage.get -> bool
5+
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.IncludeFormattedMessage.set -> void
66
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.IncludeScopes.get -> bool
77
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.IncludeScopes.set -> void
88
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ParseStateValues.get -> bool

src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
OpenTelemetry.Logs.LogRecord.ForEachScope<TState>(System.Action<object, TState> callback, TState state) -> void
2-
OpenTelemetry.Logs.LogRecord.Message.get -> string
2+
OpenTelemetry.Logs.LogRecord.FormattedMessage.get -> string
33
OpenTelemetry.Logs.LogRecord.StateValues.get -> System.Collections.Generic.IReadOnlyList<System.Collections.Generic.KeyValuePair<string, object>>
4-
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.IncludeMessage.get -> bool
5-
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.IncludeMessage.set -> void
4+
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.IncludeFormattedMessage.get -> bool
5+
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.IncludeFormattedMessage.set -> void
66
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.IncludeScopes.get -> bool
77
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.IncludeScopes.set -> void
88
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ParseStateValues.get -> bool

src/OpenTelemetry/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ please check the latest changes
4343
`ParentBasedSampler` will no longer explicitly consider Activity links.
4444
([#1851](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1851))
4545

46+
* Added `IncludeScopes`, `IncludeFormattedMessage`, & `ParseStateValues` on
47+
`OpenTelemetryLoggerOptions`. Added `FormattedMessage`, `StateValues`, &
48+
`ForEachScope` on `LogRecord`.
49+
([#1869](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1869) &
50+
[#1883](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1883))
51+
4652
## 1.0.1
4753

4854
Released 2021-Feb-10

src/OpenTelemetry/Logs/LogRecord.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ internal LogRecord(
3535
string categoryName,
3636
LogLevel logLevel,
3737
EventId eventId,
38-
string message,
38+
string formattedMessage,
3939
object state,
4040
Exception exception,
4141
IReadOnlyList<KeyValuePair<string, object>> stateValues)
@@ -55,7 +55,7 @@ internal LogRecord(
5555
this.CategoryName = categoryName;
5656
this.LogLevel = logLevel;
5757
this.EventId = eventId;
58-
this.Message = message;
58+
this.FormattedMessage = formattedMessage;
5959
this.State = state;
6060
this.StateValues = stateValues;
6161
this.Exception = exception;
@@ -77,7 +77,7 @@ internal LogRecord(
7777

7878
public EventId EventId { get; }
7979

80-
public string Message { get; }
80+
public string FormattedMessage { get; }
8181

8282
public object State { get; }
8383

src/OpenTelemetry/Logs/OpenTelemetryLogger.cs

Lines changed: 5 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
#if NET461 || NETSTANDARD2_0
1818
using System;
1919
using System.Collections.Generic;
20-
using System.Reflection.Emit;
2120
using System.Runtime.CompilerServices;
2221
using Microsoft.Extensions.Logging;
2322

@@ -38,7 +37,8 @@ internal OpenTelemetryLogger(string categoryName, OpenTelemetryLoggerProvider pr
3837

3938
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
4039
{
41-
if (!this.IsEnabled(logLevel) || Sdk.SuppressInstrumentation)
40+
if (!this.IsEnabled(logLevel)
41+
|| Sdk.SuppressInstrumentation)
4242
{
4343
return;
4444
}
@@ -54,7 +54,7 @@ public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Except
5454
this.categoryName,
5555
logLevel,
5656
eventId,
57-
options.IncludeMessage ? formatter(state, exception) : null,
57+
options.IncludeFormattedMessage ? formatter(state, exception) : null,
5858
options.ParseStateValues ? null : (object)state,
5959
exception,
6060
options.ParseStateValues ? this.ParseState(state) : null);
@@ -73,9 +73,9 @@ public bool IsEnabled(LogLevel logLevel)
7373

7474
private IReadOnlyList<KeyValuePair<string, object>> ParseState<TState>(TState state)
7575
{
76-
if (state is IReadOnlyList<KeyValuePair<string, object>>)
76+
if (state is IReadOnlyList<KeyValuePair<string, object>> stateList)
7777
{
78-
return StateValueListParser<TState>.ParseStateFunc(state);
78+
return stateList;
7979
}
8080
else if (state is IEnumerable<KeyValuePair<string, object>> stateValues)
8181
{
@@ -89,107 +89,6 @@ private IReadOnlyList<KeyValuePair<string, object>> ParseState<TState>(TState st
8989
};
9090
}
9191
}
92-
93-
private static class StateValueListParser<TState>
94-
{
95-
static StateValueListParser()
96-
{
97-
/* The code below is building a dynamic method to do this...
98-
99-
int count = state.Count;
100-
101-
List<KeyValuePair<string, object>> stateValues = new List<KeyValuePair<string, object>>(count);
102-
103-
for (int i = 0; i < count; i++)
104-
{
105-
stateValues.Add(state[i]);
106-
}
107-
108-
return stateValues;
109-
110-
...so we don't box structs or allocate an enumerator. */
111-
112-
var stateType = typeof(TState);
113-
var listType = typeof(List<KeyValuePair<string, object>>);
114-
var readOnlyListType = typeof(IReadOnlyList<KeyValuePair<string, object>>);
115-
116-
var dynamicMethod = new DynamicMethod(
117-
nameof(StateValueListParser<TState>),
118-
readOnlyListType,
119-
new[] { stateType },
120-
typeof(StateValueListParser<TState>).Module,
121-
skipVisibility: true);
122-
123-
var generator = dynamicMethod.GetILGenerator();
124-
125-
var testLabel = generator.DefineLabel();
126-
var writeItemLabel = generator.DefineLabel();
127-
128-
generator.DeclareLocal(typeof(int)); // count
129-
generator.DeclareLocal(listType); // list
130-
generator.DeclareLocal(typeof(int)); // i
131-
132-
if (stateType.IsValueType)
133-
{
134-
generator.Emit(OpCodes.Ldarga_S, 0); // state
135-
generator.Emit(OpCodes.Call, stateType.GetProperty("Count").GetMethod);
136-
}
137-
else
138-
{
139-
generator.Emit(OpCodes.Ldarg_0); // state
140-
generator.Emit(OpCodes.Callvirt, typeof(IReadOnlyCollection<KeyValuePair<string, object>>).GetProperty("Count").GetMethod);
141-
}
142-
143-
generator.Emit(OpCodes.Stloc_0); // count = state.Count
144-
generator.Emit(OpCodes.Ldloc_0);
145-
generator.Emit(OpCodes.Newobj, listType.GetConstructor(new Type[] { typeof(int) }));
146-
generator.Emit(OpCodes.Stloc_1); // list = new List(count)
147-
148-
generator.Emit(OpCodes.Ldc_I4_0);
149-
generator.Emit(OpCodes.Stloc_2); // i = 0
150-
151-
generator.Emit(OpCodes.Br_S, testLabel);
152-
generator.MarkLabel(writeItemLabel);
153-
generator.Emit(OpCodes.Ldloc_1); // list
154-
if (stateType.IsValueType)
155-
{
156-
generator.Emit(OpCodes.Ldarga_S, 0); // state
157-
}
158-
else
159-
{
160-
generator.Emit(OpCodes.Ldarg_0); // state
161-
}
162-
163-
generator.Emit(OpCodes.Ldloc_2); // i
164-
if (stateType.IsValueType)
165-
{
166-
generator.Emit(OpCodes.Call, stateType.GetProperty("Item").GetMethod);
167-
}
168-
else
169-
{
170-
generator.Emit(OpCodes.Callvirt, readOnlyListType.GetProperty("Item").GetMethod);
171-
}
172-
173-
generator.Emit(OpCodes.Callvirt, listType.GetMethod("Add", new Type[] { typeof(KeyValuePair<string, object>) })); // list.Add(state[i])
174-
175-
generator.Emit(OpCodes.Ldloc_2); // i
176-
generator.Emit(OpCodes.Ldc_I4_1);
177-
generator.Emit(OpCodes.Add); // i++
178-
generator.Emit(OpCodes.Stloc_2);
179-
180-
generator.MarkLabel(testLabel);
181-
generator.Emit(OpCodes.Ldloc_2); // i
182-
generator.Emit(OpCodes.Ldloc_0); // count
183-
generator.Emit(OpCodes.Blt_S, writeItemLabel);
184-
185-
generator.Emit(OpCodes.Ldloc_1); // list
186-
generator.Emit(OpCodes.Ret);
187-
188-
ParseStateFunc = (Func<TState, IReadOnlyList<KeyValuePair<string, object>>>)dynamicMethod.CreateDelegate(typeof(Func<TState, IReadOnlyList<KeyValuePair<string, object>>>));
189-
}
190-
191-
public static Func<TState, IReadOnlyList<KeyValuePair<string, object>>> ParseStateFunc { get; }
192-
}
19392
}
19493
}
19594
#endif

src/OpenTelemetry/Logs/OpenTelemetryLoggerOptions.cs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,29 @@ public class OpenTelemetryLoggerOptions
2525
internal readonly List<BaseProcessor<LogRecord>> Processors = new List<BaseProcessor<LogRecord>>();
2626

2727
/// <summary>
28-
/// Gets or sets a value indicating whether or not log scopes should be included on generated <see cref="LogRecord"/>s. Default value: False.
28+
/// Gets or sets a value indicating whether or not log scopes should be
29+
/// included on generated <see cref="LogRecord"/>s. Default value:
30+
/// False.
2931
/// </summary>
3032
public bool IncludeScopes { get; set; }
3133

3234
/// <summary>
33-
/// Gets or sets a value indicating whether or not log message should be included on generated <see cref="LogRecord"/>s. Default value: False.
35+
/// Gets or sets a value indicating whether or not formatted log message
36+
/// should be included on generated <see cref="LogRecord"/>s. Default
37+
/// value: False.
3438
/// </summary>
35-
public bool IncludeMessage { get; set; }
39+
public bool IncludeFormattedMessage { get; set; }
3640

3741
/// <summary>
38-
/// Gets or sets a value indicating whether or not log state should be parsed into <see cref="LogRecord.StateValues"/> on generated <see cref="LogRecord"/>s. Default value: False.
42+
/// Gets or sets a value indicating whether or not log state should be
43+
/// parsed into <see cref="LogRecord.StateValues"/> on generated <see
44+
/// cref="LogRecord"/>s. Default value: False.
3945
/// </summary>
46+
/// <remarks>
47+
/// Note: When <see cref="ParseStateValues"/> is set to <see
48+
/// langword="true"/> <see cref="LogRecord.State"/> will always be <see
49+
/// langword="null"/>.
50+
/// </remarks>
4051
public bool ParseStateValues { get; set; }
4152

4253
/// <summary>

0 commit comments

Comments
 (0)