-
Notifications
You must be signed in to change notification settings - Fork 857
LogEmitter System.Diagnostics.Tracing extension project #3305
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
Changes from 8 commits
6d2f153
101ce19
7eb0006
20479f5
c64ca11
53a6854
fd5a87e
035823b
80cbdbb
744c399
df93cf5
1ba8afe
9a0ee32
888eb54
558e8d2
4d76b87
617d88d
ca7e319
6fae76d
a92e78e
5e33474
6b15b3b
2114dca
0d34533
bb4293c
380f139
87597f8
345e1a2
ea63af4
a12d432
3b35268
57775a5
9ee18df
f347e51
5537c73
e0c2347
dd80cc9
4f6b9e0
1dcd193
226facf
d3c5443
31f5a97
cb69e49
8693d93
b71006f
6269015
7647145
4f498af
55537b5
d1a4b3b
ffda1ce
12c92ad
cf69b8c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,4 +1,30 @@ | ||||||
| #nullable enable | ||||||
| OpenTelemetry.Batch<T>.Batch(T! item) -> void | ||||||
| OpenTelemetry.Batch<T>.CleanupAction.get -> System.Action<T!>? | ||||||
| OpenTelemetry.Batch<T>.CleanupAction.init -> void | ||||||
| OpenTelemetry.BatchExportProcessor<T>.CleanupAction.get -> System.Action<T!>? | ||||||
| OpenTelemetry.BatchExportProcessor<T>.CleanupAction.init -> void | ||||||
| OpenTelemetry.BatchExportProcessor<T>.InitializeAction.get -> System.Action<T!>? | ||||||
| OpenTelemetry.BatchExportProcessor<T>.InitializeAction.init -> void | ||||||
| OpenTelemetry.Logs.LogEmitter | ||||||
|
||||||
| builder.Services.TryAddSingleton<LogEmitter>(); |
Users will have to find some way to access their OpenTelemetryLoggerProvider to pass to whatever library so that it can construct a LogEmitter. I'll mess with what that might look like.
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.
That's what I was trying to wrap my head around. Would regular users need to be able to do this? What's are the intended use cases for an end user using a LogEmitter?
The kind of use case I'm imagining is one where the user might not need to interact directly with the LogEmitter class and instead is using serilog or something. So, I was thinking the need to get a handle on the LogEmitter would be the responsibility of the serilog extension.
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.
Here is my suggestion:
- Use this PR to focus on the LogRecord improvements (including pooling, ref count, setters) - this would give good perf benefits, and set a cornerstone for LogEmitter or any bridge with Serilog/NLog/EventSource/etc.
- LogEmitter can either be a separate PR or included here, as long as the scope of the change is not too big + is self-contained (e.g. if LogEmitter is need to make meaningful perf tests, probably fine to keep it, but it has to be kept
internal) - Before the spec becomes stable, we can either keep LogEmitter
internal(for our own testing purpose), or making it public AND having it in a separate package (similar to OTLP Log Exporter) - if we know someone who is interested in trying it out.
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.
Sounds good. 👍 to making LogEmitter internal and leaving it where it is in this PR.
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.
-
Let's make it internal and keep where it is. We can figure out where to move it if needed before it goes public?
-
What shall I do with
LogRecordData+LogRecordAttributeList?-
If
LogRecordDatagoes internal, so to willLogRecord.GetDataRef()which gives exporters a way to get at the data more quickly and also gives users a way to mutate everything onLogRecord(which has been requested). -
If
LogRecordAttributeListgoes internal, no real downside withoutLogEmitter. I do have this in there...
if (state is LogRecordAttributeList logRecordAttributes) What that allows you to do is pass
LogRecordAttributeListasTStatetoILogger.Log<TState>and get boxing/allocation-free tags. If it goes internal, users won't be able to easily build upon that perf-path.
-
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.
👍 to LogRecordData/GetDataRef being public since that seems to be the main story regarding perf improvement.
I do not have a strong opinion about whether to make LogRecordAttributeList public at this moment. Maybe just leave it internal for now?
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.
Updated LogRecordAttributeList is now internal. Left LogRecordData & LogRecord.GetDataRef() public for now.
The primary goal of LogRecordData wasn't really performance. Originally I had LogEmitter.Log(LogRecord logRecord) as the API. But that created some problems. It meant user had to interact with the pool correctly. Switching the API to LogEmitter.Log(in LogRecordData) allowed for better encapsulation/safety. I think having struct LogRecordData is providing some perf benefit, but it wasn't the primary driver. There is a comment below specifically about the perf, I'm going to add more detail there.
We could make LogRecordData internal, remove or make LogRecord.GetDataRef internal, and just expose public setters for everything on LogRecord (or not, but I think users want to be able to mutate everything). The only downside to removing GetDataRef is exporters will take a perf hit because most things on LogRecord are now accessed via the struct. Handing back a ref to the struct is just a faster way to get all the data at time of export. It also allows users to mutate everything without also needing public setters on LogRecord.
Outdated
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.
Can LogRecordPool be internal for now too if we're keeping LogEmitter and friends internal?
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.
Could be. Only question is do we want to allow users to configure the pool size? The only thing exposed is currently LogRecordPool.Resize(int size).
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,30 @@ | ||
| #nullable enable | ||
| OpenTelemetry.Batch<T>.Batch(T! item) -> void | ||
| OpenTelemetry.Batch<T>.CleanupAction.get -> System.Action<T!>? | ||
| OpenTelemetry.Batch<T>.CleanupAction.init -> void | ||
| OpenTelemetry.BatchExportProcessor<T>.CleanupAction.get -> System.Action<T!>? | ||
| OpenTelemetry.BatchExportProcessor<T>.CleanupAction.init -> void | ||
| OpenTelemetry.BatchExportProcessor<T>.InitializeAction.get -> System.Action<T!>? | ||
| OpenTelemetry.BatchExportProcessor<T>.InitializeAction.init -> void | ||
| OpenTelemetry.Logs.LogEmitter | ||
| OpenTelemetry.Logs.LogEmitter.Log(OpenTelemetry.Logs.LogRecord! logRecord) -> void | ||
| OpenTelemetry.Logs.LogEmitter.LogEmitter(OpenTelemetry.Logs.OpenTelemetryLoggerProvider! loggerProvider) -> void | ||
| OpenTelemetry.Logs.LogRecord.CategoryName.set -> void | ||
| OpenTelemetry.Logs.LogRecord.EventId.set -> void | ||
| OpenTelemetry.Logs.LogRecord.Exception.set -> void | ||
| OpenTelemetry.Logs.LogRecord.FormattedMessage.set -> void | ||
| OpenTelemetry.Logs.LogRecord.LogLevel.set -> void | ||
| OpenTelemetry.Logs.LogRecord.SetActivityContext(System.Diagnostics.Activity? activity) -> void | ||
| OpenTelemetry.Logs.LogRecord.SpanId.set -> void | ||
| OpenTelemetry.Logs.LogRecord.State.set -> void | ||
| OpenTelemetry.Logs.LogRecord.StateValues.set -> void | ||
| OpenTelemetry.Logs.LogRecord.Timestamp.set -> void | ||
| OpenTelemetry.Logs.LogRecord.TraceFlags.set -> void | ||
| OpenTelemetry.Logs.LogRecord.TraceId.set -> void | ||
| OpenTelemetry.Logs.LogRecord.TraceState.set -> void | ||
| OpenTelemetry.Logs.LogRecordPool | ||
| OpenTelemetry.Logs.OpenTelemetryLoggerProvider.CreateEmitter() -> OpenTelemetry.Logs.LogEmitter! | ||
| static OpenTelemetry.Logs.LogRecordPool.Rent() -> OpenTelemetry.Logs.LogRecord! | ||
| static OpenTelemetry.Logs.LogRecordPool.Resize(int size) -> void | ||
| static OpenTelemetry.Logs.LogRecordPool.Return(OpenTelemetry.Logs.LogRecord! logRecord) -> void | ||
| static OpenTelemetry.Logs.LogRecordPool.TrackReference(OpenTelemetry.Logs.LogRecord! logRecord) -> void |
Uh oh!
There was an error while loading. Please reload this page.