Skip to content
This repository has been archived by the owner on Jul 1, 2022. It is now read-only.

Implement Zipkin 2 JSON Sender #399

Merged
merged 4 commits into from
May 18, 2018

Conversation

keitwb
Copy link
Contributor

@keitwb keitwb commented Apr 17, 2018

The existing ZipkinSender class only supported the Thrift v1 protocol,
but the new Zipkin2Sender supports both v1 and v2 JSON. Otherwise,
functionality is mostly the same.

There is some conceptually duplicate code in the Sender classes due to
the use of different classes between Zipkin 1/2 but it seemed overly
complicated to adapt them to a common adapter interface.

Fixes #383.

@codecov
Copy link

codecov bot commented Apr 17, 2018

Codecov Report

Merging #399 into master will decrease coverage by 0.01%.
The diff coverage is 84.21%.

Impacted file tree graph

@@             Coverage Diff             @@
##             master    #399      +/-   ##
===========================================
- Coverage     82.81%   82.8%   -0.02%     
- Complexity      490     512      +22     
===========================================
  Files            66      69       +3     
  Lines          2019    2105      +86     
  Branches        247     263      +16     
===========================================
+ Hits           1672    1743      +71     
- Misses          265     273       +8     
- Partials         82      89       +7
Impacted Files Coverage Δ Complexity Δ
.../io/jaegertracing/senders/zipkin/ZipkinSender.java 67.74% <ø> (ø) 15 <0> (ø) ⬇️
...gertracing/senders/zipkin/ThriftSpanConverter.java 85.55% <100%> (-0.62%) 21 <0> (-5)
...egertracing/zipkin/reporters/ZipkinV2Reporter.java 71.42% <71.42%> (ø) 2 <2> (?)
...in/java/io/jaegertracing/zipkin/ConverterUtil.java 75% <75%> (ø) 5 <5> (?)
.../java/io/jaegertracing/zipkin/V2SpanConverter.java 84.81% <84.81%> (ø) 20 <20> (?)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 8e237f8...b497c36. Read the comment docs.


