diff --git a/CHANGELOG.md b/CHANGELOG.md index f20a279fa42..9335557c1ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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)) diff --git a/specification/trace/sdk.md b/specification/trace/sdk.md index 2ca4aba71d3..1a84411b391 100644 --- a/specification/trace/sdk.md +++ b/specification/trace/sdk.md @@ -6,6 +6,7 @@ * [Sampling](#sampling) * [Tracer Creation](#tracer-creation) +* [Additional Span Interfaces](#additional-span-interfaces) * [Span Processor](#span-processor) * [Span Exporter](#span-exporter) @@ -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 + that was added to the span (e.g. all attributes, events, (parent) `SpanContext`, + etc.). + + A readable span interface MUST provide a method called `getInstrumentationLibrary` (or similar), + 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 + 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 @@ -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. **Returns:** `Void` @@ -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). +Protocol exporters that will implement this function are typically expected to serialize and transmit the data to the destination. @@ -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`. - -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`. **Returns:** ExportResult: