Closes#5425
Our current log `Processor` interface contains more functionality than
the [OTel
spec](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/sdk.md#logrecordprocessor-operations).
The additional functionality allows processors to report back to the API
if a Record should be constructed and emitted or not, which is quite
helpful[^1][^2][^3][^4][^5].
This removes the `Enabled` method from the `Processor` type. It adds
this functionality a new optional and experimental `FilterProcessor`
interface type. The logger and provider are updated to check for this
optional interface to be implemented with the configured processors and
uses them to back the `Logger.Enabled` method, preserving existing
functionality.
By making this change:
- The `Processor` interface is now compliant with the OTel spec and does
not contain any additional unspecified behavior.
- All `Processor` implementations are no longer required to implement an
`Enabled` method. The default, when they do not implement this method,
is to assume they are enabled.
### Benchmark
```terminal
goos: linux
goarch: amd64
pkg: go.opentelemetry.io/otel/sdk/log
cpu: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
│ old.txt │ new7.txt │
│ sec/op │ sec/op vs base │
LoggerEnabled-8 133.30n ± 3% 32.36n ± 3% -75.72% (p=0.000 n=10)
│ old.txt │ new7.txt │
│ B/op │ B/op vs base │
LoggerEnabled-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹
¹ all samples are equal
│ old.txt │ new7.txt │
│ allocs/op │ allocs/op vs base │
LoggerEnabled-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹
¹ all samples are equal
```
This is a significant performance improvement due to the `Record` no
longer being converted from the API version to the SDK version.
[^1]: https://pkg.go.dev/go.opentelemetry.io/contrib/processors/minsev
[^2]:
https://pkg.go.dev/go.opentelemetry.io/otel/sdk/log#BatchProcessor.Enabled
[^3]:
https://pkg.go.dev/go.opentelemetry.io/otel/sdk/log#SimpleProcessor.Enabled
[^4]:
af75717ac4/bridges/otelslog/handler.go (L206-L211)
[^5]:
d0309ddd8c/bridges/otelzap/core.go (L142-L146)
---------
Co-authored-by: Robert Pająk <pellared@hotmail.com>
Co-authored-by: Sam Xie <sam@samxie.me>
Ensure the `Record` and `Provider` continue to be non-comparable.
Restrict `BatchProcessor` and `SimpleProcessor` to be non-comparable.
There is no obvious reason an end-user will need to compare these types,
and we want to keep the possibility of changing the internals without
changing this behavior.
if comparability is required by end-users in the future we can add
`Equal(other T)` methods in the future.
From
https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/sdk.md#export:
> `Export` will never be called concurrently for the same exporter
instance.
From our SDK perspective this change will make
https://pkg.go.dev/go.opentelemetry.io/otel/exporters/stdout/stdoutlog
concurrent-safe when used with the simple processor. Before the change,
there can be multiple goroutines calling `Write` in parallel (via
`json.Encoder.Encode`).
### Remarks
[Maybe we should simply state that "whole" exporter implementation does
not need to be
concurrent-safe?](https://github.com/open-telemetry/opentelemetry-specification/pull/4173#discussion_r1699958752)
However:
1. we would need to make complex changes in `BatchExporter` to
synchronize the `Export`, `Shutdown`, `ForceFlush` calls
2. we would need to update all exporters (remove synchronization) and
simple exporter (add locks to `Shutdown`, `ForceFlush`)
3. I am 100% not sure if this would be compliant with the specification
- I think it would be complaint because we would simply give stronger
safety-measures
We should probably discuss it separately, but I wanted to highlight my
though process.
Even if we decide that simple and batch processors to synchronize all
calls then I would prefer to address it in a separate PR.
Related spec clarification PR:
-
https://github.com/open-telemetry/opentelemetry-specification/pull/4173
The reason for this improvement (apart that, in general, it is good to
have better performance) is there may be good use case to use a
`SimpleProcessor` to emit logs efficiently to standard output. It could
be one of the most efficient solutions (from application performance
perspective) and thanks to such configuration the user would not lose
any logs if the application suddenly crashes. For instance, a useful
configuration could be a simple processor with an OTLP file exporter
(https://github.com/open-telemetry/opentelemetry-go/issues/5408).
I think we might consider changing the following portion of
`SimpleProcessor` documentation (but I would prefer to do it as separate
PR):
> // This Processor is not recommended for production use. The
synchronous
// nature of this Processor make it good for testing, debugging, or
// showing examples of other features, but it can be slow and have a
high
// computation resource usage overhead. [NewBatchProcessor] is
recommended
// for production use instead.
```
goos: linux
goarch: amd64
pkg: go.opentelemetry.io/otel/sdk/log
cpu: Intel(R) Core(TM) i9-10885H CPU @ 2.40GHz
│ old.txt │ new.txt │
│ sec/op │ sec/op vs base │
Processor/Simple-16 449.4n ± 7% 156.2n ± 5% -65.25% (p=0.000 n=10)
Processor/ModifyTimestampSimple-16 468.0n ± 6% 171.3n ± 15% -63.40% (p=0.000 n=10)
Processor/ModifyAttributesSimple-16 515.8n ± 3% 233.2n ± 8% -54.77% (p=0.000 n=10)
geomean 476.9n 184.1n -61.40%
│ old.txt │ new.txt │
│ B/op │ B/op vs base │
Processor/Simple-16 417.0 ± 0% 0.0 ± 0% -100.00% (p=0.000 n=10)
Processor/ModifyTimestampSimple-16 417.0 ± 0% 0.0 ± 0% -100.00% (p=0.000 n=10)
Processor/ModifyAttributesSimple-16 465.00 ± 0% 48.00 ± 0% -89.68% (p=0.000 n=10)
geomean 432.4 ? ¹ ²
¹ summaries must be >0 to compute geomean
² ratios must be >0 to compute geomean
│ old.txt │ new.txt │
│ allocs/op │ allocs/op vs base │
Processor/Simple-16 1.000 ± 0% 0.000 ± 0% -100.00% (p=0.000 n=10)
Processor/ModifyTimestampSimple-16 1.000 ± 0% 0.000 ± 0% -100.00% (p=0.000 n=10)
Processor/ModifyAttributesSimple-16 2.000 ± 0% 1.000 ± 0% -50.00% (p=0.000 n=10)
geomean 1.260 ? ¹ ²
¹ summaries must be >0 to compute geomean
² ratios must be >0 to compute geomean
```
---------
Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
* Add the Enabled method to the Logger
* Add a changelog entry
* Rename enabled.go to min_sev.go
* Remove MinSeverityProcessor
* Document lack of interaction between OnEmit and Enabled
* Update sdk/log/processor.go
---------
Co-authored-by: Robert Pająk <pellared@hotmail.com>