public static zipkin2.Span convertSpan(Span span) {
Tracer tracer = span.getTracer();
Endpoint host = zipkin2.Endpoint.newBuilder()
Copy link
Contributor

Choose a reason for hiding this comment

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

To avoid confusion I would remove the import zipkin2.Endpoint and use zipkin2.Endpoint host = ... here.


static boolean isRpc(Span span) {
Object spanKindValue = span.getTags().get(Tags.SPAN_KIND.getKey());
return Tags.SPAN_KIND_CLIENT.equals(spanKindValue) || Tags.SPAN_KIND_SERVER.equals(spanKindValue);
Copy link
Contributor

Choose a reason for hiding this comment

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

I know you're just moving code around here, but this could simply be return isRpcServer(span) || isRpcClient(span). Also clean up the superfluous empty newlines here and at the end of the class.

Tracer tracer = span.getTracer();
Endpoint host = zipkin2.Endpoint.newBuilder()
.ip(convertIp(tracer.getIpv4()))
.port(0)
Copy link
Contributor

Choose a reason for hiding this comment

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

You can probably just omit that. Might be good to add a comment saying that we don't have a local endpoint port to put in at all.

}

private static zipkin2.Span.Kind convertKind(Object kind) {
if (kind == null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

If you reverse your equals calls you don't need that initial null check and have a single location where you return null from this method

}

private static InetAddress convertIp(Integer ip) {
byte[] bytes = ByteBuffer.allocate(4).putInt(ip).array();
Copy link
Contributor

Choose a reason for hiding this comment

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

Can ip be null here? If so, you probably need to handle that. If not, then you can change the method parameter to be the unboxed int

Copy link
Contributor

@mpetazzoni mpetazzoni left a comment

Choose a reason for hiding this comment

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

LGTM, but I'll of course defer to the maintainers here.

@jpkrohling
Copy link
Collaborator

@keitwb, thank you for this PR and sorry for the delay in reviewing it. I've been AFK for most of last week and will be for most of this week again.

Perhaps @pavolloffay would have some time this week to review, otherwise, I'll review it next week.

@pavolloffay
Copy link
Member

Based on #383 (comment) I think it would be better to have an adapter for zipkin reporter. It's more flexible and allows us

  • use any zipkin supported sender: okhttp, urlconnection, kafka...
  • leverage zipkin reporters
  • less code to maintain?

@keitwb
Copy link
Contributor Author

keitwb commented May 2, 2018

@pavolloffay I added an abstract base class for the two Zipkin senders so that there is quite a bit less duplication now. This always allowed using any kind of Zipkin sender (http clients, kafka, etc.), and I don't understand what you mean about a Zipkin reporter adapter.

@keitwb keitwb force-pushed the zipkin2-sender branch from 8724fef to 60b8584 Compare May 2, 2018 21:18
@pavolloffay
Copy link
Member

I mean instead of implementing sender interface e.g. ZipkinSender we could implement ZipkinReporter

class ZipkinReporter implements io.jaegertracing.Reporter {
   private io.zipkin.Reporter delegate;

   public ZipkinReporter(io.zipkin.Reporter reporter) {
     this.delegate = reporter;
   {

   public report(io.jaegertracing.Span jaegerSpan) {
       io.zipkin.Span ipkinSpan  = convertToZipkin(span);
       delegate.report(span);
   }
}

@pavolloffay
Copy link
Member

Something like 431a558.

But note that it deals only with jsonv1 and jsonv2. It should be also possible to add thrift.

One disadvantage is that flush is not supporter, but we could bind to zipkin's AsyncReporter (instead to zipkin.Reporter) which implements flush.

@keitwb
Copy link
Contributor Author

keitwb commented May 7, 2018

@pavolloffay ok, yes I have started reimplementing this using reporters and it seems much cleaner and makes much better reuse of zipkin code instead of reinventing the wheel in this lib. My main question at this point is whether there is anything special about the use of the older com.twitter.zipkin.thriftjava.Span class vs. just converting the jaeger spans to zipkin.Span and using the Thrift encoding from the Zipkin v1 reporter.

@pavolloffay
Copy link
Member

I think those two should be compatible.

@keitwb keitwb force-pushed the zipkin2-sender branch from 60b8584 to 6d72916 Compare May 9, 2018 18:22
@keitwb
Copy link
Contributor Author

keitwb commented May 9, 2018

@pavolloffay ok, I made an initial attempt at reusing Zipkin reporters as much as possible. It is a bit tricky since there are Zipkin 1 and 2 reporters with a different Java interface, but I think I have simplified it as much as possible.

This does break existing users of this lib since it totally removes ZipkinSender from this repo, but I am unsure if that is important or not.

@@ -1,12 +1,16 @@
description = 'Integration library for Zipkin'

dependencies {
compile group: 'io.zipkin.reporter', name: 'zipkin-reporter', version: '1.1.2'
compile group: 'io.zipkin.reporter', name: 'zipkin-sender-urlconnection', version: '1.1.2'
compile group: 'io.zipkin.reporter', name: 'zipkin-reporter', version: '1.0.4'
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 had to downgrade this because of some nasty classpath conflicts between the version of Zipkin that 1.1.2 and 2.6.0 of the reporter were using. Is there some way to pin the version of Zipkin used by dependencies of this module?

Copy link
Member

Choose a reason for hiding this comment

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

Do you know what artifact is causing the problems?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

zipkin-reporter 1.1.2 depends on Zipkin 2.2.1 and zipkin-reporter 2.6.0 depends on Zipkin 2.8.1. Between those two versions of Zipkin, an overloaded version of listSizeInBytes was added that takes an int in zipkin2.codec.Encoding. If I try and use the OkHttpSender from zipkin-reporter 2.6.0, I get the following exception:

java.lang.NoSuchMethodError: zipkin2.codec.Encoding.listSizeInBytes(I)I
        at zipkin2.reporter.okhttp3.OkHttpSender.messageSizeInBytes(OkHttpSender.java:211)
        at zipkin2.reporter.AsyncReporter$BoundedAsyncReporter.report(AsyncReporter.java:232)
        at io.jaegertracing.senders.zipkin.ZipkinReporter.report(ZipkinReporter.java:36)
        at io.jaegertracing.Tracer.reportSpan(Tracer.java:160)
        at io.jaegertracing.Span.finishWithDuration(Span.java:183)
        at io.jaegertracing.Span.finish(Span.java:160)

Because it is trying to use the new int overloaded method but zipkin 2.2.1 is getting chosen on the classpath instead of 2.8.1.

Do you know any simple way to make it always use the newer version of Zipkin?

Copy link
Member

Choose a reason for hiding this comment

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

What If you exclude the old zipkin(2.2.1) from reporter 1.1.2?

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'll see if it is still an issue after I revert the ZipkinSender and only implement the V2 Reporter.

endLabel = zipkin.Constants.CLIENT_RECV;
}

builder.addAnnotation(span.getStart(), startLabel);
Copy link
Contributor Author

@keitwb keitwb May 10, 2018

Choose a reason for hiding this comment

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

Are these special annotations necessary in v2 Zipkin?

Copy link
Member

Choose a reason for hiding this comment

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

I don't think so

cs time - is kind=client and start time
cr time - is kind=client starttime+duration

the same for server side, but the kind is server

@keitwb
Copy link
Contributor Author

keitwb commented May 14, 2018

@pavolloffay How does it look now?

@pavolloffay
Copy link
Member

I think it's better to keep the zipkin sender and just deprecate it.

Copy link
Member

@pavolloffay pavolloffay left a comment

Choose a reason for hiding this comment

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

I have checked the convertor it looks good.

Could you please revert the old sender back? Do not deprecate it and just introduce ZipkinV2Reporter?In the appropriate package e.g. io.jaegertracing.zipkin (for convertor) and io.jaegertracing.zipkin.reporters for reporter?

In the next PR we could introduce ZipkinV1Reporter and deprecate the sender to keep the changes small and clean.

compile project(path: ':jaeger-core', configuration: 'shadow')

testCompile group: 'io.zipkin.reporter', name: 'zipkin-sender-urlconnection', version: '1.0.4'
testCompile group: 'io.zipkin.reporter2', name: 'zipkin-sender-urlconnection', version: '2.6.0'
Copy link
Member

Choose a reason for hiding this comment

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

Is this needed? If not do not include it

@Before
public void setUp() {
tracer =
new Tracer.Builder("test-service-name", new InMemoryReporter(), new ConstSampler(true))
Copy link
Member

Choose a reason for hiding this comment

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

please do not use deprecated APIs

@keitwb
Copy link
Contributor Author

keitwb commented May 15, 2018

@pavolloffay ok, I reverted the original ZipkinSender and rearranged things a bit. I think I figured out how to exclude Zipkin 2.2.1 from polluting the classpath. Let me know what you think.

@pavolloffay
Copy link
Member

pavolloffay commented May 16, 2018

@keitwb could you please keep ThriftSpanConverter in the old package? Just keep the changes minimal

and ThriftSpanConverterTest.java too

import zipkin2.reporter.AsyncReporter;
import zipkin2.reporter.urlconnection.URLConnectionSender;

reporter = new Zipkin2Reporter(
Copy link
Member

Choose a reason for hiding this comment

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

nit: could you please just rename it to ZipkinV2Reporter?

endLabel = zipkin.Constants.CLIENT_RECV;
}

builder.addAnnotation(span.getStart(), startLabel);
Copy link
Member

Choose a reason for hiding this comment

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

From the previous review: these are not needed in V2

@pavolloffay
Copy link
Member

@keitwb the PR looks good, I had just a couple of minor comments.

This adds a new class called Zipkin2Reporter that adapts a Zipkin v2
reporter and converts Jaeger spans to Zipkin v2 spans.  This enables us
to send spans to a Zipkin v2 server using the newer protocol.

This also moves the existing Thrift conversion logic to a new package
`io.jaegertracing.zipkin` where it exists alongside the new v2
conversion logic.

Signed-off-by: Ben Keith <bkeith@signalfx.com>
componentName = span.getTracer().getServiceName();
}

builder.putTag(zipkin.Constants.LOCAL_COMPONENT, componentName);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

What about this one? In Zipkin v2 spans, the local endpoint field contains the service name so this seems redundant to add this special tag.

I'm going to remove it for now but let me know if you think it should remain.

@keitwb
Copy link
Contributor Author

keitwb commented May 16, 2018

@pavolloffay ok, I moved the Thrift converter back to its original location and rebased. Also, I removed some logic for the local component special tag since it was in the local endpoint object already (see comment). I put the new stuff as a separate commit so you can see it clearly. Thanks!

@pavolloffay
Copy link
Member

@keitwb travis is failing

@keitwb
Copy link
Contributor Author

keitwb commented May 16, 2018

There is some race between the zipkin reporter finishing a span and reporting it when the close method is called on the reporter. Let me see what I can do to prevent it.

Also removing Zipkin v1 special tag handling from V2SpanConverter
because they are not necessary

Signed-off-by: Ben Keith <bkeith@signalfx.com>
@keitwb
Copy link
Contributor Author

keitwb commented May 16, 2018

Ok, I did the same thing the Zipkin reporter tests do and it seemed to fix it.

@pavolloffay
Copy link
Member

@keitwb great work! Thanks for the PR

I will wait for 24h in case anybody else wants to review

Copy link
Collaborator

@jpkrohling jpkrohling left a comment

Choose a reason for hiding this comment

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

I trust that @pavolloffay checked the Zipkin semantics already, so, I had only a couple of comments, all optional.

exclude group:'io.zipkin.java'
}
compile(group: 'io.zipkin.reporter', name: 'zipkin-sender-urlconnection', version: '1.1.2') {
exclude group:'io.zipkin.zipkin2'
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this needed, if you are declaring it as a direct dependency of your project?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Tested it, and you are right, it doesn't appear to be necessary due to the explicit dependency.

} else if (Tags.SPAN_KIND_PRODUCER.equals(kind)) {
return zipkin2.Span.Kind.PRODUCER;
} else {
return null;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this an expected case? If not, a log statement should be produced, like, "Could not identify the span kind during conversion. Skipping."

Copy link
Member

Choose a reason for hiding this comment

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

IIRC internal spans has a null kind.

Copy link
Member

Choose a reason for hiding this comment

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

yes they have kind set to null

try {
return InetAddress.getByAddress(bytes);
} catch (UnknownHostException e) {
return null;
Copy link
Collaborator

Choose a reason for hiding this comment

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

IIRC, this should never happen but would be worth adding a log statement here.

Tracer tracer;

@Before
public void setUp() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

s/setUp/setup

Ben Keith and others added 2 commits May 17, 2018 09:39
@ghost ghost assigned pavolloffay May 18, 2018
@ghost ghost added the review label May 18, 2018
@pavolloffay
Copy link
Member

I am just linking a similar PR in go jaegertracing/jaeger-client-go#310. I have updated the branch and I will merge on green

@pavolloffay pavolloffay merged commit 07df0b8 into jaegertracing:master May 18, 2018
@ghost ghost removed the review label May 18, 2018
@keitwb keitwb deleted the zipkin2-sender branch May 18, 2018 17:16
rmfitzpatrick pushed a commit to rmfitzpatrick/jaeger-client-python that referenced this pull request Jul 6, 2018
Expands span reporter selection by breaking out Reporter into base
QueueReporter class and using reporting method-specific ThriftReporter
and ZipkinV2Reporter.  Also breaks LocalAgentSender into two classes
including LocalAgentReader for ThriftReporter only usage of
TBufferedTransport.

These changes allow users to continue reporting spans oob to the local
jaeger-agent but with the option of reporting to Zipkin backend.

In the spirit of
jaegertracing/jaeger-client-java#399
and
jaegertracing/jaeger-client-go#310

Signed-off-by: Ryan Fitzpatrick <rmfitzpatrick@signalfx.com>
rmfitzpatrick pushed a commit to rmfitzpatrick/jaeger-client-python that referenced this pull request Jul 6, 2018
Expands span reporter selection by breaking out Reporter into base
QueueReporter class and using reporting method-specific ThriftReporter
and ZipkinV2Reporter.  Also breaks LocalAgentSender into two classes
including LocalAgentReader for ThriftReporter only usage of
TBufferedTransport.

These changes allow users to continue reporting spans oob to the local
jaeger-agent but with the option of reporting to Zipkin backend.

In the spirit of
jaegertracing/jaeger-client-java#399
and
jaegertracing/jaeger-client-go#310

Signed-off-by: Ryan Fitzpatrick <rmfitzpatrick@signalfx.com>
rmfitzpatrick pushed a commit to rmfitzpatrick/jaeger-client-python that referenced this pull request Jul 6, 2018
Expands span reporter selection by breaking out Reporter into base
QueueReporter class and using reporting method-specific ThriftReporter
and ZipkinV2Reporter.  Also breaks LocalAgentSender into two classes
including LocalAgentReader for ThriftReporter only usage of
TBufferedTransport.

These changes allow users to continue reporting spans oob to the local
jaeger-agent but with the option of reporting to Zipkin backend.

In the spirit of
jaegertracing/jaeger-client-java#399
and
jaegertracing/jaeger-client-go#310

Signed-off-by: Ryan Fitzpatrick <rmfitzpatrick@signalfx.com>
rmfitzpatrick pushed a commit to rmfitzpatrick/jaeger-client-python that referenced this pull request Jul 6, 2018
Expands span reporter selection by breaking out Reporter into base
QueueReporter class and using reporting method-specific ThriftReporter
and ZipkinV2Reporter.  Also breaks LocalAgentSender into two classes
including LocalAgentReader for ThriftReporter only usage of
TBufferedTransport.

These changes allow users to continue reporting spans oob to the local
jaeger-agent but with the option of reporting to Zipkin backend.

In the spirit of
jaegertracing/jaeger-client-java#399
and
jaegertracing/jaeger-client-go#310

Signed-off-by: Ryan Fitzpatrick <rmfitzpatrick@signalfx.com>
rmfitzpatrick pushed a commit to rmfitzpatrick/jaeger-client-python that referenced this pull request Jul 6, 2018
Expands span reporter selection by breaking out Reporter into base
QueueReporter class and using reporting method-specific ThriftReporter
and ZipkinV2Reporter.  Also breaks LocalAgentSender into two classes
including LocalAgentReader for ThriftReporter only usage of
TBufferedTransport.

These changes allow users to continue reporting spans oob to the local
jaeger-agent but with the option of reporting to Zipkin backend.

In the spirit of
jaegertracing/jaeger-client-java#399
and
jaegertracing/jaeger-client-go#310

Signed-off-by: Ryan Fitzpatrick <rmfitzpatrick@signalfx.com>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants