-
Notifications
You must be signed in to change notification settings - Fork 893
Extend ConsoleExporter to add support for Logs #1438
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 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -17,42 +17,28 @@ | |||
| using System; | ||||
| using System.Diagnostics; | ||||
| using System.Linq; | ||||
| using System.Text.Json; | ||||
| using System.Text.Json.Serialization; | ||||
| #if NET461 || NETSTANDARD2_0 | ||||
| using OpenTelemetry.Logs; | ||||
| #endif | ||||
| using OpenTelemetry.Resources; | ||||
| using OpenTelemetry.Trace; | ||||
|
|
||||
| namespace OpenTelemetry.Exporter | ||||
| { | ||||
| public class ConsoleExporter : BaseExporter<Activity> | ||||
| public class ConsoleExporter<T> : BaseExporter<T> | ||||
| where T : class | ||||
| { | ||||
| private readonly JsonSerializerOptions serializerOptions; | ||||
| private readonly bool displayAsJson; | ||||
|
|
||||
| public ConsoleExporter(ConsoleExporterOptions options) | ||||
| { | ||||
| this.serializerOptions = new JsonSerializerOptions() | ||||
| { | ||||
| WriteIndented = true, | ||||
| }; | ||||
|
|
||||
| this.displayAsJson = options?.DisplayAsJson ?? false; | ||||
|
|
||||
| this.serializerOptions.Converters.Add(new JsonStringEnumConverter()); | ||||
| this.serializerOptions.Converters.Add(new ActivitySpanIdConverter()); | ||||
| this.serializerOptions.Converters.Add(new ActivityTraceIdConverter()); | ||||
| } | ||||
|
|
||||
| public override ExportResult Export(in Batch<Activity> batch) | ||||
| public override ExportResult Export(in Batch<T> batch) | ||||
| { | ||||
| foreach (var activity in batch) | ||||
| if (typeof(T) == typeof(Activity)) | ||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: Would prob be more efficient to check the type in ctor and then set a field instead of checking every batch. |
||||
| { | ||||
| if (this.displayAsJson) | ||||
| { | ||||
| Console.WriteLine(JsonSerializer.Serialize(activity, this.serializerOptions)); | ||||
| } | ||||
| else | ||||
| foreach (var item in batch) | ||||
| { | ||||
| var activity = item as Activity; | ||||
| Console.WriteLine($"Activity.Id: {activity.Id}"); | ||||
| if (!string.IsNullOrEmpty(activity.ParentId)) | ||||
| { | ||||
|
|
@@ -123,6 +109,30 @@ public override ExportResult Export(in Batch<Activity> batch) | |||
| Console.WriteLine(); | ||||
| } | ||||
| } | ||||
| #if NET461 || NETSTANDARD2_0 | ||||
| else if (typeof(T) == typeof(LogRecord)) | ||||
| { | ||||
| var rightPaddingLength = 30; | ||||
| foreach (var item in batch) | ||||
| { | ||||
| var logRecord = item as LogRecord; | ||||
| Console.WriteLine($"{"LogRecord.TraceId:".PadRight(rightPaddingLength)}{logRecord.TraceId}"); | ||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: the output is a bit different from the Activity one (e.g. here we have the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's LogRecord.propertyName right now, what you suggest it be? Should we use "Activity" instead of "LogRecord"?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would you help to update the example to use the console exporter?
We can use it to drive the output format discussion. |
||||
| Console.WriteLine($"{"LogRecord.SpanId:".PadRight(rightPaddingLength)}{logRecord.SpanId}"); | ||||
| Console.WriteLine($"{"LogRecord.Timestamp:".PadRight(rightPaddingLength)}{logRecord.Timestamp:yyyy-MM-ddTHH:mm:ss.fffffffZ}"); | ||||
| Console.WriteLine($"{"LogRecord.EventId:".PadRight(rightPaddingLength)}{logRecord.EventId}"); | ||||
| Console.WriteLine($"{"LogRecord.CategoryName:".PadRight(rightPaddingLength)}{logRecord.CategoryName}"); | ||||
| Console.WriteLine($"{"LogRecord.LogLevel:".PadRight(rightPaddingLength)}{logRecord.LogLevel}"); | ||||
| Console.WriteLine($"{"LogRecord.TraceFlags:".PadRight(rightPaddingLength)}{logRecord.TraceFlags}"); | ||||
| Console.WriteLine($"{"LogRecord.State:".PadRight(rightPaddingLength)}{logRecord.State}"); | ||||
| if (logRecord.Exception is { }) | ||||
| { | ||||
| Console.WriteLine($"{"LogRecord.Exception:".PadRight(rightPaddingLength)}{logRecord.Exception?.Message}"); | ||||
| } | ||||
|
|
||||
| Console.WriteLine(); | ||||
| } | ||||
| } | ||||
| #endif | ||||
|
|
||||
| return ExportResult.Success; | ||||
| } | ||||
|
|
||||
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.
So now I can do ConsoleExporter<some_custom_type> and it will emit nothing? I don't see a lot of value in having the generic, TBH. Why don't we just have
ConsoleLogExporter : BaseExporter<LogRecord>&ConsoleActivityExporter : BaseExporter<Activity>? There's really not that much code being duplicated.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.
OR how about something 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.
I don't think you can add an Exporter of a type anything other than Activity or LogRecord. To add an exporter for traces, you have to use the TracerProviderBuilder AddProcessor(BaseProcessor processor) method of TracerProviderBuilder class. Here, both SimpleExportProcessor and BatchExportProcessor will enforce you to only use Activity as the type.
Similarly, to add an exporter to Logs, you have to use the extension method OpenTelemetryLoggerOptions AddProcessor(BaseProcessor processor). Here, both SimpleExportProcessor and BatchExportProcessor will enforce you to only use LogRecord as the type.
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 a good point. I still feel like it is misusing generics and we could improve it though. If it was internal, no prob, but it is part of the public API so we'll have to live with it forever.
@cijothomas @reyang Any thoughts?
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.
No strong opinion from my side.
I agree that having a switch-case (or if-else) in generic method (e.g. if T is
Activitydo this, if T isLogRecorddo that) is not very idiomatic / performant.