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

Adding Zipkin exporter #320

Merged
merged 12 commits into from
Dec 30, 2019
Merged

Conversation

codeboten
Copy link
Contributor

Fixes #318

Pulled some of the code from the OC implementation and looked at the javascript implementation

Not addressed yet:

  • what do to on failures beyond returning NOT_RETRYABLE

Zipkin Spec:
https://github.com/openzipkin/zipkin-api/blob/master/zipkin2-api.yaml

Signed-off-by: Alex Boten aboten@lightstep.com

Signed-off-by: Alex Boten <aboten@lightstep.com>
@codecov-io
Copy link

codecov-io commented Dec 6, 2019

Codecov Report

Merging #320 into master will increase coverage by 0.09%.
The diff coverage is 84.41%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #320      +/-   ##
==========================================
+ Coverage   84.73%   84.82%   +0.09%     
==========================================
  Files          35       38       +3     
  Lines        1716     1839     +123     
  Branches      200      217      +17     
==========================================
+ Hits         1454     1560     +106     
- Misses        204      214      +10     
- Partials       58       65       +7
Impacted Files Coverage Δ
...xt-zipkin/src/opentelemetry/ext/zipkin/__init__.py 84.41% <84.41%> (ø)
...y-ext-flask/src/opentelemetry/ext/flask/version.py 100% <0%> (ø)
...-ext-flask/src/opentelemetry/ext/flask/__init__.py 88.88% <0%> (ø)

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 8fa21e6...b20310c. Read the comment docs.

@a-feld a-feld removed their request for review December 10, 2019 00:53
@c24t c24t added the needs reviewers PRs with this label are ready for review and needs people to review to move forward. label Dec 10, 2019
Copy link
Member

@c24t c24t left a comment

Choose a reason for hiding this comment

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

This looks great, some minor comments only.

Alex Boten added 2 commits December 16, 2019 13:52
@codeboten codeboten requested a review from a team December 16, 2019 21:56
Alex Boten added 3 commits December 16, 2019 14:02
Signed-off-by: Alex Boten <aboten@lightstep.com>
Signed-off-by: Alex Boten <aboten@lightstep.com>
@c24t
Copy link
Member

c24t commented Dec 17, 2019

Recent changes LGTM too, cc @open-telemetry/python-approvers to get another review on this.

@hectorhdzg
Copy link
Member

Would be good to add README with installation/usage instructions like other ext packages

Copy link
Member

@toumorokoshi toumorokoshi left a comment

Choose a reason for hiding this comment

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

Nice! looks great. some nice to haves to fix, but it looks good to me functionally.

=src
packages=find_namespace:
install_requires =
requests~=2.7
Copy link
Member

Choose a reason for hiding this comment

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

should we enforce this on the package? I have a feeling it will make it hard for people to adopt.

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 would you recommend here?

Copy link
Member

Choose a reason for hiding this comment

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

nevermind, I think I forgot the usage of the compatible release qualifier. This looks good.

self.ipv4 = ipv4
self.ipv6 = ipv6

def export(self, spans: Sequence[Span]) -> "SpanExportResult":
Copy link
Member

Choose a reason for hiding this comment

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

any need to reference this by a string vs class directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is not, updated.


def export(self, spans: Sequence[Span]) -> "SpanExportResult":
zipkin_spans = self._translate_to_zipkin(spans)
result = requests.post(
Copy link
Member

Choose a reason for hiding this comment

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

general question: does the SpanExporterer have any handling for when an export takes too long?

I was going to suggest putting a timeout on this request, but it seems like, to keep the export working, we would need to provide a more general timeout mechanism, potentially in the caller to export.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point, i don't know that the exporter currently does anything here. From some quick testing, it looks like the exporter could hang indefinitely waiting for an export to complete.

SpanKind.CONSUMER: "CONSUMER",
}

SUCCESS_STATUS_CODE = (200, 202)
Copy link
Member

Choose a reason for hiding this comment

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

nitpick: "SUCCESS_STATUS_CODE" implies a single int. would be nice to callout a plural (CODES) or a CODE_LIST.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good catch, updated to CODES

result.status_code,
result.text,
)
# TODO: should we retry here?
Copy link
Member

Choose a reason for hiding this comment

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

maybe it's good as a configuration variable?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good idea, i added a retry option to configure the behaviour

pass


def _format(unformatted_id):
Copy link
Member

Choose a reason for hiding this comment

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

this seems like a fairly small method. is it worth keeping?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed it

return None
tags = {}
for attribute_key, attribute_value in attr.items():
if isinstance(attribute_value, (int, bool, float)):
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 case allowed? it seems like we should do some enforcement on the creation of attributes spans, rather than try to catch it on the flush side here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Attributes are assigned one of the following values:

AttributeValue = typing.Union[str, bool, float]

Looks like int is not one of them though, i'll remove it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Although that isn't enforced at this point... I can create a separate ticket for this

Copy link
Member

Choose a reason for hiding this comment

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

I'm in issues anyway: #347. Thanks!

if isinstance(attribute_value, (int, bool, float)):
value = str(attribute_value)
elif isinstance(attribute_value, str):
res = attribute_value[:128]
Copy link
Member

Choose a reason for hiding this comment

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

is the "res" variable needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it is not. good catch. removed

def _extract_annotations_from_events(events):
if not events:
return None
annotations = []
Copy link
Member

Choose a reason for hiding this comment

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

nitpick: this could be a fairly intuitive list comprehension.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated

start_timestamp_mus = _nsec_to_usec_round(span.start_time)
duration_mus = _nsec_to_usec_round(span.end_time - span.start_time)

zipkin_span = {
Copy link
Member

Choose a reason for hiding this comment

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

it looks like there's no handling of the "debug" field here, which could be extracted from the boolean flags in the TraceOptions.

Copy link
Member

Choose a reason for hiding this comment

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

theoretically we could include debug as a bit in trace_options, or use the sampled bit and consider that debug: https://www.w3.org/TR/trace-context-1/#trace-flags

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 didn't see anything referencing a debug field in the zipkin API https://zipkin.io/zipkin-api/#/default/post_spans. can you elaborate on this?

Copy link
Member

@hectorhdzg hectorhdzg Dec 20, 2019

Choose a reason for hiding this comment

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

Documentation is in that page under Models - Span

https://zipkin.io/zipkin-api/#/default/post_spans

debug boolean True is a request to store this span even if it overrides sampling policy.This is true when the X-B3-Flags header has a value of 1.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Easy enough to use the sampling bit.

@toumorokoshi toumorokoshi removed the needs reviewers PRs with this label are ready for review and needs people to review to move forward. label Dec 20, 2019
Signed-off-by: Alex Boten <aboten@lightstep.com>
@codeboten
Copy link
Contributor Author

Would be good to add README with installation/usage instructions like other ext packages

Added

Alex Boten added 3 commits December 20, 2019 08:23
Signed-off-by: Alex Boten <aboten@lightstep.com>
Signed-off-by: Alex Boten <aboten@lightstep.com>
- adding retry configuration option
- adding link to zipkin documentation for microseconds

Signed-off-by: Alex Boten <aboten@lightstep.com>
Signed-off-by: Alex Boten <aboten@lightstep.com>
@toumorokoshi toumorokoshi merged commit 4458698 into open-telemetry:master Dec 30, 2019
@toumorokoshi
Copy link
Member

Amazing! Thanks.

@codeboten codeboten deleted the issue-318 branch October 9, 2020 18:50
srikanthccv pushed a commit to srikanthccv/opentelemetry-python that referenced this pull request Nov 1, 2020
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.

Add Zipkin exporter
5 participants