Skip to content
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

[Exporter.Geneva] Add TLDTraceExporter #662

Merged
merged 18 commits into from
Jan 11, 2023

Conversation

utpilla
Copy link
Contributor

@utpilla utpilla commented Sep 27, 2022

Changes

  • Add TLDTraceExporter
  • GenevaTraceExporter to use TLDExporter when the user provides "PrivatePreviewEnableTraceLoggingDynamic=true" in the connectionString

TODOs:

  • Use a single ThreadLocal instead of multiple
  • Avoid potential unbounded memory usage for List<KeyValuePair<string, object>> keyValuePairs

Setup and usage:

using var tracerProvider = Sdk.CreateTracerProviderBuilder()
            .SetSampler(new AlwaysOnSampler())
            .AddSource(Source.Name)
            .AddGenevaTraceExporter(options =>
            {
                options.ConnectionString = "EtwSession=OpenTelemetry;PrivatePreviewEnableTraceLoggingDynamic=true";// Add PrivatePreviewEnableTraceLoggingDynamic=true in the connection string
                options.PrepopulatedFields = new Dictionary<string, object>
                {
                    ["cloud.role"] = "BusyWorker",
                    ["cloud.roleInstance"] = "CY1SCH030021417",
                    ["cloud.roleVer"] = "9.0.15289.2",
                };
            })
            .Build();

//Emit activity
using (var activity = Source.StartActivity("SayHello"))
        {
            activity?.SetTag("foo", 1);
            activity?.SetTag("bar", "Hello, World!");
            activity?.SetTag("baz", new int[] { 1, 2, 3 });
            activity?.SetStatus(ActivityStatusCode.Ok);
        }

You could us any ETW collection tools such as WPA, PerfView etc. to view the data:

Example with PerfView:
For the connectionString = "EtwSession=OpenTelemetry;PrivatePreviewEnableTraceLoggingDynamic=true", you can run the following command in Command Prompt:

PerfView.exe collect -MaxCollectSec:3600 -NoGui /onlyProviders=*OpenTelemetry

@utpilla utpilla requested a review from a team September 27, 2022 02:46
@utpilla utpilla added the comp:exporter.geneva Things related to OpenTelemetry.Exporter.Geneva label Sep 27, 2022
@codecov
Copy link

codecov bot commented Sep 27, 2022

Codecov Report

Merging #662 (4d7e856) into main (70f9f0f) will decrease coverage by 8.29%.
The diff coverage is 29.17%.

❗ Current head 4d7e856 differs from pull request most recent head a4168b7. Consider uploading reports for the commit a4168b7 to get more accurate results

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #662      +/-   ##
==========================================
- Coverage   79.07%   70.77%   -8.30%     
==========================================
  Files         182      187       +5     
  Lines        5614     6724    +1110     
==========================================
+ Hits         4439     4759     +320     
- Misses       1175     1965     +790     
Impacted Files Coverage Δ
...orter.Geneva/TLDExporter/UncheckedASCIIEncoding.cs 15.68% <15.68%> (ø)
...ry.Exporter.Geneva/External/TraceLoggingDynamic.cs 22.46% <22.46%> (ø)
...lemetry.Exporter.Geneva/TLDExporter/TLDExporter.cs 27.84% <27.84%> (ø)
...ry.Exporter.Geneva/TLDExporter/TLDTraceExporter.cs 32.51% <32.51%> (ø)
...xporter.Geneva/Internal/ConnectionStringBuilder.cs 93.58% <60.00%> (-2.31%) ⬇️
...etry.Exporter.Geneva/TLDExporter/JsonSerializer.cs 61.26% <61.26%> (ø)
...enTelemetry.Exporter.Geneva/GenevaTraceExporter.cs 75.00% <75.00%> (-5.00%) ⬇️
...ter.Geneva/MsgPackExporter/MsgPackTraceExporter.cs 92.42% <0.00%> (-0.51%) ⬇️

