You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-08-10 22:31:50 +02:00
chore: Update Logs API design doc (#6206)
There were some changes in the design that should be updated. Most importantly: - Logs Bridge API -> Logs API that can be called directly: https://github.com/open-telemetry/opentelemetry-go/pull/6167 - addition of converting functions: https://github.com/open-telemetry/opentelemetry-go/pull/6180 - event support: https://github.com/open-telemetry/opentelemetry-go/pull/6187
This commit is contained in:
@@ -1,16 +1,16 @@
|
|||||||
# Logs Bridge API
|
# Logs API
|
||||||
|
|
||||||
## Abstract
|
## Abstract
|
||||||
|
|
||||||
`go.opentelemetry.io/otel/log` provides
|
`go.opentelemetry.io/otel/log` provides
|
||||||
[Logs Bridge API](https://opentelemetry.io/docs/specs/otel/logs/bridge-api/).
|
[Logs API](https://opentelemetry.io/docs/specs/otel/logs/api/).
|
||||||
|
|
||||||
The prototype was created in
|
The prototype was created in
|
||||||
[#4725](https://github.com/open-telemetry/opentelemetry-go/pull/4725).
|
[#4725](https://github.com/open-telemetry/opentelemetry-go/pull/4725).
|
||||||
|
|
||||||
## Background
|
## Background
|
||||||
|
|
||||||
The key challenge is to create a performant API compliant with the [specification](https://opentelemetry.io/docs/specs/otel/logs/bridge-api/)
|
The key challenge is to create a performant API compliant with the [specification](https://opentelemetry.io/docs/specs/otel/logs/api/)
|
||||||
with an intuitive and user friendly design.
|
with an intuitive and user friendly design.
|
||||||
Performance is seen as one of the most important characteristics of logging libraries in Go.
|
Performance is seen as one of the most important characteristics of logging libraries in Go.
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ Rejected alternative:
|
|||||||
|
|
||||||
### LoggerProvider
|
### LoggerProvider
|
||||||
|
|
||||||
The [`LoggerProvider` abstraction](https://opentelemetry.io/docs/specs/otel/logs/bridge-api/#loggerprovider)
|
The [`LoggerProvider` abstraction](https://opentelemetry.io/docs/specs/otel/logs/api/#loggerprovider)
|
||||||
is defined as `LoggerProvider` interface in [provider.go](provider.go).
|
is defined as `LoggerProvider` interface in [provider.go](provider.go).
|
||||||
|
|
||||||
The specification may add new operations to `LoggerProvider`.
|
The specification may add new operations to `LoggerProvider`.
|
||||||
@@ -51,7 +51,7 @@ This approach is already used in Trace API and Metrics API.
|
|||||||
|
|
||||||
#### LoggerProvider.Logger
|
#### LoggerProvider.Logger
|
||||||
|
|
||||||
The `Logger` method implements the [`Get a Logger` operation](https://opentelemetry.io/docs/specs/otel/logs/bridge-api/#get-a-logger).
|
The `Logger` method implements the [`Get a Logger` operation](https://opentelemetry.io/docs/specs/otel/logs/api/#get-a-logger).
|
||||||
|
|
||||||
The required `name` parameter is accepted as a `string` method argument.
|
The required `name` parameter is accepted as a `string` method argument.
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ The `LoggerOption` options are defined to support optional parameters.
|
|||||||
|
|
||||||
Implementation requirements:
|
Implementation requirements:
|
||||||
|
|
||||||
- The [specification requires](https://opentelemetry.io/docs/specs/otel/logs/bridge-api/#concurrency-requirements)
|
- The [specification requires](https://opentelemetry.io/docs/specs/otel/logs/api/#concurrency-requirements)
|
||||||
the method to be safe to be called concurrently.
|
the method to be safe to be called concurrently.
|
||||||
|
|
||||||
- The method should use some default name if the passed name is empty
|
- The method should use some default name if the passed name is empty
|
||||||
@@ -78,7 +78,7 @@ Rejected alternative:
|
|||||||
|
|
||||||
### Logger
|
### Logger
|
||||||
|
|
||||||
The [`Logger` abstraction](https://opentelemetry.io/docs/specs/otel/logs/bridge-api/#logger)
|
The [`Logger` abstraction](https://opentelemetry.io/docs/specs/otel/logs/api/#logger)
|
||||||
is defined as `Logger` interface in [logger.go](logger.go).
|
is defined as `Logger` interface in [logger.go](logger.go).
|
||||||
|
|
||||||
The specification may add new operations to `Logger`.
|
The specification may add new operations to `Logger`.
|
||||||
@@ -89,14 +89,14 @@ This approach is already used in Trace API and Metrics API.
|
|||||||
|
|
||||||
### Logger.Emit
|
### Logger.Emit
|
||||||
|
|
||||||
The `Emit` method implements the [`Emit a LogRecord` operation](https://opentelemetry.io/docs/specs/otel/logs/bridge-api/#emit-a-logrecord).
|
The `Emit` method implements the [`Emit a LogRecord` operation](https://opentelemetry.io/docs/specs/otel/logs/api/#emit-a-logrecord).
|
||||||
|
|
||||||
[`Context` associated with the `LogRecord`](https://opentelemetry.io/docs/specs/otel/context/)
|
[`Context` associated with the `LogRecord`](https://opentelemetry.io/docs/specs/otel/context/)
|
||||||
is accepted as a `context.Context` method argument.
|
is accepted as a `context.Context` method argument.
|
||||||
|
|
||||||
Calls to `Emit` are supposed to be on the hot path.
|
Calls to `Emit` are supposed to be on the hot path.
|
||||||
Therefore, in order to reduce the number of heap allocations,
|
Therefore, in order to reduce the number of heap allocations,
|
||||||
the [`LogRecord` abstraction](https://opentelemetry.io/docs/specs/otel/logs/bridge-api/#emit-a-logrecord),
|
the [`LogRecord` abstraction](https://opentelemetry.io/docs/specs/otel/logs/api/#emit-a-logrecord),
|
||||||
is defined as `Record` struct in [record.go](record.go).
|
is defined as `Record` struct in [record.go](record.go).
|
||||||
|
|
||||||
[`Timestamp`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-timestamp)
|
[`Timestamp`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-timestamp)
|
||||||
@@ -115,6 +115,14 @@ func (r *Record) ObservedTimestamp() time.Time
|
|||||||
func (r *Record) SetObservedTimestamp(t time.Time)
|
func (r *Record) SetObservedTimestamp(t time.Time)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
[`EventName`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-eventname)
|
||||||
|
is accessed using following methods:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *Record) EventName() string
|
||||||
|
func (r *Record) SetEventName(s string)
|
||||||
|
```
|
||||||
|
|
||||||
[`SeverityNumber`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitynumber)
|
[`SeverityNumber`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitynumber)
|
||||||
is accessed using following methods:
|
is accessed using following methods:
|
||||||
|
|
||||||
@@ -222,13 +230,13 @@ after the call (even when the documentation says that the caller must not do it)
|
|||||||
|
|
||||||
Implementation requirements:
|
Implementation requirements:
|
||||||
|
|
||||||
- The [specification requires](https://opentelemetry.io/docs/specs/otel/logs/bridge-api/#concurrency-requirements)
|
- The [specification requires](https://opentelemetry.io/docs/specs/otel/logs/api/#concurrency-requirements)
|
||||||
the method to be safe to be called concurrently.
|
the method to be safe to be called concurrently.
|
||||||
|
|
||||||
- The method must not interrupt the record processing if the context is canceled
|
- The method must not interrupt the record processing if the context is canceled
|
||||||
per ["ignoring context cancellation" guideline](../CONTRIBUTING.md#ignoring-context-cancellation).
|
per ["ignoring context cancellation" guideline](../CONTRIBUTING.md#ignoring-context-cancellation).
|
||||||
|
|
||||||
- The [specification requires](https://opentelemetry.io/docs/specs/otel/logs/bridge-api/#emit-a-logrecord)
|
- The [specification requires](https://opentelemetry.io/docs/specs/otel/logs/api/#emit-a-logrecord)
|
||||||
use the current time as observed timestamp if the passed is empty.
|
use the current time as observed timestamp if the passed is empty.
|
||||||
|
|
||||||
- The method should handle the trace context passed via `ctx` argument in order to meet the
|
- The method should handle the trace context passed via `ctx` argument in order to meet the
|
||||||
@@ -253,7 +261,7 @@ Rejected alternatives:
|
|||||||
|
|
||||||
### Logger.Enabled
|
### Logger.Enabled
|
||||||
|
|
||||||
The `Enabled` method implements the [`Enabled` operation](https://opentelemetry.io/docs/specs/otel/logs/bridge-api/#enabled).
|
The `Enabled` method implements the [`Enabled` operation](https://opentelemetry.io/docs/specs/otel/logs/api/#enabled).
|
||||||
|
|
||||||
[`Context` associated with the `LogRecord`](https://opentelemetry.io/docs/specs/otel/context/)
|
[`Context` associated with the `LogRecord`](https://opentelemetry.io/docs/specs/otel/context/)
|
||||||
is accepted as a `context.Context` method argument.
|
is accepted as a `context.Context` method argument.
|
||||||
@@ -271,7 +279,7 @@ where `Enabled` is called.
|
|||||||
### noop package
|
### noop package
|
||||||
|
|
||||||
The `go.opentelemetry.io/otel/log/noop` package provides
|
The `go.opentelemetry.io/otel/log/noop` package provides
|
||||||
[Logs Bridge API No-Op Implementation](https://opentelemetry.io/docs/specs/otel/logs/noop/).
|
[Logs API No-Op Implementation](https://opentelemetry.io/docs/specs/otel/logs/noop/).
|
||||||
|
|
||||||
### Trace context correlation
|
### Trace context correlation
|
||||||
|
|
||||||
@@ -319,7 +327,7 @@ nor any other logging library.
|
|||||||
|
|
||||||
The API needs to evolve orthogonally to `slog`.
|
The API needs to evolve orthogonally to `slog`.
|
||||||
|
|
||||||
`slog` is not compliant with the [Logs Bridge API](https://opentelemetry.io/docs/specs/otel/logs/bridge-api/).
|
`slog` is not compliant with the [Logs API](https://opentelemetry.io/docs/specs/otel/logs/api/).
|
||||||
and we cannot expect the Go team to make `slog` compliant with it.
|
and we cannot expect the Go team to make `slog` compliant with it.
|
||||||
|
|
||||||
The interoperability can be achieved using [a log bridge](https://opentelemetry.io/docs/specs/otel/glossary/#log-appender--bridge).
|
The interoperability can be achieved using [a log bridge](https://opentelemetry.io/docs/specs/otel/glossary/#log-appender--bridge).
|
||||||
@@ -423,10 +431,12 @@ One of the proposals[^6] was to have `Record` as a simple struct:
|
|||||||
type Record struct {
|
type Record struct {
|
||||||
Timestamp time.Time
|
Timestamp time.Time
|
||||||
ObservedTimestamp time.Time
|
ObservedTimestamp time.Time
|
||||||
|
EventName string
|
||||||
Severity Severity
|
Severity Severity
|
||||||
SeverityText string
|
SeverityText string
|
||||||
Body Value
|
Body Value
|
||||||
Attributes []KeyValue
|
Attributes []KeyValue
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The bridge implementations could use [`sync.Pool`](https://pkg.go.dev/sync#Pool)
|
The bridge implementations could use [`sync.Pool`](https://pkg.go.dev/sync#Pool)
|
||||||
@@ -508,7 +518,7 @@ It should be more user friendly to have them separated.
|
|||||||
Especially when having getter and setter methods, setting one value
|
Especially when having getter and setter methods, setting one value
|
||||||
when the other is already set would be unpleasant.
|
when the other is already set would be unpleasant.
|
||||||
|
|
||||||
## Reuse attribute package
|
### Reuse attribute package
|
||||||
|
|
||||||
It was tempting to reuse the existing
|
It was tempting to reuse the existing
|
||||||
[https://pkg.go.dev/go.opentelemetry.io/otel/attribute] package
|
[https://pkg.go.dev/go.opentelemetry.io/otel/attribute] package
|
||||||
@@ -523,7 +533,7 @@ has anything in common with a common attribute value.
|
|||||||
Therefore, we define new types representing the abstract types defined
|
Therefore, we define new types representing the abstract types defined
|
||||||
in the [Logs Data Model](https://opentelemetry.io/docs/specs/otel/logs/data-model/#definitions-used-in-this-document).
|
in the [Logs Data Model](https://opentelemetry.io/docs/specs/otel/logs/data-model/#definitions-used-in-this-document).
|
||||||
|
|
||||||
## Mix receiver types for Record
|
### Mix receiver types for Record
|
||||||
|
|
||||||
Methods of [`slog.Record`](https://pkg.go.dev/log/slog#Record)
|
Methods of [`slog.Record`](https://pkg.go.dev/log/slog#Record)
|
||||||
have different receiver types.
|
have different receiver types.
|
||||||
@@ -577,17 +587,9 @@ we decided to use pointer receivers for all `Record` methods.
|
|||||||
|
|
||||||
### Add XYZ method to Logger
|
### Add XYZ method to Logger
|
||||||
|
|
||||||
The `Logger` does not have methods like `Enabled`, `SetSeverity`, etc.
|
The `Logger` does not have methods like `SetSeverity`, etc.
|
||||||
as the Bridge API needs to follow (be compliant with)
|
as the Logs API needs to follow (be compliant with)
|
||||||
the [specification](https://opentelemetry.io/docs/specs/otel/logs/bridge-api/)
|
the [specification](https://opentelemetry.io/docs/specs/otel/logs/api/)
|
||||||
|
|
||||||
Moreover, the Bridge API is intended to be used to implement bridges.
|
|
||||||
Applications should not use it directly. The applications should use logging packages
|
|
||||||
such as [`slog`](https://pkg.go.dev/log/slog),
|
|
||||||
[`logrus`](https://pkg.go.dev/github.com/sirupsen/logrus),
|
|
||||||
[`zap`](https://pkg.go.dev/go.uber.org/zap),
|
|
||||||
[`zerolog`](https://pkg.go.dev/github.com/rs/zerolog),
|
|
||||||
[`logr`](https://pkg.go.dev/github.com/go-logr/logr).
|
|
||||||
|
|
||||||
### Rename KeyValue to Attr
|
### Rename KeyValue to Attr
|
||||||
|
|
||||||
@@ -597,16 +599,17 @@ the OpenTelemetry parlance.
|
|||||||
|
|
||||||
During the discussion we agreed to keep the `KeyValue` name.
|
During the discussion we agreed to keep the `KeyValue` name.
|
||||||
|
|
||||||
The type is used in two semantics:
|
The type is used in multiple semantics:
|
||||||
|
|
||||||
- as a log attribute
|
- as a log attribute,
|
||||||
- as a map item
|
- as a map item,
|
||||||
|
- as a log record Body.
|
||||||
|
|
||||||
As for map item semantics, this type is a key-value pair, not an attribute.
|
As for map item semantics, this type is a key-value pair, not an attribute.
|
||||||
Naming the type as `Attr` would convey semantical meaning
|
Naming the type as `Attr` would convey semantical meaning
|
||||||
that would not be correct for a map.
|
that would not be correct for a map.
|
||||||
|
|
||||||
We expect that most of the Bridge API users will be OpenTelemetry contributors.
|
We expect that most of the Logs API users will be OpenTelemetry contributors.
|
||||||
We plan to implement bridges for the most popular logging libraries ourselves.
|
We plan to implement bridges for the most popular logging libraries ourselves.
|
||||||
Given we will all have the context needed to disambiguate these overlapping
|
Given we will all have the context needed to disambiguate these overlapping
|
||||||
names, developers' confusion should not be an issue.
|
names, developers' confusion should not be an issue.
|
||||||
@@ -615,10 +618,8 @@ For bridges not developed by us,
|
|||||||
developers will likely look at our existing bridges for inspiration.
|
developers will likely look at our existing bridges for inspiration.
|
||||||
Our correct use of these types will be a reference to them.
|
Our correct use of these types will be a reference to them.
|
||||||
|
|
||||||
At last, we could consider a design defining both types: `KeyValue` and `Attr`.
|
At last, we provide `ValueFromAttribute` and `KeyValueFromAttribute`
|
||||||
However, in this approach we would need have factory functions for both types.
|
to offer reuse of `attribute.Value` and `attribute.KeyValue`.
|
||||||
It would make the API surface unnecessarily big,
|
|
||||||
and we may even have problems naming the functions.
|
|
||||||
|
|
||||||
[^1]: [Handle structured body and attributes](https://github.com/pellared/opentelemetry-go/pull/7)
|
[^1]: [Handle structured body and attributes](https://github.com/pellared/opentelemetry-go/pull/7)
|
||||||
[^2]: Jonathan Amsterdam, [The Go Blog: Structured Logging with slog](https://go.dev/blog/slog)
|
[^2]: Jonathan Amsterdam, [The Go Blog: Structured Logging with slog](https://go.dev/blog/slog)
|
||||||
|
Reference in New Issue
Block a user