Skip to content

Conversation

@lidavidm
Copy link
Member

@lidavidm lidavidm commented Dec 9, 2021

This adds two exporters that can be toggled with an environment variable, for debug use. One is the standard ostream exporter, which logs a human-friendly but machine-unfriendly format. The other uses a trick to log the JSON OTLP request format, which is easily parsable JSON but not very readable.

@github-actions
Copy link

github-actions bot commented Dec 9, 2021

@lidavidm
Copy link
Member Author

lidavidm commented Dec 9, 2021

Example of ostream output:

{
  name          : test
  trace_id      : 577bb5359fd4c9babdfb7e8def43d476
  span_id       : 41655856137c4635
  tracestate    : 
  parent_span_id: 0000000000000000
  start         : 1639087427620946845
  duration      : 8538876
  description   : 
  span kind     : Internal
  status        : Unset
  attributes    : 
	thread_id: 140062552533184
	foo: bar
  events        : 
  links         : 
  resources     : 
	service.name: unknown_service
	telemetry.sdk.version: 1.1.0
	telemetry.sdk.name: opentelemetry
	telemetry.sdk.language: cpp
  instr-lib     : arrow
}

Example of OTLP output:

{"resource":{"attributes":[{"key":"service.name","value":{"stringValue":"unknown_service"}},{"key":"telemetry.sdk.version","value":{"stringValue":"1.1.0"}},{"key":"telemetry.sdk.name","value":{"stringValue":"opentelemetry"}},{"key":"telemetry.sdk.language","value":{"stringValue":"cpp"}}]},"instrumentationLibrarySpans":[{"instrumentationLibrary":{"name":"arrow"},"spans":[{"traceId":"ID+DVD1Rarxdh8dNLchUmw==","spanId":"7IGA2C88AQk=","parentSpanId":"AAAAAAAAAAA=","name":"test","kind":"SPAN_KIND_INTERNAL","startTimeUnixNano":"1639087084846448841","endTimeUnixNano":"1639087084849284338","attributes":[{"key":"foo","value":{"stringValue":"bar"}},{"key":"thread_id","value":{"stringValue":"140253881153728"}}]},{"traceId":"pPN+j22d17tQVbHZpG6pbA==","spanId":"6apExpYokXw=","parentSpanId":"AAAAAAAAAAA=","name":"test","kind":"SPAN_KIND_INTERNAL","startTimeUnixNano":"1639087084850354448","endTimeUnixNano":"1639087084853673659","attributes":[{"key":"foo","value":{"stringValue":"bar"}},{"key":"thread_id","value":{"stringValue":"140253881153728"}}]},{"traceId":"yVWEeB/z4NedBKrCdezTMg==","spanId":"4AGb3ndTHek=","parentSpanId":"AAAAAAAAAAA=","name":"test","kind":"SPAN_KIND_INTERNAL","startTimeUnixNano":"1639087084873028556","endTimeUnixNano":"1639087084876243603","attributes":[{"key":"foo","value":{"stringValue":"bar"}},{"key":"thread_id","value":{"stringValue":"140253881153728"}}]}]}]}

namespace sdktrace = opentelemetry::sdk::trace;

// Custom JSON stdout exporter. Leverages the OTLP HTTP exporter's
// utilities to log the same format that would be sent to OTLP.
Copy link
Member

Choose a reason for hiding this comment

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

Is there a feature request on the OpenTelemetry side for them to expose this?

Copy link
Member Author

Choose a reason for hiding this comment

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

There is open-telemetry/opentelemetry-cpp#1111 which would effectively accomplish the same thing. However if they do add it to the contrib repo that would involve some more packaging work for us.

Copy link
Member Author

Choose a reason for hiding this comment

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

The least riskiest thing would be to just define our own JSON format and not try to reuse any upstream components.

Copy link
Member

Choose a reason for hiding this comment

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

If that's not too much work that would sound reasonable to me.

Copy link
Member Author

Choose a reason for hiding this comment

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

