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
|
||||
|
||||
`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
|
||||
[#4725](https://github.com/open-telemetry/opentelemetry-go/pull/4725).
|
||||
|
||||
## 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.
|
||||
Performance is seen as one of the most important characteristics of logging libraries in Go.
|
||||
|
||||
@@ -40,7 +40,7 @@ Rejected alternative:
|
||||
|
||||
### 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).
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
@@ -59,7 +59,7 @@ The `LoggerOption` options are defined to support optional parameters.
|
||||
|
||||
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 should use some default name if the passed name is empty
|
||||
@@ -78,7 +78,7 @@ Rejected alternative:
|
||||
|
||||
### 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).
|
||||
|
||||
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
|
||||
|
||||
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/)
|
||||
is accepted as a `context.Context` method argument.
|
||||
|
||||
Calls to `Emit` are supposed to be on the hot path.
|
||||
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).
|
||||
|
||||
[`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)
|
||||
```
|
||||
|
||||
[`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)
|
||||
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:
|
||||
|
||||
- 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 must not interrupt the record processing if the context is canceled
|
||||
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.
|
||||
|
||||
- The method should handle the trace context passed via `ctx` argument in order to meet the
|
||||
@@ -253,7 +261,7 @@ Rejected alternatives:
|
||||
|
||||
### 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/)
|
||||
is accepted as a `context.Context` method argument.
|
||||
@@ -271,7 +279,7 @@ where `Enabled` is called.
|
||||
### noop package
|
||||
|
||||
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
|
||||
|
||||
@@ -319,7 +327,7 @@ nor any other logging library.
|
||||
|
||||
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.
|
||||
|
||||
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 {
|
||||
Timestamp time.Time
|
||||
ObservedTimestamp time.Time
|
||||
EventName string
|
||||
Severity Severity
|
||||
SeverityText string
|
||||
Body Value
|
||||
Attributes []KeyValue
|
||||
}
|
||||
```
|
||||
|
||||
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
|
||||
when the other is already set would be unpleasant.
|
||||
|
||||
## Reuse attribute package
|
||||
### Reuse attribute package
|
||||
|
||||
It was tempting to reuse the existing
|
||||
[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
|
||||
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)
|
||||
have different receiver types.
|
||||
@@ -577,17 +587,9 @@ we decided to use pointer receivers for all `Record` methods.
|
||||
|
||||
### Add XYZ method to Logger
|
||||
|
||||
The `Logger` does not have methods like `Enabled`, `SetSeverity`, etc.
|
||||
as the Bridge API needs to follow (be compliant with)
|
||||
the [specification](https://opentelemetry.io/docs/specs/otel/logs/bridge-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).
|
||||
The `Logger` does not have methods like `SetSeverity`, etc.
|
||||
as the Logs API needs to follow (be compliant with)
|
||||
the [specification](https://opentelemetry.io/docs/specs/otel/logs/api/)
|
||||
|
||||
### Rename KeyValue to Attr
|
||||
|
||||
@@ -597,16 +599,17 @@ the OpenTelemetry parlance.
|
||||
|
||||
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 map item
|
||||
- as a log attribute,
|
||||
- as a map item,
|
||||
- as a log record Body.
|
||||
|
||||
As for map item semantics, this type is a key-value pair, not an attribute.
|
||||
Naming the type as `Attr` would convey semantical meaning
|
||||
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.
|
||||
Given we will all have the context needed to disambiguate these overlapping
|
||||
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.
|
||||
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`.
|
||||
However, in this approach we would need have factory functions for both types.
|
||||
It would make the API surface unnecessarily big,
|
||||
and we may even have problems naming the functions.
|
||||
At last, we provide `ValueFromAttribute` and `KeyValueFromAttribute`
|
||||
to offer reuse of `attribute.Value` and `attribute.KeyValue`.
|
||||
|
||||
[^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)
|
||||
|
Reference in New Issue
Block a user