private readonly EventProvider eventProvider;
private static readonly ThreadLocal<EventBuilder> eventBuilder = new(() => new(UncheckedASCIIEncoding.SharedInstance));
private static readonly ThreadLocal<List<KeyValuePair<string, object>>> keyValuePairs = new(() => new());
private static readonly ThreadLocal<KeyValuePair<string, object>[]> partCFields = new(() => new KeyValuePair<string, object>[120]); // This is used to temporarily store the PartC fields from tags
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might lead to IndexOutOfRange exceptions if there are too many Part C tags. I chose the size as 120 as we cannot exceed 127 fields otherwise the event gets dropped and we have at least around 7 fields from Part A and Part B itself.


private readonly EventProvider eventProvider;
private static readonly ThreadLocal<EventBuilder> eventBuilder = new(() => new(UncheckedASCIIEncoding.SharedInstance));
private static readonly ThreadLocal<List<KeyValuePair<string, object>>> keyValuePairs = new(() => new());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is used for serializing ActivityLinks and env_properties. I chose a List here instead of an array as we don't know how many such fields there could be.

Copy link
Member

@reyang reyang Sep 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the initial capacity? (and what's the reallocation behavior? e.g. would this give OOM?)

Copy link
Contributor Author

@utpilla utpilla Sep 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the initial capacity?

I let it use the default behavior.

(and what's the reallocation behavior? e.g. would this give OOM?)

I understand that this might lead to unbounded memory usage and possibly even lead to OOM in extreme cases but I didn't know if we could enforce some sort of limitation on the number of links or env_properties allowed. It's straightforward for PartC fields as the TLD spec enforces a limit on the number of fields allowed. In this case though, links or env_properties would only count towards one field.

Could we enforce such a limitation? If yes, we could very well use an array and just tell the user that they have too many links or env_properties if they exceed a certain number. If not, I guess we would have to go back to the two iterations approach.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a TODO for this.

#pragma warning disable CA5350
#pragma warning disable CA5392

internal sealed class EventProvider
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have simply copied the contents of this file here: https://github.com/microsoft/tracelogging/blob/main/etw/cs/traceloggingdynamic/TraceLoggingDynamic.cs

Only additional changes that I made are that I have marked the types internal and internal sealed.

private static readonly string INVALID_SPAN_ID = default(ActivitySpanId).ToHexString();

private readonly EventProvider eventProvider;
private static readonly ThreadLocal<EventBuilder> eventBuilder = new(() => new(UncheckedASCIIEncoding.SharedInstance));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which one would be better?

  1. Having 3 ThreadLocals
  2. Having a single ThreadLocal which points to a complex struct/object with 3 fields

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no strong preference. I suppose there's no performance implications of using one over the other. If the second approach looks more readable, I could make that change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a TODO for this.

@github-actions
Copy link
Contributor

github-actions bot commented Oct 5, 2022

This PR was marked stale due to lack of activity. It will be closed in 7 days.

@github-actions github-actions bot added the Stale label Oct 5, 2022
@utpilla utpilla removed the Stale label Oct 10, 2022
@github-actions
Copy link
Contributor

This PR was marked stale due to lack of activity. It will be closed in 7 days.

@github-actions github-actions bot added the Stale label Oct 18, 2022
@reyang reyang removed the Stale label Oct 19, 2022
@github-actions
Copy link
Contributor

This PR was marked stale due to lack of activity. It will be closed in 7 days.

@github-actions github-actions bot added the Stale label Oct 28, 2022
@github-actions
Copy link
Contributor

github-actions bot commented Nov 5, 2022

Closed as inactive. Feel free to reopen if this PR is still being worked on.

@github-actions github-actions bot closed this Nov 5, 2022
@utpilla utpilla reopened this Jan 7, 2023
@utpilla utpilla removed the Stale label Jan 7, 2023
@utpilla utpilla merged commit cea38d3 into open-telemetry:main Jan 11, 2023
mmanciop pushed a commit to lumigo-io/opentelemetry-dotnet-contrib that referenced this pull request Jan 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
comp:exporter.geneva Things related to OpenTelemetry.Exporter.Geneva
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants