[chore] Simplify the OTEL setup (#4110)

# Description

This simplifies our OTEL setup by:

* Getting rid of some deprecated things.
* Using `autoexport` and letting things get configured by the `OTEL_` environment variables.
* Removing all the unnecessary config options.

## Checklist

Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]`

If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want).

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [ ] I/we have commented the added code, particularly in hard-to-understand areas.
- [x] I/we have made any necessary changes to documentation.
- [ ] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4110
Reviewed-by: tobi <kipvandenbos@noreply.codeberg.org>
Co-authored-by: Daenney <daenney@noreply.codeberg.org>
Co-committed-by: Daenney <daenney@noreply.codeberg.org>
This commit is contained in:
Daenney 2025-05-05 16:22:45 +00:00 committed by tobi
commit ecbdc4227b
145 changed files with 21740 additions and 1319 deletions

634
vendor/go.opentelemetry.io/otel/log/DESIGN.md generated vendored Normal file
View file

@ -0,0 +1,634 @@
# Logs API
## Abstract
`go.opentelemetry.io/otel/log` provides
[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/api/)
with an intuitive and user friendly design.
Performance is seen as one of the most important characteristics of logging libraries in Go.
## Design
This proposed design aims to:
- be specification compliant,
- be similar to Trace and Metrics API,
- take advantage of both OpenTelemetry and `slog` experience to achieve acceptable performance.
### Module structure
The API is published as a single `go.opentelemetry.io/otel/log` Go module.
The package structure is similar to Trace API and Metrics API.
The Go module consists of the following packages:
- `go.opentelemetry.io/otel/log`
- `go.opentelemetry.io/otel/log/embedded`
- `go.opentelemetry.io/otel/log/logtest`
- `go.opentelemetry.io/otel/log/noop`
Rejected alternative:
- [Reuse slog](#reuse-slog)
### 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`.
The interface may have methods added without a package major version bump.
This embeds `embedded.LoggerProvider` to help inform an API implementation
author about this non-standard API evolution.
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/api/#get-a-logger).
The required `name` parameter is accepted as a `string` method argument.
The `LoggerOption` options are defined to support optional parameters.
Implementation 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
in order to meet the [specification's SDK requirement](https://opentelemetry.io/docs/specs/otel/logs/sdk/#logger-creation)
to return a working logger when an invalid name is passed
as well as to resemble the behavior of getting tracers and meters.
`Logger` can be extended by adding new `LoggerOption` options
and adding new exported fields to the `LoggerConfig` struct.
This design is already used in Trace API for getting tracers
and in Metrics API for getting meters.
Rejected alternative:
- [Passing struct as parameter to LoggerProvider.Logger](#passing-struct-as-parameter-to-loggerproviderlogger).
### 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`.
The interface may have methods added without a package major version bump.
This embeds `embedded.Logger` to help inform an API implementation
author about this non-standard API evolution.
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/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/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)
is accessed using following methods:
```go
func (r *Record) Timestamp() time.Time
func (r *Record) SetTimestamp(t time.Time)
```
[`ObservedTimestamp`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-observedtimestamp)
is accessed using following methods:
```go
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:
```go
func (r *Record) Severity() Severity
func (r *Record) SetSeverity(s Severity)
```
`Severity` type is defined in [severity.go](severity.go).
The constants are are based on
[Displaying Severity recommendation](https://opentelemetry.io/docs/specs/otel/logs/data-model/#displaying-severity).
Additionally, `Severity[Level]` constants are defined to make the API more readable and user friendly.
[`SeverityText`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitytext)
is accessed using following methods:
```go
func (r *Record) SeverityText() string
func (r *Record) SetSeverityText(s string)
```
[`Body`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-body)
is accessed using following methods:
```go
func (r *Record) Body() Value
func (r *Record) SetBody(v Value)
```
[Log record attributes](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-attributes)
are accessed using following methods:
```go
func (r *Record) WalkAttributes(f func(KeyValue) bool)
func (r *Record) AddAttributes(attrs ...KeyValue)
```
`Record` has a `AttributesLen` method that returns
the number of attributes to allow slice preallocation
when converting records to a different representation:
```go
func (r *Record) AttributesLen() int
```
The records attributes design and implementation is based on
[`slog.Record`](https://pkg.go.dev/log/slog#Record).
It allows achieving high-performance access and manipulation of the attributes
while keeping the API user friendly.
It relieves the user from making his own improvements
for reducing the number of allocations when passing attributes.
The abstractions described in
[the specification](https://opentelemetry.io/docs/specs/otel/logs/#new-first-party-application-logs)
are defined in [keyvalue.go](keyvalue.go).
`Value` is representing `any`.
`KeyValue` is representing a key(string)-value(`any`) pair.
`Kind` is an enumeration used for specifying the underlying value type.
`KindEmpty` is used for an empty (zero) value.
`KindBool` is used for boolean value.
`KindFloat64` is used for a double precision floating point (IEEE 754-1985) value.
`KindInt64` is used for a signed integer value.
`KindString` is used for a string value.
`KindBytes` is used for a slice of bytes (in spec: A byte array).
`KindSlice` is used for a slice of values (in spec: an array (a list) of any values).
`KindMap` is used for a slice of key-value pairs (in spec: `map<string, any>`).
These types are defined in `go.opentelemetry.io/otel/log` package
as they are tightly coupled with the API and different from common attributes.
The internal implementation of `Value` is based on
[`slog.Value`](https://pkg.go.dev/log/slog#Value)
and the API is mostly inspired by
[`attribute.Value`](https://pkg.go.dev/go.opentelemetry.io/otel/attribute#Value).
The benchmarks[^1] show that the implementation is more performant than
[`attribute.Value`](https://pkg.go.dev/go.opentelemetry.io/otel/attribute#Value).
The value accessors (`func (v Value) As[Kind]` methods) must not panic,
as it would violate the [specification](https://opentelemetry.io/docs/specs/otel/error-handling/):
> API methods MUST NOT throw unhandled exceptions when used incorrectly by end
> users. The API and SDK SHOULD provide safe defaults for missing or invalid
> arguments. [...] Whenever the library suppresses an error that would otherwise
> have been exposed to the user, the library SHOULD log the error using
> language-specific conventions.
Therefore, the value accessors should return a zero value
and log an error when a bad accessor is called.
The `Severity`, `Kind`, `Value`, `KeyValue` may implement
the [`fmt.Stringer`](https://pkg.go.dev/fmt#Stringer) interface.
However, it is not needed for the first stable release
and the `String` methods can be added later.
The caller must not subsequently mutate the record passed to `Emit`.
This would allow the implementation to not clone the record,
but simply retain, modify or discard it.
The implementation may still choose to clone the record or copy its attributes
if it needs to retain or modify it,
e.g. in case of asynchronous processing to eliminate the possibility of data races,
because the user can technically reuse the record and add new attributes
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/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/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
[specification's SDK requirement](https://opentelemetry.io/docs/specs/otel/logs/sdk/#readablelogrecord)
to populate the trace context fields from the resolved context.
`Emit` can be extended by adding new exported fields to the `Record` struct.
Rejected alternatives:
- [Record as interface](#record-as-interface)
- [Options as parameter to Logger.Emit](#options-as-parameter-to-loggeremit)
- [Passing record as pointer to Logger.Emit](#passing-record-as-pointer-to-loggeremit)
- [Logger.WithAttributes](#loggerwithattributes)
- [Record attributes as slice](#record-attributes-as-slice)
- [Use any instead of defining Value](#use-any-instead-of-defining-value)
- [Severity type encapsulating number and text](#severity-type-encapsulating-number-and-text)
- [Reuse attribute package](#reuse-attribute-package)
- [Mix receiver types for Record](#mix-receiver-types-for-record)
- [Add XYZ method to Logger](#add-xyz-method-to-logger)
- [Rename KeyValue to Attr](#rename-keyvalue-to-attr)
### Logger.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.
Calls to `Enabled` are supposed to be on the hot path and the list of arguments
can be extendend in future. Therefore, in order to reduce the number of heap
allocations and make it possible to handle new arguments, `Enabled` accepts
a `EnabledParameters` struct, defined in [logger.go](logger.go), as the second
method argument.
The `EnabledParameters` uses fields, instead of getters and setters, to allow
simpler usage which allows configuring the `EnabledParameters` in the same line
where `Enabled` is called.
### noop package
The `go.opentelemetry.io/otel/log/noop` package provides
[Logs API No-Op Implementation](https://opentelemetry.io/docs/specs/otel/logs/noop/).
### Trace context correlation
The bridge implementation should do its best to pass
the `ctx` containing the trace context from the caller
so it can later be passed via `Logger.Emit`.
It is not expected that users (caller or bridge implementation) reconstruct
a `context.Context`. Reconstructing a `context.Context` with
[`trace.ContextWithSpanContext`](https://pkg.go.dev/go.opentelemetry.io/otel/trace#ContextWithSpanContext)
and [`trace.NewSpanContext`](https://pkg.go.dev/go.opentelemetry.io/otel/trace#NewSpanContext)
would usually involve more memory allocations.
The logging libraries which have recording methods that accepts `context.Context`,
such us [`slog`](https://pkg.go.dev/log/slog),
[`logrus`](https://pkg.go.dev/github.com/sirupsen/logrus),
[`zerolog`](https://pkg.go.dev/github.com/rs/zerolog),
makes passing the trace context trivial.
However, some libraries do not accept a `context.Context` in their recording methods.
Structured logging libraries,
such as [`logr`](https://pkg.go.dev/github.com/go-logr/logr)
and [`zap`](https://pkg.go.dev/go.uber.org/zap),
offer passing `any` type as a log attribute/field.
Therefore, their bridge implementations can define a "special" log attributes/field
that will be used to capture the trace context.
[The prototype](https://github.com/open-telemetry/opentelemetry-go/pull/4725)
has bridge implementations that handle trace context correlation efficiently.
## Benchmarking
The benchmarks take inspiration from [`slog`](https://pkg.go.dev/log/slog),
because for the Go team it was also critical to create API that would be fast
and interoperable with existing logging packages.[^2][^3]
The benchmark results can be found in [the prototype](https://github.com/open-telemetry/opentelemetry-go/pull/4725).
## Rejected alternatives
### Reuse slog
The API must not be coupled to [`slog`](https://pkg.go.dev/log/slog),
nor any other logging library.
The API needs to evolve orthogonally to `slog`.
`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).
You can read more about OpenTelemetry Logs design on [opentelemetry.io](https://opentelemetry.io/docs/concepts/signals/logs/).
### Record as interface
`Record` is defined as a `struct` because of the following reasons.
Log record is a value object without any behavior.
It is used as data input for Logger methods.
The log record resembles the instrument config structs like [metric.Float64CounterConfig](https://pkg.go.dev/go.opentelemetry.io/otel/metric#Float64CounterConfig).
Using `struct` instead of `interface` improves the performance as e.g.
indirect calls are less optimized,
usage of interfaces tend to increase heap allocations.[^3]
### Options as parameter to Logger.Emit
One of the initial ideas was to have:
```go
type Logger interface{
embedded.Logger
Emit(ctx context.Context, options ...RecordOption)
}
```
The main reason was that design would be similar
to the [Meter API](https://pkg.go.dev/go.opentelemetry.io/otel/metric#Meter)
for creating instruments.
However, passing `Record` directly, instead of using options,
is more performant as it reduces heap allocations.[^4]
Another advantage of passing `Record` is that API would not have functions like `NewRecord(options...)`,
which would be used by the SDK and not by the users.
Finally, the definition would be similar to [`slog.Handler.Handle`](https://pkg.go.dev/log/slog#Handler)
that was designed to provide optimization opportunities.[^2]
### Passing record as pointer to Logger.Emit
So far the benchmarks do not show differences that would
favor passing the record via pointer (and vice versa).
Passing via value feels safer because of the following reasons.
The user would not be able to pass `nil`.
Therefore, it reduces the possibility to have a nil pointer dereference.
It should reduce the possibility of a heap allocation.
It follows the design of [`slog.Handler`](https://pkg.go.dev/log/slog#Handler).
If follows one of Google's Go Style Decisions
to prefer [passing values](https://google.github.io/styleguide/go/decisions#pass-values).
### Passing struct as parameter to LoggerProvider.Logger
Similarly to `Logger.Emit`, we could have something like:
```go
type LoggerProvider interface{
embedded.LoggerProvider
Logger(name string, config LoggerConfig)
}
```
The drawback of this idea would be that this would be
a different design from Trace and Metrics API.
The performance of acquiring a logger is not as critical
as the performance of emitting a log record. While a single
HTTP/RPC handler could write hundreds of logs, it should not
create a new logger for each log entry.
The bridge implementation should reuse loggers whenever possible.
### Logger.WithAttributes
We could add `WithAttributes` to the `Logger` interface.
Then `Record` could be a simple struct with only exported fields.
The idea was that the SDK would implement the performance improvements
instead of doing it in the API.
This would allow having different optimization strategies.
During the analysis[^5], it occurred that the main problem of this proposal
is that the variadic slice passed to an interface method is always heap allocated.
Moreover, the logger returned by `WithAttribute` was allocated on the heap.
Lastly, the proposal was not specification compliant.
### Record attributes as slice
One of the proposals[^6] was to have `Record` as a simple struct:
```go
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)
for reducing the number of allocations when passing attributes.
The benchmarks results were better.
In such a design, most bridges would have a `sync.Pool`
to reduce the number of heap allocations.
However, the `sync.Pool` will not work correctly with API implementations
that would take ownership of the record
(e.g. implementations that do not copy records for asynchronous processing).
The current design, even in case of improper API implementation,
has lower chances of encountering a bug as most bridges would
create a record, pass it, and forget about it.
For reference, here is the reason why `slog` does not use `sync.Pool`[^3]
as well:
> We can use a sync pool for records though we decided not to.
You can but it's a bad idea for us. Why?
Because users have control of Records.
Handler writers can get their hands on a record
and we'd have to ask them to free it
or try to free it magically at some some point.
But either way, they could get themselves in trouble by freeing it twice
or holding on to one after they free it.
That's a use after free bug and that's why `zerolog` was problematic for us.
`zerolog` as as part of its speed exposes a pool allocated value to users
if you use `zerolog` the normal way, that you'll see in all the examples,
you will never encounter a problem.
But if you do something a little out of the ordinary you can get
use after free bugs and we just didn't want to put that in the standard library.
Therefore, we decided to not follow the proposal as it is
less user friendly (users and bridges would use e.g. a `sync.Pool` to reduce
the number of heap allocation), less safe (more prone to use after free bugs
and race conditions), and the benchmark differences were not significant.
### Use any instead of defining Value
[Logs Data Model](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-body)
defines Body to be `any`.
One could propose to define `Body` (and attribute values) as `any`
instead of a defining a new type (`Value`).
First of all, [`any` type defined in the specification](https://opentelemetry.io/docs/specs/otel/logs/data-model/#type-any)
is not the same as `any` (`interface{}`) in Go.
Moreover, using `any` as a field would decrease the performance.[^7]
Notice it will be still possible to add following kind and factories
in a backwards compatible way:
```go
const KindMap Kind
func AnyValue(value any) KeyValue
func Any(key string, value any) KeyValue
```
However, currently, it would not be specification compliant.
### Severity type encapsulating number and text
We could combine severity into a single field defining a type:
```go
type Severity struct {
Number SeverityNumber
Text string
}
```
However, the [Logs Data Model](https://opentelemetry.io/docs/specs/otel/logs/data-model/#log-and-event-record-definition)
define it as independent fields.
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
It was tempting to reuse the existing
[https://pkg.go.dev/go.opentelemetry.io/otel/attribute] package
for defining log attributes and body.
However, this would be wrong because [the log attribute definition](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-attributes)
is different from [the common attribute definition](https://opentelemetry.io/docs/specs/otel/common/#attribute).
Moreover, it there is nothing telling that [the body definition](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-body)
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
Methods of [`slog.Record`](https://pkg.go.dev/log/slog#Record)
have different receiver types.
In `log/slog` GitHub issue we can only find that the reason is:[^8]
>> some receiver of Record struct is by value
> Passing Records by value means they incur no heap allocation.
> That improves performance overall, even though they are copied.
However, the benchmarks do not show any noticeable differences.[^9]
The compiler is smart-enough to not make a heap allocation for any of these methods.
The use of a pointer receiver does not cause any heap allocation.
From Go FAQ:[^10]
> In the current compilers, if a variable has its address taken,
> that variable is a candidate for allocation on the heap.
> However, a basic escape analysis recognizes some cases
> when such variables will not live past the return from the function
> and can reside on the stack.
The [Understanding Allocations: the Stack and the Heap](https://www.youtube.com/watch?v=ZMZpH4yT7M0)
presentation by Jacob Walker describes the escape analysis with details.
Moreover, also from Go FAQ:[^10]
> Also, if a local variable is very large,
> it might make more sense to store it on the heap rather than the stack.
Therefore, even if we use a value receiver and the value is very large
it may be heap allocated.
Both [Go Code Review Comments](https://go.dev/wiki/CodeReviewComments#receiver-type)
and [Google's Go Style Decisions](https://google.github.io/styleguide/go/decisions#receiver-type)
highly recommend making the methods for a type either all pointer methods
or all value methods. Google's Go Style Decisions even goes further and says:
> There is a lot of misinformation about whether passing a value or a pointer
> to a function can affect performance.
> The compiler can choose to pass pointers to values on the stack
> as well as copying values on the stack,
> but these considerations should not outweigh the readability
> and correctness of the code in most circumstances.
> When the performance does matter, it is important to profile both approaches
> with a realistic benchmark before deciding that one approach outperforms the other.
Because, the benchmarks[^9] do not proof any performance difference
and the general recommendation is to not mix receiver types,
we decided to use pointer receivers for all `Record` methods.
### Add XYZ method to Logger
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
There was a proposal to rename `KeyValue` to `Attr` (or `Attribute`).[^11]
New developers may not intuitively know that `log.KeyValue` is an attribute in
the OpenTelemetry parlance.
During the discussion we agreed to keep the `KeyValue` name.
The type is used in multiple semantics:
- 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 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.
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 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)
[^3]: Jonathan Amsterdam, [GopherCon Europe 2023: A Fast Structured Logging Package](https://www.youtube.com/watch?v=tC4Jt3i62ns)
[^4]: [Emit definition discussion with benchmarks](https://github.com/open-telemetry/opentelemetry-go/pull/4725#discussion_r1400869566)
[^5]: [Logger.WithAttributes analysis](https://github.com/pellared/opentelemetry-go/pull/3)
[^6]: [Record attributes as field and use sync.Pool for reducing allocations](https://github.com/pellared/opentelemetry-go/pull/4) and [Record attributes based on slog.Record](https://github.com/pellared/opentelemetry-go/pull/6)
[^7]: [Record.Body as any](https://github.com/pellared/opentelemetry-go/pull/5)
[^8]: [log/slog: structured, leveled logging](https://github.com/golang/go/issues/56345#issuecomment-1302563756)
[^9]: [Record with pointer receivers only](https://github.com/pellared/opentelemetry-go/pull/8)
[^10]: [Go FAQ: Stack or heap](https://go.dev/doc/faq#stack_or_heap)
[^11]: [Rename KeyValue to Attr discussion](https://github.com/open-telemetry/opentelemetry-go/pull/4809#discussion_r1476080093)

201
vendor/go.opentelemetry.io/otel/log/LICENSE generated vendored Normal file
View file

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

3
vendor/go.opentelemetry.io/otel/log/README.md generated vendored Normal file
View file

@ -0,0 +1,3 @@
# Log API
[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/log)](https://pkg.go.dev/go.opentelemetry.io/otel/log)

76
vendor/go.opentelemetry.io/otel/log/doc.go generated vendored Normal file
View file

@ -0,0 +1,76 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
/*
Package log provides the OpenTelemetry Logs API.
This package is intended to be used by bridges between existing logging
libraries and OpenTelemetry. Users should not directly use this package as a
logging library. Instead, install one of the bridges listed in the
[registry], and use the associated logging library.
# API Implementations
This package does not conform to the standard Go versioning policy, all of its
interfaces may have methods added to them without a package major version bump.
This non-standard API evolution could surprise an uninformed implementation
author. They could unknowingly build their implementation in a way that would
result in a runtime panic for their users that update to the new API.
The API is designed to help inform an instrumentation author about this
non-standard API evolution. It requires them to choose a default behavior for
unimplemented interface methods. There are three behavior choices they can
make:
- Compilation failure
- Panic
- Default to another implementation
All interfaces in this API embed a corresponding interface from
[go.opentelemetry.io/otel/log/embedded]. If an author wants the default
behavior of their implementations to be a compilation failure, signaling to
their users they need to update to the latest version of that implementation,
they need to embed the corresponding interface from
[go.opentelemetry.io/otel/log/embedded] in their implementation. For example,
import "go.opentelemetry.io/otel/log/embedded"
type LoggerProvider struct {
embedded.LoggerProvider
// ...
}
If an author wants the default behavior of their implementations to a panic,
they need to embed the API interface directly.
import "go.opentelemetry.io/otel/log"
type LoggerProvider struct {
log.LoggerProvider
// ...
}
This is not a recommended behavior as it could lead to publishing packages that
contain runtime panics when users update other package that use newer versions
of [go.opentelemetry.io/otel/log].
Finally, an author can embed another implementation in theirs. The embedded
implementation will be used for methods not defined by the author. For example,
an author who wants to default to silently dropping the call can use
[go.opentelemetry.io/otel/log/noop]:
import "go.opentelemetry.io/otel/log/noop"
type LoggerProvider struct {
noop.LoggerProvider
// ...
}
It is strongly recommended that authors only embed
go.opentelemetry.io/otel/log/noop if they choose this default behavior. That
implementation is the only one OpenTelemetry authors can guarantee will fully
implement all the API interfaces when a user updates their API.
[registry]: https://opentelemetry.io/ecosystem/registry/?language=go&component=log-bridge
*/
package log // import "go.opentelemetry.io/otel/log"

View file

@ -0,0 +1,3 @@
# Log Embedded
[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/log/embedded)](https://pkg.go.dev/go.opentelemetry.io/otel/log/embedded)

View file

@ -0,0 +1,36 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
// Package embedded provides interfaces embedded within the [OpenTelemetry Logs
// Bridge API].
//
// Implementers of the [OpenTelemetry Logs Bridge API] can embed the relevant
// type from this package into their implementation directly. Doing so will
// result in a compilation error for users when the [OpenTelemetry Logs Bridge
// API] is extended (which is something that can happen without a major version
// bump of the API package).
//
// [OpenTelemetry Logs Bridge API]: https://pkg.go.dev/go.opentelemetry.io/otel/log
package embedded // import "go.opentelemetry.io/otel/log/embedded"
// LoggerProvider is embedded in the [Logs Bridge API LoggerProvider].
//
// Embed this interface in your implementation of the [Logs Bridge API
// LoggerProvider] if you want users to experience a compilation error,
// signaling they need to update to your latest implementation, when the [Logs
// Bridge API LoggerProvider] interface is extended (which is something that
// can happen without a major version bump of the API package).
//
// [Logs Bridge API LoggerProvider]: https://pkg.go.dev/go.opentelemetry.io/otel/log#LoggerProvider
type LoggerProvider interface{ loggerProvider() }
// Logger is embedded in [Logs Bridge API Logger].
//
// Embed this interface in your implementation of the [Logs Bridge API Logger]
// if you want users to experience a compilation error, signaling they need to
// update to your latest implementation, when the [Logs Bridge API Logger]
// interface is extended (which is something that can happen without a major
// version bump of the API package).
//
// [Logs Bridge API Logger]: https://pkg.go.dev/go.opentelemetry.io/otel/log#Logger
type Logger interface{ logger() }

443
vendor/go.opentelemetry.io/otel/log/keyvalue.go generated vendored Normal file
View file

@ -0,0 +1,443 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
//go:generate stringer -type=Kind -trimprefix=Kind
package log // import "go.opentelemetry.io/otel/log"
import (
"bytes"
"cmp"
"errors"
"fmt"
"math"
"slices"
"strconv"
"unsafe"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/internal/global"
)
// errKind is logged when a Value is decoded to an incompatible type.
var errKind = errors.New("invalid Kind")
// Kind is the kind of a [Value].
type Kind int
// Kind values.
const (
KindEmpty Kind = iota
KindBool
KindFloat64
KindInt64
KindString
KindBytes
KindSlice
KindMap
)
// A Value represents a structured log value.
// A zero value is valid and represents an empty value.
type Value struct {
// Ensure forward compatibility by explicitly making this not comparable.
noCmp [0]func() //nolint: unused // This is indeed used.
// num holds the value for Int64, Float64, and Bool. It holds the length
// for String, Bytes, Slice, Map.
num uint64
// any holds either the KindBool, KindInt64, KindFloat64, stringptr,
// bytesptr, sliceptr, or mapptr. If KindBool, KindInt64, or KindFloat64
// then the value of Value is in num as described above. Otherwise, it
// contains the value wrapped in the appropriate type.
any any
}
type (
// sliceptr represents a value in Value.any for KindString Values.
stringptr *byte
// bytesptr represents a value in Value.any for KindBytes Values.
bytesptr *byte
// sliceptr represents a value in Value.any for KindSlice Values.
sliceptr *Value
// mapptr represents a value in Value.any for KindMap Values.
mapptr *KeyValue
)
// StringValue returns a new [Value] for a string.
func StringValue(v string) Value {
return Value{
num: uint64(len(v)),
any: stringptr(unsafe.StringData(v)),
}
}
// IntValue returns a [Value] for an int.
func IntValue(v int) Value { return Int64Value(int64(v)) }
// Int64Value returns a [Value] for an int64.
func Int64Value(v int64) Value {
// This can be later converted back to int64 (overflow not checked).
return Value{num: uint64(v), any: KindInt64} // nolint:gosec
}
// Float64Value returns a [Value] for a float64.
func Float64Value(v float64) Value {
return Value{num: math.Float64bits(v), any: KindFloat64}
}
// BoolValue returns a [Value] for a bool.
func BoolValue(v bool) Value { //nolint:revive // Not a control flag.
var n uint64
if v {
n = 1
}
return Value{num: n, any: KindBool}
}
// BytesValue returns a [Value] for a byte slice. The passed slice must not be
// changed after it is passed.
func BytesValue(v []byte) Value {
return Value{
num: uint64(len(v)),
any: bytesptr(unsafe.SliceData(v)),
}
}
// SliceValue returns a [Value] for a slice of [Value]. The passed slice must
// not be changed after it is passed.
func SliceValue(vs ...Value) Value {
return Value{
num: uint64(len(vs)),
any: sliceptr(unsafe.SliceData(vs)),
}
}
// MapValue returns a new [Value] for a slice of key-value pairs. The passed
// slice must not be changed after it is passed.
func MapValue(kvs ...KeyValue) Value {
return Value{
num: uint64(len(kvs)),
any: mapptr(unsafe.SliceData(kvs)),
}
}
// AsString returns the value held by v as a string.
func (v Value) AsString() string {
if sp, ok := v.any.(stringptr); ok {
return unsafe.String(sp, v.num)
}
global.Error(errKind, "AsString", "Kind", v.Kind())
return ""
}
// asString returns the value held by v as a string. It will panic if the Value
// is not KindString.
func (v Value) asString() string {
return unsafe.String(v.any.(stringptr), v.num)
}
// AsInt64 returns the value held by v as an int64.
func (v Value) AsInt64() int64 {
if v.Kind() != KindInt64 {
global.Error(errKind, "AsInt64", "Kind", v.Kind())
return 0
}
return v.asInt64()
}
// asInt64 returns the value held by v as an int64. If v is not of KindInt64,
// this will return garbage.
func (v Value) asInt64() int64 {
// Assumes v.num was a valid int64 (overflow not checked).
return int64(v.num) // nolint: gosec
}
// AsBool returns the value held by v as a bool.
func (v Value) AsBool() bool {
if v.Kind() != KindBool {
global.Error(errKind, "AsBool", "Kind", v.Kind())
return false
}
return v.asBool()
}
// asBool returns the value held by v as a bool. If v is not of KindBool, this
// will return garbage.
func (v Value) asBool() bool { return v.num == 1 }
// AsFloat64 returns the value held by v as a float64.
func (v Value) AsFloat64() float64 {
if v.Kind() != KindFloat64 {
global.Error(errKind, "AsFloat64", "Kind", v.Kind())
return 0
}
return v.asFloat64()
}
// asFloat64 returns the value held by v as a float64. If v is not of
// KindFloat64, this will return garbage.
func (v Value) asFloat64() float64 { return math.Float64frombits(v.num) }
// AsBytes returns the value held by v as a []byte.
func (v Value) AsBytes() []byte {
if sp, ok := v.any.(bytesptr); ok {
return unsafe.Slice((*byte)(sp), v.num)
}
global.Error(errKind, "AsBytes", "Kind", v.Kind())
return nil
}
// asBytes returns the value held by v as a []byte. It will panic if the Value
// is not KindBytes.
func (v Value) asBytes() []byte {
return unsafe.Slice((*byte)(v.any.(bytesptr)), v.num)
}
// AsSlice returns the value held by v as a []Value.
func (v Value) AsSlice() []Value {
if sp, ok := v.any.(sliceptr); ok {
return unsafe.Slice((*Value)(sp), v.num)
}
global.Error(errKind, "AsSlice", "Kind", v.Kind())
return nil
}
// asSlice returns the value held by v as a []Value. It will panic if the Value
// is not KindSlice.
func (v Value) asSlice() []Value {
return unsafe.Slice((*Value)(v.any.(sliceptr)), v.num)
}
// AsMap returns the value held by v as a []KeyValue.
func (v Value) AsMap() []KeyValue {
if sp, ok := v.any.(mapptr); ok {
return unsafe.Slice((*KeyValue)(sp), v.num)
}
global.Error(errKind, "AsMap", "Kind", v.Kind())
return nil
}
// asMap returns the value held by v as a []KeyValue. It will panic if the
// Value is not KindMap.
func (v Value) asMap() []KeyValue {
return unsafe.Slice((*KeyValue)(v.any.(mapptr)), v.num)
}
// Kind returns the Kind of v.
func (v Value) Kind() Kind {
switch x := v.any.(type) {
case Kind:
return x
case stringptr:
return KindString
case bytesptr:
return KindBytes
case sliceptr:
return KindSlice
case mapptr:
return KindMap
default:
return KindEmpty
}
}
// Empty returns if v does not hold any value.
func (v Value) Empty() bool { return v.Kind() == KindEmpty }
// Equal returns if v is equal to w.
func (v Value) Equal(w Value) bool {
k1 := v.Kind()
k2 := w.Kind()
if k1 != k2 {
return false
}
switch k1 {
case KindInt64, KindBool:
return v.num == w.num
case KindString:
return v.asString() == w.asString()
case KindFloat64:
return v.asFloat64() == w.asFloat64()
case KindSlice:
return slices.EqualFunc(v.asSlice(), w.asSlice(), Value.Equal)
case KindMap:
sv := sortMap(v.asMap())
sw := sortMap(w.asMap())
return slices.EqualFunc(sv, sw, KeyValue.Equal)
case KindBytes:
return bytes.Equal(v.asBytes(), w.asBytes())
case KindEmpty:
return true
default:
global.Error(errKind, "Equal", "Kind", k1)
return false
}
}
func sortMap(m []KeyValue) []KeyValue {
sm := make([]KeyValue, len(m))
copy(sm, m)
slices.SortFunc(sm, func(a, b KeyValue) int {
return cmp.Compare(a.Key, b.Key)
})
return sm
}
// String returns Value's value as a string, formatted like [fmt.Sprint].
//
// The returned string is meant for debugging;
// the string representation is not stable.
func (v Value) String() string {
switch v.Kind() {
case KindString:
return v.asString()
case KindInt64:
// Assumes v.num was a valid int64 (overflow not checked).
return strconv.FormatInt(int64(v.num), 10) // nolint: gosec
case KindFloat64:
return strconv.FormatFloat(v.asFloat64(), 'g', -1, 64)
case KindBool:
return strconv.FormatBool(v.asBool())
case KindBytes:
return fmt.Sprint(v.asBytes())
case KindMap:
return fmt.Sprint(v.asMap())
case KindSlice:
return fmt.Sprint(v.asSlice())
case KindEmpty:
return "<nil>"
default:
// Try to handle this as gracefully as possible.
//
// Don't panic here. The goal here is to have developers find this
// first if a slog.Kind is is not handled. It is
// preferable to have user's open issue asking why their attributes
// have a "unhandled: " prefix than say that their code is panicking.
return fmt.Sprintf("<unhandled log.Kind: %s>", v.Kind())
}
}
// A KeyValue is a key-value pair used to represent a log attribute (a
// superset of [go.opentelemetry.io/otel/attribute.KeyValue]) and map item.
type KeyValue struct {
Key string
Value Value
}
// Equal returns if a is equal to b.
func (a KeyValue) Equal(b KeyValue) bool {
return a.Key == b.Key && a.Value.Equal(b.Value)
}
// String returns a KeyValue for a string value.
func String(key, value string) KeyValue {
return KeyValue{key, StringValue(value)}
}
// Int64 returns a KeyValue for an int64 value.
func Int64(key string, value int64) KeyValue {
return KeyValue{key, Int64Value(value)}
}
// Int returns a KeyValue for an int value.
func Int(key string, value int) KeyValue {
return KeyValue{key, IntValue(value)}
}
// Float64 returns a KeyValue for a float64 value.
func Float64(key string, value float64) KeyValue {
return KeyValue{key, Float64Value(value)}
}
// Bool returns a KeyValue for a bool value.
func Bool(key string, value bool) KeyValue {
return KeyValue{key, BoolValue(value)}
}
// Bytes returns a KeyValue for a []byte value.
// The passed slice must not be changed after it is passed.
func Bytes(key string, value []byte) KeyValue {
return KeyValue{key, BytesValue(value)}
}
// Slice returns a KeyValue for a []Value value.
// The passed slice must not be changed after it is passed.
func Slice(key string, value ...Value) KeyValue {
return KeyValue{key, SliceValue(value...)}
}
// Map returns a KeyValue for a map value.
// The passed slice must not be changed after it is passed.
func Map(key string, value ...KeyValue) KeyValue {
return KeyValue{key, MapValue(value...)}
}
// Empty returns a KeyValue with an empty value.
func Empty(key string) KeyValue {
return KeyValue{key, Value{}}
}
// String returns key-value pair as a string, formatted like "key:value".
//
// The returned string is meant for debugging;
// the string representation is not stable.
func (a KeyValue) String() string {
return fmt.Sprintf("%s:%s", a.Key, a.Value)
}
// ValueFromAttribute converts [attribute.Value] to [Value].
func ValueFromAttribute(value attribute.Value) Value {
switch value.Type() {
case attribute.INVALID:
return Value{}
case attribute.BOOL:
return BoolValue(value.AsBool())
case attribute.BOOLSLICE:
val := value.AsBoolSlice()
res := make([]Value, 0, len(val))
for _, v := range val {
res = append(res, BoolValue(v))
}
return SliceValue(res...)
case attribute.INT64:
return Int64Value(value.AsInt64())
case attribute.INT64SLICE:
val := value.AsInt64Slice()
res := make([]Value, 0, len(val))
for _, v := range val {
res = append(res, Int64Value(v))
}
return SliceValue(res...)
case attribute.FLOAT64:
return Float64Value(value.AsFloat64())
case attribute.FLOAT64SLICE:
val := value.AsFloat64Slice()
res := make([]Value, 0, len(val))
for _, v := range val {
res = append(res, Float64Value(v))
}
return SliceValue(res...)
case attribute.STRING:
return StringValue(value.AsString())
case attribute.STRINGSLICE:
val := value.AsStringSlice()
res := make([]Value, 0, len(val))
for _, v := range val {
res = append(res, StringValue(v))
}
return SliceValue(res...)
}
// This code should never be reached
// as log attributes are a superset of standard attributes.
panic("unknown attribute type")
}
// KeyValueFromAttribute converts [attribute.KeyValue] to [KeyValue].
func KeyValueFromAttribute(kv attribute.KeyValue) KeyValue {
return KeyValue{
Key: string(kv.Key),
Value: ValueFromAttribute(kv.Value),
}
}

30
vendor/go.opentelemetry.io/otel/log/kind_string.go generated vendored Normal file
View file

@ -0,0 +1,30 @@
// Code generated by "stringer -type=Kind -trimprefix=Kind"; DO NOT EDIT.
package log
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[KindEmpty-0]
_ = x[KindBool-1]
_ = x[KindFloat64-2]
_ = x[KindInt64-3]
_ = x[KindString-4]
_ = x[KindBytes-5]
_ = x[KindSlice-6]
_ = x[KindMap-7]
}
const _Kind_name = "EmptyBoolFloat64Int64StringBytesSliceMap"
var _Kind_index = [...]uint8{0, 5, 9, 16, 21, 27, 32, 37, 40}
func (i Kind) String() string {
if i < 0 || i >= Kind(len(_Kind_index)-1) {
return "Kind(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _Kind_name[_Kind_index[i]:_Kind_index[i+1]]
}

140
vendor/go.opentelemetry.io/otel/log/logger.go generated vendored Normal file
View file

@ -0,0 +1,140 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package log // import "go.opentelemetry.io/otel/log"
import (
"context"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/log/embedded"
)
// Logger emits log records.
//
// Warning: Methods may be added to this interface in minor releases. See
// package documentation on API implementation for information on how to set
// default behavior for unimplemented methods.
type Logger interface {
// Users of the interface can ignore this. This embedded type is only used
// by implementations of this interface. See the "API Implementations"
// section of the package documentation for more information.
embedded.Logger
// Emit emits a log record.
//
// The record may be held by the implementation. Callers should not mutate
// the record after passed.
//
// Implementations of this method need to be safe for a user to call
// concurrently.
Emit(ctx context.Context, record Record)
// Enabled returns whether the Logger emits for the given context and
// param.
//
// This is useful for users that want to know if a [Record]
// will be processed or dropped before they perform complex operations to
// construct the [Record].
//
// The passed param is likely to be a partial record information being
// provided (e.g a param with only the Severity set).
// If a Logger needs more information than is provided, it
// is said to be in an indeterminate state (see below).
//
// The returned value will be true when the Logger will emit for the
// provided context and param, and will be false if the Logger will not
// emit. The returned value may be true or false in an indeterminate state.
// An implementation should default to returning true for an indeterminate
// state, but may return false if valid reasons in particular circumstances
// exist (e.g. performance, correctness).
//
// The param should not be held by the implementation. A copy should be
// made if the param needs to be held after the call returns.
//
// Implementations of this method need to be safe for a user to call
// concurrently.
Enabled(ctx context.Context, param EnabledParameters) bool
}
// LoggerOption applies configuration options to a [Logger].
type LoggerOption interface {
// applyLogger is used to set a LoggerOption value of a LoggerConfig.
applyLogger(LoggerConfig) LoggerConfig
}
// LoggerConfig contains options for a [Logger].
type LoggerConfig struct {
// Ensure forward compatibility by explicitly making this not comparable.
noCmp [0]func() //nolint: unused // This is indeed used.
version string
schemaURL string
attrs attribute.Set
}
// NewLoggerConfig returns a new [LoggerConfig] with all the options applied.
func NewLoggerConfig(options ...LoggerOption) LoggerConfig {
var c LoggerConfig
for _, opt := range options {
c = opt.applyLogger(c)
}
return c
}
// InstrumentationVersion returns the version of the library providing
// instrumentation.
func (cfg LoggerConfig) InstrumentationVersion() string {
return cfg.version
}
// InstrumentationAttributes returns the attributes associated with the library
// providing instrumentation.
func (cfg LoggerConfig) InstrumentationAttributes() attribute.Set {
return cfg.attrs
}
// SchemaURL returns the schema URL of the library providing instrumentation.
func (cfg LoggerConfig) SchemaURL() string {
return cfg.schemaURL
}
type loggerOptionFunc func(LoggerConfig) LoggerConfig
func (fn loggerOptionFunc) applyLogger(cfg LoggerConfig) LoggerConfig {
return fn(cfg)
}
// WithInstrumentationVersion returns a [LoggerOption] that sets the
// instrumentation version of a [Logger].
func WithInstrumentationVersion(version string) LoggerOption {
return loggerOptionFunc(func(config LoggerConfig) LoggerConfig {
config.version = version
return config
})
}
// WithInstrumentationAttributes returns a [LoggerOption] that sets the
// instrumentation attributes of a [Logger].
//
// The passed attributes will be de-duplicated.
func WithInstrumentationAttributes(attr ...attribute.KeyValue) LoggerOption {
return loggerOptionFunc(func(config LoggerConfig) LoggerConfig {
config.attrs = attribute.NewSet(attr...)
return config
})
}
// WithSchemaURL returns a [LoggerOption] that sets the schema URL for a
// [Logger].
func WithSchemaURL(schemaURL string) LoggerOption {
return loggerOptionFunc(func(config LoggerConfig) LoggerConfig {
config.schemaURL = schemaURL
return config
})
}
// EnabledParameters represents payload for [Logger]'s Enabled method.
type EnabledParameters struct {
Severity Severity
}

3
vendor/go.opentelemetry.io/otel/log/noop/README.md generated vendored Normal file
View file

@ -0,0 +1,3 @@
# Log Noop
[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/log/noop)](https://pkg.go.dev/go.opentelemetry.io/otel/log/noop)

50
vendor/go.opentelemetry.io/otel/log/noop/noop.go generated vendored Normal file
View file

@ -0,0 +1,50 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
// Package noop provides an implementation of the [OpenTelemetry Logs Bridge
// API] that produces no telemetry and minimizes used computation resources.
//
// Using this package to implement the [OpenTelemetry Logs Bridge API] will
// effectively disable OpenTelemetry.
//
// This implementation can be embedded in other implementations of the
// [OpenTelemetry Logs Bridge API]. Doing so will mean the implementation
// defaults to no operation for methods it does not implement.
//
// [OpenTelemetry Logs Bridge API]: https://pkg.go.dev/go.opentelemetry.io/otel/log
package noop // import "go.opentelemetry.io/otel/log/noop"
import (
"context"
"go.opentelemetry.io/otel/log"
"go.opentelemetry.io/otel/log/embedded"
)
var (
// Compile-time check this implements the OpenTelemetry API.
_ log.LoggerProvider = LoggerProvider{}
_ log.Logger = Logger{}
)
// LoggerProvider is an OpenTelemetry No-Op LoggerProvider.
type LoggerProvider struct{ embedded.LoggerProvider }
// NewLoggerProvider returns a LoggerProvider that does not record any telemetry.
func NewLoggerProvider() LoggerProvider {
return LoggerProvider{}
}
// Logger returns an OpenTelemetry Logger that does not record any telemetry.
func (LoggerProvider) Logger(string, ...log.LoggerOption) log.Logger {
return Logger{}
}
// Logger is an OpenTelemetry No-Op Logger.
type Logger struct{ embedded.Logger }
// Emit does nothing.
func (Logger) Emit(context.Context, log.Record) {}
// Enabled returns false. No log records are ever emitted.
func (Logger) Enabled(context.Context, log.EnabledParameters) bool { return false }

37
vendor/go.opentelemetry.io/otel/log/provider.go generated vendored Normal file
View file

@ -0,0 +1,37 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package log // import "go.opentelemetry.io/otel/log"
import "go.opentelemetry.io/otel/log/embedded"
// LoggerProvider provides access to [Logger].
//
// Warning: Methods may be added to this interface in minor releases. See
// package documentation on API implementation for information on how to set
// default behavior for unimplemented methods.
type LoggerProvider interface {
// Users of the interface can ignore this. This embedded type is only used
// by implementations of this interface. See the "API Implementations"
// section of the package documentation for more information.
embedded.LoggerProvider
// Logger returns a new [Logger] with the provided name and configuration.
//
// The name needs to uniquely identify the source of logged code. It is
// recommended that name is the Go package name of the library using a log
// bridge (note: this is not the name of the bridge package). Most
// commonly, this means a bridge will need to accept this value from its
// users.
//
// If name is empty, implementations need to provide a default name.
//
// The version of the packages using a bridge can be critical information
// to include when logging. The bridge should accept this version
// information and use the [WithInstrumentationVersion] option to configure
// the Logger appropriately.
//
// Implementations of this method need to be safe for a user to call
// concurrently.
Logger(name string, options ...LoggerOption) Logger
}

144
vendor/go.opentelemetry.io/otel/log/record.go generated vendored Normal file
View file

@ -0,0 +1,144 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package log // import "go.opentelemetry.io/otel/log"
import (
"slices"
"time"
)
// attributesInlineCount is the number of attributes that are efficiently
// stored in an array within a Record. This value is borrowed from slog which
// performed a quantitative survey of log library use and found this value to
// cover 95% of all use-cases (https://go.dev/blog/slog#performance).
const attributesInlineCount = 5
// Record represents a log record.
// A log record with non-empty event name is interpreted as an event record.
type Record struct {
// Ensure forward compatibility by explicitly making this not comparable.
noCmp [0]func() //nolint: unused // This is indeed used.
eventName string
timestamp time.Time
observedTimestamp time.Time
severity Severity
severityText string
body Value
// The fields below are for optimizing the implementation of Attributes and
// AddAttributes. This design is borrowed from the slog Record type:
// https://cs.opensource.google/go/go/+/refs/tags/go1.22.0:src/log/slog/record.go;l=20
// Allocation optimization: an inline array sized to hold
// the majority of log calls (based on examination of open-source
// code). It holds the start of the list of attributes.
front [attributesInlineCount]KeyValue
// The number of attributes in front.
nFront int
// The list of attributes except for those in front.
// Invariants:
// - len(back) > 0 if nFront == len(front)
// - Unused array elements are zero-ed. Used to detect mistakes.
back []KeyValue
}
// EventName returns the event name.
// A log record with non-empty event name is interpreted as an event record.
func (r *Record) EventName() string {
return r.eventName
}
// SetEventName sets the event name.
// A log record with non-empty event name is interpreted as an event record.
func (r *Record) SetEventName(s string) {
r.eventName = s
}
// Timestamp returns the time when the log record occurred.
func (r *Record) Timestamp() time.Time {
return r.timestamp
}
// SetTimestamp sets the time when the log record occurred.
func (r *Record) SetTimestamp(t time.Time) {
r.timestamp = t
}
// ObservedTimestamp returns the time when the log record was observed.
func (r *Record) ObservedTimestamp() time.Time {
return r.observedTimestamp
}
// SetObservedTimestamp sets the time when the log record was observed.
func (r *Record) SetObservedTimestamp(t time.Time) {
r.observedTimestamp = t
}
// Severity returns the [Severity] of the log record.
func (r *Record) Severity() Severity {
return r.severity
}
// SetSeverity sets the [Severity] level of the log record.
func (r *Record) SetSeverity(level Severity) {
r.severity = level
}
// SeverityText returns severity (also known as log level) text. This is the
// original string representation of the severity as it is known at the source.
func (r *Record) SeverityText() string {
return r.severityText
}
// SetSeverityText sets severity (also known as log level) text. This is the
// original string representation of the severity as it is known at the source.
func (r *Record) SetSeverityText(text string) {
r.severityText = text
}
// Body returns the body of the log record.
func (r *Record) Body() Value {
return r.body
}
// SetBody sets the body of the log record.
func (r *Record) SetBody(v Value) {
r.body = v
}
// WalkAttributes walks all attributes the log record holds by calling f for
// each on each [KeyValue] in the [Record]. Iteration stops if f returns false.
func (r *Record) WalkAttributes(f func(KeyValue) bool) {
for i := 0; i < r.nFront; i++ {
if !f(r.front[i]) {
return
}
}
for _, a := range r.back {
if !f(a) {
return
}
}
}
// AddAttributes adds attributes to the log record.
func (r *Record) AddAttributes(attrs ...KeyValue) {
var i int
for i = 0; i < len(attrs) && r.nFront < len(r.front); i++ {
a := attrs[i]
r.front[r.nFront] = a
r.nFront++
}
r.back = slices.Grow(r.back, len(attrs[i:]))
r.back = append(r.back, attrs[i:]...)
}
// AttributesLen returns the number of attributes in the log record.
func (r *Record) AttributesLen() int {
return r.nFront + len(r.back)
}

64
vendor/go.opentelemetry.io/otel/log/severity.go generated vendored Normal file
View file

@ -0,0 +1,64 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
//go:generate stringer -type=Severity -linecomment
package log // import "go.opentelemetry.io/otel/log"
// Severity represents a log record severity (also known as log level). Smaller
// numerical values correspond to less severe log records (such as debug
// events), larger numerical values correspond to more severe log records (such
// as errors and critical events).
type Severity int
// Severity values defined by OpenTelemetry.
const (
// SeverityUndefined represents an unset Severity.
SeverityUndefined Severity = 0 // UNDEFINED
// A fine-grained debugging log record. Typically disabled in default
// configurations.
SeverityTrace1 Severity = 1 // TRACE
SeverityTrace2 Severity = 2 // TRACE2
SeverityTrace3 Severity = 3 // TRACE3
SeverityTrace4 Severity = 4 // TRACE4
// A debugging log record.
SeverityDebug1 Severity = 5 // DEBUG
SeverityDebug2 Severity = 6 // DEBUG2
SeverityDebug3 Severity = 7 // DEBUG3
SeverityDebug4 Severity = 8 // DEBUG4
// An informational log record. Indicates that an event happened.
SeverityInfo1 Severity = 9 // INFO
SeverityInfo2 Severity = 10 // INFO2
SeverityInfo3 Severity = 11 // INFO3
SeverityInfo4 Severity = 12 // INFO4
// A warning log record. Not an error but is likely more important than an
// informational event.
SeverityWarn1 Severity = 13 // WARN
SeverityWarn2 Severity = 14 // WARN2
SeverityWarn3 Severity = 15 // WARN3
SeverityWarn4 Severity = 16 // WARN4
// An error log record. Something went wrong.
SeverityError1 Severity = 17 // ERROR
SeverityError2 Severity = 18 // ERROR2
SeverityError3 Severity = 19 // ERROR3
SeverityError4 Severity = 20 // ERROR4
// A fatal log record such as application or system crash.
SeverityFatal1 Severity = 21 // FATAL
SeverityFatal2 Severity = 22 // FATAL2
SeverityFatal3 Severity = 23 // FATAL3
SeverityFatal4 Severity = 24 // FATAL4
// Convenience definitions for the base severity of each level.
SeverityTrace = SeverityTrace1
SeverityDebug = SeverityDebug1
SeverityInfo = SeverityInfo1
SeverityWarn = SeverityWarn1
SeverityError = SeverityError1
SeverityFatal = SeverityFatal1
)

47
vendor/go.opentelemetry.io/otel/log/severity_string.go generated vendored Normal file
View file

@ -0,0 +1,47 @@
// Code generated by "stringer -type=Severity -linecomment"; DO NOT EDIT.
package log
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[SeverityUndefined-0]
_ = x[SeverityTrace1-1]
_ = x[SeverityTrace2-2]
_ = x[SeverityTrace3-3]
_ = x[SeverityTrace4-4]
_ = x[SeverityDebug1-5]
_ = x[SeverityDebug2-6]
_ = x[SeverityDebug3-7]
_ = x[SeverityDebug4-8]
_ = x[SeverityInfo1-9]
_ = x[SeverityInfo2-10]
_ = x[SeverityInfo3-11]
_ = x[SeverityInfo4-12]
_ = x[SeverityWarn1-13]
_ = x[SeverityWarn2-14]
_ = x[SeverityWarn3-15]
_ = x[SeverityWarn4-16]
_ = x[SeverityError1-17]
_ = x[SeverityError2-18]
_ = x[SeverityError3-19]
_ = x[SeverityError4-20]
_ = x[SeverityFatal1-21]
_ = x[SeverityFatal2-22]
_ = x[SeverityFatal3-23]
_ = x[SeverityFatal4-24]
}
const _Severity_name = "UNDEFINEDTRACETRACE2TRACE3TRACE4DEBUGDEBUG2DEBUG3DEBUG4INFOINFO2INFO3INFO4WARNWARN2WARN3WARN4ERRORERROR2ERROR3ERROR4FATALFATAL2FATAL3FATAL4"
var _Severity_index = [...]uint8{0, 9, 14, 20, 26, 32, 37, 43, 49, 55, 59, 64, 69, 74, 78, 83, 88, 93, 98, 104, 110, 116, 121, 127, 133, 139}
func (i Severity) String() string {
if i < 0 || i >= Severity(len(_Severity_index)-1) {
return "Severity(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _Severity_name[_Severity_index[i]:_Severity_index[i+1]]
}