Sounds good. CC @cpcloud any thoughts? There was such an exporter on the original PR (#10260 (comment)) but as I recall the recommendation was to use the OTLP collector instead, so it was dropped. However, it seems the collector would be a lot more work for Conbench to integrate + is less convenient for local development workflows.

Copy link
Contributor

@cpcloud cpcloud Dec 15, 2021

Choose a reason for hiding this comment

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

Interesting. Typically, the collector usage is deploying a container alongside the application, so without knowing anything else I'm not sure why it would be a lot more work.

@lidavidm and I went back and forth on the original PR about this, but I'm generally -1 on adding an exporter because exporters force a choice when used inside of a library. The Otel docs are pretty clear on how to use it within libraries (https://opentelemetry.io/docs/concepts/instrumenting-library/#opentelemetry-api)

Libraries should just instrument ideally, and testing can be done by constructing exporters in tests.

Including an exporter inside a library can also easily conflict with an application's N other exporters.

If these exporters are included I think they should be restricted to only when tests are being compiled.

Copy link
Contributor

Choose a reason for hiding this comment

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

Not totally understanding why a custom JSON format is less risky than using an upstream component or just having some documentation showing how to use the collector

Copy link
Member Author

Choose a reason for hiding this comment

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

Not totally understanding why a custom JSON format is less risky than using an upstream component or just having some documentation showing how to use the collector

Sorry, I meant just in terms of upstream changing APIs on us or something like that. The approach taken here does use the upstream generated Protobuf code and they might hide it from the public headers in the future, for instance.

Libraries should just instrument ideally, and testing can be done by constructing exporters in tests.

That is the intent, but I think Arrow occupies a halfway point between library and application, especially when bindings come into play. You can't enable C++ exporters from Python or R, for instance.

The exporters are not configured by default, for what it's worth - but they can be enabled by env var. The intent is that for development or testing, the env var can be used to easily dump spans somewhere, but an application would not use the env var and would configure its own exporter/tracer provider.

That said, this would all mostly be moot if Conbench ran a collector alongside test runs.

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't enable C++ exporters from Python or R, for instance.

/me grumbles. I forgot about that. Ugh, I guess that means you'd probably have to use context propagation in-process which is kind of gross.

Copy link
Member Author

Choose a reason for hiding this comment

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

Also see: open-telemetry/community#734

Yeah, in-process propagation is gross, the original PR used to have an example of that (to instrument Flight in Python) but I dropped it in the name of slimming the PR down.

@cpcloud
Copy link
Contributor

cpcloud commented Dec 15, 2021

The other uses a trick to log the JSON OTLP request format, which is easily parsable JSON but not very readable.

Can't we just output the machine-readable JSON and users can use jq or something? No reason to write code for tools that already do an amazing job of formatting JSON

@lidavidm
Copy link
Member Author

I'm not planning on writing any code to format the OTLP output further. I just added that to contrast it with the ostream exporter. (That said, the ostream exporter is not super useful once you log more than ~50 traces, so maybe it's not worth having at all.)

@cpcloud
Copy link
Contributor

cpcloud commented Dec 15, 2021

This LGTM.

@lidavidm
Copy link
Member Author

@pitrou any other comments here?

@pitrou
Copy link
Member

pitrou commented Dec 16, 2021

@github-actions crossbow submit -g cpp

@github-actions
Copy link

Revision: f7cbd4d

Submitted crossbow builds: ursacomputing/crossbow @ actions-1317

Task Status
test-build-cpp-fuzz Github Actions
test-conda-cpp Github Actions
test-conda-cpp-valgrind Azure
test-debian-10-cpp-amd64 Github Actions
test-debian-10-cpp-i386 Github Actions
test-debian-11-cpp-amd64 Github Actions
test-debian-11-cpp-i386 Github Actions
test-fedora-33-cpp Github Actions
test-ubuntu-18.04-cpp Github Actions
test-ubuntu-18.04-cpp-release Github Actions
test-ubuntu-18.04-cpp-static Github Actions
test-ubuntu-20.04-cpp Github Actions
test-ubuntu-20.04-cpp-14 Github Actions
test-ubuntu-20.04-cpp-17 Github Actions
test-ubuntu-20.04-cpp-bundled Github Actions
test-ubuntu-20.04-cpp-thread-sanitizer Github Actions

@pitrou pitrou closed this in 8a4d812 Dec 16, 2021
@ursabot
Copy link

ursabot commented Dec 16, 2021

Benchmark runs are scheduled for baseline = 27724a5 and contender = 8a4d812. 8a4d812 is a master commit associated with this PR. Results will be available as each benchmark for each run completes.
Conbench compare runs links:
[Finished ⬇️0.0% ⬆️0.0%] ec2-t3-xlarge-us-east-2
[Finished ⬇️0.0% ⬆️0.9%] ursa-i9-9960x
[Finished ⬇️0.93% ⬆️0.4%] ursa-thinkcentre-m75q
Supported benchmarks:
ec2-t3-xlarge-us-east-2: Supported benchmark langs: Python. Runs only benchmarks with cloud = True
ursa-i9-9960x: Supported benchmark langs: Python, R, JavaScript
ursa-thinkcentre-m75q: Supported benchmark langs: C++, Java

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants