-
Notifications
You must be signed in to change notification settings - Fork 359
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LogRecord pipeline addition #5124
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the overall direction. I didn't look too closely at the implementation details but nothing jumped out as being problematic. If the dotnet-monitor crew want to drill into the details go for it, but looks fine to me.
(Let me know if you need me to mash the merge button) |
@@ -13,12 +15,21 @@ public class LogObject : IReadOnlyList<KeyValuePair<string, object>>, IStateWith | |||
public static readonly Func<object, Exception, string> Callback = (state, exception) => ((LogObject)state).ToString(); | |||
|
|||
private readonly string _formattedMessage; | |||
private List<KeyValuePair<string, object>> _items = new(); | |||
private KeyValuePair<string, object>[] _items = new KeyValuePair<string, object>[8]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why move from List to array?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would CollectionsMarshal.AsSpan work here?
if (_logger != null) | ||
{ | ||
eventSource.Dynamic.AddCallbackForProviderEvent(LoggingSourceConfiguration.MicrosoftExtensionsLoggingProviderName, "MessageJson", (traceEvent) => { | ||
if (!activityIdToScope.TryGetValue(traceEvent.ActivityID, out LogScopeItem scopeItem)) | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm assuming you kept the two code paths separate because ultimately we will remove the _logger == null path. However, I'm assuming there's a lot of overlap between our reading of the log events and the new code.
|
||
namespace Microsoft.Diagnostics.Monitoring.EventPipe | ||
{ | ||
internal readonly struct LogRecordException : IEquatable<LogRecordException> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a record struct might give you these semantics automatically.
{ | ||
private static readonly UTF8Encoding s_Utf8Encoding = new(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); | ||
[ThreadStatic] | ||
private static LogObject[]? s_ScopeStorage; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this state get cleaned up after each session?
The existing
EventLogsPipeline
routes log messages retrieved usingMicrosoft-Extensions-Logging
through anILogger
shim. There isn't anything necessarily wrong with this, but it adds a lot of extra work and memory pressure to the monitoring host. There also really isn't a way to add data such as Timestamp, TraceId, SpanId, etc., without having to hack ILogger.Working through a prototype of a
dotnet-monitor
which exports OpenTelemetry format (OTLP) we (@samsp-msft @wiktork and @rajkumar-rangaraj) felt it was better to treat logging as we do the other pipelines and have a simple DTO to store all the log information (independent of ILogger) consumers can use to process logs.What this PR does is add a new interface into
EventLogsPipeline
(ILogRecordLogger
) which can be used to opt-into this new pipeline behavior.Once consumers have been updated we should be able to remove the old one. But they exist side-by-side for now so nothing currently reliant on the internals breaks.