Skip to content

Commit

Permalink
Ensure logs bridge API doesn't contain implementation details (open-t…
Browse files Browse the repository at this point in the history
…elemetry#3275)

Contributes to open-telemetry#3268.

@MrAlias did some good work in the metrics API / SDK recently in open-telemetry#3171
and open-telemetry#3067 to ensure that the metrics API spec doesn't contain SDK
implementation details.

This PR adopts similar language in the Logs Bridge API / SDK documents,
which includes breaking out a `noop.md` document.
  • Loading branch information
jack-berg authored Mar 27, 2023
1 parent b99800e commit 58063e7
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 77 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ release.
([#3334](https://github.com/open-telemetry/opentelemetry-specification/pull/3334))
- Break out compatibility document on recording trace context in non-OTLP Log Format
([#3331](https://github.com/open-telemetry/opentelemetry-specification/pull/3331))
- Ensure Logs Bridge API doesn't contain SDK implementation details
([#3275](https://github.com/open-telemetry/opentelemetry-specification/pull/3275))

### Resource

Expand Down
114 changes: 55 additions & 59 deletions specification/logs/bridge-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
* [Logger operations](#logger-operations)
+ [Emit LogRecord](#emit-logrecord)
- [LogRecord](#logrecord)
- [Optional and required parameters](#optional-and-required-parameters)
- [Concurrency requirements](#concurrency-requirements)
- [Usage](#usage)
* [How to Create Log4J Style Appender](#how-to-create-log4j-style-appender)
* [Implicit Context Injection](#implicit-context-injection)
Expand Down Expand Up @@ -53,13 +55,6 @@ Normally, the `LoggerProvider` is expected to be accessed from a central place.
Thus, the API SHOULD provide a way to set/register and access a global default
`LoggerProvider`.

Notwithstanding any global `LoggerProvider`, some applications may want to or have
to use multiple `LoggerProvider` instances, e.g. to have different configuration
(like [LogRecordProcessors](sdk.md#logrecordprocessor)) for each (and
consequently for the `Logger`s obtained from them), or because it's easier with
dependency injection frameworks. Thus, implementations of `LoggerProvider` SHOULD
allow creating an arbitrary number of instances.

### LoggerProvider operations

The `LoggerProvider` MUST provide the following functions:
Expand All @@ -70,57 +65,39 @@ The `LoggerProvider` MUST provide the following functions:

This API MUST accept the following parameters:

- `name` (required): This name SHOULD uniquely identify the [instrumentation scope](../glossary.md#instrumentation-scope),
such as the [instrumentation library](../glossary.md#instrumentation-library)
(e.g. `io.opentelemetry.contrib.mongodb`), package, module or class name.
If an application or library has built-in OpenTelemetry instrumentation, both
[Instrumented library](../glossary.md#instrumented-library) and
[Instrumentation library](../glossary.md#instrumentation-library) may refer to
the same library. In that scenario, the `name` denotes a module name or component
name within that library or application. In case an invalid name
(null or empty string) is specified, a working Logger implementation MUST be
returned as a fallback rather than returning null or throwing an exception, its
`name` property SHOULD be set to an empty string, and a message reporting that
the specified value is invalid SHOULD be logged. A library implementing the
OpenTelemetry API may also ignore this name and return a default instance for
all calls, if it does not support "named" functionality (e.g. an implementation
which is not even observability-related). A `LoggerProvider` could also return a
no-op `Logger` here if application owners configure the SDK to suppress telemetry
produced by this library.
- `version` (optional): Specifies the version of the instrumentation scope if
the scope has a version (e.g. a library version). Example value: 1.0.0.
- `schema_url` (optional): Specifies the Schema URL that should be recorded in
the emitted telemetry.
- `include_trace_context` (optional): Specifies whether the Trace Context should
automatically be passed on to the `LogRecord`s emitted by the `Logger`. This
SHOULD be true by default.
- `attributes` (optional): Specifies the instrumentation scope attributes to
associate with emitted telemetry.
* `name`: This name uniquely identifies the [instrumentation scope](../glossary.md#instrumentation-scope),
such as the [instrumentation library](../glossary.md#instrumentation-library)
(e.g. `io.opentelemetry.contrib.mongodb`), package, module or class name.
If an application or library has built-in OpenTelemetry instrumentation, both
[Instrumented library](../glossary.md#instrumented-library) and
[Instrumentation library](../glossary.md#instrumentation-library) may refer to
the same library. In that scenario, the `name` denotes a module name or component
name within that library or application.

* `version` (optional): Specifies the version of the instrumentation scope if
the scope has a version (e.g. a library version). Example value: 1.0.0.

* `schema_url` (optional): Specifies the Schema URL that should be recorded in
the emitted telemetry.

* `attributes` (optional): Specifies the instrumentation scope attributes to
associate with emitted telemetry. This API MUST be structured to accept a
variable number of attributes, including none.

* `include_trace_context` (optional): Specifies whether the Trace Context should
automatically be passed on to the `LogRecord`s emitted by the `Logger`.
If `include_trace_context` is not specified, it SHOULD be `true` by default.

`Logger`s are identified by `name`, `version`, and `schema_url` fields. When more
than one `Logger` of the same `name`, `version`, and `schema_url` is created, it
is unspecified whether or under which conditions the same or different `Logger`
instances are returned. It is a user error to create Loggers with different
attributes but the same identity.
`include_trace_context` or `attributes` but the same identity.

The term *identical* applied to `Logger`s describes instances where all
identifying fields are equal. The term *distinct* applied to `Logger`s describes
instances where at least one identifying field has a different value.

Implementations MUST NOT require users to repeatedly obtain a `Logger` again with
the same name+version+schema_url+include_trace_context+attributes
to pick up configuration changes. This can be achieved either by allowing to
work with an outdated configuration or by ensuring that new configuration
applies also to previously returned `Logger`s.

Note: This could, for example, be implemented by storing any mutable
configuration in the `LoggerProvider` and having `Logger` implementation objects
have a reference to the `LoggerProvider` from which they were obtained.
If configuration must be stored per-Logger (such as disabling a certain `Logger`),
the `Logger` could, for example, do a look-up with its name+version+schema_url+include_trace_context+attributes
in a map in the `LoggerProvider`, or the `LoggerProvider` could maintain a registry
of all returned `Logger`s and actively update their configuration if it changes.

The effect of associating a Schema URL with a `Logger` MUST be that the telemetry
emitted using the `Logger` will be associated with the Schema URL, provided that
the emitted data format is capable of representing such association.
Expand All @@ -129,9 +106,6 @@ the emitted data format is capable of representing such association.

The `Logger` is responsible for emitting `LogRecord`s.

Note that `Logger`s should not be responsible for configuration. This should be
the responsibility of the `LoggerProvider` instead.

### Logger operations

The `Logger` MUST provide functions to:
Expand All @@ -151,7 +125,7 @@ This function MAY be named `logRecord`.
The API emits [LogRecords](#emit-logrecord) using the `LogRecord` [data model](data-model.md).

A function receiving this as an argument MUST be able to set the following
fields:
parameters:

- [Timestamp](./data-model.md#field-timestamp)
- [Observed Timestamp](./data-model.md#field-observedtimestamp)
Expand All @@ -162,20 +136,42 @@ fields:
- [Body](./data-model.md#field-body)
- [Attributes](./data-model.md#field-attributes)

All parameters are optional.

## Optional and required parameters

The operations defined include various parameters, some of which are marked
optional. Parameters not marked optional are required.

For each optional parameter, the API MUST be structured to accept it, but MUST
NOT obligate a user to provide it.

For each required parameter, the API MUST be structured to obligate a user to
provide it.

## Concurrency requirements

For languages which support concurrent execution the Logs Bridge APIs provide
specific guarantees and safeties.

**LoggerProvider** - all methods are safe to be called concurrently.

**Logger** - all methods are safe to be called concurrently.

## Usage

### How to Create Log4J Style Appender

An Appender implementation can be used to allow emitting logs via
An Appender implementation can be used to bridge logs into the [Log SDK](./sdk.md)
OpenTelemetry [LogRecordExporters](sdk.md#logrecordexporter). This approach is
typically used for applications which are fine with changing the log transport
and is [one of the supported](README.md#direct-to-collector) log collection
approaches.

The Appender implementation will typically acquire a [Logger](#logger) from the
global [LoggerProvider](#loggerprovider) at startup time, then construct
`LogRecord`s for each log received from the application, and then call
[Emit LogRecord](#emit-logrecord).
global [LoggerProvider](#loggerprovider) at startup time, then
call [Emit LogRecord](#emit-logrecord) for `LogRecord`s received from the
application.

[Implicit Context Injection](#implicit-context-injection)
and [Explicit Context Injection](#explicit-context-injection) describe how an
Expand All @@ -198,9 +194,9 @@ popular logging library.

### Implicit Context Injection

When Context is implicitly available (e.g. in Java) the log library extension
can rely on automatic context propagation
by [obtaining a Logger](#get-a-logger) with `include_trace_context=true`.
When Context is implicitly available (e.g. in Java) the Appender can rely on
automatic context propagation by [obtaining a Logger](#get-a-logger)
with `include_trace_context=true`.

Some log libraries have mechanisms specifically tailored for injecting contextual
information into logs, such as MDC in Log4j. When available such mechanisms may
Expand Down
4 changes: 2 additions & 2 deletions specification/logs/event-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ instrumentation authors are encouraged to call this API directly.
## EventLogger

The `EventLogger` is the entrypoint of the Event API, and is responsible for
emitting `Events` as `LogRecords`.
emitting `Events` as `LogRecord`s.

### EventLogger Operations

Expand All @@ -64,7 +64,7 @@ on `EventLogger`.
**Parameters:**

* `logger` - the delegate [Logger](./bridge-api.md#logger) used to emit `Events`
as `LogRecords`.
as `LogRecord`s.
* `event_domain` - the domain of emitted events, used to set the `event.domain`
attribute.

Expand Down
57 changes: 57 additions & 0 deletions specification/logs/noop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<!--- Hugo front matter used to generate the website version of this page:
linkTitle: noop
--->

# Logs Bridge API No-Op Implementation

**Status**: [Experimental](../document-status.md)

<details>
<summary> Table of Contents </summary>

<!-- toc -->

- [LoggerProvider](#loggerprovider)
* [Logger Creation](#logger-creation)
- [Logger](#logger)
* [Emit LogRecord](#emit-logrecord)

<!-- tocstop -->

</details>

Users of OpenTelemetry need a way to disable the API from actually
performing any operations. The No-Op OpenTelemetry API implementation
(henceforth referred to as the No-Op) provides users with this
functionally. It implements the [OpenTelemetry Logs Bridge API](./bridge-api.md)
so that no telemetry is produced and computation resources are minimized.

All language implementations of OpenTelemetry MUST provide a No-Op.

The [Logs Bridge API](./bridge-api.md) defines classes with various operations.
All No-Op classes MUST NOT hold configuration or operational state. All No-op
operations MUST accept all defined parameters, MUST NOT validate any arguments
received, and MUST NOT return any non-empty error or log any message.

## LoggerProvider

The No-Op MUST allow the creation of multiple `LoggerProviders`s.

Since all `LoggerProviders`s hold the same empty state, a No-Op MAY
provide the same `LoggerProvider` instances to all creation requests.

### Logger Creation

New `Logger` instances are always created with a [LoggerProvider](./bridge-api.md#loggerprovider).
Therefore, `LoggerProvider` MUST allow for the creation of `Logger`s.
All `Logger`s created MUST be an instance of the [No-Op Logger](#logger).

Since all `Logger`s will hold the same empty state, a `LoggerProvider` MAY
return the same `Logger` instances to all creation requests.

## Logger

### Emit LogRecord

The No-Op `Logger` MUST allow
for [emitting LogRecords](./bridge-api.md#emit-logrecord).
Loading

0 comments on commit 58063e7

Please sign in to comment.