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

Include net.peer.port in ZipkinSpan.RemoteEndpoint.ServiceName #1168

Merged

Conversation

alanwest
Copy link
Member

Fixes #968.

@CodeBlanch I'm particularly interested in your review of this since I think you've worked in the space more than most. I'm not terribly excited about how things turned out, but at least should provide a starting place for discussion.

Once we settle on this PR, I will follow up with a similar PR for Jaeger.

Changes

If net.peer.name or net.peer.ip attribute is present then net.peer.port should be included (if present) when setting the remote service endpoint for a Zipkin span.

For significant contributions please make sure you have completed the following items:

  • CHANGELOG.md updated for non-trivial changes
  • Design discussion issue #
  • Changes in public API reviewed

@alanwest alanwest requested a review from a team August 26, 2020 01:07
@codecov
Copy link

codecov bot commented Aug 26, 2020

Codecov Report

Merging #1168 into master will increase coverage by 0.02%.
The diff coverage is 95.83%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1168      +/-   ##
==========================================
+ Coverage   77.44%   77.46%   +0.02%     
==========================================
  Files         219      219              
  Lines        6255     6270      +15     
==========================================
+ Hits         4844     4857      +13     
- Misses       1411     1413       +2     
Impacted Files Coverage Δ
...plementation/ZipkinActivityConversionExtensions.cs 91.17% <95.00%> (-0.04%) ⬇️
...y.Exporter.Zipkin/Implementation/ZipkinEndpoint.cs 81.08% <100.00%> (-0.74%) ⬇️
....Prometheus/PrometheusExporterMetricsHttpServer.cs 74.50% <0.00%> (-1.97%) ⬇️
...emetry.Api/Internal/OpenTelemetryApiEventSource.cs 64.70% <0.00%> (+2.94%) ⬆️

