-
Notifications
You must be signed in to change notification settings - Fork 772
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
Add ActivityEventAttachingLogProcessor to build ActivityEvents from logs #1833
Add ActivityEventAttachingLogProcessor to build ActivityEvents from logs #1833
Conversation
Wanted to get feedback before starting on tests. |
} | ||
|
||
public ILogger CreateLogger(string categoryName) | ||
{ | ||
lock (this.loggers) | ||
if (!this.loggers.TryGetValue(categoryName, out var logger)) |
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.
Curious - Is this thread safe (e.g. would it be possible to break the internal state of Dictionary if other threads are trying to write to it)? https://stackoverflow.com/questions/6738634/is-this-non-locked-trygetvalue-dictionary-access-thread-safe
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.
Thanks for the tip! Sadly I have this pattern in a bunch of places I now need to go fix up 😭 I updated the code to use a ConcurrentDictionary
instead. Check it out, LMK if it looks better now. I think it's worth avoiding the lock here because a lot of threads could all be asking for ILogger
s/writing messages at the same time?
|
||
namespace OpenTelemetry.Logs | ||
{ | ||
internal class ActivityEventAttachingLogProcessor : BaseProcessor<LogRecord> |
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 struggling with this name, meanwhile I don't have a good proposal...
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.
Ya I know it's a mouthful. Open to suggestions.
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.
open-telemetry/opentelemetry-specification#1461
This PR suggests that span events are conceptually the same as logs.
I guess we could consider something like this?
TracerProvider.LogRecordToActivityEventProcessor()
(inherited from LogProcessor): ConvertsLogRecord
toActivityEvent
, and usesActivity.AddEvent
to attach it to the current Activity. If there there is no "current activity", this processor will simply ignore the log record.LoggerProvider.ActivityEventToLogRecordProcessor(logger)
(inherited from ActivityProcessor): Converts theActivityEvents
objects to LogRecords.
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.
LGTM once we've confirmed the thread-safety in the double-lock dictionary code https://github.com/open-telemetry/opentelemetry-dotnet/pull/1833/files#r577044684.
One design question that we might need to consider - there might be a scenario where the user wants to convert Activity events to logs (e.g. underlying distributed tracing system does not support Activity event). We might need to avoid the infinite loop if folks misconfigured the SDK to convert logs to activity events AND activity events to logs. Since there will be requirements to convert logs to traces, traces to logs, logs to metrics and metrics to logs, we might need to plan ahead-of-time:
|
Codecov Report
@@ Coverage Diff @@
## main #1833 +/- ##
==========================================
- Coverage 83.77% 81.79% -1.99%
==========================================
Files 187 190 +3
Lines 5967 6213 +246
==========================================
+ Hits 4999 5082 +83
- Misses 968 1131 +163
|
This is all good stuff I have been thinking about and don't have an immediate answer to/for! I am setting the |
|
||
if (this.loggers.TryGetValue(categoryName, out logger)) | ||
if (this.loggers.TryAdd(categoryName, logger)) |
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.
Do we know if this.loggers.TryGetValue(categoryName, out var logger)
will always succeed when TryAdd
failed?
If yes, the code can be simplified by returning this.loggers[categoryName]
(and avoid the while-loop).
If no, perhaps store the logger locally to avoid creating multiple instances in the loop?
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.
@reyang I updated it (again) to use Hashtable
. @mconnew just pointed out to me that Hashtable
has unique thread safety gurantees which make it useful for caching scenarios.
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.
Looks great! 💯
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.
LGTM.
…h/opentelemetry-dotnet into logs-to-activityevents
Fixes #1739
Fixes #1834
Changes
LogRecord
ActivityEventAttachingLogProcessor
which will convertLogRecord
objects intoActivityEvent
objects on theActivity.Current
instance.Considerations + Design
I wanted to allow users to push details from their
ILogger
structured logging into their traces but parsing state & scope(s) is an expensive operation. There are also many ways to approach it.Public API
Took inspiration from iSeiryu@c132085 & OpenTracing.Contrib.NetCore.
Examples
Example code:
No state, no scope, no message:
Message, no state, no scope:
State, no scopes, no message:
State + scopes, no message:
TODOs
CHANGELOG.md
updated for non-trivial changes