Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Context and DistributedContext specification #75

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion specification/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ describes the key types and the overall behavior.
Main APIs:

- [Tracing API](tracing-api.md).
- [Resources API](resources-api.md).
- [Context and Tags API](context-api.md).
- [Resources API](resources-api.md).
105 changes: 105 additions & 0 deletions specification/context-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Context and Tags API

The Context API consists of a few main classes:

- `Context` is the implicit or explicit context handle, specific to each language
- `TagMap` is an immutable object storing the key:value assignments.

## `Context`

Whether the current `Context` is an explicit or implicit construct in the target language, the API provides accessors to retrieve the current `Span` and the current `TagMap`.

### `Context` constructors

#### `Context.Empty()`: returns context with no `SpanContext` and an empty `TagMap`

The `Context` API provides a way to obtain an empty `Context`, which has no associated `SpanContext` and an empty `TagMap`.

#### `Context.WithMap(replacement)`: support binding a new TagMap to a Context
Copy link
Member

Choose a reason for hiding this comment

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

WithMap sounds very generic, please consider WithTagMap.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't know what do with this, since the TagMap type has been named DistributedContext. I suppose WithDistributedContext (it's sooooooo long).


The `Context` API provides a way to replace the current `TagMap` with a new one. Returns a new `Context` with the provided `TagMap`.

#### `Context.NewContext(mutators...)`: support extending from an existing `TagMap`

The `Context` API provides a way to derive a new `Context` by modifying the existing `Context`'s `TagMap`, using one of the provided mutators:

The defined mutators are:
- `Insert(key, value)`: Enter a new key:value only if the key is not already defined
- `Upsert(key, value)`: Enter a new key:value or update the existing key:value unconditionally
Copy link
Contributor

Choose a reason for hiding this comment

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

Upsert ? ;)

Copy link
Contributor Author

@jmacd jmacd Jun 7, 2019

Choose a reason for hiding this comment

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

This is what OpenCensus called it. I haven't personally seen a need to distinguish Insert from Upsert semantics, but neither do I doubt its usefulness.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@bogdandrutu Have we decided to keep Upsert, Insert, and Remove operations on DistributedContext?

- `Delete(key, value)`: Remove a key:value from the map, if it exists.

This is defined as `Context.WithMap(TagMap.FromContext().Apply(mutators))`. Returns a new `Context` with the derived `TagMap`. The incoming context is not modified.

### `Context` manipulation

#### `Context.Enter()/Exit()`: methods to switch the active `Context`

The `Context` API provides a way to execute code scoped to a new
context. Depending on language features, the SDK should provide APIs
that ensure execution automatically switches out of the Context after
the scoped activity finishes. In practice, this usually means the
`Context` API relies on try/finally statements, defered callbacks, or
automatic destructors to modify the active `Context`.

### `Context` accessors

#### `Context.Active()`: Get the current Span
Copy link
Contributor

Choose a reason for hiding this comment

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

It has been discouraged in the past to expose the actual Span in the Context object, as we have been afraid of users passing Context around, as it were container.

Something along Span.FromContext() is valid though (which is currently exposed by Tracer.getCurrentSpan())

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If an application is using more than one Tracer, that seems problematic. Is this a static method?

I would like to see the conversation where this fear of passing context was discussed. Any pointers?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm coming from Go, where Context is explicitly passed around. I wrote this specification with Go in mind, and it's difficult to generalize across explicit/non-explicit languages.


This may be use to get the current `SpanContext` as well. Use `Trace.Start` to update the active span.

#### `TagMap.FromContext()`: Get the current map

This returns the `TagMap` belonging to the active `Context`.

## `TagMap`

### `TagMap` constructors

#### `TagMap.NewMap(pairs...)`: New map from list of key:value pairs

Construct a new map by giving an explicit key:value list.

#### `TagMap.Apply(mutators...)`: New map from list of mutators (see `Context.NewContext`)

Construct a new map by giving a sequence of key:value mutators.

### `TagMap.MaxHops`

`TagMap` is an immutable map of key:value assignments with metadata about how each key:value assignment (i.e., tag) should propagate. Keys are individually assigned a "Max Hops" value which determines the number of remote processes it will propagate into. Values for Max Hops:

- `0`: The tag will propagate to internal `Contexts` belonging to the same trace, within the local process, but will not propagate to a remote host
- `>=1`: The tag will propagate to a depth of (up to) 1 or more remote hosts from the current node in the trace
Copy link
Contributor

Choose a reason for hiding this comment

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

s/remote hosts/remote processes/.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

- `-1`: The tag will propagate indefinitely (default).

The default behavior is to propagate tags indefinitely.

#### Providing explicit Max Hops

Mutators have a additional modifiers allowing `MaxHops` to be set in the application:

- `Insert(key, value).WithMaxHops(n)`: Mutator with optional MaxHops setting.
- `Upsert(key, value).WithMaxHops(n)`: Mutator with optional MaxHops setting.
- `Delete(key, value).WithMaxHops(n)`: Mutator with optional MaxHops setting.

#### `TagMap.SetMaxHops(key)`: Modify the MaxHops setting for a single key

The `SetMaxHops` API supports controlling tag propagation for a single key.

### TagMap accessors

#### `TagMap.Foreach`: Iterate over the key:values of a map

This function calls a callback with the full set of key:value assignments, along with metadata.

#### `TagMap.Len`: Count the number of key:value assignments

This function returns the map size.

#### `TagMap.HasValue`: Check whether a key exists

This function returns true if the key is defined in the map.

#### `TagMap.Value`: Lookup the key's value

This function returns the current key assignment and a boolean to indicate whether it exists.

28 changes: 25 additions & 3 deletions terminology.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,31 @@ Trace instead of trusting incoming Trace context.

TODO: Describe metrics terminology https:/open-telemetry/opentelemetry-specification/issues/45

## Tags

TODO: Describe tags terminology https:/open-telemetry/opentelemetry-specification/issues/46
## Context and Tags

**Tags** are key:value attributes, which are associated with **Spans**,
**Events**, and **Stats** data, that propagate alongside **SpanContext**
Copy link
Member

Choose a reason for hiding this comment

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

Do we still use term stats or we are moving to "metrics"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've been working on writing down a position on this topic, and it seems we are using both terms. An open question, in my mind, is whether stats and metrics can be specified in a way so that pre-aggregated metrics layers on top of the stats. Then metrics can be seen as a technique for type-safety and an optimization, but semantically equivalent to recording a stats measurement.

across causal relationships in a **Trace** through a device known as
**Context Propagation**.

The term **Context** is specifically used to describe a
language-dependent feature or construct, which encapsulates the notion
that there is an "active" or "current" diagnostic state, ever-present
in the application and dictated by the control-flow of the
application, that defines both causal relationships, between
**SpanContexts**, and the associated **Context Tags**.

Abstractly, **Context Propagation** is the mechanism for conveying the
current **SpanContext** and **Context Tags** throughout an application
and across machines when starting remote **Spans**. OpenTelemetry
specifies that **Context Propagation** should be done in the way
prescribed by the language, when possible. Some languages will use
thread-local state, while other languages will use explicit context
objects for context propagation.

More importantly, OpenTelemetry shall prefer to use an existing,
established context package, where the language and community support
it, provided that support is extensible.

## Resources

Expand Down