@@ -177,6 +177,7 @@ public void ZipkinExporterIntegrationTest(bool useShortTraceIds)
internal static Activity CreateTestActivity(
bool setAttributes = true,
Dictionary<string, object> additionalAttributes = null,
bool convertAttributeValuesToString = true,
Copy link
Member Author

@alanwest alanwest Aug 26, 2020

Choose a reason for hiding this comment

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

I introduced this to enable testing the code path in ProcessTags that handles things when net.peer.port is an integer. Meh? Better ideas?

The net452 compilation uses Newtonsoft.Json and other compilations use the newer System.Text.Json.

My understanding is that this helper method does a ToString on all attribute values to eliminate any serialization differences between net452 and other target compilations. That is, there are some tests (not touched by this PR) that depend on the result of serialization being the same. Namely here:

Assert.Equal(
$@"[{{""traceId"":""{traceId}"",""name"":""Name"",""parentId"":""{ZipkinActivityConversionExtensions.EncodeSpanId(activity.ParentSpanId)}"",""id"":""{ZipkinActivityConversionExtensions.EncodeSpanId(context.SpanId)}"",""kind"":""CLIENT"",""timestamp"":{timestamp},""duration"":60000000,""localEndpoint"":{{""serviceName"":""OpenTelemetry Exporter""{ipInformation}}},""annotations"":[{{""timestamp"":{eventTimestamp},""value"":""Event1""}},{{""timestamp"":{eventTimestamp},""value"":""Event2""}}],""tags"":{{""stringKey"":""value"",""longKey"":""1"",""longKey2"":""1"",""doubleKey"":""1"",""doubleKey2"":""1"",""boolKey"":""True"",""library.name"":""CreateTestActivity""}}}}]",
Responses[requestId]);

Should we be at all concerned that these two compilations result in serializing the Zipkin payload differently?

Copy link
Member

Choose a reason for hiding this comment

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

@alanwest Are you saying if you put an int port into attributes, Zipkin sends it as an int? If yes, that might be a bug in the exporter. I think in Zipkin spec everything is sent as strings. /cc @eddynaka

Copy link
Member Author

@alanwest alanwest Aug 26, 2020

Choose a reason for hiding this comment

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

Zipkin will send numeric attribute values for the net452 compilation that uses Newtonsoft.Json. If you remove the ToString() from here and run the Zipkin tests, you'll see what I mean:

? attributes.Select(kvp => new KeyValuePair<string, object>(kvp.Key, kvp.Value.ToString()))

So I think this ToString is masking the bug because it means that the Activity created from this helper method will only ever have string attributes, so I don't think we are testing the serialization of the Zipkin payload when an Activity has non-string attributes.

I simply needed to be able to test the code path I put in place that does special handling of the net.peer.port attribute when it is an int, and by removing the ToString() it seems I uncovered the bug.

If the Zipkin spec states that everything should be sent as strings then I think we should remove this ToString and fix the bug. If we do that, then the convertAttributeValuesToString parameter I've introduced here would be unneeded.

Copy link
Contributor

Choose a reason for hiding this comment

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

@alanwest, I think we should change to bet 452 as well. When I changed the others to output as string I didn't look at net452. Let me know if u will change or I can open another pr

Copy link
Member Author

Choose a reason for hiding this comment

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

@eddynaka if you're interested in doing that PR, that would be super. I think what I will do for now is revert the changes to this helper method, but I think that if you land a fix for 452 then this ToString() should be able to be removed.

Copy link
Contributor

Choose a reason for hiding this comment

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

just opened a pr solving this!

if ((attributeEnumerationState.RemoteEndpointServiceName == null || attributeEnumerationState.RemoteEndpointServiceNamePriority > 0)
&& hostNameOrIpAddress != null)
{
var remoteEndpointStr = attributeEnumerationState.Port != default
Copy link
Member

Choose a reason for hiding this comment

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

@alanwest It would be great if we didn't need this string allocation. Check out #1153. It's using ValueTuple for the dictionary key. If we made the key ValueTuple<string, int?> we might be able to avoid it?

Copy link
Member Author

Choose a reason for hiding this comment

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

@CodeBlanch I'm not opposed to using a caching mechanism here to avoid string allocations, but I want to be sure to avoid any risk of unbounded memory growth of the cache. I could make a cache local to an individual export operation, but that might limit any perf gain.

It's not immediately apparent to me if the StackExchangeRedisCallsInstrumentation avoids unbounded memory growth. What, if anything, ever clears items from the cache?

Copy link
Member

Choose a reason for hiding this comment

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

@alanwest The one in Redis should only be caching live traces/spans. They should remove as they complete. This cache here, will grow unbounded. It is cheating/assuming that the user will only ever connect to a reasonable set of remote services. That assumption may or may not be accurate, and we might want to add some expiration? But moving from a string key to a ValueTuple doesn't really change that 😄

Copy link
Member Author

@alanwest alanwest Aug 26, 2020

Choose a reason for hiding this comment

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

The one in Redis should only be caching live traces/spans. They should remove as they complete.

Hmm... not seeing where this happens - I'm not very familiar with the Redis instrumentation. Though, I will parking-lot this concern since it's not related to this PR.

It is cheating/assuming that the user will only ever connect to a reasonable set of remote services.

I think it's safer to not make this assumption. I think it is often the case that the set remote services is of a reasonable size, but I've seen numerous instances in customers applications where this set can be very large. This can be common in mutli-tenant architectures where number of hostnames can be large and hostname is used to route to a specific tenant. I think it might make sense to come back to the thought of a cache expiration in a separate issue.

But moving from a string key to a ValueTuple doesn't really change that

Agreed, I've made this change since it seems like a solid approach. Note that the net452 build still uses a string as a key. Could have made this a regular Tuple, but I figured trading a string allocation for a Tuple allocation for net452 didn't make a lot of sense.

Copy link
Member

@CodeBlanch CodeBlanch left a comment

Choose a reason for hiding this comment

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

LGTM! It's a bit complicated, but that is more because of the allocation free foreach stuff which really put you in a corner. Sorry about that 😅

@cijothomas cijothomas merged commit 4915d74 into open-telemetry:master Aug 27, 2020
@alanwest alanwest deleted the alanwest/zipkin-remoteendpoint-port branch August 27, 2020 18:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

gRPC: When exported to Zipkin, server address doesn't include port
4 participants