From dff8df9c05cdee96bc19cb9642ccd1d4a6667ec5 Mon Sep 17 00:00:00 2001 From: tedsuo Date: Sun, 8 Sep 2019 10:01:10 -0700 Subject: [PATCH 01/36] Proposal to separate context propagation from observability --- text/0000-separate-context-propagation.md | 195 +++++++++++++++++++ text/img/context_propagation_details.png | Bin 0 -> 83684 bytes text/img/context_propagation_explanation.png | Bin 0 -> 43406 bytes 3 files changed, 195 insertions(+) create mode 100644 text/0000-separate-context-propagation.md create mode 100644 text/img/context_propagation_details.png create mode 100644 text/img/context_propagation_explanation.png diff --git a/text/0000-separate-context-propagation.md b/text/0000-separate-context-propagation.md new file mode 100644 index 000000000..08e10911f --- /dev/null +++ b/text/0000-separate-context-propagation.md @@ -0,0 +1,195 @@ +# Proposal: Separate Layer for Context Propagation + +Status: `proposed` + +Design OpenTelemetry as a set of separate applications which operate on a shared context propagation mechanism. + + +## Motivation + +Based on prior art, we know that fusing the observability system and the context propagation system together creates issues. Observability systems have special rules for propagating information, such as sampling, and may have different requirements from other systems which require non-local information to be sent downstream. +* Separation of concerns + * Remove dependecy the Tracer dependency from context propagation mechanisms. + * Separate distributed context into Baggage and Correlations +* Extensibility + * Allow users to create new applications for context propagation. + * For example: A/B testing, encrypted or authenticated data, and new, experimental forms of observability. + +## Explanation + +# OpenTelemetry Layered Architecture + +![drawing](img/context_propagation_explanation.png) + +OpenTelemetry is a distributed program, which requires non-local, transaction-level context in order to execute correctly. Transaction-level context can also be used to build other distributed programs, such as security, versioning, and network switching programs. + +To allow for this extensibility, OpenTelemetry is separated into **application layer** and a **context propagation layer**. In this architecture, multiple distributed applications - such as the observability and baggage systems provided by OpenTelemetry - simultaneously share the same underlying context propagation system in order to execute their programs. + + +# Application Layer + +## Observability API + +OpenTelemetry currently contains two observability systems - Tracing and Metrics – and may be extended over time. These separate systems are bound into a unified Observability API through sharing labels – a mechanism for correlating independent observations – and through sharing propagators. + +**Observe( context, labels…, observations...) context** +The general form for all observability APIs is a function which takes a Context, label keys, and observations as input, and returns an updated Context. + +**Correlate( context, label, value, hoplimit) context** +To set the label values used by all observations in the current transaction, the Observability API provides a function which takes a context, a label key, a value, and a hoplimit, and returns an updated context. If the hoplimit is set to NO_PROPAGATION, the label will only be available to observability functions in the same process. If the hoplimit is set to UNLIMITED_PROPAGATION, it will be available to all downstream services. + +**GetPropagator( type) inject, extract** +To register with the propagation system, the Observability API provides a set of propagation functions for every propagation type. + + +## Baggage API + +In addition to observability, OpenTelemetry provides a simple mechanism for propagating arbitrary data, called Baggage. This allows new distributed applications to be implemented without having to create new propagators. + +To manage the state of a distributed application, the Baggage API provides a set of functions which read, write, and remove data. + +**SetBaggage(context, key, value) context** +To record the distributed state of an application, the Baggage API provides a function which takes a context, a key, and a value as input, and returns an updated context which contains the new value. + +**GetBaggage( context, key) value** +To access the distributed state of an application, the Baggage API provides a function which takes a context and a key as input, and returns a value. + +**RemoveBaggage( context, key) context** +To delete distributed state from an application, the Baggage API provides a function which takes a context, a key, and a value as input, and returns an updated context which contains the new value. + +**CleanBaggage( context) context** +To avoid sending baggage to an untrusted downstream process, the Baggage API provides a function remove all baggage from a context, + +**GetPropagator( type) inject, extract** +To register with the propagation system, the Baggage API provides a set of propagation functions for every propagation type. + + +## Additional APIs + +Because the application and context propagation layers are separated, it is possible to create new distributed applications which do not depend on either the Observability or Baggage APIs. + +**GetPropagator(type) inject, extract** +To register with the propagation system, additional APIs provide a set of propagation functions for every propagation type. + + +# Context Propagation Layer + +## Context API + +Distributed applications access data in-process using a shared context object. Each distributed application sets a single key in the context, containing all of the data for that system. + +**SetValue( context, key, value) context** +To record the local state of an application, the Context API provides a function which takes a context, a key, and a value as input, and returns an updated context which contains the new value. + +**GetValue( context, key) value** +To access the local state of an application, the Context API provides a function which takes a context and a key as input, and returns a value. + +**Optional: Automated Context Management** +When possible, context should automatically be associated with program execution . Note that some languages do not provide any facility for setting and getting a current context. In these cases, the user is responsible for managing the current context. + +**Optional: SetCurrentContext( context)** +To associate a context with program execution, the Context API provides a function which takes a Context. + +**Optional: GetCurrentContext() context** +To access the context associated with program execution, the Context API provides a function which takes no arguments and returns a Context. + + +## Propagation API + +Distributed applications send data to downstream processes via propagators, functions which read and write application context into RPC requests. Each distributed application creates a set of propagators for every type of supported medium - currently HTTP and Binary. + +**Inject( context, request)** +To send the data for all distributed applications downstream to the next process, the Propagation API provides a function which takes a context and a request, and mutates the request to include the encoded context. The canonical representation of a request is as a map. + +**Extract( context, request) context** +To receive the data from all distributed applications set by prior upstream processes, the Propagation API provides a function which takes a context and a request, and mutates the request to include the encoded context. The canonical representation of a request is as a map. + +**RegisterPropagator( type, inject, extract)** +In order for the application layer to function correctly, Propagation choices must be syncronized between all processes in the distributed system, and multiple applications must be able to inject and extract their context into the same request. To meet these requirements, the Propagation API provides a function which registers a set of propagators, which will all be executed in order when the future calls to inject and extract are made. A canonical propagator consists of an inject and an extract function. + +OpenTelemetry currently contains two types of Propagators: + +* **HTTP** - context is written into and read from a map of HTTP headers. +* **Binary** - context is serialized into and deserialized from a stream of bytes. + +# Internal details + +![drawing](img/context_propagation_details.png) + +## Context details +OpenTelemetry currently implements three context types of context propagation. + +**Span Context -** Observability data used by the tracing system. The readable attributes are defined to match those found in the W3C **traceparent** header. Span Context is used as labels for metrics and traces. This can quickly add overhead when propagated in-band. But, because this data is write-only, how this information is transmitted remains undefined. + +**Correlation Context -** Transaction-level observability data, which can be applied as labels to spans and metrics. + +**Baggage Context -** Transaction-level application data, meant to be shared with downstream components. + +Note that when possible, OpenTelemetry APIs calls are given access to the entire context object, and not a specific context type. + + +## Context Management and in-process propagation + +In order for Context to function, it must always remain bound to the execution of code it represents. By default, this means that the programmer must pass a Context down the call stack as a function parameter. However, many languages provide automated context management facilities, such as thread locals. OpenTelemetry should leverage these facilities when available, in order to provide automatic context management. + +## Pre-existing Context implementations + +In some languages, a single, widely used Context implementation exists. In other languages, there many be too many implementations, or none at all. In the cases where there is not an extremely clear pre-existing option available, OpenTelemetry should provide its own Context implementation. + +While the above explanation represents the default OpenTelemetry approach to context propagation, it is important to note that some languages may already contain a form of context propagation. For example, Go has a the context.Context object, and widespread conventions for how to pass. + +Span data is used as labels for metrics and traces. This can quickly add overhead when propagated in-band. But, because this data is write-only, how this information is transmitted remains undefined. + +## Default Propagators + +When available, OpenTelemetry defaults to propagating via HTTP header definitions which have been standardized by the W3C. + + +# Trade-offs and mitigations + +## Why separate Baggage from Correlations? + +Since Baggage Context and Correlation Context appear very similar, why have two? + +First and foremost, the intended uses for Baggage and Correlations are completely different. Secondly, the propagation requirements diverge significantly. + +Correlations values are solely to be used as labels for metrics and traces. By making Correlation Context data write-only, how and when it is transmitted remains undefined. This leaves the door open to optimizations, such as propagating some data out-of-band, and situations where sampling decisions may cease the need to propagate correlation context any further. + +Baggage values, on the other hand, are explicitly added in order to be accessed by downstream by other application code. Therefore, Baggage Context must be readable, and reliably propagated in-band in order to accomplish this goal. + +There may be cases where a key-value pair is propagated as TagMap for observability and as a Baggage for application specific use. AB testing is one example of such use case. There is potential duplication here at call site where a pair is created and also at propagation. + +Solving this issue is not worth having semantic confusion with dual purpose. However, because all observability functions take the complete context as input, it may still be possible to use baggage values as labels. + + +## What about complex propagation behavior? + +Some OpenTelemetry proposals have called for more complex propagation behavior. For example, having a fallback to extracting B3 headersif Trace-Context headers are not found. Chained propagators and other complex behavior can be modeled as implementation details behind the Propagator interface. Therefore, the propagation system itself does not need to provide chained propagators or other additional facilities. + + +## Did you add a context parameter to every API call because Go has infected your brain? + +No. The concept of an explicit context is fundamental to a model where independent distributed applications share the same context propagation layer. How this context appears or is expressed is language specific, but it must be present in some form. + + +# Prior art and alternatives + +Prior art: +* OpenTelemetry distributed context +* OpenCensus propagators +* OpenTracing spans +* gRPC context + +# Open questions + +Related work on HTTP propagators has not been completed yet. + +* [W3C Trace-Context](https://www.w3.org/TR/trace-context/) candidate is not yet accepted +* Work on [W3C Correlation-Context](https://w3c.github.io/correlation-context/) has begun, but was halted to focus on Trace-Context. +* No work has begun on a theoretical W3C Baggage-Context. + +Given that we must ship with working propagators, and the W3C specifications are not yet complete, how should we move forwards with implementing context propagation? + +# Future possibilities + +Cleanly splitting OpenTelemetry into an Application and Context Propagation layer may allow us to move the Context Propagation layer into its own, stand-alone project. This may facilitate adoption, by allowing us to share Context Propagation with gRPC and other projects. diff --git a/text/img/context_propagation_details.png b/text/img/context_propagation_details.png new file mode 100644 index 0000000000000000000000000000000000000000..459c847aa063c726deceee6522be6f28e318813e GIT binary patch literal 83684 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 literal 0 HcmV?d00001 From 5ad7d1c3650712b7b5ad1f7aff3b9dab02a00550 Mon Sep 17 00:00:00 2001 From: tedsuo Date: Mon, 9 Sep 2019 22:09:44 -0700 Subject: [PATCH 02/36] cleanup description for Extract --- text/0000-separate-context-propagation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-separate-context-propagation.md b/text/0000-separate-context-propagation.md index 08e10911f..08c8ba655 100644 --- a/text/0000-separate-context-propagation.md +++ b/text/0000-separate-context-propagation.md @@ -9,7 +9,7 @@ Design OpenTelemetry as a set of separate applications which operate on a shared Based on prior art, we know that fusing the observability system and the context propagation system together creates issues. Observability systems have special rules for propagating information, such as sampling, and may have different requirements from other systems which require non-local information to be sent downstream. * Separation of concerns - * Remove dependecy the Tracer dependency from context propagation mechanisms. + * Remove the Tracer dependency from context propagation mechanisms. * Separate distributed context into Baggage and Correlations * Extensibility * Allow users to create new applications for context propagation. @@ -102,7 +102,7 @@ Distributed applications send data to downstream processes via propagators, func To send the data for all distributed applications downstream to the next process, the Propagation API provides a function which takes a context and a request, and mutates the request to include the encoded context. The canonical representation of a request is as a map. **Extract( context, request) context** -To receive the data from all distributed applications set by prior upstream processes, the Propagation API provides a function which takes a context and a request, and mutates the request to include the encoded context. The canonical representation of a request is as a map. +To receive data injected by prior upstream processes, the Propagation API provides a function which takes a context and a request, and returns an updated context. **RegisterPropagator( type, inject, extract)** In order for the application layer to function correctly, Propagation choices must be syncronized between all processes in the distributed system, and multiple applications must be able to inject and extract their context into the same request. To meet these requirements, the Propagation API provides a function which registers a set of propagators, which will all be executed in order when the future calls to inject and extract are made. A canonical propagator consists of an inject and an extract function. From 1dc3c7b6f841cca042f5f9ad6093570eae01facf Mon Sep 17 00:00:00 2001 From: Ted Young Date: Tue, 10 Sep 2019 08:01:37 -0700 Subject: [PATCH 03/36] commas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Christian Neumüller --- text/0000-separate-context-propagation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-separate-context-propagation.md b/text/0000-separate-context-propagation.md index 08c8ba655..5dd9dca38 100644 --- a/text/0000-separate-context-propagation.md +++ b/text/0000-separate-context-propagation.md @@ -58,7 +58,7 @@ To access the distributed state of an application, the Baggage API provides a fu To delete distributed state from an application, the Baggage API provides a function which takes a context, a key, and a value as input, and returns an updated context which contains the new value. **CleanBaggage( context) context** -To avoid sending baggage to an untrusted downstream process, the Baggage API provides a function remove all baggage from a context, +To avoid sending baggage to an untrusted downstream process, the Baggage API provides a function remove all baggage from a context. **GetPropagator( type) inject, extract** To register with the propagation system, the Baggage API provides a set of propagation functions for every propagation type. From 58248e6e0fdc3beab7873c36fa019fa4938690a4 Mon Sep 17 00:00:00 2001 From: Ted Young Date: Tue, 10 Sep 2019 13:39:59 -0700 Subject: [PATCH 04/36] Update text/0000-separate-context-propagation.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Christian Neumüller --- text/0000-separate-context-propagation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-separate-context-propagation.md b/text/0000-separate-context-propagation.md index 5dd9dca38..bf6cce277 100644 --- a/text/0000-separate-context-propagation.md +++ b/text/0000-separate-context-propagation.md @@ -164,7 +164,7 @@ Solving this issue is not worth having semantic confusion with dual purpose. How ## What about complex propagation behavior? -Some OpenTelemetry proposals have called for more complex propagation behavior. For example, having a fallback to extracting B3 headersif Trace-Context headers are not found. Chained propagators and other complex behavior can be modeled as implementation details behind the Propagator interface. Therefore, the propagation system itself does not need to provide chained propagators or other additional facilities. +Some OpenTelemetry proposals have called for more complex propagation behavior. For example, falling back to extracting B3 headers if W3C Trace-Context headers are not found. Chained propagators and other complex behavior can be modeled as implementation details behind the Propagator interface. Therefore, the propagation system itself does not need to provide chained propagators or other additional facilities. ## Did you add a context parameter to every API call because Go has infected your brain? From 68cb0ba458f434382115444e24bec58e75cc0533 Mon Sep 17 00:00:00 2001 From: Ted Young Date: Mon, 12 Aug 2019 19:48:43 -0700 Subject: [PATCH 05/36] RFC proposal: A layered approach to data formats --- text/0000-data-formats.md | 151 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 text/0000-data-formats.md diff --git a/text/0000-data-formats.md b/text/0000-data-formats.md new file mode 100644 index 000000000..21546f075 --- /dev/null +++ b/text/0000-data-formats.md @@ -0,0 +1,151 @@ +# RFC: Data Formats for OpenTelemetry + +# Overview +OpenTelemetry is an observability system, which generates observations, and then sends that data to remote systems for analysis. Describing how this observability data is represented and transmitted is critical part of the OpenTelemetry specification. + +**Proposed Layers** +* Metadata and Semantic Conventions +* Logical Structure +* Encodings +* Exchange Protocols + + +# Metadata and Semantic Conventions + +Spans represent specific operations in and between systems. Some of these operations represent calls that use well-known protocols like HTTP or database calls. Depending on the protocol and the type of operation, additional information is needed to represent and analyze a span correctly in monitoring systems. It is also important to unify how this attribution is made in different languages. This way, the operator will not need to learn specifics of a language and telemetry collected from multi-language micro-service can still be easily correlated and cross-analyzed. + +## Requirements + + +### Handle complex data + +Semantic information is often complex and multi-valued. How we represent semantic data is related to how attributes are defined at the logical layer. + +* At minimum, nested lists of key/value pairs are necessary to represent them. +* Is it advantageous to also have strongly typed data structures? +* Are there issues with having strongly typed data structures in certain environment, such as dynamic languages? + + +### Compose Multiple Semantics + +Objects in OpenTelemetry may describe more than one type of operation. For example, a span may simultaneously represent a MySQL transaction and a TCP/IP request. Pieces of metadata must compose well, without losing the structure integrity of each piece or risking a conflict in meaning. + + +### Easily Extensible + +Not all semantics conventions and common operations are known at this time. It must be possible to add more semantic definitions without creating to versioning or compatibility issues with OpenTelemetry implementations. + + +## Examples of Common Operations + +#### RPC calls + +Modeling distributed transactions is a core usecase, it is common to analyze errors and latency for RPC calls. Because multiple individual network requests may be involved in a single logical RPC operation, it must be possible to describe RPC calls as logical operations, independent from the descriptions of transport and application protocols which they contain. + +Examples: +* A client sending a request to a remote server. +* A server receiving a request from a remote client. +* Logical vs physical networking: a request for “[https://www.wikipedia.org/wiki/Rabbit](https://www.wikipedia.org/wiki/Rabbit)” results in two physical HTTP requests - one 301 redirection, and another 200 okay. The logical RPC operation represents both requests together. + +#### Network protocols + +The internet suite of network protocols is thoroughly standardized, and the details of network interactions calls are critical to analysing the behavior of distributed systems. + +Examples: +* Application Protocols: HTTP/1.1, HTTP/2, gRPC +* Transport Protocols: TCP, UDP +* Internet Protocols: IPv4, IPv6 + +#### Database protocols + +Database requests often contain information which is key to root causing errors and latency. + +Examples: +* SQL: MySQL, Postrgres +* NoSQL: MongoDB + + +# Logical Structure + +OpenTelemetry observability model, defined as data structures instead of API calls. A logical layer describes the default data structures expected to be produced by OpenTelemetry APIs for transport. + +## Requirements + +### Support Metadata + +The logical structure must be able to support all of the requirements for the metadata layer. + + +### Support both an API and a Streaming Representation + +OpenTelemetry data structures must work well with the APIs and SDKs which produce them. It must be possible to stream data from services without resorting to an encoding or exchange protocol which bears little resemblance to the API. + + +# Encoding Formats + +While there is a single set of OpenTelemetry data structures, they can be encoded in a variety of serialization formats. + +## Requirements + +### Prefer pre-existing formats + +Codecs must be commonly available in all major languages. It is outside the bounds of the OpenTelemetry project to define new serialization formats. + +**Examples:** +* Protobuf +* JSON + + +# Exchange Protocols + +Exchange protocols describe how to transmit serialized OpenTelemetry data. Beyond just defining which application and transport protocol should be used, the exchange protocol defines transmission qualities such as streaming, retry, acks, backpressure, and throttling. + +## Requirements + +### Support Common Topologies + +Be suitable for use between all of the following node types: instrumented applications, telemetry backends, local agents, stand-alone collectors/forwarders. + +* Be load-balancer friendly (do not hinder re-balancing). +* Allow backpressure signalling. + + +### Be Reliable and Observable + +* Prefer transports which have high reliability of data delivery. +* When data must be dropped, have visibility into what was not delivered. + + +### Be Efficient + +* Have low CPU usage for serialization and deserialization. +* Impose minimal pressure on memory manager, including pass-through scenarios, where deserialized data is short-lived and must be serialized as-is shortly after and where such short-lived data is created and discarded at high frequency (think telemetry data forwarders). +* Support ability to efficiently modify deserialized data and serialize again to pass further. This is related but slightly different from the previous requirement. +* Ensure high throughput (within the available bandwidth) in high latency networks (e.g. scenarios where telemetry source and the backend are separated by high latency network). + +--- + +# Appendix + + +## Currently Open Issues and PRs + +* Exchange Protocol: [https://github.com/open-telemetry/opentelemetry-specification/pull/193](https://github.com/open-telemetry/opentelemetry-specification/pull/193) + + +## Prior art + +* [https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-semantic-conventions.md](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-semantic-conventions.md) +* [https://github.com/open-telemetry/opentelemetry-proto/](https://github.com/open-telemetry/opentelemetry-proto/pull/21) +* [https://github.com/open-telemetry/opentelemetry-specification/tree/master/work_in_progress/typedspans](https://github.com/open-telemetry/opentelemetry-specification/tree/master/work_in_progress/typedspans) +* [https://github.com/dynatrace-innovationlab/TracingApiDatamodel](https://github.com/dynatrace-innovationlab/TracingApiDatamodel) + + +## Questions, TODOs + +* Should “span status” be at the logical or semantic layer? + * Already overlaps with some semantics, like `http.status` + * Separate PR for this +* Are transports separate from the exchange protocol? + * Supported Transport protocols, such as HTTP and UDP, may be part of the exchange protocol, or they may be a separate layer. + * [https://github.com/open-telemetry/opentelemetry-specification/pull/193#issuecomment-516325059](https://github.com/open-telemetry/opentelemetry-specification/pull/193#issuecomment-516325059) From 3dc6a7633c623bf6f19105e15fa939c0134dd728 Mon Sep 17 00:00:00 2001 From: Ted Young Date: Thu, 22 Aug 2019 08:59:05 -0700 Subject: [PATCH 06/36] whitespace Co-Authored-By: Reiley Yang --- text/0000-data-formats.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-data-formats.md b/text/0000-data-formats.md index 21546f075..1dd91bde5 100644 --- a/text/0000-data-formats.md +++ b/text/0000-data-formats.md @@ -1,7 +1,7 @@ # RFC: Data Formats for OpenTelemetry # Overview -OpenTelemetry is an observability system, which generates observations, and then sends that data to remote systems for analysis. Describing how this observability data is represented and transmitted is critical part of the OpenTelemetry specification. +OpenTelemetry is an observability system, which generates observations, and then sends that data to remote systems for analysis. Describing how this observability data is represented and transmitted is critical part of the OpenTelemetry specification. **Proposed Layers** * Metadata and Semantic Conventions From 459435e850e8467ad9eb991a437c688f37714278 Mon Sep 17 00:00:00 2001 From: Ted Young Date: Thu, 22 Aug 2019 08:59:24 -0700 Subject: [PATCH 07/36] Capitalization Co-Authored-By: Reiley Yang --- text/0000-data-formats.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-data-formats.md b/text/0000-data-formats.md index 1dd91bde5..0143bd9cf 100644 --- a/text/0000-data-formats.md +++ b/text/0000-data-formats.md @@ -17,7 +17,7 @@ Spans represent specific operations in and between systems. Some of these operat ## Requirements -### Handle complex data +### Handle Complex Data Semantic information is often complex and multi-valued. How we represent semantic data is related to how attributes are defined at the logical layer. From c9c64f46d8fc7c75fe75bf7e8112a606f308a2ec Mon Sep 17 00:00:00 2001 From: Ted Young Date: Thu, 22 Aug 2019 08:59:38 -0700 Subject: [PATCH 08/36] whitespace Co-Authored-By: Reiley Yang --- text/0000-data-formats.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-data-formats.md b/text/0000-data-formats.md index 0143bd9cf..c64451af0 100644 --- a/text/0000-data-formats.md +++ b/text/0000-data-formats.md @@ -40,7 +40,7 @@ Not all semantics conventions and common operations are known at this time. It m #### RPC calls -Modeling distributed transactions is a core usecase, it is common to analyze errors and latency for RPC calls. Because multiple individual network requests may be involved in a single logical RPC operation, it must be possible to describe RPC calls as logical operations, independent from the descriptions of transport and application protocols which they contain. +Modeling distributed transactions is a core usecase, it is common to analyze errors and latency for RPC calls. Because multiple individual network requests may be involved in a single logical RPC operation, it must be possible to describe RPC calls as logical operations, independent from the descriptions of transport and application protocols which they contain. Examples: * A client sending a request to a remote server. From c3c7c24e86a2ed4fecdb3ff12f75da759d9ffc0b Mon Sep 17 00:00:00 2001 From: tedsuo Date: Tue, 10 Sep 2019 13:19:09 -0700 Subject: [PATCH 09/36] CleanBaggage -> ClearBaggage --- text/0000-separate-context-propagation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-separate-context-propagation.md b/text/0000-separate-context-propagation.md index bf6cce277..b23d5bb0f 100644 --- a/text/0000-separate-context-propagation.md +++ b/text/0000-separate-context-propagation.md @@ -57,8 +57,8 @@ To access the distributed state of an application, the Baggage API provides a fu **RemoveBaggage( context, key) context** To delete distributed state from an application, the Baggage API provides a function which takes a context, a key, and a value as input, and returns an updated context which contains the new value. -**CleanBaggage( context) context** -To avoid sending baggage to an untrusted downstream process, the Baggage API provides a function remove all baggage from a context. +**ClearBaggage( context) context** +To avoid sending baggage to an untrusted downstream process, the Baggage API provides a function remove all baggage from a context. **GetPropagator( type) inject, extract** To register with the propagation system, the Baggage API provides a set of propagation functions for every propagation type. From 45880966ba64cf51059a603a50af3afbca3fc1c9 Mon Sep 17 00:00:00 2001 From: tedsuo Date: Tue, 10 Sep 2019 13:22:25 -0700 Subject: [PATCH 10/36] move function descriptions to new line --- text/0000-separate-context-propagation.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/text/0000-separate-context-propagation.md b/text/0000-separate-context-propagation.md index b23d5bb0f..9c822194d 100644 --- a/text/0000-separate-context-propagation.md +++ b/text/0000-separate-context-propagation.md @@ -32,13 +32,13 @@ To allow for this extensibility, OpenTelemetry is separated into **application l OpenTelemetry currently contains two observability systems - Tracing and Metrics – and may be extended over time. These separate systems are bound into a unified Observability API through sharing labels – a mechanism for correlating independent observations – and through sharing propagators. -**Observe( context, labels…, observations...) context** +**Observe( context, labels…, observations...) context** The general form for all observability APIs is a function which takes a Context, label keys, and observations as input, and returns an updated Context. -**Correlate( context, label, value, hoplimit) context** +**Correlate( context, label, value, hoplimit) context** To set the label values used by all observations in the current transaction, the Observability API provides a function which takes a context, a label key, a value, and a hoplimit, and returns an updated context. If the hoplimit is set to NO_PROPAGATION, the label will only be available to observability functions in the same process. If the hoplimit is set to UNLIMITED_PROPAGATION, it will be available to all downstream services. -**GetPropagator( type) inject, extract** +**GetPropagator( type) inject, extract** To register with the propagation system, the Observability API provides a set of propagation functions for every propagation type. @@ -48,19 +48,24 @@ In addition to observability, OpenTelemetry provides a simple mechanism for prop To manage the state of a distributed application, the Baggage API provides a set of functions which read, write, and remove data. -**SetBaggage(context, key, value) context** +**SetBaggage(context, key, value) context** To record the distributed state of an application, the Baggage API provides a function which takes a context, a key, and a value as input, and returns an updated context which contains the new value. -**GetBaggage( context, key) value** +**GetBaggage( context, key) value** To access the distributed state of an application, the Baggage API provides a function which takes a context and a key as input, and returns a value. -**RemoveBaggage( context, key) context** +**RemoveBaggage( context, key) context** To delete distributed state from an application, the Baggage API provides a function which takes a context, a key, and a value as input, and returns an updated context which contains the new value. +<<<<<<< HEAD **ClearBaggage( context) context** To avoid sending baggage to an untrusted downstream process, the Baggage API provides a function remove all baggage from a context. +======= +**ClearBaggage( context) context** +To avoid sending baggage to an untrusted downstream process, the Baggage API provides a function remove all baggage from a context, +>>>>>>> move function descriptions to new line -**GetPropagator( type) inject, extract** +**GetPropagator( type) inject, extract** To register with the propagation system, the Baggage API provides a set of propagation functions for every propagation type. @@ -68,7 +73,7 @@ To register with the propagation system, the Baggage API provides a set of propa Because the application and context propagation layers are separated, it is possible to create new distributed applications which do not depend on either the Observability or Baggage APIs. -**GetPropagator(type) inject, extract** +**GetPropagator(type) inject, extract** To register with the propagation system, additional APIs provide a set of propagation functions for every propagation type. From 2d80daebbb74a850097d582fbcb59f2c47f6acbb Mon Sep 17 00:00:00 2001 From: tedsuo Date: Tue, 10 Sep 2019 13:30:35 -0700 Subject: [PATCH 11/36] Add Optional subheader --- text/0000-separate-context-propagation.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/text/0000-separate-context-propagation.md b/text/0000-separate-context-propagation.md index 9c822194d..da3385b3a 100644 --- a/text/0000-separate-context-propagation.md +++ b/text/0000-separate-context-propagation.md @@ -89,13 +89,13 @@ To record the local state of an application, the Context API provides a function **GetValue( context, key) value** To access the local state of an application, the Context API provides a function which takes a context and a key as input, and returns a value. -**Optional: Automated Context Management** +### Optional: Automated Context Management When possible, context should automatically be associated with program execution . Note that some languages do not provide any facility for setting and getting a current context. In these cases, the user is responsible for managing the current context. -**Optional: SetCurrentContext( context)** +**SetCurrentContext( context)** To associate a context with program execution, the Context API provides a function which takes a Context. -**Optional: GetCurrentContext() context** +**GetCurrentContext() context** To access the context associated with program execution, the Context API provides a function which takes no arguments and returns a Context. From 7a73210fb0d7a6374eb7dbf82d21abbffc77e060 Mon Sep 17 00:00:00 2001 From: tedsuo Date: Tue, 10 Sep 2019 13:35:19 -0700 Subject: [PATCH 12/36] cleanup rough edits --- text/0000-separate-context-propagation.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/text/0000-separate-context-propagation.md b/text/0000-separate-context-propagation.md index da3385b3a..c18d96769 100644 --- a/text/0000-separate-context-propagation.md +++ b/text/0000-separate-context-propagation.md @@ -141,9 +141,7 @@ In order for Context to function, it must always remain bound to the execution o In some languages, a single, widely used Context implementation exists. In other languages, there many be too many implementations, or none at all. In the cases where there is not an extremely clear pre-existing option available, OpenTelemetry should provide its own Context implementation. -While the above explanation represents the default OpenTelemetry approach to context propagation, it is important to note that some languages may already contain a form of context propagation. For example, Go has a the context.Context object, and widespread conventions for how to pass. - -Span data is used as labels for metrics and traces. This can quickly add overhead when propagated in-band. But, because this data is write-only, how this information is transmitted remains undefined. +While the specification defines the default OpenTelemetry approach to context propagation, it is important to note that in some languages, a form of context propagation may already exist. For example, Go has a the context.Context object, and widespread conventions for how to pass it down the call stack. ## Default Propagators @@ -158,7 +156,7 @@ Since Baggage Context and Correlation Context appear very similar, why have two? First and foremost, the intended uses for Baggage and Correlations are completely different. Secondly, the propagation requirements diverge significantly. -Correlations values are solely to be used as labels for metrics and traces. By making Correlation Context data write-only, how and when it is transmitted remains undefined. This leaves the door open to optimizations, such as propagating some data out-of-band, and situations where sampling decisions may cease the need to propagate correlation context any further. +Correlation values are solely to be used as labels for metrics and traces. By making Correlation data write-only, how and when it is transmitted remains undefined. This leaves the door open to optimizations, such as propagating some data out-of-band, and situations where sampling decisions may cease the need to propagate correlation context any further. Baggage values, on the other hand, are explicitly added in order to be accessed by downstream by other application code. Therefore, Baggage Context must be readable, and reliably propagated in-band in order to accomplish this goal. From 0d8e41be26baba8b3af4e46e1d708599db3518a0 Mon Sep 17 00:00:00 2001 From: tedsuo Date: Tue, 10 Sep 2019 14:04:40 -0700 Subject: [PATCH 13/36] clean up advice on pre-existing context implementations --- text/0000-separate-context-propagation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-separate-context-propagation.md b/text/0000-separate-context-propagation.md index c18d96769..96ab66535 100644 --- a/text/0000-separate-context-propagation.md +++ b/text/0000-separate-context-propagation.md @@ -139,9 +139,9 @@ In order for Context to function, it must always remain bound to the execution o ## Pre-existing Context implementations -In some languages, a single, widely used Context implementation exists. In other languages, there many be too many implementations, or none at all. In the cases where there is not an extremely clear pre-existing option available, OpenTelemetry should provide its own Context implementation. +In some languages, a single, widely used Context implementation exists. In other languages, there many be too many implementations, or none at all. For example, Go has a the context.Context object, and widespread conventions for how to pass it down the call stack. -While the specification defines the default OpenTelemetry approach to context propagation, it is important to note that in some languages, a form of context propagation may already exist. For example, Go has a the context.Context object, and widespread conventions for how to pass it down the call stack. +In the cases where an extremely clear, pre-existing option is not available, OpenTelemetry should provide its own Context implementation. ## Default Propagators From aad5605de488a4873904f33d1ed283ea47a16e72 Mon Sep 17 00:00:00 2001 From: tedsuo Date: Tue, 10 Sep 2019 14:16:00 -0700 Subject: [PATCH 14/36] Better context descriptions --- text/0000-separate-context-propagation.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/text/0000-separate-context-propagation.md b/text/0000-separate-context-propagation.md index 96ab66535..3c2f054cc 100644 --- a/text/0000-separate-context-propagation.md +++ b/text/0000-separate-context-propagation.md @@ -124,11 +124,11 @@ OpenTelemetry currently contains two types of Propagators: ## Context details OpenTelemetry currently implements three context types of context propagation. -**Span Context -** Observability data used by the tracing system. The readable attributes are defined to match those found in the W3C **traceparent** header. Span Context is used as labels for metrics and traces. This can quickly add overhead when propagated in-band. But, because this data is write-only, how this information is transmitted remains undefined. +**Span Context -** The serializable portion of a span, which is injected and extracted. The readable attributes are defined to match those found in the W3C **traceparent** header. -**Correlation Context -** Transaction-level observability data, which can be applied as labels to spans and metrics. +**Correlation Context -** Correlation Context contains a map of labels and values, to be shared between metrics and traces. This allows observability data to be indexed and dimensionalized in a variety of ways. Note that correlations can quickly add overhead when propagated in-band. But because this data is write-only, it may be possible to optimize how it is transmitted. -**Baggage Context -** Transaction-level application data, meant to be shared with downstream components. +**Baggage Context -** Transaction-level application data, meant to be shared with downstream components. This data is readable, and must be propagated in-band. Because of this, Baggage should be used sparingly, to avoid ballooning the size of RPC requests. Note that when possible, OpenTelemetry APIs calls are given access to the entire context object, and not a specific context type. From 4a930ebb612ec286c426b1bd8c1c6060a1908d33 Mon Sep 17 00:00:00 2001 From: tedsuo Date: Tue, 10 Sep 2019 19:54:56 -0700 Subject: [PATCH 15/36] remove data format file --- text/0000-data-formats.md | 151 -------------------------------------- 1 file changed, 151 deletions(-) delete mode 100644 text/0000-data-formats.md diff --git a/text/0000-data-formats.md b/text/0000-data-formats.md deleted file mode 100644 index c64451af0..000000000 --- a/text/0000-data-formats.md +++ /dev/null @@ -1,151 +0,0 @@ -# RFC: Data Formats for OpenTelemetry - -# Overview -OpenTelemetry is an observability system, which generates observations, and then sends that data to remote systems for analysis. Describing how this observability data is represented and transmitted is critical part of the OpenTelemetry specification. - -**Proposed Layers** -* Metadata and Semantic Conventions -* Logical Structure -* Encodings -* Exchange Protocols - - -# Metadata and Semantic Conventions - -Spans represent specific operations in and between systems. Some of these operations represent calls that use well-known protocols like HTTP or database calls. Depending on the protocol and the type of operation, additional information is needed to represent and analyze a span correctly in monitoring systems. It is also important to unify how this attribution is made in different languages. This way, the operator will not need to learn specifics of a language and telemetry collected from multi-language micro-service can still be easily correlated and cross-analyzed. - -## Requirements - - -### Handle Complex Data - -Semantic information is often complex and multi-valued. How we represent semantic data is related to how attributes are defined at the logical layer. - -* At minimum, nested lists of key/value pairs are necessary to represent them. -* Is it advantageous to also have strongly typed data structures? -* Are there issues with having strongly typed data structures in certain environment, such as dynamic languages? - - -### Compose Multiple Semantics - -Objects in OpenTelemetry may describe more than one type of operation. For example, a span may simultaneously represent a MySQL transaction and a TCP/IP request. Pieces of metadata must compose well, without losing the structure integrity of each piece or risking a conflict in meaning. - - -### Easily Extensible - -Not all semantics conventions and common operations are known at this time. It must be possible to add more semantic definitions without creating to versioning or compatibility issues with OpenTelemetry implementations. - - -## Examples of Common Operations - -#### RPC calls - -Modeling distributed transactions is a core usecase, it is common to analyze errors and latency for RPC calls. Because multiple individual network requests may be involved in a single logical RPC operation, it must be possible to describe RPC calls as logical operations, independent from the descriptions of transport and application protocols which they contain. - -Examples: -* A client sending a request to a remote server. -* A server receiving a request from a remote client. -* Logical vs physical networking: a request for “[https://www.wikipedia.org/wiki/Rabbit](https://www.wikipedia.org/wiki/Rabbit)” results in two physical HTTP requests - one 301 redirection, and another 200 okay. The logical RPC operation represents both requests together. - -#### Network protocols - -The internet suite of network protocols is thoroughly standardized, and the details of network interactions calls are critical to analysing the behavior of distributed systems. - -Examples: -* Application Protocols: HTTP/1.1, HTTP/2, gRPC -* Transport Protocols: TCP, UDP -* Internet Protocols: IPv4, IPv6 - -#### Database protocols - -Database requests often contain information which is key to root causing errors and latency. - -Examples: -* SQL: MySQL, Postrgres -* NoSQL: MongoDB - - -# Logical Structure - -OpenTelemetry observability model, defined as data structures instead of API calls. A logical layer describes the default data structures expected to be produced by OpenTelemetry APIs for transport. - -## Requirements - -### Support Metadata - -The logical structure must be able to support all of the requirements for the metadata layer. - - -### Support both an API and a Streaming Representation - -OpenTelemetry data structures must work well with the APIs and SDKs which produce them. It must be possible to stream data from services without resorting to an encoding or exchange protocol which bears little resemblance to the API. - - -# Encoding Formats - -While there is a single set of OpenTelemetry data structures, they can be encoded in a variety of serialization formats. - -## Requirements - -### Prefer pre-existing formats - -Codecs must be commonly available in all major languages. It is outside the bounds of the OpenTelemetry project to define new serialization formats. - -**Examples:** -* Protobuf -* JSON - - -# Exchange Protocols - -Exchange protocols describe how to transmit serialized OpenTelemetry data. Beyond just defining which application and transport protocol should be used, the exchange protocol defines transmission qualities such as streaming, retry, acks, backpressure, and throttling. - -## Requirements - -### Support Common Topologies - -Be suitable for use between all of the following node types: instrumented applications, telemetry backends, local agents, stand-alone collectors/forwarders. - -* Be load-balancer friendly (do not hinder re-balancing). -* Allow backpressure signalling. - - -### Be Reliable and Observable - -* Prefer transports which have high reliability of data delivery. -* When data must be dropped, have visibility into what was not delivered. - - -### Be Efficient - -* Have low CPU usage for serialization and deserialization. -* Impose minimal pressure on memory manager, including pass-through scenarios, where deserialized data is short-lived and must be serialized as-is shortly after and where such short-lived data is created and discarded at high frequency (think telemetry data forwarders). -* Support ability to efficiently modify deserialized data and serialize again to pass further. This is related but slightly different from the previous requirement. -* Ensure high throughput (within the available bandwidth) in high latency networks (e.g. scenarios where telemetry source and the backend are separated by high latency network). - ---- - -# Appendix - - -## Currently Open Issues and PRs - -* Exchange Protocol: [https://github.com/open-telemetry/opentelemetry-specification/pull/193](https://github.com/open-telemetry/opentelemetry-specification/pull/193) - - -## Prior art - -* [https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-semantic-conventions.md](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-semantic-conventions.md) -* [https://github.com/open-telemetry/opentelemetry-proto/](https://github.com/open-telemetry/opentelemetry-proto/pull/21) -* [https://github.com/open-telemetry/opentelemetry-specification/tree/master/work_in_progress/typedspans](https://github.com/open-telemetry/opentelemetry-specification/tree/master/work_in_progress/typedspans) -* [https://github.com/dynatrace-innovationlab/TracingApiDatamodel](https://github.com/dynatrace-innovationlab/TracingApiDatamodel) - - -## Questions, TODOs - -* Should “span status” be at the logical or semantic layer? - * Already overlaps with some semantics, like `http.status` - * Separate PR for this -* Are transports separate from the exchange protocol? - * Supported Transport protocols, such as HTTP and UDP, may be part of the exchange protocol, or they may be a separate layer. - * [https://github.com/open-telemetry/opentelemetry-specification/pull/193#issuecomment-516325059](https://github.com/open-telemetry/opentelemetry-specification/pull/193#issuecomment-516325059) From e1ef61fb074fa1dfe1a3b836e81180c547605a4f Mon Sep 17 00:00:00 2001 From: tedsuo Date: Tue, 10 Sep 2019 19:56:53 -0700 Subject: [PATCH 16/36] remove git diff message --- text/0000-separate-context-propagation.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/text/0000-separate-context-propagation.md b/text/0000-separate-context-propagation.md index 3c2f054cc..e6857210a 100644 --- a/text/0000-separate-context-propagation.md +++ b/text/0000-separate-context-propagation.md @@ -57,13 +57,8 @@ To access the distributed state of an application, the Baggage API provides a fu **RemoveBaggage( context, key) context** To delete distributed state from an application, the Baggage API provides a function which takes a context, a key, and a value as input, and returns an updated context which contains the new value. -<<<<<<< HEAD -**ClearBaggage( context) context** -To avoid sending baggage to an untrusted downstream process, the Baggage API provides a function remove all baggage from a context. -======= **ClearBaggage( context) context** To avoid sending baggage to an untrusted downstream process, the Baggage API provides a function remove all baggage from a context, ->>>>>>> move function descriptions to new line **GetPropagator( type) inject, extract** To register with the propagation system, the Baggage API provides a set of propagation functions for every propagation type. From f94943501d91b261d10d252cde33fa81abd2f70d Mon Sep 17 00:00:00 2001 From: tedsuo Date: Tue, 10 Sep 2019 19:58:57 -0700 Subject: [PATCH 17/36] improved code sytnax --- text/0000-separate-context-propagation.md | 32 +++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/text/0000-separate-context-propagation.md b/text/0000-separate-context-propagation.md index e6857210a..ff09ec8d2 100644 --- a/text/0000-separate-context-propagation.md +++ b/text/0000-separate-context-propagation.md @@ -32,13 +32,13 @@ To allow for this extensibility, OpenTelemetry is separated into **application l OpenTelemetry currently contains two observability systems - Tracing and Metrics – and may be extended over time. These separate systems are bound into a unified Observability API through sharing labels – a mechanism for correlating independent observations – and through sharing propagators. -**Observe( context, labels…, observations...) context** +**Observe(context, labels…, observations...) -> context** The general form for all observability APIs is a function which takes a Context, label keys, and observations as input, and returns an updated Context. -**Correlate( context, label, value, hoplimit) context** +**Correlate(context, label, value, hoplimit) -> context** To set the label values used by all observations in the current transaction, the Observability API provides a function which takes a context, a label key, a value, and a hoplimit, and returns an updated context. If the hoplimit is set to NO_PROPAGATION, the label will only be available to observability functions in the same process. If the hoplimit is set to UNLIMITED_PROPAGATION, it will be available to all downstream services. -**GetPropagator( type) inject, extract** +**GetPropagator(type) -> (inject, extract)** To register with the propagation system, the Observability API provides a set of propagation functions for every propagation type. @@ -48,19 +48,19 @@ In addition to observability, OpenTelemetry provides a simple mechanism for prop To manage the state of a distributed application, the Baggage API provides a set of functions which read, write, and remove data. -**SetBaggage(context, key, value) context** +**SetBaggage(context, key, value) -> context** To record the distributed state of an application, the Baggage API provides a function which takes a context, a key, and a value as input, and returns an updated context which contains the new value. -**GetBaggage( context, key) value** +**GetBaggage(context, key) -> value** To access the distributed state of an application, the Baggage API provides a function which takes a context and a key as input, and returns a value. -**RemoveBaggage( context, key) context** +**RemoveBaggage(context, key) -> context** To delete distributed state from an application, the Baggage API provides a function which takes a context, a key, and a value as input, and returns an updated context which contains the new value. -**ClearBaggage( context) context** +**ClearBaggage(context) -> context** To avoid sending baggage to an untrusted downstream process, the Baggage API provides a function remove all baggage from a context, -**GetPropagator( type) inject, extract** +**GetPropagator(type) -> (inject, extract)** To register with the propagation system, the Baggage API provides a set of propagation functions for every propagation type. @@ -68,7 +68,7 @@ To register with the propagation system, the Baggage API provides a set of propa Because the application and context propagation layers are separated, it is possible to create new distributed applications which do not depend on either the Observability or Baggage APIs. -**GetPropagator(type) inject, extract** +**GetPropagator(type) -> (inject, extract)** To register with the propagation system, additional APIs provide a set of propagation functions for every propagation type. @@ -78,19 +78,19 @@ To register with the propagation system, additional APIs provide a set of propag Distributed applications access data in-process using a shared context object. Each distributed application sets a single key in the context, containing all of the data for that system. -**SetValue( context, key, value) context** +**SetValue(context, key, value) -> context** To record the local state of an application, the Context API provides a function which takes a context, a key, and a value as input, and returns an updated context which contains the new value. -**GetValue( context, key) value** +**GetValue(context, key) -> value** To access the local state of an application, the Context API provides a function which takes a context and a key as input, and returns a value. ### Optional: Automated Context Management When possible, context should automatically be associated with program execution . Note that some languages do not provide any facility for setting and getting a current context. In these cases, the user is responsible for managing the current context. -**SetCurrentContext( context)** +**SetCurrentContext(context)** To associate a context with program execution, the Context API provides a function which takes a Context. -**GetCurrentContext() context** +**GetCurrentContext() -> context** To access the context associated with program execution, the Context API provides a function which takes no arguments and returns a Context. @@ -98,13 +98,13 @@ To access the context associated with program execution, the Context API provide Distributed applications send data to downstream processes via propagators, functions which read and write application context into RPC requests. Each distributed application creates a set of propagators for every type of supported medium - currently HTTP and Binary. -**Inject( context, request)** +**Inject(context, request)** To send the data for all distributed applications downstream to the next process, the Propagation API provides a function which takes a context and a request, and mutates the request to include the encoded context. The canonical representation of a request is as a map. -**Extract( context, request) context** +**Extract(context, request) -> context** To receive data injected by prior upstream processes, the Propagation API provides a function which takes a context and a request, and returns an updated context. -**RegisterPropagator( type, inject, extract)** +**RegisterPropagator(type, inject, extract)** In order for the application layer to function correctly, Propagation choices must be syncronized between all processes in the distributed system, and multiple applications must be able to inject and extract their context into the same request. To meet these requirements, the Propagation API provides a function which registers a set of propagators, which will all be executed in order when the future calls to inject and extract are made. A canonical propagator consists of an inject and an extract function. OpenTelemetry currently contains two types of Propagators: From 1cb155efd784a52d50f3ae5b0fe00983006dd654 Mon Sep 17 00:00:00 2001 From: tedsuo Date: Tue, 10 Sep 2019 20:00:40 -0700 Subject: [PATCH 18/36] stop stuttering --- text/0000-separate-context-propagation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-separate-context-propagation.md b/text/0000-separate-context-propagation.md index ff09ec8d2..3bffe9664 100644 --- a/text/0000-separate-context-propagation.md +++ b/text/0000-separate-context-propagation.md @@ -87,10 +87,10 @@ To access the local state of an application, the Context API provides a function ### Optional: Automated Context Management When possible, context should automatically be associated with program execution . Note that some languages do not provide any facility for setting and getting a current context. In these cases, the user is responsible for managing the current context. -**SetCurrentContext(context)** +**SetCurrent(context)** To associate a context with program execution, the Context API provides a function which takes a Context. -**GetCurrentContext() -> context** +**GetCurrent() -> context** To access the context associated with program execution, the Context API provides a function which takes no arguments and returns a Context. From 7b9e86188827c74876cd7b07a2b191acb606a7f2 Mon Sep 17 00:00:00 2001 From: Ted Young Date: Tue, 10 Sep 2019 20:02:48 -0700 Subject: [PATCH 19/36] Update text/0000-separate-context-propagation.md Co-Authored-By: Reiley Yang --- text/0000-separate-context-propagation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-separate-context-propagation.md b/text/0000-separate-context-propagation.md index 3bffe9664..0fcff1c7f 100644 --- a/text/0000-separate-context-propagation.md +++ b/text/0000-separate-context-propagation.md @@ -190,4 +190,4 @@ Given that we must ship with working propagators, and the W3C specifications are # Future possibilities -Cleanly splitting OpenTelemetry into an Application and Context Propagation layer may allow us to move the Context Propagation layer into its own, stand-alone project. This may facilitate adoption, by allowing us to share Context Propagation with gRPC and other projects. +Cleanly splitting OpenTelemetry into an Application and Context Propagation layer may allow us to move the Context Propagation layer into its own, stand-alone project. This may facilitate adoption, by allowing us to share Context Propagation with gRPC and other projects. From 07eb397257f1de112ae0b05a02f406d7de5722c8 Mon Sep 17 00:00:00 2001 From: tedsuo Date: Tue, 10 Sep 2019 20:04:33 -0700 Subject: [PATCH 20/36] spacing --- text/0000-separate-context-propagation.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/text/0000-separate-context-propagation.md b/text/0000-separate-context-propagation.md index 0fcff1c7f..6a29f00ae 100644 --- a/text/0000-separate-context-propagation.md +++ b/text/0000-separate-context-propagation.md @@ -7,7 +7,7 @@ Design OpenTelemetry as a set of separate applications which operate on a shared ## Motivation -Based on prior art, we know that fusing the observability system and the context propagation system together creates issues. Observability systems have special rules for propagating information, such as sampling, and may have different requirements from other systems which require non-local information to be sent downstream. +Based on prior art, we know that fusing the observability system and the context propagation system together creates issues. Observability systems have special rules for propagating information, such as sampling, and may have different requirements from other systems which require non-local information to be sent downstream. * Separation of concerns * Remove the Tracer dependency from context propagation mechanisms. * Separate distributed context into Baggage and Correlations @@ -23,7 +23,7 @@ Based on prior art, we know that fusing the observability system and the context OpenTelemetry is a distributed program, which requires non-local, transaction-level context in order to execute correctly. Transaction-level context can also be used to build other distributed programs, such as security, versioning, and network switching programs. -To allow for this extensibility, OpenTelemetry is separated into **application layer** and a **context propagation layer**. In this architecture, multiple distributed applications - such as the observability and baggage systems provided by OpenTelemetry - simultaneously share the same underlying context propagation system in order to execute their programs. +To allow for this extensibility, OpenTelemetry is separated into **application layer** and a **context propagation layer**. In this architecture, multiple distributed applications - such as the observability and baggage systems provided by OpenTelemetry - simultaneously share the same underlying context propagation system in order to execute their programs. # Application Layer @@ -130,7 +130,7 @@ Note that when possible, OpenTelemetry APIs calls are given access to the entire ## Context Management and in-process propagation -In order for Context to function, it must always remain bound to the execution of code it represents. By default, this means that the programmer must pass a Context down the call stack as a function parameter. However, many languages provide automated context management facilities, such as thread locals. OpenTelemetry should leverage these facilities when available, in order to provide automatic context management. +In order for Context to function, it must always remain bound to the execution of code it represents. By default, this means that the programmer must pass a Context down the call stack as a function parameter. However, many languages provide automated context management facilities, such as thread locals. OpenTelemetry should leverage these facilities when available, in order to provide automatic context management. ## Pre-existing Context implementations From 0ebeb6c52451b8dde55c97d29d0d61e78fe1b002 Mon Sep 17 00:00:00 2001 From: tedsuo Date: Wed, 25 Sep 2019 12:50:49 -0700 Subject: [PATCH 21/36] Refine propagation * Remove registry concept * Add explicit chaining --- text/0000-separate-context-propagation.md | 40 +++++++++++++---------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/text/0000-separate-context-propagation.md b/text/0000-separate-context-propagation.md index 6a29f00ae..749271632 100644 --- a/text/0000-separate-context-propagation.md +++ b/text/0000-separate-context-propagation.md @@ -23,7 +23,7 @@ Based on prior art, we know that fusing the observability system and the context OpenTelemetry is a distributed program, which requires non-local, transaction-level context in order to execute correctly. Transaction-level context can also be used to build other distributed programs, such as security, versioning, and network switching programs. -To allow for this extensibility, OpenTelemetry is separated into **application layer** and a **context propagation layer**. In this architecture, multiple distributed applications - such as the observability and baggage systems provided by OpenTelemetry - simultaneously share the same underlying context propagation system in order to execute their programs. +To allow for this extensibility, OpenTelemetry is separated into an **application layer** and a **context propagation layer**. In this architecture, multiple distributed applications - such as the observability and baggage systems provided by OpenTelemetry - simultaneously share the same underlying context propagation system in order to execute their programs. # Application Layer @@ -38,8 +38,11 @@ The general form for all observability APIs is a function which takes a Context, **Correlate(context, label, value, hoplimit) -> context** To set the label values used by all observations in the current transaction, the Observability API provides a function which takes a context, a label key, a value, and a hoplimit, and returns an updated context. If the hoplimit is set to NO_PROPAGATION, the label will only be available to observability functions in the same process. If the hoplimit is set to UNLIMITED_PROPAGATION, it will be available to all downstream services. -**GetPropagator(type) -> (inject, extract)** -To register with the propagation system, the Observability API provides a set of propagation functions for every propagation type. +**GetHTTPExtractor() -> extractor** +To deserialize the state of the observability system in the prior upstream process, the Observability API provides a function which returns a HTTPExtract function. + +**GetHTTPInjector() -> injector** +To serialize the the current state of the observability system and send it to the next downstream process, the Observability API provides a function which returns a HTTPInject function. ## Baggage API @@ -59,17 +62,22 @@ To delete distributed state from an application, the Baggage API provides a func **ClearBaggage(context) -> context** To avoid sending baggage to an untrusted downstream process, the Baggage API provides a function remove all baggage from a context, +**GetHTTPExtractor() -> extractor** +To deserialize the state of the system in the prior upstream process, the Baggage API provides a function which returns a HTTPExtract function. -**GetPropagator(type) -> (inject, extract)** -To register with the propagation system, the Baggage API provides a set of propagation functions for every propagation type. +**GetHTTPInjector() -> injector** +To serialize the the current state of the system and send it to the next downstream process, the Baggage API provides a function which returns a HTTPInject function. ## Additional APIs Because the application and context propagation layers are separated, it is possible to create new distributed applications which do not depend on either the Observability or Baggage APIs. -**GetPropagator(type) -> (inject, extract)** -To register with the propagation system, additional APIs provide a set of propagation functions for every propagation type. +**GetHTTPExtractor() -> extractor** +To deserialize the state of the system in the prior upstream process, all additional APIs provide a function which returns a HTTPExtract function. + +**GetHTTPInjector() -> injector** +To serialize the the current state of the system and send it to the next downstream process, all additional APIs provide a function which returns a HTTPInject function. # Context Propagation Layer @@ -96,21 +104,19 @@ To access the context associated with program execution, the Context API provide ## Propagation API -Distributed applications send data to downstream processes via propagators, functions which read and write application context into RPC requests. Each distributed application creates a set of propagators for every type of supported medium - currently HTTP and Binary. +Distributed applications propagate their state by data to downstream processes via injectors, functions which read and write application context into RPC requests. Each distributed application creates a set of propagators for every type of supported medium - currently only HTTP requests. -**Inject(context, request)** -To send the data for all distributed applications downstream to the next process, the Propagation API provides a function which takes a context and a request, and mutates the request to include the encoded context. The canonical representation of a request is as a map. +**HTTPInject(context, request)** +To send the data for all distributed applications downstream to the next process, the Propagation API provides a function which takes a context and an HTTP request, and mutates the HTTP request to include an HTTP Header representation of the context. -**Extract(context, request) -> context** -To receive data injected by prior upstream processes, the Propagation API provides a function which takes a context and a request, and returns an updated context. +**HTTPExtract(context, request) -> context** +To receive data injected by prior upstream processes, the Propagation API provides a function which takes a context and an HTTP request, and returns context which represents the state of the upstream system. -**RegisterPropagator(type, inject, extract)** +**ChainHTTPInjector(injector, injector) injector** In order for the application layer to function correctly, Propagation choices must be syncronized between all processes in the distributed system, and multiple applications must be able to inject and extract their context into the same request. To meet these requirements, the Propagation API provides a function which registers a set of propagators, which will all be executed in order when the future calls to inject and extract are made. A canonical propagator consists of an inject and an extract function. -OpenTelemetry currently contains two types of Propagators: - -* **HTTP** - context is written into and read from a map of HTTP headers. -* **Binary** - context is serialized into and deserialized from a stream of bytes. +**ChainHTTPExtractor(extractor, extractor) extractor** +In order for the application layer to function correctly, Propagation choices must be syncronized between all processes in the distributed system, and multiple applications must be able to inject and extract their context into the same request. To meet these requirements, the Propagation API provides a function which registers a set of propagators, which will all be executed in order when the future calls to inject and extract are made. A canonical propagator consists of an inject and an extract function. # Internal details From 147d6b05e3127a0cb435fee92026d1da675e4404 Mon Sep 17 00:00:00 2001 From: tedsuo Date: Tue, 1 Oct 2019 00:34:40 -0700 Subject: [PATCH 22/36] Add RFC ID number from PR --- ...ontext-propagation.md => 0042-separate-context-propagation.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename text/{0000-separate-context-propagation.md => 0042-separate-context-propagation.md} (100%) diff --git a/text/0000-separate-context-propagation.md b/text/0042-separate-context-propagation.md similarity index 100% rename from text/0000-separate-context-propagation.md rename to text/0042-separate-context-propagation.md From 72d4651d85446bad4cbba1d00c269dab9c0867fe Mon Sep 17 00:00:00 2001 From: tedsuo Date: Tue, 1 Oct 2019 00:35:17 -0700 Subject: [PATCH 23/36] remove RFC status line --- text/0042-separate-context-propagation.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/text/0042-separate-context-propagation.md b/text/0042-separate-context-propagation.md index 749271632..1c9ae12f5 100644 --- a/text/0042-separate-context-propagation.md +++ b/text/0042-separate-context-propagation.md @@ -1,6 +1,4 @@ -# Proposal: Separate Layer for Context Propagation - -Status: `proposed` +# Proposal: Separate Layer for Context Propagation Design OpenTelemetry as a set of separate applications which operate on a shared context propagation mechanism. From 14721978c2208fbdb33f951bcd48384a1b37390b Mon Sep 17 00:00:00 2001 From: tedsuo Date: Tue, 1 Oct 2019 00:39:13 -0700 Subject: [PATCH 24/36] slight calrification for GetHTTPExtractor --- text/0042-separate-context-propagation.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/text/0042-separate-context-propagation.md b/text/0042-separate-context-propagation.md index 1c9ae12f5..e309596b4 100644 --- a/text/0042-separate-context-propagation.md +++ b/text/0042-separate-context-propagation.md @@ -37,7 +37,7 @@ The general form for all observability APIs is a function which takes a Context, To set the label values used by all observations in the current transaction, the Observability API provides a function which takes a context, a label key, a value, and a hoplimit, and returns an updated context. If the hoplimit is set to NO_PROPAGATION, the label will only be available to observability functions in the same process. If the hoplimit is set to UNLIMITED_PROPAGATION, it will be available to all downstream services. **GetHTTPExtractor() -> extractor** -To deserialize the state of the observability system in the prior upstream process, the Observability API provides a function which returns a HTTPExtract function. +To deserialize the state of the system sent from the prior upstream process, the Observability API provides a function which returns a HTTPExtract function. **GetHTTPInjector() -> injector** To serialize the the current state of the observability system and send it to the next downstream process, the Observability API provides a function which returns a HTTPInject function. @@ -60,8 +60,9 @@ To delete distributed state from an application, the Baggage API provides a func **ClearBaggage(context) -> context** To avoid sending baggage to an untrusted downstream process, the Baggage API provides a function remove all baggage from a context, + **GetHTTPExtractor() -> extractor** -To deserialize the state of the system in the prior upstream process, the Baggage API provides a function which returns a HTTPExtract function. +To deserialize the state of the system sent from the the prior upstream process, the Baggage API provides a function which returns a HTTPExtract function. **GetHTTPInjector() -> injector** To serialize the the current state of the system and send it to the next downstream process, the Baggage API provides a function which returns a HTTPInject function. @@ -75,7 +76,7 @@ Because the application and context propagation layers are separated, it is poss To deserialize the state of the system in the prior upstream process, all additional APIs provide a function which returns a HTTPExtract function. **GetHTTPInjector() -> injector** -To serialize the the current state of the system and send it to the next downstream process, all additional APIs provide a function which returns a HTTPInject function. +To serialize the the current state of the system and send it to the next downstream process, all additional APIs provide a function which returns a HTTPInject function. # Context Propagation Layer From 18a37d444a55c10b7a1dc7ef2f0180b8ef7372eb Mon Sep 17 00:00:00 2001 From: tedsuo Date: Tue, 1 Oct 2019 01:04:16 -0700 Subject: [PATCH 25/36] add global propagators --- text/0042-separate-context-propagation.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/text/0042-separate-context-propagation.md b/text/0042-separate-context-propagation.md index e309596b4..e81389786 100644 --- a/text/0042-separate-context-propagation.md +++ b/text/0042-separate-context-propagation.md @@ -117,6 +117,21 @@ In order for the application layer to function correctly, Propagation choices mu **ChainHTTPExtractor(extractor, extractor) extractor** In order for the application layer to function correctly, Propagation choices must be syncronized between all processes in the distributed system, and multiple applications must be able to inject and extract their context into the same request. To meet these requirements, the Propagation API provides a function which registers a set of propagators, which will all be executed in order when the future calls to inject and extract are made. A canonical propagator consists of an inject and an extract function. +### Optional: Global Propagators +It is often convenient to create a chain of propagators during program initialization, and then access these combined propagators later in the program. To facilitate this, global injectors and extractors are optionally available. However, there is no requirement to use this feature. + +**SetHTTPInjector(injector)** +To update the global injector, the Propagation API provides a function which takes an injector. + +**GetHTTPInjector() -> injector** +To access the global injector, the Propagation API provides a function which returns an injector. + +**SetHTTPExtractor(extractor)** +To update the global extractor, the Propagation API provides a function which takes an injector. + +**GetHTTPExtractor() -> extractor** +To access the global extractor, the Propagation API provides a function which returns an extractor. + # Internal details ![drawing](img/context_propagation_details.png) From 7ea1834f5a3cf739b1414954f339d7764af0b6a7 Mon Sep 17 00:00:00 2001 From: tedsuo Date: Mon, 14 Oct 2019 19:33:34 -0700 Subject: [PATCH 26/36] Clean up motivation --- text/0042-separate-context-propagation.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/text/0042-separate-context-propagation.md b/text/0042-separate-context-propagation.md index e81389786..6542aedc0 100644 --- a/text/0042-separate-context-propagation.md +++ b/text/0042-separate-context-propagation.md @@ -5,13 +5,16 @@ Design OpenTelemetry as a set of separate applications which operate on a shared ## Motivation -Based on prior art, we know that fusing the observability system and the context propagation system together creates issues. Observability systems have special rules for propagating information, such as sampling, and may have different requirements from other systems which require non-local information to be sent downstream. -* Separation of concerns - * Remove the Tracer dependency from context propagation mechanisms. - * Separate distributed context into Baggage and Correlations -* Extensibility - * Allow users to create new applications for context propagation. - * For example: A/B testing, encrypted or authenticated data, and new, experimental forms of observability. +Based on prior art, we know that fusing the observability system and the context propagation system together creates issues. Observability systems have special rules for propagating information, such as sampling. This can create difficulty for other systems, which may want to leverage the same context propagation mechanism, but have different rules and requirements regarding the data they are sending. The Baggage system within OpenTelemetry is one such example. + +This RFC addresses the following topics: + +**Separatation of concerns** +* Remove the Tracer dependency from context propagation mechanisms. +* Handle user data (Baggage) and observability data (Correlations) seprately. + +**Extensibility** +* Allow users to create new applications for context propagation. For example: A/B testing, encrypted or authenticated data, and new, experimental forms of observability. ## Explanation From 73177470a969ef0043b12d49e715d2074ce98e5b Mon Sep 17 00:00:00 2001 From: tedsuo Date: Mon, 14 Oct 2019 19:48:21 -0700 Subject: [PATCH 27/36] Clean up explanbation intro --- text/0042-separate-context-propagation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0042-separate-context-propagation.md b/text/0042-separate-context-propagation.md index 6542aedc0..6752ff4dd 100644 --- a/text/0042-separate-context-propagation.md +++ b/text/0042-separate-context-propagation.md @@ -22,9 +22,9 @@ This RFC addresses the following topics: ![drawing](img/context_propagation_explanation.png) -OpenTelemetry is a distributed program, which requires non-local, transaction-level context in order to execute correctly. Transaction-level context can also be used to build other distributed programs, such as security, versioning, and network switching programs. +Distributed tracing is an example of a cross-cutting concern, which requires non-local, transaction-level context propagation in order to execute correctly. Transaction-level context propagation can also be useful for other cross-cutting concerns, e.g., for security, versioning, and network switching. We refer to these types of cross-cutting concerns as **distributed applications**. -To allow for this extensibility, OpenTelemetry is separated into an **application layer** and a **context propagation layer**. In this architecture, multiple distributed applications - such as the observability and baggage systems provided by OpenTelemetry - simultaneously share the same underlying context propagation system in order to execute their programs. +OpenTelemetry is separated into an **application layer** and a **context propagation layer**. In this architecture, multiple distributed applications - including the observability and baggage systems provided by OpenTelemetry - share the same underlying context propagation system. # Application Layer From 43ba8fd36a1148713ab1f7954cee71898d0487d1 Mon Sep 17 00:00:00 2001 From: tedsuo Date: Mon, 14 Oct 2019 21:50:00 -0700 Subject: [PATCH 28/36] Clarify context types --- text/0042-separate-context-propagation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0042-separate-context-propagation.md b/text/0042-separate-context-propagation.md index 6752ff4dd..3ad53424a 100644 --- a/text/0042-separate-context-propagation.md +++ b/text/0042-separate-context-propagation.md @@ -95,7 +95,7 @@ To record the local state of an application, the Context API provides a function To access the local state of an application, the Context API provides a function which takes a context and a key as input, and returns a value. ### Optional: Automated Context Management -When possible, context should automatically be associated with program execution . Note that some languages do not provide any facility for setting and getting a current context. In these cases, the user is responsible for managing the current context. +When possible, the OpenTelemetry context should automatically be associated with the program execution context. Note that some languages do not provide any facility for setting and getting a current context. In these cases, the user is responsible for managing the current context. **SetCurrent(context)** To associate a context with program execution, the Context API provides a function which takes a Context. From d7d6f1c70a525249eb262d270a0e0530b0a9953a Mon Sep 17 00:00:00 2001 From: tedsuo Date: Mon, 14 Oct 2019 22:12:41 -0700 Subject: [PATCH 29/36] Fix ChainHTTPInjector and ChainHTTPExtractor --- text/0042-separate-context-propagation.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/text/0042-separate-context-propagation.md b/text/0042-separate-context-propagation.md index 3ad53424a..92c4f19e5 100644 --- a/text/0042-separate-context-propagation.md +++ b/text/0042-separate-context-propagation.md @@ -114,11 +114,12 @@ To send the data for all distributed applications downstream to the next process **HTTPExtract(context, request) -> context** To receive data injected by prior upstream processes, the Propagation API provides a function which takes a context and an HTTP request, and returns context which represents the state of the upstream system. -**ChainHTTPInjector(injector, injector) injector** -In order for the application layer to function correctly, Propagation choices must be syncronized between all processes in the distributed system, and multiple applications must be able to inject and extract their context into the same request. To meet these requirements, the Propagation API provides a function which registers a set of propagators, which will all be executed in order when the future calls to inject and extract are made. A canonical propagator consists of an inject and an extract function. +**ChainHTTPInjector(injector, injector) -> injector** +To allow multiple distributed applications to inject their context into the same request, the Propagation API provides a function which takes two injectors, and returns a single injector which calls the two original injectors in order. + +**ChainHTTPExtractor(extractor, extractor) -> extractor** +To allow multiple distributed applications to extract their context from the same request, the Propagation API provides a function which takes two extractors, and returns a single extractor which calls the two original extractors in order. -**ChainHTTPExtractor(extractor, extractor) extractor** -In order for the application layer to function correctly, Propagation choices must be syncronized between all processes in the distributed system, and multiple applications must be able to inject and extract their context into the same request. To meet these requirements, the Propagation API provides a function which registers a set of propagators, which will all be executed in order when the future calls to inject and extract are made. A canonical propagator consists of an inject and an extract function. ### Optional: Global Propagators It is often convenient to create a chain of propagators during program initialization, and then access these combined propagators later in the program. To facilitate this, global injectors and extractors are optionally available. However, there is no requirement to use this feature. From 3a817a2d1b3afe7f0215854ed7e2a6d051e1642a Mon Sep 17 00:00:00 2001 From: tedsuo Date: Mon, 14 Oct 2019 22:25:58 -0700 Subject: [PATCH 30/36] typo --- text/0042-separate-context-propagation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0042-separate-context-propagation.md b/text/0042-separate-context-propagation.md index 92c4f19e5..42eb447f0 100644 --- a/text/0042-separate-context-propagation.md +++ b/text/0042-separate-context-propagation.md @@ -131,7 +131,7 @@ To update the global injector, the Propagation API provides a function which tak To access the global injector, the Propagation API provides a function which returns an injector. **SetHTTPExtractor(extractor)** -To update the global extractor, the Propagation API provides a function which takes an injector. +To update the global extractor, the Propagation API provides a function which takes an extractor. **GetHTTPExtractor() -> extractor** To access the global extractor, the Propagation API provides a function which returns an extractor. From 3381e0f32a4e2468d663500a49e6729b79a3122b Mon Sep 17 00:00:00 2001 From: tedsuo Date: Mon, 14 Oct 2019 22:27:06 -0700 Subject: [PATCH 31/36] Reference Trace-Context, not just traceparent --- text/0042-separate-context-propagation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0042-separate-context-propagation.md b/text/0042-separate-context-propagation.md index 42eb447f0..425e83bb2 100644 --- a/text/0042-separate-context-propagation.md +++ b/text/0042-separate-context-propagation.md @@ -143,7 +143,7 @@ To access the global extractor, the Propagation API provides a function which re ## Context details OpenTelemetry currently implements three context types of context propagation. -**Span Context -** The serializable portion of a span, which is injected and extracted. The readable attributes are defined to match those found in the W3C **traceparent** header. +**Span Context -** The serializable portion of a span, which is injected and extracted. The readable attributes are defined to match those found in the [W3C Trace Context specification](https://www.w3.org/TR/trace-context/). **Correlation Context -** Correlation Context contains a map of labels and values, to be shared between metrics and traces. This allows observability data to be indexed and dimensionalized in a variety of ways. Note that correlations can quickly add overhead when propagated in-band. But because this data is write-only, it may be possible to optimize how it is transmitted. From c15a1077cb65b439c67cad5374140e3b0ccd09d5 Mon Sep 17 00:00:00 2001 From: tedsuo Date: Mon, 14 Oct 2019 22:27:58 -0700 Subject: [PATCH 32/36] Bagge context cleanup --- text/0042-separate-context-propagation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0042-separate-context-propagation.md b/text/0042-separate-context-propagation.md index 425e83bb2..e1bcbbebe 100644 --- a/text/0042-separate-context-propagation.md +++ b/text/0042-separate-context-propagation.md @@ -147,7 +147,7 @@ OpenTelemetry currently implements three context types of context propagation. **Correlation Context -** Correlation Context contains a map of labels and values, to be shared between metrics and traces. This allows observability data to be indexed and dimensionalized in a variety of ways. Note that correlations can quickly add overhead when propagated in-band. But because this data is write-only, it may be possible to optimize how it is transmitted. -**Baggage Context -** Transaction-level application data, meant to be shared with downstream components. This data is readable, and must be propagated in-band. Because of this, Baggage should be used sparingly, to avoid ballooning the size of RPC requests. +**Baggage -** Transaction-level application data, meant to be shared with downstream components. This data is readable, and must be propagated in-band. Because of this, Baggage should be used sparingly, to avoid ballooning the size of all downstream requests. Note that when possible, OpenTelemetry APIs calls are given access to the entire context object, and not a specific context type. From 310e8d589eba7658b24a8b53a4ca22162e2a5a33 Mon Sep 17 00:00:00 2001 From: tedsuo Date: Mon, 14 Oct 2019 22:31:39 -0700 Subject: [PATCH 33/36] stronger language around context access --- text/0042-separate-context-propagation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0042-separate-context-propagation.md b/text/0042-separate-context-propagation.md index e1bcbbebe..50f4916e9 100644 --- a/text/0042-separate-context-propagation.md +++ b/text/0042-separate-context-propagation.md @@ -149,7 +149,7 @@ OpenTelemetry currently implements three context types of context propagation. **Baggage -** Transaction-level application data, meant to be shared with downstream components. This data is readable, and must be propagated in-band. Because of this, Baggage should be used sparingly, to avoid ballooning the size of all downstream requests. -Note that when possible, OpenTelemetry APIs calls are given access to the entire context object, and not a specific context type. +Note that OpenTelemetry APIs calls should *always* be given access to the entire context object, and never just a subset of the context, such as the value in a single key. This allows the SDK to make improvements and leverage additional data that may be available, without changes to all of the call sites. ## Context Management and in-process propagation From f59fc27eb9083a0a1bde50662d5805b8428a223e Mon Sep 17 00:00:00 2001 From: Ted Young Date: Mon, 14 Oct 2019 22:34:02 -0700 Subject: [PATCH 34/36] Update text/0042-separate-context-propagation.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Christian Neumüller --- text/0042-separate-context-propagation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0042-separate-context-propagation.md b/text/0042-separate-context-propagation.md index 50f4916e9..5de766132 100644 --- a/text/0042-separate-context-propagation.md +++ b/text/0042-separate-context-propagation.md @@ -158,7 +158,7 @@ In order for Context to function, it must always remain bound to the execution o ## Pre-existing Context implementations -In some languages, a single, widely used Context implementation exists. In other languages, there many be too many implementations, or none at all. For example, Go has a the context.Context object, and widespread conventions for how to pass it down the call stack. +In some languages, a single, widely used Context implementation exists. In other languages, there many be too many implementations, or none at all. For example, Go has a the `context.Context` object, and widespread conventions for how to pass it down the call stack. In the cases where an extremely clear, pre-existing option is not available, OpenTelemetry should provide its own Context implementation. From 153b9aadf50581ad2875dbb38b156bac63e07e0b Mon Sep 17 00:00:00 2001 From: tedsuo Date: Mon, 14 Oct 2019 23:32:41 -0700 Subject: [PATCH 35/36] clean up tradeoffs --- text/0042-separate-context-propagation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0042-separate-context-propagation.md b/text/0042-separate-context-propagation.md index 5de766132..b05557952 100644 --- a/text/0042-separate-context-propagation.md +++ b/text/0042-separate-context-propagation.md @@ -179,9 +179,9 @@ Correlation values are solely to be used as labels for metrics and traces. By ma Baggage values, on the other hand, are explicitly added in order to be accessed by downstream by other application code. Therefore, Baggage Context must be readable, and reliably propagated in-band in order to accomplish this goal. -There may be cases where a key-value pair is propagated as TagMap for observability and as a Baggage for application specific use. AB testing is one example of such use case. There is potential duplication here at call site where a pair is created and also at propagation. +There may be cases where a key-value pair is propagated as a Correlation for observability and as a Baggage item for application-specific use. AB testing is one example of such use case. This would result in extra overhead, as the same key-value pair would be present in two separate headers. -Solving this issue is not worth having semantic confusion with dual purpose. However, because all observability functions take the complete context as input, it may still be possible to use baggage values as labels. +Solving this issue is not worth having semantic confusion with dual purpose. However, because all observability functions take the complete context as input – and baggage is not sampled – it may still be possible to use baggage values as labels for observability. ## What about complex propagation behavior? From f70855a4016ca41ce1eae78fed9420c304e2b2ba Mon Sep 17 00:00:00 2001 From: Ted Young Date: Mon, 14 Oct 2019 23:42:30 -0700 Subject: [PATCH 36/36] Update text/0042-separate-context-propagation.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Christian Neumüller --- text/0042-separate-context-propagation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0042-separate-context-propagation.md b/text/0042-separate-context-propagation.md index b05557952..4246502ab 100644 --- a/text/0042-separate-context-propagation.md +++ b/text/0042-separate-context-propagation.md @@ -204,7 +204,7 @@ Prior art: # Open questions -Related work on HTTP propagators has not been completed yet. +Related work on HTTP propagatation has not been completed yet: * [W3C Trace-Context](https://www.w3.org/TR/trace-context/) candidate is not yet accepted * Work on [W3C Correlation-Context](https://w3c.github.io/correlation-context/) has begun, but was halted to focus on Trace-Context.