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

Add stackdriver trace exporter #288

Closed
wants to merge 13 commits into from

Conversation

clsung
Copy link
Contributor

@clsung clsung commented Nov 13, 2019

Implement #287
TODO:

  • add GCP/AWS/Azure labels if planned
    • in OC, it detects GAE/K8S/AWS
  • increase test coverage

Tested on:

TODO:
  - add GCP/AWS/Azure labels if planned
  - increase test coverage
Test on:
  - examples/client.py and examples/server.py
  - https://github.com/open-telemetry/opentelemetry-go/tree/master/example/http-stackdriver
@codecov-io
Copy link

codecov-io commented Nov 14, 2019

Codecov Report

Merging #288 into master will decrease coverage by 1.5%.
The diff coverage is 61.9%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #288      +/-   ##
==========================================
- Coverage   85.66%   84.16%   -1.51%     
==========================================
  Files          33       35       +2     
  Lines        1612     1756     +144     
  Branches      180      206      +26     
==========================================
+ Hits         1381     1478      +97     
- Misses        185      215      +30     
- Partials       46       63      +17
Impacted Files Coverage Δ
...river/src/opentelemetry/ext/stackdriver/version.py 100% <100%> (ø)
...rc/opentelemetry/ext/stackdriver/trace/__init__.py 61.6% <61.6%> (ø)
...ntelemetry-api/src/opentelemetry/trace/__init__.py 83.73% <0%> (-2.56%) ⬇️
...ry-ext-wsgi/src/opentelemetry/ext/wsgi/__init__.py 90.54% <0%> (-0.37%) ⬇️
...src/opentelemetry/ext/opentracing_shim/__init__.py 95.86% <0%> (-0.1%) ⬇️
...emetry-sdk/src/opentelemetry/sdk/trace/__init__.py 89.94% <0%> (+0.83%) ⬆️
...sdk/src/opentelemetry/sdk/trace/export/__init__.py 86.79% <0%> (+0.94%) ⬆️
...elemetry-api/src/opentelemetry/metrics/__init__.py 86% <0%> (+1.55%) ⬆️
... and 1 more

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 693391c...e1b07e7. Read the comment docs.

@codeboten
Copy link
Contributor

Should this exporter be outside of the main opentelemetry repo?

@clsung
Copy link
Contributor Author

clsung commented Nov 15, 2019

Should this exporter be outside of the main opentelemetry repo?

Are we going to move them out now? Not sure if there's a guideline to follow.

@Oberon00
Copy link
Member

This is currently being discussed at #272 and it looks like yes, vendor-specific exporters should not be living in the main Python repository.

@c24t
Copy link
Member

c24t commented Nov 23, 2019

I think it's fine to have two PRs here: one to create the exporter and another to move in into a separate repo. We need the same reviewers in any case, and doing it this way makes it easier to write the exporter in the same style as the others, use the same style checks and CI, etc.

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.

The direction looks good, but I've got a few blocking comments on the exporter and I think the tests need some work still.

I reviewed the code, but haven't tested against stackdriver yet. Have you tried sending traces to stackdriver? How did you test this?

It would also be helpful to list the features of the OC exporter (besides resource detection) that aren't implemented here to help reviewers compare the two.

@clsung
Copy link
Contributor Author

clsung commented Nov 23, 2019

I reviewed the code, but haven't tested against stackdriver yet. Have you tried sending traces to stackdriver? How did you test this?

Hi, I tested it on my own GCP project, with examples/*.py (and cross-test client.py/server.py with server/client in opentelemetry-go/example/http-stackdriver)

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

@dgzlopes dgzlopes left a comment

Choose a reason for hiding this comment

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

It looks good, but I found some things that might need a fix :)

if not links:
return None

links = []
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this won't work.

An empty list is assigned to the links function argument.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, single use function too.

"annotation": annotation_json,
}
)
return {"timeEvent": logs}
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit.

If I have a function called extract_events I expect that it returns events, not logs.

Copy link
Contributor

Choose a reason for hiding this comment

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

Don't define extract_events at all, it is single use too.

return (result, truncated_byte_count)


def extract_status(status: trace_api.Status):
Copy link
Contributor

Choose a reason for hiding this comment

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

These functions aren't supposed to be accessed "from the outside" and should be led by an underscore (see Jaeger implementation as an example).

Copy link
Contributor

Choose a reason for hiding this comment

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

Even better, don't even define extract_status. Its code is only used in one place, just move it there.

Copy link
Contributor

Choose a reason for hiding this comment

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

Even better, don't even define this function since it is single use. Just move its code where it is needed.

Copy link
Contributor

Choose a reason for hiding this comment

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

Do you think it's necessary to remove all the single-use functions? Speaking because Jaeger and Zipkin exporters have some of them too (Example in Jaeger: _extract_refs_from_span _extract_logs_from_span)... And maybe they need a second look.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think it is necessary, but it is very convenient 🙂

They may be present somewhere else, but that does not mean we should have them here, of course. Removing them means less code, less stuff to document, but above all, it means that when you are reading code you don't have to stop, read code somewhere else (maybe doing some mental replacement of variable names that were passed as arguments) and then come back to the original point in the code.

Copy link
Contributor

Choose a reason for hiding this comment

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

Makes sense. Thank you for taking the time to explain!

from opentelemetry.sdk.trace.export import SimpleExportSpanProcessor

trace.set_preferred_tracer_implementation(lambda T: Tracer())
tracer = trace.tracer()
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe that this should use Named tracers work from #301. Examples in other places: Here or here.

# durations = 50 * 10 ** 6
# end_times = start_times + durations
span_datas = [
Span(
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it is necessary to test multiple spans with different fields to make the tests more reliable. Example from Jaeger translation tests.

Half of the fields right now aren't tested (startTime, endTime, parent, links...).

class StackdriverSpanExporter(SpanExporter):
"""Stackdriver span exporter for OpenTelemetry.

Args:
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure if we are being strict on this, but PEP 257 says that the documentation for these arguments goes in the documentation for __init__.


return SpanExportResult.SUCCESS

def translate_to_stackdriver(
Copy link
Contributor

Choose a reason for hiding this comment

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

Is better to avoid single call functions like this one because the reader has to look for the code here then return to this line.

parent_id = "{:016x}".format(span.parent.span_id)

start_time = None
if span.start_time:
Copy link
Contributor

Choose a reason for hiding this comment

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

If span.start_time can be None use if span.start_time is not None.


logger = logging.getLogger(__name__)

AGENT = "opentelemetry-python [{}]".format(__version__)
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a single use global variable, better just move to where it is used.

"""Translate the spans to Stackdriver format.

Args:
spans: Tuple of spans to convert
Copy link
Contributor

Choose a reason for hiding this comment

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

A list could also be used as the spans argument.

return result


def map_attributes(attribute_map):
Copy link
Contributor

Choose a reason for hiding this comment

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

Single use function here, too.

"""Convert the attributes to stackdriver attributes."""
if attribute_map is None:
return attribute_map
for (key, value) in attribute_map.items():
Copy link
Contributor

Choose a reason for hiding this comment

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

attribute_map is a dictionary, Instead of looking through all of its keys (O(N)), just access "attributeMap" directly (O(1)).

return attribute_map


def _format_attribute_value(value):
Copy link
Contributor

Choose a reason for hiding this comment

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

Single use function too. Also, just something to consider:

>>> type(1).__name__
'int'
>>> type(False).__name__
'bool'
>>> type("string").__name__
'str'
>>> type(1.1).__name__
'float'

return result


def check_str_length(str_to_check, limit=MAX_LENGTH):
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 just have 128 here instead of having a global variable named MAX_LENGTH.

def test_export(self):
trace_id = "6e0c63257de34c92bf9efcd03927272e"
span_id = "95bb5edabd45950f"
# start_times = 683647322 * 10 ** 9 # in ns
Copy link
Contributor

Choose a reason for hiding this comment

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

Please remove commented code.

@lizthegrey
Copy link
Member

this should go into its own repo as it's a vendor exporter, no?

@kintel kintel mentioned this pull request May 20, 2020
@codeboten
Copy link
Contributor

Closed in favour of #698

@codeboten codeboten closed this May 21, 2020
srikanthccv pushed a commit to srikanthccv/opentelemetry-python that referenced this pull request Nov 1, 2020
* chore: update zipkin exporter README

* chore: remove Prerequisites section
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs reviewers PRs with this label are ready for review and needs people to review to move forward.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants