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

Trace SDK: Provide definitions for readable and read/write span. #669

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Updates:

- Add semantic convention for NGINX custom HTTP 499 status code.
- Adapt semantic conventions for the span name of messaging systems ([#690](https://github.com/open-telemetry/opentelemetry-specification/pull/690))
- Provide clear definitions for readable and read/write span interfaces in the SDK ([#669](https://github.com/open-telemetry/opentelemetry-specification/pull/669))
* SpanProcessors must provide read/write access at least in OnStart.
- Specify how `Probability` sampler is used with `ParentOrElse` sampler.
- Clean up api-propagators.md, by extending documentation and removing redundant sections ([#577](https://github.com/open-telemetry/opentelemetry-specification/pull/577))

Expand Down
66 changes: 49 additions & 17 deletions specification/trace/sdk.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

* [Sampling](#sampling)
* [Tracer Creation](#tracer-creation)
* [Additional Span Interfaces](#additional-span-interfaces)
* [Span Processor](#span-processor)
* [Span Exporter](#span-exporter)

Expand Down Expand Up @@ -152,9 +153,42 @@ Note: Implementation-wise, this could mean that `Tracer` instances have a
reference to their `TracerProvider` and access configuration only via this
reference.

The readable representations of all `Span` instances created by a `Tracer` must
provide a `getInstrumentationLibrary` method that returns the
`InstrumentationLibrary` information held by the `Tracer`.
## Additional Span Interfaces

The [API-level definition for Span's interface](api.md#span-operations)
only defines write-only access to the span.
This is good because instrumentations and applications are not meant to use the data
stored in a span for application logic.
However, the SDK needs to eventually read back the data in some locations.
Thus, the SDK specification defines two new terms:

* **Readable span**: A span interface satisfies the requirements of being a
readable span if it allows to retrieve all information
Oberon00 marked this conversation as resolved.
Show resolved Hide resolved
that was added to the span (e.g. all attributes, events, (parent) `SpanContext`,
etc.).
Oberon00 marked this conversation as resolved.
Show resolved Hide resolved

A readable span interface MUST provide a method called `getInstrumentationLibrary` (or similar),
Oberon00 marked this conversation as resolved.
Show resolved Hide resolved
that returns the `InstrumentationLibrary` information held by the `Tracer` that created the span.
* **Read/write span**: A span interface satisfies this requirement of being a
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 really needed? This may make user to do hacks. Imagine we have this interface in the OnStart, they know that the object we return implements both, OnEnd we return only read, then they will guess is the same interface and may do a cast to the ReadWrite interface.

My suggestion is that Span is the write interface and ReadableSpan is the read interface, if access required to both we should pass both interfaces. Maybe I am to "evil" and think of possible hacks and abuses, but I've seen all of these happening in my previous life :)

Copy link
Member Author

Choose a reason for hiding this comment

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

You could pass a wrapper object that only implements the readable interface to protect against that.

I think we can mention passing the read-only and write-only interface separately as an allowed implementation option for read/write span though.

Copy link
Contributor

Choose a reason for hiding this comment

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

@Oberon00 suggested I do that hack when I need to mutate the span in OnEnd :) I think there is a need to be able to mutate spans globally before export (usually to use other tags as signals to user-defined domain-specific tags) so hope we can find a way. The issue we were worried about is the ordering between OnEnd and export

Copy link
Member Author

Choose a reason for hiding this comment

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

More importantly, spans are already ended at that point and can't be modified anyway. #669 (comment)

Copy link
Member Author

Choose a reason for hiding this comment

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

@bogdandrutu I incorporated the "read/write implemented as two separate objects" option in 0b9709d.

read/write span if it provides both the full span API as defined in the
[API-level definition for span's interface](api.md#span-operations) and
additionally satisfies the requirements for being a readable span
as defined in the above bullet point.

Note: First, these requirements use "interface" in the most abstract sense --
it does not need to be an actual Java `interface` for example but could also be
a `final` POJO, or, especially in the case of read/write span, even two (or more)
separate objects that are passed together to give full read/write capabilities
(when chosing this implemenation technique,
changes through one object should be reflected in the other
objects immediately if they are observable through them at all
to avoid introducing subtle gotchas).
Second, these are abstract requirements for interfaces. Not all
places in the spec that talk about a readable span need to be implemented by the
same concrete interface. For example, this allows using a different interface
for the readable span passed to an exporter than for the readable span passed
to a SpanProcessor's OnEnd. On the other hand,
it allows implementing a readable span as a read/write span.

## Span processor

Expand Down Expand Up @@ -203,18 +237,21 @@ exceptions.

**Parameters:**

* `Span` - a readable span object.
* `Span` - a [read/write span object](#additional-span-interfaces) for the started span.

**Returns:** `Void`

#### OnEnd(Span)

`OnEnd` is called when a span is ended. This method is called synchronously on
the execution thread, therefore it should not block or throw an exception.
`OnEnd` is called after a span is ended (i.e., the end timestamp is already set).
This method MUST be called synchronously within the [`Span.End()` API](api.md#end),
therefore it should not block or throw an exception.

**Parameters:**

* `Span` - a readable span object.
* `Span` - a [readable span object](#additional-span-interfaces) for the ended span.
Note: Even if the passed Span may be technically writable,
since it's already ended at this point, modifying it is not allowed.
arminru marked this conversation as resolved.
Show resolved Hide resolved

**Returns:** `Void`

Expand Down Expand Up @@ -290,7 +327,8 @@ interfaces, one that accepts spans (SpanExporter) and one that accepts metrics

#### `Export(batch)`

Exports a batch of telemetry data. Protocol exporters that will implement this
Exports a batch of [readable spans](#additional-span-interfaces).
Oberon00 marked this conversation as resolved.
Show resolved Hide resolved
Oberon00 marked this conversation as resolved.
Show resolved Hide resolved
Protocol exporters that will implement this
function are typically expected to serialize and transmit the data to the
destination.

Expand All @@ -307,15 +345,9 @@ and backend the spans are being sent to.

**Parameters:**

batch - a batch of telemetry data. The exact data type of the batch is language
specific, typically it is a list of telemetry items, e.g. for spans in Java it
will be typically `Collection<ExportableSpan>`.

Note that the data type for a span for illustration purposes here is written as
an imaginary type ExportableSpan (similarly for metrics it would be e.g.
ExportableMetrics). The actual data type must be specified by language library
authors, it should be able to represent the span data that can be read by the
exporter.
batch - a batch of [readable spans](#additional-span-interfaces). The exact data type of the batch is language
specific, typically it is some kind of list,
e.g. for spans in Java it will be typically `Collection<SpanData>`.

**Returns:** ExportResult:

Expand Down