-
Notifications
You must be signed in to change notification settings - Fork 559
Add interfaces for exporter, processor and span data #55
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
Changes from all commits
6292ec2
54a9130
e8d867c
132f0e7
e7711b2
c71261c
773a8b9
56f10e6
fe15d7b
b18a663
62491c1
2e4d835
8574b66
d634bed
454aa8f
e1362d8
e365767
a9e6cac
c4c1f09
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| #pragma once | ||
|
|
||
| #include <memory> | ||
| #include "opentelemetry/nostd/span.h" | ||
| #include "opentelemetry/sdk/trace/recordable.h" | ||
|
|
||
| OPENTELEMETRY_BEGIN_NAMESPACE | ||
| namespace sdk | ||
| { | ||
| namespace trace | ||
| { | ||
| /** | ||
| * ExportResult is returned as result of exporting a span batch. | ||
| */ | ||
| enum class ExportResult | ||
| { | ||
| /** | ||
| * Batch was successfully exported. | ||
| */ | ||
| kSuccess = 0, | ||
| /** | ||
| * Exporting failed. The caller must not retry exporting the same batch; the | ||
| * batch must be dropped. | ||
| */ | ||
| kFailure | ||
| }; | ||
| /** | ||
| * SpanExporter defines the interface that protocol-specific span exporters must | ||
| * implement. | ||
| */ | ||
| class SpanExporter | ||
| { | ||
| public: | ||
| virtual ~SpanExporter() = default; | ||
|
|
||
| /** | ||
| * Create a span recordable. This object will be used to record span data and | ||
| * will subsequently be passed to SpanExporter::Export. Vendors can implement | ||
| * custom recordables or use the default SpanData recordable provided by the | ||
| * SDK. | ||
| * @return a newly initialized Recordable object | ||
| */ | ||
| virtual std::unique_ptr<Recordable> MakeRecordable() noexcept = 0; | ||
|
|
||
| /** | ||
| * Exports a batch of span recordables. This method must not be called | ||
| * concurrently for the same exporter instance. | ||
| * @param spans a span of unique pointers to span recordables | ||
| */ | ||
| virtual ExportResult Export( | ||
| nostd::span<std::unique_ptr<opentelemetry::sdk::trace::Recordable>> &spans) noexcept = 0; | ||
|
|
||
| /** | ||
| * Shut down the exporter. | ||
| * @param timeout an optional timeout, the default timeout of 0 means that no | ||
| * timeout is applied. | ||
| */ | ||
| virtual void Shutdown( | ||
| std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept = 0; | ||
| }; | ||
| } // namespace trace | ||
| } // namespace sdk | ||
| OPENTELEMETRY_END_NAMESPACE | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| #pragma once | ||
|
|
||
| #include <chrono> | ||
| #include <memory> | ||
| #include "opentelemetry/sdk/trace/recordable.h" | ||
|
|
||
| OPENTELEMETRY_BEGIN_NAMESPACE | ||
| namespace sdk | ||
| { | ||
| namespace trace | ||
| { | ||
| /** | ||
| * Span processor allow hooks for span start and end method invocations. | ||
| * | ||
| * Built-in span processors are responsible for batching and conversion of | ||
| * spans to exportable representation and passing batches to exporters. | ||
| */ | ||
| class SpanProcessor | ||
| { | ||
| public: | ||
| virtual ~SpanProcessor() = default; | ||
|
|
||
| /** | ||
| * Create a span recordable. This requests a new span recordable from the | ||
| * associated exporter. | ||
| * @return a newly initialized recordable | ||
| */ | ||
| virtual std::unique_ptr<Recordable> MakeRecordable() noexcept = 0; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this in the interface? Do I need to implement this function in order to implement an exporter?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| /** | ||
| * OnStart is called when a span is started. | ||
| * @param span a recordable for a span that was just started | ||
| */ | ||
| virtual void OnStart(Recordable &span) noexcept = 0; | ||
|
|
||
| /** | ||
| * OnEnd is called when a span is ended. | ||
| * @param span a recordable for a span that was ended | ||
| */ | ||
| virtual void OnEnd(std::unique_ptr<Recordable> &&span) noexcept = 0; | ||
|
|
||
| /** | ||
| * Export all ended spans that have not yet been exported. | ||
| * @param timeout an optional timeout, the default timeout of 0 means that no | ||
| * timeout is applied. | ||
| */ | ||
| virtual void ForceFlush( | ||
| std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept = 0; | ||
|
|
||
| /** | ||
| * Shut down the processor and do any cleanup required. Ended spans are | ||
| * exported before shutdown. After the call to Shutdown, subsequent calls to | ||
| * OnStart, OnEnd, ForceFlush or Shutdown will return immediately without | ||
| * doing anything. | ||
| * @param timeout an optional timeout, the default timeout of 0 means that no | ||
| * timeout is applied. | ||
| */ | ||
| virtual void Shutdown( | ||
| std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept = 0; | ||
| }; | ||
| } // namespace trace | ||
| } // namespace sdk | ||
| OPENTELEMETRY_END_NAMESPACE | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,8 @@ | |
| #include "opentelemetry/core/timestamp.h" | ||
| #include "opentelemetry/nostd/string_view.h" | ||
| #include "opentelemetry/trace/canonical_code.h" | ||
| #include "opentelemetry/trace/span_id.h" | ||
| #include "opentelemetry/trace/trace_id.h" | ||
| #include "opentelemetry/version.h" | ||
|
|
||
| OPENTELEMETRY_BEGIN_NAMESPACE | ||
|
|
@@ -21,6 +23,16 @@ class Recordable | |
| public: | ||
| virtual ~Recordable() = default; | ||
|
|
||
| /** | ||
|
Comment on lines
24
to
+26
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In other languages |
||
| * Set a trace id, span id and parent span id for this span. | ||
| * @param trace_id the trace id to set | ||
| * @param span_id the span id to set | ||
| * @param parent_span_id the parent span id to set | ||
| */ | ||
| virtual void SetIds(opentelemetry::trace::TraceId trace_id, | ||
| opentelemetry::trace::SpanId span_id, | ||
| opentelemetry::trace::SpanId parent_span_id) noexcept = 0; | ||
|
|
||
| /** | ||
| * Add an event to a span. | ||
| * @param name the name of the event | ||
|
|
@@ -41,6 +53,18 @@ class Recordable | |
| * @param name the name to set | ||
| */ | ||
| virtual void SetName(nostd::string_view name) noexcept = 0; | ||
|
|
||
| /** | ||
| * Set the start time of the span. | ||
| * @param start_time the start time to set | ||
| */ | ||
| virtual void SetStartTime(opentelemetry::core::SystemTimestamp start_time) noexcept = 0; | ||
|
|
||
| /** | ||
| * Set the duration of the span. | ||
| * @param duration the duration to set | ||
| */ | ||
| virtual void SetDuration(std::chrono::nanoseconds duration) noexcept = 0; | ||
| }; | ||
| } // namespace trace | ||
| } // namespace sdk | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| #pragma once | ||
|
|
||
| #include <chrono> | ||
| #include "opentelemetry/core/timestamp.h" | ||
| #include "opentelemetry/nostd/string_view.h" | ||
| #include "opentelemetry/sdk/trace/recordable.h" | ||
| #include "opentelemetry/trace/canonical_code.h" | ||
| #include "opentelemetry/trace/span_id.h" | ||
| #include "opentelemetry/trace/trace_id.h" | ||
|
|
||
| OPENTELEMETRY_BEGIN_NAMESPACE | ||
| namespace sdk | ||
| { | ||
| namespace trace | ||
| { | ||
| /** | ||
| * SpanData is a representation of all data collected by a span. | ||
| */ | ||
| class SpanData final : public Recordable | ||
| { | ||
| public: | ||
| /** | ||
| * Get the trace id for this span | ||
| * @return the trace id for this span | ||
| */ | ||
| opentelemetry::trace::TraceId GetTraceId() const noexcept { return trace_id_; } | ||
|
|
||
| /** | ||
| * Get the span id for this span | ||
| * @return the span id for this span | ||
| */ | ||
| opentelemetry::trace::SpanId GetSpanId() const noexcept { return span_id_; } | ||
|
|
||
| /** | ||
| * Get the parent span id for this span | ||
| * @return the span id for this span's parent | ||
| */ | ||
| opentelemetry::trace::SpanId GetParentSpanId() const noexcept { return parent_span_id_; } | ||
|
|
||
| /** | ||
| * Get the name for this span | ||
| * @return the name for this span | ||
| */ | ||
| opentelemetry::nostd::string_view GetName() const noexcept { return name_; } | ||
|
|
||
| /** | ||
| * Get the status for this span | ||
| * @return the status for this span | ||
| */ | ||
| opentelemetry::trace::CanonicalCode GetStatus() const noexcept { return status_code_; } | ||
|
|
||
| /** | ||
| * Get the status description for this span | ||
| * @return the description of the the status of this span | ||
| */ | ||
| opentelemetry::nostd::string_view GetDescription() const noexcept { return status_desc_; } | ||
|
|
||
| /** | ||
| * Get the start time for this span | ||
| * @return the start time for this span | ||
| */ | ||
| opentelemetry::core::SystemTimestamp GetStartTime() const noexcept { return start_time_; } | ||
|
|
||
| /** | ||
| * Get the duration for this span | ||
| * @return the duration for this span | ||
| */ | ||
| std::chrono::nanoseconds GetDuration() const noexcept { return duration_; } | ||
|
|
||
| void SetIds(opentelemetry::trace::TraceId trace_id, | ||
| opentelemetry::trace::SpanId span_id, | ||
| opentelemetry::trace::SpanId parent_span_id) noexcept override | ||
| { | ||
| trace_id_ = trace_id; | ||
| span_id_ = span_id; | ||
| parent_span_id_ = parent_span_id; | ||
| } | ||
|
|
||
| void AddEvent(nostd::string_view name, core::SystemTimestamp timestamp) noexcept override | ||
| { | ||
| (void)name; | ||
| (void)timestamp; | ||
| } | ||
|
|
||
| void SetStatus(trace_api::CanonicalCode code, nostd::string_view description) noexcept override | ||
| { | ||
| status_code_ = code; | ||
| status_desc_ = std::string(description); | ||
| } | ||
|
|
||
| void SetName(nostd::string_view name) noexcept override { name_ = std::string(name); } | ||
|
|
||
| void SetStartTime(opentelemetry::core::SystemTimestamp start_time) noexcept override | ||
| { | ||
| start_time_ = start_time; | ||
| } | ||
|
|
||
| void SetDuration(std::chrono::nanoseconds duration) noexcept override { duration_ = duration; } | ||
|
|
||
| private: | ||
| opentelemetry::trace::TraceId trace_id_; | ||
| opentelemetry::trace::SpanId span_id_; | ||
| opentelemetry::trace::SpanId parent_span_id_; | ||
| core::SystemTimestamp start_time_; | ||
| std::chrono::nanoseconds duration_{0}; | ||
| std::string name_; | ||
| opentelemetry::trace::CanonicalCode status_code_{opentelemetry::trace::CanonicalCode::OK}; | ||
| std::string status_desc_; | ||
| }; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Events? Is that TODO?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, for now I left events (as well as attributes, links and resources) out on purpose. I'd like to handle that in a separate PR. |
||
| } // namespace trace | ||
| } // namespace sdk | ||
| OPENTELEMETRY_END_NAMESPACE | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| #pragma once | ||
|
|
||
| #include "opentelemetry/sdk/trace/exporter.h" | ||
| #include "opentelemetry/sdk/trace/processor.h" | ||
|
|
||
| OPENTELEMETRY_BEGIN_NAMESPACE | ||
| namespace sdk | ||
| { | ||
| namespace trace | ||
| { | ||
| /** | ||
| * The simple span processor passes finished recordables to the configured | ||
| * SpanExporter, as soon as they are finished. | ||
| * | ||
| * OnEnd and ForceFlush are no-ops. | ||
| */ | ||
| class SimpleSpanProcessor : public SpanProcessor | ||
| { | ||
| public: | ||
| /** | ||
| * Initialize a simple span processor. | ||
| * @param exporter the exporter used by the span processor | ||
| */ | ||
| explicit SimpleSpanProcessor(std::unique_ptr<SpanExporter> &&exporter) noexcept | ||
| : exporter_(std::move(exporter)) | ||
| {} | ||
|
|
||
| std::unique_ptr<Recordable> MakeRecordable() noexcept override | ||
| { | ||
| return exporter_->MakeRecordable(); | ||
| } | ||
|
|
||
| void OnStart(Recordable &span) noexcept override {} | ||
|
|
||
| void OnEnd(std::unique_ptr<Recordable> &&span) noexcept override | ||
| { | ||
| nostd::span<std::unique_ptr<Recordable>> batch(&span, 1); | ||
| if (exporter_->Export(batch) == ExportResult::kFailure) | ||
| { | ||
| /* Once it is defined how the SDK does logging, an error should be | ||
| * logged in this case. */ | ||
| } | ||
| } | ||
|
|
||
| void ForceFlush( | ||
| std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override | ||
| {} | ||
|
|
||
| void Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override | ||
| { | ||
| exporter_->Shutdown(timeout); | ||
| } | ||
|
|
||
| private: | ||
| std::unique_ptr<SpanExporter> exporter_; | ||
| }; | ||
| } // namespace trace | ||
| } // namespace sdk | ||
| OPENTELEMETRY_END_NAMESPACE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this in the interface? Do I need to implement this function in order to implement an exporter?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's to allow for more efficient implementations.
It's expensive to build up a SpanData-like object that provides an accessor interface. Having this as a customization point, allows for direct serialization approaches where memory is allocated in larger blocks and the serialization is built up eagerly as methods on the tracer are called (I outlined the approach in #2)
See, for example, this benchmark from lightstep's cpp tracer where we compare a custom eager serialization approach (manual) to a SpanData-like appraoch that uses protobuf-generated objects (legacy_manual). The results show that the cost can be substantially less (ranges from 2x-5x in that run). If you look at the profiles (manual vs legacy_manual), you'll see the eager serialization approach saves a lot from avoiding small memory allocations.
But there's a SpanData Recordable in the SDK, so if an implementer doesn't want to provide their own Recordable, they can write MakeRecordable as a stub that returns a SpanData.