[chore] bump dependencies (#4406)

- codeberg.org/gruf/go-ffmpreg: v0.6.9 -> v0.6.10
- github.com/ncruces/go-sqlite3: v0.27.1 -> v0.28.0
- github.com/stretchr/testify: v1.10.0 -> v1.11.1
- github.com/tdewolff/minify/v2 v2.23.11 -> v2.24.2
- go.opentelemetry.io/otel{,/*}: v1.37.0 -> v1.38.0
- go.opentelemetry.io/contrib/*: v0.62.0 -> v0.63.0

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4406
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
This commit is contained in:
kim 2025-09-04 15:29:27 +02:00 committed by kim
commit 78defcd916
274 changed files with 9213 additions and 2368 deletions

View file

@ -199,3 +199,33 @@
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.
--------------------------------------------------------------------------------
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -13,7 +13,6 @@ import (
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/sdk/instrumentation"
@ -231,7 +230,7 @@ func convertExponentialBuckets(bucketSpans []*dto.BucketSpan, deltas []int64) me
// Increase the count index by the Offset to insert Offset zeroes
countIndex += bs.GetOffset()
}
for j := uint32(0); j < bs.GetLength(); j++ {
for range bs.GetLength() {
// Convert deltas to the cumulative number of observations
count += deltas[deltaIndex]
deltaIndex++
@ -367,11 +366,12 @@ func convertExemplar(exemplar *dto.Exemplar) metricdata.Exemplar[float64] {
var traceID, spanID []byte
// find the trace ID and span ID in attributes, if it exists
for _, label := range exemplar.GetLabel() {
if label.GetName() == traceIDLabel {
switch label.GetName() {
case traceIDLabel:
traceID = []byte(label.GetValue())
} else if label.GetName() == spanIDLabel {
case spanIDLabel:
spanID = []byte(label.GetValue())
} else {
default:
attrs = append(attrs, attribute.String(label.GetName(), label.GetValue()))
}
}

View file

@ -199,3 +199,33 @@
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.
--------------------------------------------------------------------------------
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -84,10 +84,10 @@ func init() {
return nil, errInvalidOTLPProtocol
}
})
RegisterLogExporter("console", func(ctx context.Context) (log.Exporter, error) {
RegisterLogExporter("console", func(context.Context) (log.Exporter, error) {
return stdoutlog.New()
})
RegisterLogExporter("none", func(ctx context.Context) (log.Exporter, error) {
RegisterLogExporter("none", func(context.Context) (log.Exporter, error) {
return noopLogExporter{}, nil
})
}

View file

@ -15,14 +15,14 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
prometheusbridge "go.opentelemetry.io/contrib/bridges/prometheus"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp"
promexporter "go.opentelemetry.io/otel/exporters/prometheus"
"go.opentelemetry.io/otel/exporters/stdout/stdoutmetric"
"go.opentelemetry.io/otel/sdk/metric"
prometheusbridge "go.opentelemetry.io/contrib/bridges/prometheus"
)
const otelExporterOTLPMetricsProtoEnvKey = "OTEL_EXPORTER_OTLP_METRICS_PROTOCOL"
@ -154,7 +154,7 @@ func init() {
}
return metric.NewPeriodicReader(r, readerOpts...), nil
})
RegisterMetricReader("none", func(ctx context.Context) (metric.Reader, error) {
RegisterMetricReader("none", func(context.Context) (metric.Reader, error) {
return newNoopMetricReader(), nil
})
RegisterMetricReader("prometheus", func(ctx context.Context) (metric.Reader, error) {
@ -211,10 +211,10 @@ func init() {
return readerWithServer{lis.Addr(), reader, &server}, nil
})
RegisterMetricProducer("prometheus", func(ctx context.Context) (metric.Producer, error) {
RegisterMetricProducer("prometheus", func(context.Context) (metric.Producer, error) {
return prometheusbridge.NewMetricProducer(), nil
})
RegisterMetricProducer("none", func(ctx context.Context) (metric.Producer, error) {
RegisterMetricProducer("none", func(context.Context) (metric.Producer, error) {
return newNoopMetricProducer(), nil
})
}

View file

@ -18,12 +18,12 @@ type noopSpanExporter struct{}
var _ trace.SpanExporter = noopSpanExporter{}
// ExportSpans is part of trace.SpanExporter interface.
func (e noopSpanExporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) error {
func (noopSpanExporter) ExportSpans(context.Context, []trace.ReadOnlySpan) error {
return nil
}
// Shutdown is part of trace.SpanExporter interface.
func (e noopSpanExporter) Shutdown(ctx context.Context) error {
func (noopSpanExporter) Shutdown(context.Context) error {
return nil
}
@ -51,7 +51,7 @@ func IsNoneMetricReader(e metric.Reader) bool {
type noopMetricProducer struct{}
func (e noopMetricProducer) Produce(ctx context.Context) ([]metricdata.ScopeMetrics, error) {
func (noopMetricProducer) Produce(context.Context) ([]metricdata.ScopeMetrics, error) {
return nil, nil
}
@ -65,17 +65,17 @@ type noopLogExporter struct{}
var _ log.Exporter = noopLogExporter{}
// ExportSpans is part of log.Exporter interface.
func (e noopLogExporter) Export(ctx context.Context, records []log.Record) error {
func (noopLogExporter) Export(context.Context, []log.Record) error {
return nil
}
// Shutdown is part of log.Exporter interface.
func (e noopLogExporter) Shutdown(ctx context.Context) error {
func (noopLogExporter) Shutdown(context.Context) error {
return nil
}
// ForceFlush is part of log.Exporter interface.
func (e noopLogExporter) ForceFlush(ctx context.Context) error {
func (noopLogExporter) ForceFlush(context.Context) error {
return nil
}

View file

@ -89,10 +89,10 @@ func init() {
return nil, errInvalidOTLPProtocol
}
})
RegisterSpanExporter("console", func(ctx context.Context) (trace.SpanExporter, error) {
RegisterSpanExporter("console", func(context.Context) (trace.SpanExporter, error) {
return stdouttrace.New()
})
RegisterSpanExporter("none", func(ctx context.Context) (trace.SpanExporter, error) {
RegisterSpanExporter("none", func(context.Context) (trace.SpanExporter, error) {
return noopSpanExporter{}, nil
})
}

View file

@ -199,3 +199,33 @@
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.
--------------------------------------------------------------------------------
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -56,7 +56,7 @@ func (r *runtime) register() error {
}
_, err = r.meter.RegisterCallback(
func(ctx context.Context, o metric.Observer) error {
func(_ context.Context, o metric.Observer) error {
o.ObserveInt64(uptime, time.Since(startTime).Milliseconds())
o.ObserveInt64(goroutines, int64(goruntime.NumGoroutine()))
o.ObserveInt64(cgoCalls, goruntime.NumCgoCall())
@ -179,7 +179,7 @@ func (r *runtime) registerMemStats() error {
// observation interval is too slow.
if pauseTotalNs, err = r.meter.Int64ObservableCounter(
"process.runtime.go.gc.pause_total_ns",
// TODO: nanoseconds units
metric.WithUnit("ns"),
metric.WithDescription("Cumulative nanoseconds in GC stop-the-world pauses since the program started"),
); err != nil {
return err
@ -187,7 +187,7 @@ func (r *runtime) registerMemStats() error {
if gcPauseNs, err = r.meter.Int64Histogram(
"process.runtime.go.gc.pause_ns",
// TODO: nanoseconds units
metric.WithUnit("ns"),
metric.WithDescription("Amount of nanoseconds in GC stop-the-world pauses"),
); err != nil {
return err
@ -244,7 +244,7 @@ func clampUint64(v uint64) int64 {
if v > math.MaxInt64 {
return math.MaxInt64
}
return int64(v) // nolint: gosec // Overflow checked above.
return int64(v)
}
func computeGCPauses(
@ -271,7 +271,7 @@ func computeGCPauses(
return
}
length := uint64(n) // nolint: gosec // n >= 0
length := uint64(n)
i := uint64(lastNumGC) % length
j := uint64(currentNumGC) % length

View file

@ -12,7 +12,7 @@ import (
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/semconv/v1.34.0/goconv"
"go.opentelemetry.io/otel/semconv/v1.37.0/goconv"
"go.opentelemetry.io/contrib/instrumentation/runtime/internal/deprecatedruntime"
"go.opentelemetry.io/contrib/instrumentation/runtime/internal/x"
@ -90,7 +90,7 @@ func Start(opts ...Option) error {
collector := newCollector(c.MinimumReadMemStatsInterval, runtimeMetrics)
var lock sync.Mutex
_, err = meter.RegisterCallback(
func(ctx context.Context, o metric.Observer) error {
func(_ context.Context, o metric.Observer) error {
lock.Lock()
defer lock.Unlock()
collector.refresh()
@ -187,7 +187,7 @@ func (g *goCollector) getInt(name string) int64 {
if v > math.MaxInt64 {
return math.MaxInt64
}
return int64(v) // nolint: gosec // Overflow checked above.
return int64(v)
}
return 0
}

View file

@ -5,6 +5,6 @@ package runtime // import "go.opentelemetry.io/contrib/instrumentation/runtime"
// Version is the current release version of the runtime instrumentation.
func Version() string {
return "0.62.0"
return "0.63.0"
// This string is updated by the pre_release.sh script during release
}

View file

@ -7,3 +7,4 @@ ans
nam
valu
thirdparty
addOpt

View file

@ -10,6 +10,7 @@ linters:
- depguard
- errcheck
- errorlint
- gocritic
- godot
- gosec
- govet
@ -86,6 +87,18 @@ linters:
deny:
- pkg: go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal
desc: Do not use cross-module internal packages.
gocritic:
disabled-checks:
- appendAssign
- commentedOutCode
- dupArg
- hugeParam
- importShadow
- preferDecodeRune
- rangeValCopy
- unnamedResult
- whyNoLint
enable-all: true
godot:
exclude:
# Exclude links.
@ -167,7 +180,10 @@ linters:
- fmt.Print
- fmt.Printf
- fmt.Println
- name: unused-parameter
- name: unused-receiver
- name: unnecessary-stmt
- name: use-any
- name: useless-break
- name: var-declaration
- name: var-naming
@ -224,10 +240,6 @@ linters:
- linters:
- gosec
text: 'G402: TLS MinVersion too low.'
paths:
- third_party$
- builtin$
- examples$
issues:
max-issues-per-linter: 0
max-same-issues: 0
@ -237,14 +249,12 @@ formatters:
- goimports
- golines
settings:
gofumpt:
extra-rules: true
goimports:
local-prefixes:
- go.opentelemetry.io
- go.opentelemetry.io/otel
golines:
max-len: 120
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$

View file

@ -2,5 +2,8 @@ http://localhost
http://jaeger-collector
https://github.com/open-telemetry/opentelemetry-go/milestone/
https://github.com/open-telemetry/opentelemetry-go/projects
# Weaver model URL for semantic-conventions repository.
https?:\/\/github\.com\/open-telemetry\/semantic-conventions\/archive\/refs\/tags\/[^.]+\.zip\[[^]]+]
file:///home/runner/work/opentelemetry-go/opentelemetry-go/libraries
file:///home/runner/work/opentelemetry-go/opentelemetry-go/manual
http://4.3.2.1:78/user/123

View file

@ -11,6 +11,93 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
<!-- Released section -->
<!-- Don't change this section unless doing release -->
## [1.38.0/0.60.0/0.14.0/0.0.13] 2025-08-29
This release is the last to support [Go 1.23].
The next release will require at least [Go 1.24].
### Added
- Add native histogram exemplar support in `go.opentelemetry.io/otel/exporters/prometheus`. (#6772)
- Add template attribute functions to the `go.opentelmetry.io/otel/semconv/v1.34.0` package. (#6939)
- `ContainerLabel`
- `DBOperationParameter`
- `DBSystemParameter`
- `HTTPRequestHeader`
- `HTTPResponseHeader`
- `K8SCronJobAnnotation`
- `K8SCronJobLabel`
- `K8SDaemonSetAnnotation`
- `K8SDaemonSetLabel`
- `K8SDeploymentAnnotation`
- `K8SDeploymentLabel`
- `K8SJobAnnotation`
- `K8SJobLabel`
- `K8SNamespaceAnnotation`
- `K8SNamespaceLabel`
- `K8SNodeAnnotation`
- `K8SNodeLabel`
- `K8SPodAnnotation`
- `K8SPodLabel`
- `K8SReplicaSetAnnotation`
- `K8SReplicaSetLabel`
- `K8SStatefulSetAnnotation`
- `K8SStatefulSetLabel`
- `ProcessEnvironmentVariable`
- `RPCConnectRPCRequestMetadata`
- `RPCConnectRPCResponseMetadata`
- `RPCGRPCRequestMetadata`
- `RPCGRPCResponseMetadata`
- Add `ErrorType` attribute helper function to the `go.opentelmetry.io/otel/semconv/v1.34.0` package. (#6962)
- Add `WithAllowKeyDuplication` in `go.opentelemetry.io/otel/sdk/log` which can be used to disable deduplication for log records. (#6968)
- Add `WithCardinalityLimit` option to configure the cardinality limit in `go.opentelemetry.io/otel/sdk/metric`. (#6996, #7065, #7081, #7164, #7165, #7179)
- Add `Clone` method to `Record` in `go.opentelemetry.io/otel/log` that returns a copy of the record with no shared state. (#7001)
- Add experimental self-observability span and batch span processor metrics in `go.opentelemetry.io/otel/sdk/trace`.
Check the `go.opentelemetry.io/otel/sdk/trace/internal/x` package documentation for more information. (#7027, #6393, #7209)
- The `go.opentelemetry.io/otel/semconv/v1.36.0` package.
The package contains semantic conventions from the `v1.36.0` version of the OpenTelemetry Semantic Conventions.
See the [migration documentation](./semconv/v1.36.0/MIGRATION.md) for information on how to upgrade from `go.opentelemetry.io/otel/semconv/v1.34.0.`(#7032, #7041)
- Add support for configuring Prometheus name translation using `WithTranslationStrategy` option in `go.opentelemetry.io/otel/exporters/prometheus`. The current default translation strategy when UTF-8 mode is enabled is `NoUTF8EscapingWithSuffixes`, but a future release will change the default strategy to `UnderscoreEscapingWithSuffixes` for compliance with the specification. (#7111)
- Add experimental self-observability log metrics in `go.opentelemetry.io/otel/sdk/log`.
Check the `go.opentelemetry.io/otel/sdk/log/internal/x` package documentation for more information. (#7121)
- Add experimental self-observability trace exporter metrics in `go.opentelemetry.io/otel/exporters/stdout/stdouttrace`.
Check the `go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/x` package documentation for more information. (#7133)
- Support testing of [Go 1.25]. (#7187)
- The `go.opentelemetry.io/otel/semconv/v1.37.0` package.
The package contains semantic conventions from the `v1.37.0` version of the OpenTelemetry Semantic Conventions.
See the [migration documentation](./semconv/v1.37.0/MIGRATION.md) for information on how to upgrade from `go.opentelemetry.io/otel/semconv/v1.36.0.`(#7254)
### Changed
- Optimize `TraceIDFromHex` and `SpanIDFromHex` in `go.opentelemetry.io/otel/sdk/trace`. (#6791)
- Change `AssertEqual` in `go.opentelemetry.io/otel/log/logtest` to accept `TestingT` in order to support benchmarks and fuzz tests. (#6908)
- Change `DefaultExemplarReservoirProviderSelector` in `go.opentelemetry.io/otel/sdk/metric` to use `runtime.GOMAXPROCS(0)` instead of `runtime.NumCPU()` for the `FixedSizeReservoirProvider` default size. (#7094)
### Fixed
- `SetBody` method of `Record` in `go.opentelemetry.io/otel/sdk/log` now deduplicates key-value collections (`log.Value` of `log.KindMap` from `go.opentelemetry.io/otel/log`). (#7002)
- Fix `go.opentelemetry.io/otel/exporters/prometheus` to not append a suffix if it's already present in metric name. (#7088)
- Fix the `go.opentelemetry.io/otel/exporters/stdout/stdouttrace` self-observability component type and name. (#7195)
- Fix partial export count metric in `go.opentelemetry.io/otel/exporters/stdout/stdouttrace`. (#7199)
### Deprecated
- Deprecate `WithoutUnits` and `WithoutCounterSuffixes` options, preferring `WithTranslationStrategy` instead. (#7111)
- Deprecate support for `OTEL_GO_X_CARDINALITY_LIMIT` environment variable in `go.opentelemetry.io/otel/sdk/metric`. Use `WithCardinalityLimit` option instead. (#7166)
## [0.59.1] 2025-07-21
### Changed
- Retract `v0.59.0` release of `go.opentelemetry.io/otel/exporters/prometheus` module which appends incorrect unit suffixes. (#7046)
- Change `go.opentelemetry.io/otel/exporters/prometheus` to no longer deduplicate suffixes when UTF8 is enabled.
It is recommended to disable unit and counter suffixes in the exporter, and manually add suffixes if you rely on the existing behavior. (#7044)
### Fixed
- Fix `go.opentelemetry.io/otel/exporters/prometheus` to properly handle unit suffixes when the unit is in brackets.
E.g. `{spans}`. (#7044)
## [1.37.0/0.59.0/0.13.0] 2025-06-25
### Added
@ -3343,7 +3430,8 @@ It contains api and sdk for trace and meter.
- CircleCI build CI manifest files.
- CODEOWNERS file to track owners of this project.
[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.37.0...HEAD
[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.38.0...HEAD
[1.38.0/0.60.0/0.14.0/0.0.13]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.38.0
[1.37.0/0.59.0/0.13.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.37.0
[0.12.2]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/log/v0.12.2
[0.12.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/log/v0.12.1
@ -3439,6 +3527,7 @@ It contains api and sdk for trace and meter.
<!-- Released section ended -->
[Go 1.25]: https://go.dev/doc/go1.25
[Go 1.24]: https://go.dev/doc/go1.24
[Go 1.23]: https://go.dev/doc/go1.23
[Go 1.22]: https://go.dev/doc/go1.22

View file

@ -12,6 +12,6 @@
# https://help.github.com/en/articles/about-code-owners
#
* @MrAlias @XSAM @dashpole @pellared @dmathieu
* @MrAlias @XSAM @dashpole @pellared @dmathieu @flc1125
CODEOWNERS @MrAlias @pellared @dashpole @XSAM @dmathieu

View file

@ -192,6 +192,35 @@ should have `go test -bench` output in their description.
should have [`benchstat`](https://pkg.go.dev/golang.org/x/perf/cmd/benchstat)
output in their description.
## Dependencies
This project uses [Go Modules] for dependency management. All modules will use
`go.mod` to explicitly list all direct and indirect dependencies, ensuring a
clear dependency graph. The `go.sum` file for each module will be committed to
the repository and used to verify the integrity of downloaded modules,
preventing malicious tampering.
This project uses automated dependency update tools (i.e. dependabot,
renovatebot) to manage updates to dependencies. This ensures that dependencies
are kept up-to-date with the latest security patches and features and are
reviewed before being merged. If you would like to propose a change to a
dependency it should be done through a pull request that updates the `go.mod`
file and includes a description of the change.
See the [versioning and compatibility](./VERSIONING.md) policy for more details
about dependency compatibility.
[Go Modules]: https://pkg.go.dev/cmd/go#hdr-Modules__module_versions__and_more
### Environment Dependencies
This project does not partition dependencies based on the environment (i.e.
`development`, `staging`, `production`).
Only the dependencies explicitly included in the released modules have be
tested and verified to work with the released code. No other guarantee is made
about the compatibility of other dependencies.
## Documentation
Each (non-internal, non-test) package must be documented using
@ -233,6 +262,10 @@ For a non-comprehensive but foundational overview of these best practices
the [Effective Go](https://golang.org/doc/effective_go.html) documentation
is an excellent starting place.
We also recommend following the
[Go Code Review Comments](https://go.dev/wiki/CodeReviewComments)
that collects common comments made during reviews of Go code.
As a convenience for developers building this project the `make precommit`
will format, lint, validate, and in some cases fix the changes you plan to
submit. This check will need to pass for your changes to be able to be
@ -586,6 +619,10 @@ See also:
### Testing
We allow using [`testify`](https://github.com/stretchr/testify) even though
it is seen as non-idiomatic according to
the [Go Test Comments](https://go.dev/wiki/TestComments#assert-libraries) page.
The tests should never leak goroutines.
Use the term `ConcurrentSafe` in the test name when it aims to verify the
@ -640,13 +677,6 @@ should be canceled.
## Approvers and Maintainers
### Triagers
- [Alex Kats](https://github.com/akats7), Capital One
- [Cheng-Zhen Yang](https://github.com/scorpionknifes), Independent
### Approvers
### Maintainers
- [Damien Mathieu](https://github.com/dmathieu), Elastic ([GPG](https://keys.openpgp.org/search?q=5A126B972A81A6CE443E5E1B408B8E44F0873832))
@ -655,6 +685,21 @@ should be canceled.
- [Sam Xie](https://github.com/XSAM), Splunk ([GPG](https://keys.openpgp.org/search?q=AEA033782371ABB18EE39188B8044925D6FEEBEA))
- [Tyler Yahn](https://github.com/MrAlias), Splunk ([GPG](https://keys.openpgp.org/search?q=0x46B0F3E1A8B1BA5A))
For more information about the maintainer role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#maintainer).
### Approvers
- [Flc](https://github.com/flc1125), Independent
For more information about the approver role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#approver).
### Triagers
- [Alex Kats](https://github.com/akats7), Capital One
- [Cheng-Zhen Yang](https://github.com/scorpionknifes), Independent
For more information about the triager role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#triager).
### Emeritus
- [Aaron Clawson](https://github.com/MadVikingGod)
@ -665,6 +710,8 @@ should be canceled.
- [Josh MacDonald](https://github.com/jmacd)
- [Liz Fong-Jones](https://github.com/lizthegrey)
For more information about the emeritus role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#emeritus-maintainerapprovertriager).
### Become an Approver or a Maintainer
See the [community membership document in OpenTelemetry community

View file

@ -199,3 +199,33 @@
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.
--------------------------------------------------------------------------------
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -34,9 +34,6 @@ $(TOOLS)/%: $(TOOLS_MOD_DIR)/go.mod | $(TOOLS)
MULTIMOD = $(TOOLS)/multimod
$(TOOLS)/multimod: PACKAGE=go.opentelemetry.io/build-tools/multimod
SEMCONVGEN = $(TOOLS)/semconvgen
$(TOOLS)/semconvgen: PACKAGE=go.opentelemetry.io/build-tools/semconvgen
CROSSLINK = $(TOOLS)/crosslink
$(TOOLS)/crosslink: PACKAGE=go.opentelemetry.io/build-tools/crosslink
@ -71,7 +68,7 @@ GOVULNCHECK = $(TOOLS)/govulncheck
$(TOOLS)/govulncheck: PACKAGE=golang.org/x/vuln/cmd/govulncheck
.PHONY: tools
tools: $(CROSSLINK) $(GOLANGCI_LINT) $(MISSPELL) $(GOCOVMERGE) $(STRINGER) $(PORTO) $(SEMCONVGEN) $(VERIFYREADMES) $(MULTIMOD) $(SEMCONVKIT) $(GOTMPL) $(GORELEASE)
tools: $(CROSSLINK) $(GOLANGCI_LINT) $(MISSPELL) $(GOCOVMERGE) $(STRINGER) $(PORTO) $(VERIFYREADMES) $(MULTIMOD) $(SEMCONVKIT) $(GOTMPL) $(GORELEASE)
# Virtualized python tools via docker
@ -284,7 +281,7 @@ semconv-generate: $(SEMCONVKIT)
docker run --rm \
-u $(DOCKER_USER) \
--env HOME=/tmp/weaver \
--mount 'type=bind,source=$(PWD)/semconv,target=/home/weaver/templates/registry/go,readonly' \
--mount 'type=bind,source=$(PWD)/semconv/templates,target=/home/weaver/templates,readonly' \
--mount 'type=bind,source=$(PWD)/semconv/${TAG},target=/home/weaver/target' \
--mount 'type=bind,source=$(HOME)/.weaver,target=/tmp/weaver/.weaver' \
$(WEAVER_IMAGE) registry generate \

View file

@ -53,18 +53,25 @@ Currently, this project supports the following environments.
| OS | Go Version | Architecture |
|----------|------------|--------------|
| Ubuntu | 1.25 | amd64 |
| Ubuntu | 1.24 | amd64 |
| Ubuntu | 1.23 | amd64 |
| Ubuntu | 1.25 | 386 |
| Ubuntu | 1.24 | 386 |
| Ubuntu | 1.23 | 386 |
| Ubuntu | 1.25 | arm64 |
| Ubuntu | 1.24 | arm64 |
| Ubuntu | 1.23 | arm64 |
| macOS 13 | 1.25 | amd64 |
| macOS 13 | 1.24 | amd64 |
| macOS 13 | 1.23 | amd64 |
| macOS | 1.25 | arm64 |
| macOS | 1.24 | arm64 |
| macOS | 1.23 | arm64 |
| Windows | 1.25 | amd64 |
| Windows | 1.24 | amd64 |
| Windows | 1.23 | amd64 |
| Windows | 1.25 | 386 |
| Windows | 1.24 | 386 |
| Windows | 1.23 | 386 |

203
vendor/go.opentelemetry.io/otel/SECURITY-INSIGHTS.yml generated vendored Normal file
View file

@ -0,0 +1,203 @@
header:
schema-version: "1.0.0"
expiration-date: "2026-08-04T00:00:00.000Z"
last-updated: "2025-08-04"
last-reviewed: "2025-08-04"
commit-hash: 69e81088ad40f45a0764597326722dea8f3f00a8
project-url: https://github.com/open-telemetry/opentelemetry-go
project-release: "v1.37.0"
changelog: https://github.com/open-telemetry/opentelemetry-go/blob/69e81088ad40f45a0764597326722dea8f3f00a8/CHANGELOG.md
license: https://github.com/open-telemetry/opentelemetry-go/blob/69e81088ad40f45a0764597326722dea8f3f00a8/LICENSE
project-lifecycle:
status: active
bug-fixes-only: false
core-maintainers:
- https://github.com/dmathieu
- https://github.com/dashpole
- https://github.com/pellared
- https://github.com/XSAM
- https://github.com/MrAlias
release-process: |
See https://github.com/open-telemetry/opentelemetry-go/blob/69e81088ad40f45a0764597326722dea8f3f00a8/RELEASING.md
contribution-policy:
accepts-pull-requests: true
accepts-automated-pull-requests: true
automated-tools-list:
- automated-tool: dependabot
action: allowed
comment: Automated dependency updates are accepted.
- automated-tool: renovatebot
action: allowed
comment: Automated dependency updates are accepted.
- automated-tool: opentelemetrybot
action: allowed
comment: Automated OpenTelemetry actions are accepted.
contributing-policy: https://github.com/open-telemetry/opentelemetry-go/blob/69e81088ad40f45a0764597326722dea8f3f00a8/CONTRIBUTING.md
code-of-conduct: https://github.com/open-telemetry/.github/blob/ffa15f76b65ec7bcc41f6a0b277edbb74f832206/CODE_OF_CONDUCT.md
documentation:
- https://pkg.go.dev/go.opentelemetry.io/otel
- https://opentelemetry.io/docs/instrumentation/go/
distribution-points:
- pkg:golang/go.opentelemetry.io/otel
- pkg:golang/go.opentelemetry.io/otel/bridge/opencensus
- pkg:golang/go.opentelemetry.io/otel/bridge/opencensus/test
- pkg:golang/go.opentelemetry.io/otel/bridge/opentracing
- pkg:golang/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc
- pkg:golang/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp
- pkg:golang/go.opentelemetry.io/otel/exporters/otlp/otlptrace
- pkg:golang/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc
- pkg:golang/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp
- pkg:golang/go.opentelemetry.io/otel/exporters/stdout/stdoutmetric
- pkg:golang/go.opentelemetry.io/otel/exporters/stdout/stdouttrace
- pkg:golang/go.opentelemetry.io/otel/exporters/zipkin
- pkg:golang/go.opentelemetry.io/otel/metric
- pkg:golang/go.opentelemetry.io/otel/sdk
- pkg:golang/go.opentelemetry.io/otel/sdk/metric
- pkg:golang/go.opentelemetry.io/otel/trace
- pkg:golang/go.opentelemetry.io/otel/exporters/prometheus
- pkg:golang/go.opentelemetry.io/otel/log
- pkg:golang/go.opentelemetry.io/otel/log/logtest
- pkg:golang/go.opentelemetry.io/otel/sdk/log
- pkg:golang/go.opentelemetry.io/otel/sdk/log/logtest
- pkg:golang/go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc
- pkg:golang/go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp
- pkg:golang/go.opentelemetry.io/otel/exporters/stdout/stdoutlog
- pkg:golang/go.opentelemetry.io/otel/schema
security-artifacts:
threat-model:
threat-model-created: false
comment: |
No formal threat model created yet.
self-assessment:
self-assessment-created: false
comment: |
No formal self-assessment yet.
security-testing:
- tool-type: sca
tool-name: Dependabot
tool-version: latest
tool-url: https://github.com/dependabot
tool-rulesets:
- built-in
integration:
ad-hoc: false
ci: true
before-release: true
comment: |
Automated dependency updates.
- tool-type: sast
tool-name: golangci-lint
tool-version: latest
tool-url: https://github.com/golangci/golangci-lint
tool-rulesets:
- built-in
integration:
ad-hoc: false
ci: true
before-release: true
comment: |
Static analysis in CI.
- tool-type: fuzzing
tool-name: OSS-Fuzz
tool-version: latest
tool-url: https://github.com/google/oss-fuzz
tool-rulesets:
- default
integration:
ad-hoc: false
ci: false
before-release: false
comment: |
OpenTelemetry Go is integrated with OSS-Fuzz for continuous fuzz testing. See https://github.com/google/oss-fuzz/tree/f0f9b221190c6063a773bea606d192ebfc3d00cf/projects/opentelemetry-go for more details.
- tool-type: sast
tool-name: CodeQL
tool-version: latest
tool-url: https://github.com/github/codeql
tool-rulesets:
- default
integration:
ad-hoc: false
ci: true
before-release: true
comment: |
CodeQL static analysis is run in CI for all commits and pull requests to detect security vulnerabilities in the Go source code. See https://github.com/open-telemetry/opentelemetry-go/blob/d5b5b059849720144a03ca5c87561bfbdb940119/.github/workflows/codeql-analysis.yml for workflow details.
- tool-type: sca
tool-name: govulncheck
tool-version: latest
tool-url: https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck
tool-rulesets:
- default
integration:
ad-hoc: false
ci: true
before-release: true
comment: |
govulncheck is run in CI to detect known vulnerabilities in Go modules and code paths. See https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/.github/workflows/ci.yml for workflow configuration.
security-assessments:
- auditor-name: 7ASecurity
auditor-url: https://7asecurity.com
auditor-report: https://7asecurity.com/reports/pentest-report-opentelemetry.pdf
report-year: 2023
comment: |
This independent penetration test by 7ASecurity covered OpenTelemetry repositories including opentelemetry-go. The assessment focused on codebase review, threat modeling, and vulnerability identification. See the report for details of findings and recommendations applicable to opentelemetry-go. No critical vulnerabilities were found for this repository.
security-contacts:
- type: email
value: cncf-opentelemetry-security@lists.cncf.io
primary: true
- type: website
value: https://github.com/open-telemetry/opentelemetry-go/security/policy
primary: false
vulnerability-reporting:
accepts-vulnerability-reports: true
email-contact: cncf-opentelemetry-security@lists.cncf.io
security-policy: https://github.com/open-telemetry/opentelemetry-go/security/policy
comment: |
Security issues should be reported via email or GitHub security policy page.
dependencies:
third-party-packages: true
dependencies-lists:
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/bridge/opencensus/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/bridge/opencensus/test/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/bridge/opentracing/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/otlp/otlplog/otlploggrpc/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/otlp/otlplog/otlploghttp/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/otlp/otlpmetric/otlpmetricgrpc/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/otlp/otlpmetric/otlpmetrichttp/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/otlp/otlptrace/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/otlp/otlptrace/otlptracegrpc/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/otlp/otlptrace/otlptracehttp/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/prometheus/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/stdout/stdoutlog/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/stdout/stdoutmetric/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/stdout/stdouttrace/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/zipkin/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/internal/tools/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/log/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/log/logtest/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/metric/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/schema/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/sdk/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/sdk/log/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/sdk/log/logtest/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/sdk/metric/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/trace/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/trace/internal/telemetry/test/go.mod
dependencies-lifecycle:
policy-url: https://github.com/open-telemetry/opentelemetry-go/blob/69e81088ad40f45a0764597326722dea8f3f00a8/CONTRIBUTING.md
comment: |
Dependency lifecycle managed via go.mod and renovatebot.
env-dependencies-policy:
policy-url: https://github.com/open-telemetry/opentelemetry-go/blob/69e81088ad40f45a0764597326722dea8f3f00a8/CONTRIBUTING.md
comment: |
See contributing policy for environment usage.

View file

@ -78,7 +78,7 @@ func DefaultEncoder() Encoder {
defaultEncoderOnce.Do(func() {
defaultEncoderInstance = &defaultAttrEncoder{
pool: sync.Pool{
New: func() interface{} {
New: func() any {
return &bytes.Buffer{}
},
},
@ -96,11 +96,11 @@ func (d *defaultAttrEncoder) Encode(iter Iterator) string {
for iter.Next() {
i, keyValue := iter.IndexedAttribute()
if i > 0 {
_, _ = buf.WriteRune(',')
_ = buf.WriteByte(',')
}
copyAndEscape(buf, string(keyValue.Key))
_, _ = buf.WriteRune('=')
_ = buf.WriteByte('=')
if keyValue.Value.Type() == STRING {
copyAndEscape(buf, keyValue.Value.AsString())
@ -122,14 +122,14 @@ func copyAndEscape(buf *bytes.Buffer, val string) {
for _, ch := range val {
switch ch {
case '=', ',', escapeChar:
_, _ = buf.WriteRune(escapeChar)
_ = buf.WriteByte(escapeChar)
}
_, _ = buf.WriteRune(ch)
}
}
// Valid returns true if this encoder ID was allocated by
// `NewEncoderID`. Invalid encoder IDs will not be cached.
// Valid reports whether this encoder ID was allocated by
// [NewEncoderID]. Invalid encoder IDs will not be cached.
func (id EncoderID) Valid() bool {
return id.value != 0
}

View file

@ -15,8 +15,8 @@ type Filter func(KeyValue) bool
//
// If keys is empty a deny-all filter is returned.
func NewAllowKeysFilter(keys ...Key) Filter {
if len(keys) <= 0 {
return func(kv KeyValue) bool { return false }
if len(keys) == 0 {
return func(KeyValue) bool { return false }
}
allowed := make(map[Key]struct{}, len(keys))
@ -34,8 +34,8 @@ func NewAllowKeysFilter(keys ...Key) Filter {
//
// If keys is empty an allow-all filter is returned.
func NewDenyKeysFilter(keys ...Key) Filter {
if len(keys) <= 0 {
return func(kv KeyValue) bool { return true }
if len(keys) == 0 {
return func(KeyValue) bool { return true }
}
forbid := make(map[Key]struct{}, len(keys))

View file

@ -12,7 +12,7 @@ import (
)
// BoolSliceValue converts a bool slice into an array with same elements as slice.
func BoolSliceValue(v []bool) interface{} {
func BoolSliceValue(v []bool) any {
var zero bool
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))).Elem()
reflect.Copy(cp, reflect.ValueOf(v))
@ -20,7 +20,7 @@ func BoolSliceValue(v []bool) interface{} {
}
// Int64SliceValue converts an int64 slice into an array with same elements as slice.
func Int64SliceValue(v []int64) interface{} {
func Int64SliceValue(v []int64) any {
var zero int64
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))).Elem()
reflect.Copy(cp, reflect.ValueOf(v))
@ -28,7 +28,7 @@ func Int64SliceValue(v []int64) interface{} {
}
// Float64SliceValue converts a float64 slice into an array with same elements as slice.
func Float64SliceValue(v []float64) interface{} {
func Float64SliceValue(v []float64) any {
var zero float64
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))).Elem()
reflect.Copy(cp, reflect.ValueOf(v))
@ -36,7 +36,7 @@ func Float64SliceValue(v []float64) interface{} {
}
// StringSliceValue converts a string slice into an array with same elements as slice.
func StringSliceValue(v []string) interface{} {
func StringSliceValue(v []string) any {
var zero string
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))).Elem()
reflect.Copy(cp, reflect.ValueOf(v))
@ -44,7 +44,7 @@ func StringSliceValue(v []string) interface{} {
}
// AsBoolSlice converts a bool array into a slice into with same elements as array.
func AsBoolSlice(v interface{}) []bool {
func AsBoolSlice(v any) []bool {
rv := reflect.ValueOf(v)
if rv.Type().Kind() != reflect.Array {
return nil
@ -57,7 +57,7 @@ func AsBoolSlice(v interface{}) []bool {
}
// AsInt64Slice converts an int64 array into a slice into with same elements as array.
func AsInt64Slice(v interface{}) []int64 {
func AsInt64Slice(v any) []int64 {
rv := reflect.ValueOf(v)
if rv.Type().Kind() != reflect.Array {
return nil
@ -70,7 +70,7 @@ func AsInt64Slice(v interface{}) []int64 {
}
// AsFloat64Slice converts a float64 array into a slice into with same elements as array.
func AsFloat64Slice(v interface{}) []float64 {
func AsFloat64Slice(v any) []float64 {
rv := reflect.ValueOf(v)
if rv.Type().Kind() != reflect.Array {
return nil
@ -83,7 +83,7 @@ func AsFloat64Slice(v interface{}) []float64 {
}
// AsStringSlice converts a string array into a slice into with same elements as array.
func AsStringSlice(v interface{}) []string {
func AsStringSlice(v any) []string {
rv := reflect.ValueOf(v)
if rv.Type().Kind() != reflect.Array {
return nil

View file

@ -25,8 +25,8 @@ type oneIterator struct {
attr KeyValue
}
// Next moves the iterator to the next position. Returns false if there are no
// more attributes.
// Next moves the iterator to the next position.
// Next reports whether there are more attributes.
func (i *Iterator) Next() bool {
i.idx++
return i.idx < i.Len()
@ -106,7 +106,8 @@ func (oi *oneIterator) advance() {
}
}
// Next returns true if there is another attribute available.
// Next moves the iterator to the next position.
// Next reports whether there is another attribute available.
func (m *MergeIterator) Next() bool {
if m.one.done && m.two.done {
return false

View file

@ -117,7 +117,7 @@ func (k Key) StringSlice(v []string) KeyValue {
}
}
// Defined returns true for non-empty keys.
// Defined reports whether the key is not empty.
func (k Key) Defined() bool {
return len(k) != 0
}

View file

@ -13,7 +13,7 @@ type KeyValue struct {
Value Value
}
// Valid returns if kv is a valid OpenTelemetry attribute.
// Valid reports whether kv is a valid OpenTelemetry attribute.
func (kv KeyValue) Valid() bool {
return kv.Key.Defined() && kv.Value.Type() != INVALID
}

View file

@ -31,11 +31,11 @@ type (
// Distinct is a unique identifier of a Set.
//
// Distinct is designed to be ensures equivalence stability: comparisons
// will return the save value across versions. For this reason, Distinct
// should always be used as a map key instead of a Set.
// Distinct is designed to ensure equivalence stability: comparisons will
// return the same value across versions. For this reason, Distinct should
// always be used as a map key instead of a Set.
Distinct struct {
iface interface{}
iface any
}
// Sortable implements sort.Interface, used for sorting KeyValue.
@ -70,7 +70,7 @@ func (d Distinct) reflectValue() reflect.Value {
return reflect.ValueOf(d.iface)
}
// Valid returns true if this value refers to a valid Set.
// Valid reports whether this value refers to a valid Set.
func (d Distinct) Valid() bool {
return d.iface != nil
}
@ -120,7 +120,7 @@ func (l *Set) Value(k Key) (Value, bool) {
return Value{}, false
}
// HasValue tests whether a key is defined in this set.
// HasValue reports whether a key is defined in this set.
func (l *Set) HasValue(k Key) bool {
if l == nil {
return false
@ -155,7 +155,7 @@ func (l *Set) Equivalent() Distinct {
return l.equivalent
}
// Equals returns true if the argument set is equivalent to this set.
// Equals reports whether the argument set is equivalent to this set.
func (l *Set) Equals(o *Set) bool {
return l.Equivalent() == o.Equivalent()
}
@ -344,7 +344,7 @@ func computeDistinct(kvs []KeyValue) Distinct {
// computeDistinctFixed computes a Distinct for small slices. It returns nil
// if the input is too large for this code path.
func computeDistinctFixed(kvs []KeyValue) interface{} {
func computeDistinctFixed(kvs []KeyValue) any {
switch len(kvs) {
case 1:
return [1]KeyValue(kvs)
@ -373,7 +373,7 @@ func computeDistinctFixed(kvs []KeyValue) interface{} {
// computeDistinctReflect computes a Distinct using reflection, works for any
// size input.
func computeDistinctReflect(kvs []KeyValue) interface{} {
func computeDistinctReflect(kvs []KeyValue) any {
at := reflect.New(reflect.ArrayOf(len(kvs), keyValueType)).Elem()
for i, keyValue := range kvs {
*(at.Index(i).Addr().Interface().(*KeyValue)) = keyValue
@ -387,7 +387,7 @@ func (l *Set) MarshalJSON() ([]byte, error) {
}
// MarshalLog is the marshaling function used by the logging system to represent this Set.
func (l Set) MarshalLog() interface{} {
func (l Set) MarshalLog() any {
kvs := make(map[string]string)
for _, kv := range l.ToSlice() {
kvs[string(kv.Key)] = kv.Value.Emit()

View file

@ -22,7 +22,7 @@ type Value struct {
vtype Type
numeric uint64
stringly string
slice interface{}
slice any
}
const (
@ -199,8 +199,8 @@ func (v Value) asStringSlice() []string {
type unknownValueType struct{}
// AsInterface returns Value's data as interface{}.
func (v Value) AsInterface() interface{} {
// AsInterface returns Value's data as any.
func (v Value) AsInterface() any {
switch v.Type() {
case BOOL:
return v.AsBool()
@ -262,7 +262,7 @@ func (v Value) Emit() string {
func (v Value) MarshalJSON() ([]byte, error) {
var jsonVal struct {
Type string
Value interface{}
Value any
}
jsonVal.Type = v.Type().String()
jsonVal.Value = v.AsInterface()

View file

@ -812,7 +812,7 @@ var safeKeyCharset = [utf8.RuneSelf]bool{
// validateBaggageName checks if the string is a valid OpenTelemetry Baggage name.
// Baggage name is a valid, non-empty UTF-8 string.
func validateBaggageName(s string) bool {
if len(s) == 0 {
if s == "" {
return false
}
@ -828,7 +828,7 @@ func validateBaggageValue(s string) bool {
// validateKey checks if the string is a valid W3C Baggage key.
func validateKey(s string) bool {
if len(s) == 0 {
if s == "" {
return false
}

View file

@ -67,7 +67,7 @@ func (c *Code) UnmarshalJSON(b []byte) error {
return errors.New("nil receiver passed to UnmarshalJSON")
}
var x interface{}
var x any
if err := json.Unmarshal(b, &x); err != nil {
return err
}
@ -102,5 +102,5 @@ func (c *Code) MarshalJSON() ([]byte, error) {
if !ok {
return nil, fmt.Errorf("invalid code: %d", *c)
}
return []byte(fmt.Sprintf("%q", str)), nil
return fmt.Appendf(nil, "%q", str), nil
}

View file

@ -1,4 +1,4 @@
# This is a renovate-friendly source of Docker images.
FROM python:3.13.5-slim-bullseye@sha256:5b9fc0d8ef79cfb5f300e61cb516e0c668067bbf77646762c38c94107e230dbc AS python
FROM otel/weaver:v0.15.2@sha256:b13acea09f721774daba36344861f689ac4bb8d6ecd94c4600b4d590c8fb34b9 AS weaver
FROM python:3.13.6-slim-bullseye@sha256:e98b521460ee75bca92175c16247bdf7275637a8faaeb2bcfa19d879ae5c4b9a AS python
FROM otel/weaver:v0.17.1@sha256:32523b5e44fb44418786347e9f7dde187d8797adb6d57a2ee99c245346c3cdfe AS weaver
FROM avtodev/markdown-lint:v1@sha256:6aeedc2f49138ce7a1cd0adffc1b1c0321b841dc2102408967d9301c031949ee AS markdown

View file

@ -199,3 +199,33 @@
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.
--------------------------------------------------------------------------------
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -9,6 +9,8 @@ import (
"fmt"
"time"
collogpb "go.opentelemetry.io/proto/otlp/collector/logs/v1"
logpb "go.opentelemetry.io/proto/otlp/logs/v1"
"google.golang.org/genproto/googleapis/rpc/errdetails"
"google.golang.org/grpc"
"google.golang.org/grpc/backoff"
@ -21,8 +23,6 @@ import (
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc/internal/retry"
collogpb "go.opentelemetry.io/proto/otlp/collector/logs/v1"
logpb "go.opentelemetry.io/proto/otlp/logs/v1"
)
// The methods of this type are not expected to be called concurrently.
@ -86,11 +86,12 @@ func newGRPCDialOptions(cfg config) []grpc.DialOption {
dialOpts = append(dialOpts, grpc.WithDefaultServiceConfig(cfg.serviceConfig.Value))
}
// Prioritize GRPCCredentials over Insecure (passing both is an error).
if cfg.gRPCCredentials.Value != nil {
switch {
case cfg.gRPCCredentials.Value != nil:
dialOpts = append(dialOpts, grpc.WithTransportCredentials(cfg.gRPCCredentials.Value))
} else if cfg.insecure.Value {
case cfg.insecure.Value:
dialOpts = append(dialOpts, grpc.WithTransportCredentials(insecure.NewCredentials()))
} else {
default:
// Default to using the host's root CA.
dialOpts = append(dialOpts, grpc.WithTransportCredentials(
credentials.NewTLS(nil),
@ -216,9 +217,9 @@ func newNoopClient() *noopClient {
return &noopClient{}
}
func (c *noopClient) UploadLogs(context.Context, []*logpb.ResourceLogs) error { return nil }
func (*noopClient) UploadLogs(context.Context, []*logpb.ResourceLogs) error { return nil }
func (c *noopClient) Shutdown(context.Context) error { return nil }
func (*noopClient) Shutdown(context.Context) error { return nil }
// retryable returns if err identifies a request that can be retried and a
// duration to wait for if an explicit throttle time is included in err.

View file

@ -563,7 +563,7 @@ func loadCertificates(certPath, keyPath string) ([]tls.Certificate, error) {
func insecureFromScheme(prev setting[bool], scheme string) setting[bool] {
if scheme == "https" {
return newSetting(false)
} else if len(scheme) > 0 {
} else if scheme != "" {
return newSetting(true)
}

View file

@ -8,9 +8,10 @@ import (
"sync"
"sync/atomic"
logpb "go.opentelemetry.io/proto/otlp/logs/v1"
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc/internal/transform"
"go.opentelemetry.io/otel/sdk/log"
logpb "go.opentelemetry.io/proto/otlp/logs/v1"
)
type logClient interface {
@ -88,6 +89,6 @@ func (e *Exporter) Shutdown(ctx context.Context) error {
}
// ForceFlush does nothing. The Exporter holds no state.
func (e *Exporter) ForceFlush(ctx context.Context) error {
func (*Exporter) ForceFlush(context.Context) error {
return nil
}

View file

@ -5,5 +5,5 @@ package otlploggrpc // import "go.opentelemetry.io/otel/exporters/otlp/otlplog/o
// Version is the current release version of the OpenTelemetry OTLP over gRPC logs exporter in use.
func Version() string {
return "0.13.0"
return "0.14.0"
}

View file

@ -199,3 +199,33 @@
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.
--------------------------------------------------------------------------------
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -18,12 +18,11 @@ import (
"sync"
"time"
collogpb "go.opentelemetry.io/proto/otlp/collector/logs/v1"
logpb "go.opentelemetry.io/proto/otlp/logs/v1"
"google.golang.org/protobuf/proto"
"go.opentelemetry.io/otel"
collogpb "go.opentelemetry.io/proto/otlp/collector/logs/v1"
logpb "go.opentelemetry.io/proto/otlp/logs/v1"
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp/internal/retry"
)
@ -200,7 +199,7 @@ func (c *httpClient) uploadLogs(ctx context.Context, data []*logpb.ResourceLogs)
return err
}
respStr := strings.TrimSpace(respData.String())
if len(respStr) == 0 {
if respStr == "" {
respStr = "(empty)"
}
bodyErr := fmt.Errorf("body: %s", respStr)
@ -220,7 +219,7 @@ func (c *httpClient) uploadLogs(ctx context.Context, data []*logpb.ResourceLogs)
}
var gzPool = sync.Pool{
New: func() interface{} {
New: func() any {
w := gzip.NewWriter(io.Discard)
return w
},
@ -232,7 +231,7 @@ func (c *httpClient) newRequest(ctx context.Context, body []byte) (request, erro
switch c.compression {
case NoCompression:
r.ContentLength = (int64)(len(body))
r.ContentLength = int64(len(body))
req.bodyReader = bodyReader(body)
case GzipCompression:
// Ensure the content length is not used.
@ -313,7 +312,7 @@ func (e retryableError) Unwrap() error {
return e.err
}
func (e retryableError) As(target interface{}) bool {
func (e retryableError) As(target any) bool {
if e.err == nil {
return false
}

View file

@ -58,7 +58,7 @@ func (e *Exporter) Export(ctx context.Context, records []log.Record) error {
// Shutdown shuts down the Exporter. Calls to Export or ForceFlush will perform
// no operation after this is called.
func (e *Exporter) Shutdown(ctx context.Context) error {
func (e *Exporter) Shutdown(context.Context) error {
if e.stopped.Swap(true) {
return nil
}
@ -68,6 +68,6 @@ func (e *Exporter) Shutdown(ctx context.Context) error {
}
// ForceFlush does nothing. The Exporter holds no state.
func (e *Exporter) ForceFlush(ctx context.Context) error {
func (*Exporter) ForceFlush(context.Context) error {
return nil
}

View file

@ -5,5 +5,5 @@ package otlploghttp // import "go.opentelemetry.io/otel/exporters/otlp/otlplog/o
// Version is the current release version of the OpenTelemetry OTLP over HTTP/protobuf logs exporter in use.
func Version() string {
return "0.13.0"
return "0.14.0"
}

View file

@ -199,3 +199,33 @@
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.
--------------------------------------------------------------------------------
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -8,6 +8,8 @@ import (
"errors"
"time"
colmetricpb "go.opentelemetry.io/proto/otlp/collector/metrics/v1"
metricpb "go.opentelemetry.io/proto/otlp/metrics/v1"
"google.golang.org/genproto/googleapis/rpc/errdetails"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
@ -18,8 +20,6 @@ import (
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/retry"
colmetricpb "go.opentelemetry.io/proto/otlp/collector/metrics/v1"
metricpb "go.opentelemetry.io/proto/otlp/metrics/v1"
)
type client struct {

View file

@ -9,12 +9,13 @@ import (
"fmt"
"sync"
metricpb "go.opentelemetry.io/proto/otlp/metrics/v1"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/transform"
"go.opentelemetry.io/otel/internal/global"
"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
metricpb "go.opentelemetry.io/proto/otlp/metrics/v1"
)
// Exporter is a OpenTelemetry metric Exporter using gRPC.
@ -91,7 +92,7 @@ func (e *Exporter) Export(ctx context.Context, rm *metricdata.ResourceMetrics) e
// This method returns an error if the method is canceled by the passed context.
//
// This method is safe to call concurrently.
func (e *Exporter) ForceFlush(ctx context.Context) error {
func (*Exporter) ForceFlush(ctx context.Context) error {
// The exporter and client hold no state, nothing to flush.
return ctx.Err()
}
@ -119,7 +120,7 @@ var errShutdown = errors.New("gRPC exporter is shutdown")
type shutdownClient struct{}
func (c shutdownClient) err(ctx context.Context) error {
func (shutdownClient) err(ctx context.Context) error {
if err := ctx.Err(); err != nil {
return err
}
@ -135,7 +136,7 @@ func (c shutdownClient) Shutdown(ctx context.Context) error {
}
// MarshalLog returns logging data about the Exporter.
func (e *Exporter) MarshalLog() interface{} {
func (*Exporter) MarshalLog() any {
return struct{ Type string }{Type: "OTLP/gRPC"}
}

View file

@ -5,5 +5,5 @@ package otlpmetricgrpc // import "go.opentelemetry.io/otel/exporters/otlp/otlpme
// Version is the current release version of the OpenTelemetry OTLP over gRPC metrics exporter in use.
func Version() string {
return "1.37.0"
return "1.38.0"
}

View file

@ -199,3 +199,33 @@
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.
--------------------------------------------------------------------------------
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -18,14 +18,14 @@ import (
"sync"
"time"
colmetricpb "go.opentelemetry.io/proto/otlp/collector/metrics/v1"
metricpb "go.opentelemetry.io/proto/otlp/metrics/v1"
"google.golang.org/protobuf/proto"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/retry"
colmetricpb "go.opentelemetry.io/proto/otlp/collector/metrics/v1"
metricpb "go.opentelemetry.io/proto/otlp/metrics/v1"
)
type client struct {
@ -203,7 +203,7 @@ func (c *client) UploadMetrics(ctx context.Context, protoMetrics *metricpb.Resou
return err
}
respStr := strings.TrimSpace(respData.String())
if len(respStr) == 0 {
if respStr == "" {
respStr = "(empty)"
}
bodyErr := fmt.Errorf("body: %s", respStr)
@ -223,7 +223,7 @@ func (c *client) UploadMetrics(ctx context.Context, protoMetrics *metricpb.Resou
}
var gzPool = sync.Pool{
New: func() interface{} {
New: func() any {
w := gzip.NewWriter(io.Discard)
return w
},
@ -235,7 +235,7 @@ func (c *client) newRequest(ctx context.Context, body []byte) (request, error) {
switch c.compression {
case NoCompression:
r.ContentLength = (int64)(len(body))
r.ContentLength = int64(len(body))
req.bodyReader = bodyReader(body)
case GzipCompression:
// Ensure the content length is not used.
@ -316,7 +316,7 @@ func (e retryableError) Unwrap() error {
return e.err
}
func (e retryableError) As(target interface{}) bool {
func (e retryableError) As(target any) bool {
if e.err == nil {
return false
}

View file

@ -9,12 +9,13 @@ import (
"fmt"
"sync"
metricpb "go.opentelemetry.io/proto/otlp/metrics/v1"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/transform"
"go.opentelemetry.io/otel/internal/global"
"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
metricpb "go.opentelemetry.io/proto/otlp/metrics/v1"
)
// Exporter is a OpenTelemetry metric Exporter using protobufs over HTTP.
@ -91,7 +92,7 @@ func (e *Exporter) Export(ctx context.Context, rm *metricdata.ResourceMetrics) e
// This method returns an error if the method is canceled by the passed context.
//
// This method is safe to call concurrently.
func (e *Exporter) ForceFlush(ctx context.Context) error {
func (*Exporter) ForceFlush(ctx context.Context) error {
// The exporter and client hold no state, nothing to flush.
return ctx.Err()
}
@ -119,7 +120,7 @@ var errShutdown = errors.New("HTTP exporter is shutdown")
type shutdownClient struct{}
func (c shutdownClient) err(ctx context.Context) error {
func (shutdownClient) err(ctx context.Context) error {
if err := ctx.Err(); err != nil {
return err
}
@ -135,7 +136,7 @@ func (c shutdownClient) Shutdown(ctx context.Context) error {
}
// MarshalLog returns logging data about the Exporter.
func (e *Exporter) MarshalLog() interface{} {
func (*Exporter) MarshalLog() any {
return struct{ Type string }{Type: "OTLP/HTTP"}
}

View file

@ -5,5 +5,5 @@ package otlpmetrichttp // import "go.opentelemetry.io/otel/exporters/otlp/otlpme
// Version is the current release version of the OpenTelemetry OTLP over HTTP/protobuf metrics exporter in use.
func Version() string {
return "1.37.0"
return "1.38.0"
}

View file

@ -199,3 +199,33 @@
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.
--------------------------------------------------------------------------------
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -94,7 +94,7 @@ func NewUnstarted(client Client) *Exporter {
}
// MarshalLog is the marshaling function used by the logging system to represent this Exporter.
func (e *Exporter) MarshalLog() interface{} {
func (e *Exporter) MarshalLog() any {
return struct {
Type string
Client Client

View file

@ -6,9 +6,10 @@
package tracetransform // import "go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/tracetransform"
import (
commonpb "go.opentelemetry.io/proto/otlp/common/v1"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/sdk/resource"
commonpb "go.opentelemetry.io/proto/otlp/common/v1"
)
// KeyValues transforms a slice of attribute KeyValues into OTLP key-values.

View file

@ -4,8 +4,9 @@
package tracetransform // import "go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/tracetransform"
import (
"go.opentelemetry.io/otel/sdk/instrumentation"
commonpb "go.opentelemetry.io/proto/otlp/common/v1"
"go.opentelemetry.io/otel/sdk/instrumentation"
)
func InstrumentationScope(il instrumentation.Scope) *commonpb.InstrumentationScope {

View file

@ -4,8 +4,9 @@
package tracetransform // import "go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/tracetransform"
import (
"go.opentelemetry.io/otel/sdk/resource"
resourcepb "go.opentelemetry.io/proto/otlp/resource/v1"
"go.opentelemetry.io/otel/sdk/resource"
)
// Resource transforms a Resource into an OTLP Resource.

View file

@ -6,12 +6,13 @@ package tracetransform // import "go.opentelemetry.io/otel/exporters/otlp/otlptr
import (
"math"
tracepb "go.opentelemetry.io/proto/otlp/trace/v1"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/sdk/instrumentation"
tracesdk "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/trace"
tracepb "go.opentelemetry.io/proto/otlp/trace/v1"
)
// Spans transforms a slice of OpenTelemetry spans into a slice of OTLP
@ -154,7 +155,6 @@ func links(links []tracesdk.Link) []*tracepb.Span_Link {
for _, otLink := range links {
// This redefinition is necessary to prevent otLink.*ID[:] copies
// being reused -- in short we need a new otLink per iteration.
otLink := otLink
tid := otLink.SpanContext.TraceID()
sid := otLink.SpanContext.SpanID()
@ -189,7 +189,7 @@ func spanEvents(es []tracesdk.Event) []*tracepb.Span_Event {
events := make([]*tracepb.Span_Event, len(es))
// Transform message events
for i := 0; i < len(es); i++ {
for i := range es {
events[i] = &tracepb.Span_Event{
Name: es[i].Name,
TimeUnixNano: uint64(max(0, es[i].Time.UnixNano())), // nolint:gosec // Overflow checked.

View file

@ -199,3 +199,33 @@
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.
--------------------------------------------------------------------------------
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -9,6 +9,8 @@ import (
"sync"
"time"
coltracepb "go.opentelemetry.io/proto/otlp/collector/trace/v1"
tracepb "go.opentelemetry.io/proto/otlp/trace/v1"
"google.golang.org/genproto/googleapis/rpc/errdetails"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
@ -20,8 +22,6 @@ import (
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/otlpconfig"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/retry"
coltracepb "go.opentelemetry.io/proto/otlp/collector/trace/v1"
tracepb "go.opentelemetry.io/proto/otlp/trace/v1"
)
type client struct {
@ -289,7 +289,7 @@ func throttleDelay(s *status.Status) (bool, time.Duration) {
}
// MarshalLog is the marshaling function used by the logging system to represent this Client.
func (c *client) MarshalLog() interface{} {
func (c *client) MarshalLog() any {
return struct {
Type string
Endpoint string

View file

@ -199,3 +199,33 @@
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.
--------------------------------------------------------------------------------
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -18,6 +18,8 @@ import (
"sync"
"time"
coltracepb "go.opentelemetry.io/proto/otlp/collector/trace/v1"
tracepb "go.opentelemetry.io/proto/otlp/trace/v1"
"google.golang.org/protobuf/proto"
"go.opentelemetry.io/otel"
@ -25,14 +27,12 @@ import (
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpconfig"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/retry"
coltracepb "go.opentelemetry.io/proto/otlp/collector/trace/v1"
tracepb "go.opentelemetry.io/proto/otlp/trace/v1"
)
const contentTypeProto = "application/x-protobuf"
var gzPool = sync.Pool{
New: func() interface{} {
New: func() any {
w := gzip.NewWriter(io.Discard)
return w
},
@ -104,7 +104,7 @@ func NewClient(opts ...Option) otlptrace.Client {
}
// Start does nothing in a HTTP client.
func (d *client) Start(ctx context.Context) error {
func (*client) Start(ctx context.Context) error {
// nothing to do
select {
case <-ctx.Done():
@ -209,7 +209,7 @@ func (d *client) UploadTraces(ctx context.Context, protoSpans []*tracepb.Resourc
return err
}
respStr := strings.TrimSpace(respData.String())
if len(respStr) == 0 {
if respStr == "" {
respStr = "(empty)"
}
bodyErr := fmt.Errorf("body: %s", respStr)
@ -230,7 +230,7 @@ func (d *client) UploadTraces(ctx context.Context, protoSpans []*tracepb.Resourc
func (d *client) newRequest(body []byte) (request, error) {
u := url.URL{Scheme: d.getScheme(), Host: d.cfg.Endpoint, Path: d.cfg.URLPath}
r, err := http.NewRequest(http.MethodPost, u.String(), nil)
r, err := http.NewRequest(http.MethodPost, u.String(), http.NoBody)
if err != nil {
return request{Request: r}, err
}
@ -246,7 +246,7 @@ func (d *client) newRequest(body []byte) (request, error) {
req := request{Request: r}
switch Compression(d.cfg.Compression) {
case NoCompression:
r.ContentLength = (int64)(len(body))
r.ContentLength = int64(len(body))
req.bodyReader = bodyReader(body)
case GzipCompression:
// Ensure the content length is not used.
@ -274,7 +274,7 @@ func (d *client) newRequest(body []byte) (request, error) {
}
// MarshalLog is the marshaling function used by the logging system to represent this Client.
func (d *client) MarshalLog() interface{} {
func (d *client) MarshalLog() any {
return struct {
Type string
Endpoint string
@ -340,7 +340,7 @@ func (e retryableError) Unwrap() error {
return e.err
}
func (e retryableError) As(target interface{}) bool {
func (e retryableError) As(target any) bool {
if e.err == nil {
return false
}

View file

@ -5,5 +5,5 @@ package otlptrace // import "go.opentelemetry.io/otel/exporters/otlp/otlptrace"
// Version is the current release version of the OpenTelemetry OTLP trace exporter in use.
func Version() string {
return "1.37.0"
return "1.38.0"
}

View file

@ -7,6 +7,8 @@ import (
"sync"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/model"
"github.com/prometheus/otlptranslator"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/internal/global"
@ -17,6 +19,7 @@ import (
type config struct {
registerer prometheus.Registerer
disableTargetInfo bool
translationStrategy otlptranslator.TranslationStrategyOption
withoutUnits bool
withoutCounterSuffixes bool
readerOpts []metric.ManualReaderOption
@ -25,9 +28,9 @@ type config struct {
resourceAttributesFilter attribute.Filter
}
var logDeprecatedLegacyScheme = sync.OnceFunc(func() {
var logTemporaryDefault = sync.OnceFunc(func() {
global.Warn(
"prometheus exporter legacy scheme deprecated: support for the legacy NameValidationScheme will be removed in a future release",
"The default Prometheus naming translation strategy is planned to be changed from otlptranslator.NoUTF8EscapingWithSuffixes to otlptranslator.UnderscoreEscapingWithSuffixes in a future release. Add prometheus.WithTranslationStrategy(otlptranslator.NoUTF8EscapingWithSuffixes) to preserve the existing behavior, or prometheus.WithTranslationStrategy(otlptranslator.UnderscoreEscapingWithSuffixes) to opt into the future default behavior.",
)
})
@ -38,6 +41,30 @@ func newConfig(opts ...Option) config {
cfg = opt.apply(cfg)
}
if cfg.translationStrategy == "" {
// If no translation strategy was specified, deduce one based on the global
// NameValidationScheme. NOTE: this logic will change in the future, always
// defaulting to UnderscoreEscapingWithSuffixes
//nolint:staticcheck // NameValidationScheme is deprecated but we still need it for now.
if model.NameValidationScheme == model.UTF8Validation {
logTemporaryDefault()
cfg.translationStrategy = otlptranslator.NoUTF8EscapingWithSuffixes
} else {
cfg.translationStrategy = otlptranslator.UnderscoreEscapingWithSuffixes
}
} else {
// Note, if the translation strategy implies that suffixes should be added,
// the user can still use WithoutUnits and WithoutCounterSuffixes to
// explicitly disable specific suffixes. We do not override their preference
// in this case. However if the chosen strategy disables suffixes, we should
// forcibly disable all of them.
if !cfg.translationStrategy.ShouldAddSuffixes() {
cfg.withoutCounterSuffixes = true
cfg.withoutUnits = true
}
}
if cfg.registerer == nil {
cfg.registerer = prometheus.DefaultRegisterer
}
@ -95,6 +122,30 @@ func WithoutTargetInfo() Option {
})
}
// WithTranslationStrategy provides a standardized way to define how metric and
// label names should be handled during translation to Prometheus format. See:
// https://github.com/open-telemetry/opentelemetry-specification/blob/v1.48.0/specification/metrics/sdk_exporters/prometheus.md#configuration.
// The recommended approach is to use either
// [otlptranslator.UnderscoreEscapingWithSuffixes] for full Prometheus-style
// compatibility or [otlptranslator.NoTranslation] for OpenTelemetry-style names.
//
// By default, if the NameValidationScheme variable in
// [github.com/prometheus/common/model] is "legacy", the default strategy is
// [otlptranslator.UnderscoreEscapingWithSuffixes]. If the validation scheme is
// "utf8", then currently the default Strategy is
// [otlptranslator.NoUTF8EscapingWithSuffixes].
//
// Notice: It is planned that a future release of this SDK will change the
// default to always be [otlptranslator.UnderscoreEscapingWithSuffixes] in all
// circumstances. Users wanting a different translation strategy should specify
// it explicitly.
func WithTranslationStrategy(strategy otlptranslator.TranslationStrategyOption) Option {
return optionFunc(func(cfg config) config {
cfg.translationStrategy = strategy
return cfg
})
}
// WithoutUnits disables exporter's addition of unit suffixes to metric names,
// and will also prevent unit comments from being added in OpenMetrics once
// unit comments are supported.
@ -103,6 +154,12 @@ func WithoutTargetInfo() Option {
// conventions. For example, the counter metric request.duration, with unit
// milliseconds would become request_duration_milliseconds_total.
// With this option set, the name would instead be request_duration_total.
//
// Can be used in conjunction with [WithTranslationStrategy] to disable unit
// suffixes in strategies that would otherwise add suffixes, but this behavior
// is not recommended and may be removed in a future release.
//
// Deprecated: Use [WithTranslationStrategy] instead.
func WithoutUnits() Option {
return optionFunc(func(cfg config) config {
cfg.withoutUnits = true
@ -110,12 +167,19 @@ func WithoutUnits() Option {
})
}
// WithoutCounterSuffixes disables exporter's addition _total suffixes on counters.
// WithoutCounterSuffixes disables exporter's addition _total suffixes on
// counters.
//
// By default, metric names include a _total suffix to follow Prometheus naming
// conventions. For example, the counter metric happy.people would become
// happy_people_total. With this option set, the name would instead be
// happy_people.
//
// Can be used in conjunction with [WithTranslationStrategy] to disable counter
// suffixes in strategies that would otherwise add suffixes, but this behavior
// is not recommended and may be removed in a future release.
//
// Deprecated: Use [WithTranslationStrategy] instead.
func WithoutCounterSuffixes() Option {
return optionFunc(func(cfg config) config {
cfg.withoutCounterSuffixes = true
@ -132,9 +196,11 @@ func WithoutScopeInfo() Option {
})
}
// WithNamespace configures the Exporter to prefix metric with the given namespace.
// Metadata metrics such as target_info are not prefixed since these
// have special behavior based on their name.
// WithNamespace configures the Exporter to prefix metric with the given
// namespace. Metadata metrics such as target_info are not prefixed since these
// have special behavior based on their name. Namespaces will be prepended even
// if [otlptranslator.NoTranslation] is set as a translation strategy. If the provided namespace
// is empty, nothing will be prepended to metric names.
func WithNamespace(ns string) Option {
return optionFunc(func(cfg config) config {
cfg.namespace = ns

View file

@ -15,7 +15,6 @@ import (
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
"github.com/prometheus/common/model"
"github.com/prometheus/otlptranslator"
"google.golang.org/protobuf/proto"
@ -37,7 +36,7 @@ const (
)
var metricsPool = sync.Pool{
New: func() interface{} {
New: func() any {
return &metricdata.ResourceMetrics{}
},
}
@ -49,7 +48,7 @@ type Exporter struct {
}
// MarshalLog returns logging data about the Exporter.
func (e *Exporter) MarshalLog() interface{} {
func (e *Exporter) MarshalLog() any {
const t = "Prometheus exporter"
if r, ok := e.Reader.(*metric.ManualReader); ok {
@ -104,12 +103,18 @@ func New(opts ...Option) (*Exporter, error) {
// TODO (#3244): Enable some way to configure the reader, but not change temporality.
reader := metric.NewManualReader(cfg.readerOpts...)
utf8Allowed := model.NameValidationScheme == model.UTF8Validation // nolint:staticcheck // We need this check to keep supporting the legacy scheme.
if !utf8Allowed {
// Only sanitize if prometheus does not support UTF-8.
logDeprecatedLegacyScheme()
labelNamer := otlptranslator.LabelNamer{UTF8Allowed: !cfg.translationStrategy.ShouldEscape()}
escapedNamespace := cfg.namespace
if escapedNamespace != "" {
var err error
// If the namespace needs to be escaped, do that now when creating the new
// Collector object. The escaping is not persisted in the Config itself.
escapedNamespace, err = labelNamer.Build(escapedNamespace)
if err != nil {
return nil, err
}
}
labelNamer := otlptranslator.LabelNamer{UTF8Allowed: utf8Allowed}
collector := &collector{
reader: reader,
disableTargetInfo: cfg.disableTargetInfo,
@ -117,18 +122,11 @@ func New(opts ...Option) (*Exporter, error) {
withoutCounterSuffixes: cfg.withoutCounterSuffixes,
disableScopeInfo: cfg.disableScopeInfo,
metricFamilies: make(map[string]*dto.MetricFamily),
namespace: labelNamer.Build(cfg.namespace),
namespace: escapedNamespace,
resourceAttributesFilter: cfg.resourceAttributesFilter,
metricNamer: otlptranslator.MetricNamer{
Namespace: cfg.namespace,
// We decide whether to pass type and unit to the netricNamer based
// on whether units or counter suffixes are enabled, and keep this
// always enabled.
WithMetricSuffixes: true,
UTF8Allowed: utf8Allowed,
},
unitNamer: otlptranslator.UnitNamer{UTF8Allowed: utf8Allowed},
labelNamer: labelNamer,
metricNamer: otlptranslator.NewMetricNamer(escapedNamespace, cfg.translationStrategy),
unitNamer: otlptranslator.UnitNamer{UTF8Allowed: !cfg.translationStrategy.ShouldEscape()},
labelNamer: labelNamer,
}
if err := cfg.registerer.Register(collector); err != nil {
@ -143,7 +141,7 @@ func New(opts ...Option) (*Exporter, error) {
}
// Describe implements prometheus.Collector.
func (c *collector) Describe(ch chan<- *prometheus.Desc) {
func (*collector) Describe(chan<- *prometheus.Desc) {
// The Opentelemetry SDK doesn't have information on which will exist when the collector
// is registered. By returning nothing we are an "unchecked" collector in Prometheus,
// and assume responsibility for consistency of the metrics produced.
@ -197,7 +195,11 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) {
}
if c.resourceAttributesFilter != nil && len(c.resourceKeyVals.keys) == 0 {
c.createResourceAttributes(metrics.Resource)
err := c.createResourceAttributes(metrics.Resource)
if err != nil {
otel.Handle(err)
return
}
}
for _, scopeMetrics := range metrics.ScopeMetrics {
@ -211,7 +213,11 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) {
kv.keys = append(kv.keys, scopeNameLabel, scopeVersionLabel, scopeSchemaLabel)
kv.vals = append(kv.vals, scopeMetrics.Scope.Name, scopeMetrics.Scope.Version, scopeMetrics.Scope.SchemaURL)
attrKeys, attrVals := getAttrs(scopeMetrics.Scope.Attributes, c.labelNamer)
attrKeys, attrVals, err := getAttrs(scopeMetrics.Scope.Attributes, c.labelNamer)
if err != nil {
otel.Handle(err)
continue
}
for i := range attrKeys {
attrKeys[i] = scopeLabelPrefix + attrKeys[i]
}
@ -227,7 +233,13 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) {
if typ == nil {
continue
}
name := c.getName(m)
name, err := c.getName(m)
if err != nil {
// TODO(#7066): Handle this error better. It's not clear this can be
// reached, bad metric names should / will be caught at creation time.
otel.Handle(err)
continue
}
drop, help := c.validateMetrics(name, m.Description, typ)
if drop {
@ -322,7 +334,11 @@ func addExponentialHistogramMetric[N int64 | float64](
labelNamer otlptranslator.LabelNamer,
) {
for _, dp := range histogram.DataPoints {
keys, values := getAttrs(dp.Attributes, labelNamer)
keys, values, err := getAttrs(dp.Attributes, labelNamer)
if err != nil {
otel.Handle(err)
continue
}
keys = append(keys, kv.keys...)
values = append(values, kv.vals...)
@ -382,8 +398,7 @@ func addExponentialHistogramMetric[N int64 | float64](
otel.Handle(err)
continue
}
// TODO(GiedriusS): add exemplars here after https://github.com/prometheus/client_golang/pull/1654#pullrequestreview-2434669425 is done.
m = addExemplars(m, dp.Exemplars, labelNamer)
ch <- m
}
}
@ -397,7 +412,11 @@ func addHistogramMetric[N int64 | float64](
labelNamer otlptranslator.LabelNamer,
) {
for _, dp := range histogram.DataPoints {
keys, values := getAttrs(dp.Attributes, labelNamer)
keys, values, err := getAttrs(dp.Attributes, labelNamer)
if err != nil {
otel.Handle(err)
continue
}
keys = append(keys, kv.keys...)
values = append(values, kv.vals...)
@ -433,7 +452,11 @@ func addSumMetric[N int64 | float64](
}
for _, dp := range sum.DataPoints {
keys, values := getAttrs(dp.Attributes, labelNamer)
keys, values, err := getAttrs(dp.Attributes, labelNamer)
if err != nil {
otel.Handle(err)
continue
}
keys = append(keys, kv.keys...)
values = append(values, kv.vals...)
@ -461,7 +484,11 @@ func addGaugeMetric[N int64 | float64](
labelNamer otlptranslator.LabelNamer,
) {
for _, dp := range gauge.DataPoints {
keys, values := getAttrs(dp.Attributes, labelNamer)
keys, values, err := getAttrs(dp.Attributes, labelNamer)
if err != nil {
otel.Handle(err)
continue
}
keys = append(keys, kv.keys...)
values = append(values, kv.vals...)
@ -477,7 +504,7 @@ func addGaugeMetric[N int64 | float64](
// getAttrs converts the attribute.Set to two lists of matching Prometheus-style
// keys and values.
func getAttrs(attrs attribute.Set, labelNamer otlptranslator.LabelNamer) ([]string, []string) {
func getAttrs(attrs attribute.Set, labelNamer otlptranslator.LabelNamer) ([]string, []string, error) {
keys := make([]string, 0, attrs.Len())
values := make([]string, 0, attrs.Len())
itr := attrs.Iter()
@ -495,7 +522,11 @@ func getAttrs(attrs attribute.Set, labelNamer otlptranslator.LabelNamer) ([]stri
keysMap := make(map[string][]string)
for itr.Next() {
kv := itr.Attribute()
key := labelNamer.Build(string(kv.Key))
key, err := labelNamer.Build(string(kv.Key))
if err != nil {
// TODO(#7066) Handle this error better.
return nil, nil, err
}
if _, ok := keysMap[key]; !ok {
keysMap[key] = []string{kv.Value.Emit()}
} else {
@ -509,17 +540,21 @@ func getAttrs(attrs attribute.Set, labelNamer otlptranslator.LabelNamer) ([]stri
values = append(values, strings.Join(vals, ";"))
}
}
return keys, values
return keys, values, nil
}
func (c *collector) createInfoMetric(name, description string, res *resource.Resource) (prometheus.Metric, error) {
keys, values := getAttrs(*res.Set(), c.labelNamer)
keys, values, err := getAttrs(*res.Set(), c.labelNamer)
if err != nil {
return nil, err
}
desc := prometheus.NewDesc(name, description, keys, nil)
return prometheus.NewConstMetric(desc, prometheus.GaugeValue, float64(1), values...)
}
// getName returns the sanitized name, prefixed with the namespace and suffixed with unit.
func (c *collector) getName(m metricdata.Metrics) string {
// getName returns the sanitized name, translated according to the selected
// TranslationStrategy and namespace option.
func (c *collector) getName(m metricdata.Metrics) (string, error) {
translatorMetric := otlptranslator.Metric{
Name: m.Name,
Type: c.namingMetricType(m),
@ -530,7 +565,7 @@ func (c *collector) getName(m metricdata.Metrics) string {
return c.metricNamer.Build(translatorMetric)
}
func (c *collector) metricType(m metricdata.Metrics) *dto.MetricType {
func (*collector) metricType(m metricdata.Metrics) *dto.MetricType {
switch v := m.Data.(type) {
case metricdata.ExponentialHistogram[int64], metricdata.ExponentialHistogram[float64]:
return dto.MetricType_HISTOGRAM.Enum()
@ -581,13 +616,18 @@ func (c *collector) namingMetricType(m metricdata.Metrics) otlptranslator.Metric
return otlptranslator.MetricTypeUnknown
}
func (c *collector) createResourceAttributes(res *resource.Resource) {
func (c *collector) createResourceAttributes(res *resource.Resource) error {
c.mu.Lock()
defer c.mu.Unlock()
resourceAttrs, _ := res.Set().Filter(c.resourceAttributesFilter)
resourceKeys, resourceValues := getAttrs(resourceAttrs, c.labelNamer)
resourceKeys, resourceValues, err := getAttrs(resourceAttrs, c.labelNamer)
if err != nil {
return err
}
c.resourceKeyVals = keyVals{keys: resourceKeys, vals: resourceValues}
return nil
}
func (c *collector) validateMetrics(name, description string, metricType *dto.MetricType) (drop bool, help string) {
@ -638,10 +678,14 @@ func addExemplars[N int64 | float64](
}
promExemplars := make([]prometheus.Exemplar, len(exemplars))
for i, exemplar := range exemplars {
labels := attributesToLabels(exemplar.FilteredAttributes, labelNamer)
labels, err := attributesToLabels(exemplar.FilteredAttributes, labelNamer)
if err != nil {
otel.Handle(err)
return m
}
// Overwrite any existing trace ID or span ID attributes
labels[otlptranslator.ExemplarTraceIDKey] = hex.EncodeToString(exemplar.TraceID[:])
labels[otlptranslator.ExemplarSpanIDKey] = hex.EncodeToString(exemplar.SpanID[:])
labels[otlptranslator.ExemplarTraceIDKey] = hex.EncodeToString(exemplar.TraceID)
labels[otlptranslator.ExemplarSpanIDKey] = hex.EncodeToString(exemplar.SpanID)
promExemplars[i] = prometheus.Exemplar{
Value: float64(exemplar.Value),
Timestamp: exemplar.Time,
@ -658,10 +702,14 @@ func addExemplars[N int64 | float64](
return metricWithExemplar
}
func attributesToLabels(attrs []attribute.KeyValue, labelNamer otlptranslator.LabelNamer) prometheus.Labels {
func attributesToLabels(attrs []attribute.KeyValue, labelNamer otlptranslator.LabelNamer) (prometheus.Labels, error) {
labels := make(map[string]string)
for _, attr := range attrs {
labels[labelNamer.Build(string(attr.Key))] = attr.Value.Emit()
name, err := labelNamer.Build(string(attr.Key))
if err != nil {
return nil, err
}
labels[name] = attr.Value.Emit()
}
return labels
return labels, nil
}

View file

@ -199,3 +199,33 @@
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.
--------------------------------------------------------------------------------
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -67,6 +67,6 @@ func (e *Exporter) Shutdown(context.Context) error {
}
// ForceFlush performs no action.
func (e *Exporter) ForceFlush(context.Context) error {
func (*Exporter) ForceFlush(context.Context) error {
return nil
}

View file

@ -27,7 +27,7 @@ type value struct {
func (v value) MarshalJSON() ([]byte, error) {
var jsonVal struct {
Type string
Value interface{}
Value any
}
jsonVal.Type = v.Kind().String()

View file

@ -199,3 +199,33 @@
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.
--------------------------------------------------------------------------------
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -63,7 +63,7 @@ func (e *exporter) Export(ctx context.Context, data *metricdata.ResourceMetrics)
return e.encVal.Load().(encoderHolder).Encode(data)
}
func (e *exporter) ForceFlush(context.Context) error {
func (*exporter) ForceFlush(context.Context) error {
// exporter holds no state, nothing to flush.
return nil
}
@ -77,7 +77,7 @@ func (e *exporter) Shutdown(context.Context) error {
return nil
}
func (e *exporter) MarshalLog() interface{} {
func (*exporter) MarshalLog() any {
return struct{ Type string }{Type: "STDOUT"}
}

View file

@ -199,3 +199,33 @@
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.
--------------------------------------------------------------------------------
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -3,4 +3,7 @@
// Package stdouttrace contains an OpenTelemetry exporter for tracing
// telemetry to be written to an output destination as JSON.
//
// See [go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/x] for information about
// the experimental features.
package stdouttrace // import "go.opentelemetry.io/otel/exporters/stdout/stdouttrace"

View file

@ -0,0 +1,31 @@
// Code generated by gotmpl. DO NOT MODIFY.
// source: internal/shared/counter/counter.go.tmpl
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
// Package counter provides a simple counter for generating unique IDs.
//
// This package is used to generate unique IDs while allowing testing packages
// to reset the counter.
package counter // import "go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/counter"
import "sync/atomic"
// exporterN is a global 0-based count of the number of exporters created.
var exporterN atomic.Int64
// NextExporterID returns the next unique ID for an exporter.
func NextExporterID() int64 {
const inc = 1
return exporterN.Add(inc) - inc
}
// SetExporterID sets the exporter ID counter to v and returns the previous
// value.
//
// This function is useful for testing purposes, allowing you to reset the
// counter. It should not be used in production code.
func SetExporterID(v int64) int64 {
return exporterN.Swap(v)
}

View file

@ -0,0 +1,36 @@
# Experimental Features
The `stdouttrace` exporter contains features that have not yet stabilized in the OpenTelemetry specification.
These features are added to the `stdouttrace` exporter prior to stabilization in the specification so that users can start experimenting with them and provide feedback.
These features may change in backwards incompatible ways as feedback is applied.
See the [Compatibility and Stability](#compatibility-and-stability) section for more information.
## Features
- [Self-Observability](#self-observability)
### Self-Observability
The `stdouttrace` exporter provides a self-observability feature that allows you to monitor the SDK itself.
To opt-in, set the environment variable `OTEL_GO_X_SELF_OBSERVABILITY` to `true`.
When enabled, the SDK will create the following metrics using the global `MeterProvider`:
- `otel.sdk.exporter.span.inflight`
- `otel.sdk.exporter.span.exported`
- `otel.sdk.exporter.operation.duration`
Please see the [Semantic conventions for OpenTelemetry SDK metrics] documentation for more details on these metrics.
[Semantic conventions for OpenTelemetry SDK metrics]: https://github.com/open-telemetry/semantic-conventions/blob/v1.36.0/docs/otel/sdk-metrics.md
## Compatibility and Stability
Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability [policy](../../../../../VERSIONING.md).
These features may be removed or modified in successive version releases, including patch versions.
When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.

View file

@ -0,0 +1,63 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
// Package x documents experimental features for [go.opentelemetry.io/otel/exporters/stdout/stdouttrace].
package x // import "go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/x"
import (
"os"
"strings"
)
// SelfObservability is an experimental feature flag that determines if SDK
// self-observability metrics are enabled.
//
// To enable this feature set the OTEL_GO_X_SELF_OBSERVABILITY environment variable
// to the case-insensitive string value of "true" (i.e. "True" and "TRUE"
// will also enable this).
var SelfObservability = newFeature("SELF_OBSERVABILITY", func(v string) (string, bool) {
if strings.EqualFold(v, "true") {
return v, true
}
return "", false
})
// Feature is an experimental feature control flag. It provides a uniform way
// to interact with these feature flags and parse their values.
type Feature[T any] struct {
key string
parse func(v string) (T, bool)
}
func newFeature[T any](suffix string, parse func(string) (T, bool)) Feature[T] {
const envKeyRoot = "OTEL_GO_X_"
return Feature[T]{
key: envKeyRoot + suffix,
parse: parse,
}
}
// Key returns the environment variable key that needs to be set to enable the
// feature.
func (f Feature[T]) Key() string { return f.key }
// Lookup returns the user configured value for the feature and true if the
// user has enabled the feature. Otherwise, if the feature is not enabled, a
// zero-value and false are returned.
func (f Feature[T]) Lookup() (v T, ok bool) {
// https://github.com/open-telemetry/opentelemetry-specification/blob/62effed618589a0bec416a87e559c0a9d96289bb/specification/configuration/sdk-environment-variables.md#parsing-empty-value
//
// > The SDK MUST interpret an empty value of an environment variable the
// > same way as when the variable is unset.
vRaw := os.Getenv(f.key)
if vRaw == "" {
return v, ok
}
return f.parse(vRaw)
}
// Enabled reports whether the feature is enabled.
func (f Feature[T]) Enabled() bool {
_, ok := f.Lookup()
return ok
}

View file

@ -6,13 +6,28 @@ package stdouttrace // import "go.opentelemetry.io/otel/exporters/stdout/stdoutt
import (
"context"
"encoding/json"
"errors"
"fmt"
"sync"
"time"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/counter"
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/x"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/sdk"
"go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/sdk/trace/tracetest"
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
"go.opentelemetry.io/otel/semconv/v1.37.0/otelconv"
)
// otelComponentType is a name identifying the type of the OpenTelemetry
// component. It is not a standardized OTel component type, so it uses the
// Go package prefixed type name to ensure uniqueness and identity.
const otelComponentType = "go.opentelemetry.io/otel/exporters/stdout/stdouttrace.Exporter"
var zeroTime time.Time
var _ trace.SpanExporter = &Exporter{}
@ -26,10 +41,45 @@ func New(options ...Option) (*Exporter, error) {
enc.SetIndent("", "\t")
}
return &Exporter{
exporter := &Exporter{
encoder: enc,
timestamps: cfg.Timestamps,
}, nil
}
if !x.SelfObservability.Enabled() {
return exporter, nil
}
exporter.selfObservabilityEnabled = true
exporter.selfObservabilityAttrs = []attribute.KeyValue{
semconv.OTelComponentName(fmt.Sprintf("%s/%d", otelComponentType, counter.NextExporterID())),
semconv.OTelComponentTypeKey.String(otelComponentType),
}
s := attribute.NewSet(exporter.selfObservabilityAttrs...)
exporter.selfObservabilitySetOpt = metric.WithAttributeSet(s)
mp := otel.GetMeterProvider()
m := mp.Meter(
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace",
metric.WithInstrumentationVersion(sdk.Version()),
metric.WithSchemaURL(semconv.SchemaURL),
)
var err, e error
if exporter.spanInflightMetric, e = otelconv.NewSDKExporterSpanInflight(m); e != nil {
e = fmt.Errorf("failed to create span inflight metric: %w", e)
err = errors.Join(err, e)
}
if exporter.spanExportedMetric, e = otelconv.NewSDKExporterSpanExported(m); e != nil {
e = fmt.Errorf("failed to create span exported metric: %w", e)
err = errors.Join(err, e)
}
if exporter.operationDurationMetric, e = otelconv.NewSDKExporterOperationDuration(m); e != nil {
e = fmt.Errorf("failed to create operation duration metric: %w", e)
err = errors.Join(err, e)
}
return exporter, err
}
// Exporter is an implementation of trace.SpanSyncer that writes spans to stdout.
@ -40,10 +90,110 @@ type Exporter struct {
stoppedMu sync.RWMutex
stopped bool
selfObservabilityEnabled bool
selfObservabilityAttrs []attribute.KeyValue // selfObservability common attributes
selfObservabilitySetOpt metric.MeasurementOption
spanInflightMetric otelconv.SDKExporterSpanInflight
spanExportedMetric otelconv.SDKExporterSpanExported
operationDurationMetric otelconv.SDKExporterOperationDuration
}
var (
measureAttrsPool = sync.Pool{
New: func() any {
// "component.name" + "component.type" + "error.type"
const n = 1 + 1 + 1
s := make([]attribute.KeyValue, 0, n)
// Return a pointer to a slice instead of a slice itself
// to avoid allocations on every call.
return &s
},
}
addOptPool = &sync.Pool{
New: func() any {
const n = 1 // WithAttributeSet
o := make([]metric.AddOption, 0, n)
return &o
},
}
recordOptPool = &sync.Pool{
New: func() any {
const n = 1 // WithAttributeSet
o := make([]metric.RecordOption, 0, n)
return &o
},
}
)
// ExportSpans writes spans in json format to stdout.
func (e *Exporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) error {
func (e *Exporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) (err error) {
var success int64
if e.selfObservabilityEnabled {
count := int64(len(spans))
addOpt := addOptPool.Get().(*[]metric.AddOption)
defer func() {
*addOpt = (*addOpt)[:0]
addOptPool.Put(addOpt)
}()
*addOpt = append(*addOpt, e.selfObservabilitySetOpt)
e.spanInflightMetric.Inst().Add(ctx, count, *addOpt...)
defer func(starting time.Time) {
e.spanInflightMetric.Inst().Add(ctx, -count, *addOpt...)
// Record the success and duration of the operation.
//
// Do not exclude 0 values, as they are valid and indicate no spans
// were exported which is meaningful for certain aggregations.
e.spanExportedMetric.Inst().Add(ctx, success, *addOpt...)
mOpt := e.selfObservabilitySetOpt
if err != nil {
// additional attributes for self-observability,
// only spanExportedMetric and operationDurationMetric are supported.
attrs := measureAttrsPool.Get().(*[]attribute.KeyValue)
defer func() {
*attrs = (*attrs)[:0] // reset the slice for reuse
measureAttrsPool.Put(attrs)
}()
*attrs = append(*attrs, e.selfObservabilityAttrs...)
*attrs = append(*attrs, semconv.ErrorType(err))
// Do not inefficiently make a copy of attrs by using
// WithAttributes instead of WithAttributeSet.
set := attribute.NewSet(*attrs...)
mOpt = metric.WithAttributeSet(set)
// Reset addOpt with new attribute set.
*addOpt = append((*addOpt)[:0], mOpt)
e.spanExportedMetric.Inst().Add(
ctx,
count-success,
*addOpt...,
)
}
recordOpt := recordOptPool.Get().(*[]metric.RecordOption)
defer func() {
*recordOpt = (*recordOpt)[:0]
recordOptPool.Put(recordOpt)
}()
*recordOpt = append(*recordOpt, mOpt)
e.operationDurationMetric.Inst().Record(
ctx,
time.Since(starting).Seconds(),
*recordOpt...,
)
}(time.Now())
}
if err := ctx.Err(); err != nil {
return err
}
@ -75,15 +225,17 @@ func (e *Exporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan)
}
// Encode span stubs, one by one
if err := e.encoder.Encode(stub); err != nil {
return err
if e := e.encoder.Encode(stub); e != nil {
err = errors.Join(err, fmt.Errorf("failed to encode span %d: %w", i, e))
continue
}
success++
}
return nil
return err
}
// Shutdown is called to stop the exporter, it performs no action.
func (e *Exporter) Shutdown(ctx context.Context) error {
func (e *Exporter) Shutdown(context.Context) error {
e.stoppedMu.Lock()
e.stopped = true
e.stoppedMu.Unlock()
@ -92,7 +244,7 @@ func (e *Exporter) Shutdown(ctx context.Context) error {
}
// MarshalLog is the marshaling function used by the logging system to represent this Exporter.
func (e *Exporter) MarshalLog() interface{} {
func (e *Exporter) MarshalLog() any {
return struct {
Type string
WithTimestamps bool

View file

@ -41,22 +41,22 @@ func GetLogger() logr.Logger {
// Info prints messages about the general state of the API or SDK.
// This should usually be less than 5 messages a minute.
func Info(msg string, keysAndValues ...interface{}) {
func Info(msg string, keysAndValues ...any) {
GetLogger().V(4).Info(msg, keysAndValues...)
}
// Error prints messages about exceptional states of the API or SDK.
func Error(err error, msg string, keysAndValues ...interface{}) {
func Error(err error, msg string, keysAndValues ...any) {
GetLogger().Error(err, msg, keysAndValues...)
}
// Debug prints messages about all internal changes in the API or SDK.
func Debug(msg string, keysAndValues ...interface{}) {
func Debug(msg string, keysAndValues ...any) {
GetLogger().V(8).Info(msg, keysAndValues...)
}
// Warn prints messages about warnings in the API or SDK.
// Not an error but is likely more important than an informational event.
func Warn(msg string, keysAndValues ...interface{}) {
func Warn(msg string, keysAndValues ...any) {
GetLogger().V(1).Info(msg, keysAndValues...)
}

View file

@ -26,6 +26,7 @@ import (
"sync/atomic"
"go.opentelemetry.io/auto/sdk"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"

View file

@ -199,3 +199,33 @@
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.
--------------------------------------------------------------------------------
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -242,10 +242,10 @@ func (v Value) Kind() Kind {
}
}
// Empty returns if v does not hold any value.
// Empty reports whether v does not hold any value.
func (v Value) Empty() bool { return v.Kind() == KindEmpty }
// Equal returns if v is equal to w.
// Equal reports whether v is equal to w.
func (v Value) Equal(w Value) bool {
k1 := v.Kind()
k2 := w.Kind()
@ -326,7 +326,7 @@ type KeyValue struct {
Value Value
}
// Equal returns if a is equal to b.
// Equal reports whether a is equal to b.
func (a KeyValue) Equal(b KeyValue) bool {
return a.Key == b.Key && a.Value.Equal(b.Value)
}

View file

@ -30,7 +30,7 @@ type Logger interface {
// concurrently.
Emit(ctx context.Context, record Record)
// Enabled returns whether the Logger emits for the given context and
// Enabled reports whether the Logger emits for the given context and
// param.
//
// This is useful for users that want to know if a [Record]

View file

@ -142,3 +142,11 @@ func (r *Record) AddAttributes(attrs ...KeyValue) {
func (r *Record) AttributesLen() int {
return r.nFront + len(r.back)
}
// Clone returns a copy of the record with no shared state.
// The original record and the clone can both be modified without interfering with each other.
func (r *Record) Clone() Record {
res := *r
res.back = slices.Clone(r.back)
return res
}

View file

@ -199,3 +199,33 @@
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.
--------------------------------------------------------------------------------
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -20,7 +20,7 @@ type Baggage struct{}
var _ TextMapPropagator = Baggage{}
// Inject sets baggage key-values from ctx into the carrier.
func (b Baggage) Inject(ctx context.Context, carrier TextMapCarrier) {
func (Baggage) Inject(ctx context.Context, carrier TextMapCarrier) {
bStr := baggage.FromContext(ctx).String()
if bStr != "" {
carrier.Set(baggageHeader, bStr)
@ -30,7 +30,7 @@ func (b Baggage) Inject(ctx context.Context, carrier TextMapCarrier) {
// Extract returns a copy of parent with the baggage from the carrier added.
// If carrier implements [ValuesGetter] (e.g. [HeaderCarrier]), Values is invoked
// for multiple values extraction. Otherwise, Get is called.
func (b Baggage) Extract(parent context.Context, carrier TextMapCarrier) context.Context {
func (Baggage) Extract(parent context.Context, carrier TextMapCarrier) context.Context {
if multiCarrier, ok := carrier.(ValuesGetter); ok {
return extractMultiBaggage(parent, multiCarrier)
}
@ -38,7 +38,7 @@ func (b Baggage) Extract(parent context.Context, carrier TextMapCarrier) context
}
// Fields returns the keys who's values are set with Inject.
func (b Baggage) Fields() []string {
func (Baggage) Fields() []string {
return []string{baggageHeader}
}

View file

@ -20,7 +20,7 @@ type TextMapCarrier interface {
// must never be done outside of a new major release.
// Set stores the key-value pair.
Set(key string, value string)
Set(key, value string)
// DO NOT CHANGE: any modification will not be backwards compatible and
// must never be done outside of a new major release.
@ -88,7 +88,7 @@ func (hc HeaderCarrier) Values(key string) []string {
}
// Set stores the key-value pair.
func (hc HeaderCarrier) Set(key string, value string) {
func (hc HeaderCarrier) Set(key, value string) {
http.Header(hc).Set(key, value)
}

View file

@ -36,7 +36,7 @@ var (
)
// Inject injects the trace context from ctx into carrier.
func (tc TraceContext) Inject(ctx context.Context, carrier TextMapCarrier) {
func (TraceContext) Inject(ctx context.Context, carrier TextMapCarrier) {
sc := trace.SpanContextFromContext(ctx)
if !sc.IsValid() {
return
@ -77,7 +77,7 @@ func (tc TraceContext) Extract(ctx context.Context, carrier TextMapCarrier) cont
return trace.ContextWithRemoteSpanContext(ctx, sc)
}
func (tc TraceContext) extract(carrier TextMapCarrier) trace.SpanContext {
func (TraceContext) extract(carrier TextMapCarrier) trace.SpanContext {
h := carrier.Get(traceparentHeader)
if h == "" {
return trace.SpanContext{}
@ -151,6 +151,6 @@ func extractPart(dst []byte, h *string, n int) bool {
}
// Fields returns the keys who's values are set with Inject.
func (tc TraceContext) Fields() []string {
func (TraceContext) Fields() []string {
return []string{traceparentHeader, tracestateHeader}
}

View file

@ -199,3 +199,33 @@
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.
--------------------------------------------------------------------------------
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -19,7 +19,7 @@ import (
// to the case-insensitive string value of "true" (i.e. "True" and "TRUE"
// will also enable this).
var Resource = newFeature("RESOURCE", func(v string) (string, bool) {
if strings.ToLower(v) == "true" {
if strings.EqualFold(v, "true") {
return v, true
}
return "", false
@ -59,7 +59,7 @@ func (f Feature[T]) Lookup() (v T, ok bool) {
return f.parse(vRaw)
}
// Enabled returns if the feature is enabled.
// Enabled reports whether the feature is enabled.
func (f Feature[T]) Enabled() bool {
_, ok := f.Lookup()
return ok

View file

@ -199,3 +199,33 @@
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.
--------------------------------------------------------------------------------
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -329,7 +329,7 @@ func (q *queue) TryDequeue(buf []Record, write func([]Record) bool) int {
origRead := q.read
n := min(len(buf), q.len)
for i := 0; i < n; i++ {
for i := range n {
buf[i] = q.read.Value
q.read = q.read.Next()
}

View file

@ -30,6 +30,9 @@ should be used to describe the unique runtime environment instrumented code
is being run on. That way when multiple instances of the code are collected
at a single endpoint their origin is decipherable.
See [go.opentelemetry.io/otel/sdk/log/internal/x] for information about
the experimental features.
See [go.opentelemetry.io/otel/log] for more information about
the OpenTelemetry Logs API.
*/

View file

@ -30,7 +30,7 @@ import (
// It provides a Processor used to filter out [Record]
// that has a [log.Severity] below a threshold.
type FilterProcessor interface {
// Enabled returns whether the Processor will process for the given context
// Enabled reports whether the Processor will process for the given context
// and param.
//
// The passed param is likely to be a partial record information being

View file

@ -0,0 +1,34 @@
# Experimental Features
The Logs SDK contains features that have not yet stabilized in the OpenTelemetry specification.
These features are added to the OpenTelemetry Go Logs SDK prior to stabilization in the specification so that users can start experimenting with them and provide feedback.
These feature may change in backwards incompatible ways as feedback is applied.
See the [Compatibility and Stability](#compatibility-and-stability) section for more information.
## Features
- [Self-Observability](#self-observability)
### Self-Observability
The Logs SDK provides a self-observability feature that allows you to monitor the SDK itself.
To opt-in, set the environment variable `OTEL_GO_X_SELF_OBSERVABILITY` to `true`.
When enabled, the SDK will create the following metrics using the global `MeterProvider`:
- `otel.sdk.log.created`
Please see the [Semantic conventions for OpenTelemetry SDK metrics] documentation for more details on these metrics.
[Semantic conventions for OpenTelemetry SDK metrics]: https://github.com/open-telemetry/semantic-conventions/blob/v1.36.0/docs/otel/sdk-metrics.md
## Compatibility and Stability
Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability [policy](../../../../VERSIONING.md).
These features may be removed or modified in successive version releases, including patch versions.
When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.

View file

@ -0,0 +1,63 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
// Package x documents experimental features for [go.opentelemetry.io/otel/sdk/log].
package x // import "go.opentelemetry.io/otel/sdk/log/internal/x"
import (
"os"
"strings"
)
// SelfObservability is an experimental feature flag that determines if SDK
// self-observability metrics are enabled.
//
// To enable this feature set the OTEL_GO_X_SELF_OBSERVABILITY environment variable
// to the case-insensitive string value of "true" (i.e. "True" and "TRUE"
// will also enable this).
var SelfObservability = newFeature("SELF_OBSERVABILITY", func(v string) (string, bool) {
if strings.EqualFold(v, "true") {
return v, true
}
return "", false
})
// Feature is an experimental feature control flag. It provides a uniform way
// to interact with these feature flags and parse their values.
type Feature[T any] struct {
key string
parse func(v string) (T, bool)
}
func newFeature[T any](suffix string, parse func(string) (T, bool)) Feature[T] {
const envKeyRoot = "OTEL_GO_X_"
return Feature[T]{
key: envKeyRoot + suffix,
parse: parse,
}
}
// Key returns the environment variable key that needs to be set to enable the
// feature.
func (f Feature[T]) Key() string { return f.key }
// Lookup returns the user configured value for the feature and true if the
// user has enabled the feature. Otherwise, if the feature is not enabled, a
// zero-value and false are returned.
func (f Feature[T]) Lookup() (v T, ok bool) {
// https://github.com/open-telemetry/opentelemetry-specification/blob/62effed618589a0bec416a87e559c0a9d96289bb/specification/configuration/sdk-environment-variables.md#parsing-empty-value
//
// > The SDK MUST interpret an empty value of an environment variable the
// > same way as when the variable is unset.
vRaw := os.Getenv(f.key)
if vRaw == "" {
return v, ok
}
return f.parse(vRaw)
}
// Enabled reports whether the feature is enabled.
func (f Feature[T]) Enabled() bool {
_, ok := f.Lookup()
return ok
}

View file

@ -5,12 +5,18 @@ package log // import "go.opentelemetry.io/otel/sdk/log"
import (
"context"
"fmt"
"time"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/log"
"go.opentelemetry.io/otel/log/embedded"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/sdk"
"go.opentelemetry.io/otel/sdk/instrumentation"
"go.opentelemetry.io/otel/sdk/log/internal/x"
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
"go.opentelemetry.io/otel/semconv/v1.37.0/otelconv"
"go.opentelemetry.io/otel/trace"
)
@ -24,13 +30,31 @@ type logger struct {
provider *LoggerProvider
instrumentationScope instrumentation.Scope
selfObservabilityEnabled bool
logCreatedMetric otelconv.SDKLogCreated
}
func newLogger(p *LoggerProvider, scope instrumentation.Scope) *logger {
return &logger{
l := &logger{
provider: p,
instrumentationScope: scope,
}
if !x.SelfObservability.Enabled() {
return l
}
l.selfObservabilityEnabled = true
mp := otel.GetMeterProvider()
m := mp.Meter("go.opentelemetry.io/otel/sdk/log",
metric.WithInstrumentationVersion(sdk.Version()),
metric.WithSchemaURL(semconv.SchemaURL))
var err error
if l.logCreatedMetric, err = otelconv.NewSDKLogCreated(m); err != nil {
err = fmt.Errorf("failed to create log created metric: %w", err)
otel.Handle(err)
}
return l
}
func (l *logger) Emit(ctx context.Context, r log.Record) {
@ -84,7 +108,6 @@ func (l *logger) newRecord(ctx context.Context, r log.Record) Record {
observedTimestamp: r.ObservedTimestamp(),
severity: r.Severity(),
severityText: r.SeverityText(),
body: r.Body(),
traceID: sc.TraceID(),
spanID: sc.SpanID(),
@ -94,7 +117,14 @@ func (l *logger) newRecord(ctx context.Context, r log.Record) Record {
scope: &l.instrumentationScope,
attributeValueLengthLimit: l.provider.attributeValueLengthLimit,
attributeCountLimit: l.provider.attributeCountLimit,
allowDupKeys: l.provider.allowDupKeys,
}
if l.selfObservabilityEnabled {
l.logCreatedMetric.Add(ctx, 1)
}
// This ensures we deduplicate key-value collections in the log body
newRecord.SetBody(r.Body())
// This field SHOULD be set once the event is observed by OpenTelemetry.
if newRecord.observedTimestamp.IsZero() {

View file

@ -32,6 +32,7 @@ type providerConfig struct {
fltrProcessors []FilterProcessor
attrCntLim setting[int]
attrValLenLim setting[int]
allowDupKeys setting[bool]
}
func newProviderConfig(opts []LoggerProviderOption) providerConfig {
@ -67,6 +68,7 @@ type LoggerProvider struct {
fltrProcessors []FilterProcessor
attributeCountLimit int
attributeValueLengthLimit int
allowDupKeys bool
loggersMu sync.Mutex
loggers map[instrumentation.Scope]*logger
@ -93,6 +95,7 @@ func NewLoggerProvider(opts ...LoggerProviderOption) *LoggerProvider {
fltrProcessors: cfg.fltrProcessors,
attributeCountLimit: cfg.attrCntLim.Value,
attributeValueLengthLimit: cfg.attrValLenLim.Value,
allowDupKeys: cfg.allowDupKeys.Value,
}
}
@ -254,3 +257,21 @@ func WithAttributeValueLengthLimit(limit int) LoggerProviderOption {
return cfg
})
}
// WithAllowKeyDuplication sets whether deduplication is skipped for log attributes or other key-value collections.
//
// By default, the key-value collections within a log record are deduplicated to comply with the OpenTelemetry Specification.
// Deduplication means that if multiple keyvalue pairs with the same key are present, only a single pair
// is retained and others are discarded.
//
// Disabling deduplication with this option can improve performance e.g. of adding attributes to the log record.
//
// Note that if you disable deduplication, you are responsible for ensuring that duplicate
// key-value pairs within in a single collection are not emitted,
// or that the telemetry receiver can handle such duplicates.
func WithAllowKeyDuplication() LoggerProviderOption {
return loggerProviderOptionFunc(func(cfg providerConfig) providerConfig {
cfg.allowDupKeys = newSetting(true)
return cfg
})
}

View file

@ -93,6 +93,9 @@ type Record struct {
attributeValueLengthLimit int
attributeCountLimit int
// specifies whether we should deduplicate any key value collections or not
allowDupKeys bool
noCmp [0]func() //nolint: unused // This is indeed used.
}
@ -167,7 +170,11 @@ func (r *Record) Body() log.Value {
// SetBody sets the body of the log record.
func (r *Record) SetBody(v log.Value) {
r.body = v
if !r.allowDupKeys {
r.body = r.dedupeBodyCollections(v)
} else {
r.body = v
}
}
// WalkAttributes walks all attributes the log record holds by calling f for
@ -192,56 +199,60 @@ func (r *Record) AddAttributes(attrs ...log.KeyValue) {
if n == 0 {
// Avoid the more complex duplicate map lookups below.
var drop int
attrs, drop = dedup(attrs)
r.setDropped(drop)
if !r.allowDupKeys {
attrs, drop = dedup(attrs)
r.setDropped(drop)
}
attrs, drop = head(attrs, r.attributeCountLimit)
attrs, drop := head(attrs, r.attributeCountLimit)
r.addDropped(drop)
r.addAttrs(attrs)
return
}
// Used to find duplicates between attrs and existing attributes in r.
rIndex := r.attrIndex()
defer putIndex(rIndex)
if !r.allowDupKeys {
// Used to find duplicates between attrs and existing attributes in r.
rIndex := r.attrIndex()
defer putIndex(rIndex)
// Unique attrs that need to be added to r. This uses the same underlying
// array as attrs.
//
// Note, do not iterate attrs twice by just calling dedup(attrs) here.
unique := attrs[:0]
// Used to find duplicates within attrs itself. The index value is the
// index of the element in unique.
uIndex := getIndex()
defer putIndex(uIndex)
// Unique attrs that need to be added to r. This uses the same underlying
// array as attrs.
//
// Note, do not iterate attrs twice by just calling dedup(attrs) here.
unique := attrs[:0]
// Used to find duplicates within attrs itself. The index value is the
// index of the element in unique.
uIndex := getIndex()
defer putIndex(uIndex)
// Deduplicate attrs within the scope of all existing attributes.
for _, a := range attrs {
// Last-value-wins for any duplicates in attrs.
idx, found := uIndex[a.Key]
if found {
r.addDropped(1)
unique[idx] = a
continue
}
idx, found = rIndex[a.Key]
if found {
// New attrs overwrite any existing with the same key.
r.addDropped(1)
if idx < 0 {
r.front[-(idx + 1)] = a
} else {
r.back[idx] = a
// Deduplicate attrs within the scope of all existing attributes.
for _, a := range attrs {
// Last-value-wins for any duplicates in attrs.
idx, found := uIndex[a.Key]
if found {
r.addDropped(1)
unique[idx] = a
continue
}
idx, found = rIndex[a.Key]
if found {
// New attrs overwrite any existing with the same key.
r.addDropped(1)
if idx < 0 {
r.front[-(idx + 1)] = a
} else {
r.back[idx] = a
}
} else {
// Unique attribute.
unique = append(unique, a)
uIndex[a.Key] = len(unique) - 1
}
} else {
// Unique attribute.
unique = append(unique, a)
uIndex[a.Key] = len(unique) - 1
}
attrs = unique
}
attrs = unique
if r.attributeCountLimit > 0 && n+len(attrs) > r.attributeCountLimit {
// Truncate the now unique attributes to comply with limit.
@ -297,8 +308,11 @@ func (r *Record) addAttrs(attrs []log.KeyValue) {
// SetAttributes sets (and overrides) attributes to the log record.
func (r *Record) SetAttributes(attrs ...log.KeyValue) {
var drop int
attrs, drop = dedup(attrs)
r.setDropped(drop)
r.setDropped(0)
if !r.allowDupKeys {
attrs, drop = dedup(attrs)
r.setDropped(drop)
}
attrs, drop = head(attrs, r.attributeCountLimit)
r.addDropped(drop)
@ -426,10 +440,14 @@ func (r *Record) applyValueLimits(val log.Value) log.Value {
}
val = log.SliceValue(sl...)
case log.KindMap:
// Deduplicate then truncate. Do not do at the same time to avoid
// wasted truncation operations.
kvs, dropped := dedup(val.AsMap())
r.addDropped(dropped)
kvs := val.AsMap()
if !r.allowDupKeys {
// Deduplicate then truncate. Do not do at the same time to avoid
// wasted truncation operations.
var dropped int
kvs, dropped = dedup(kvs)
r.addDropped(dropped)
}
for i := range kvs {
kvs[i] = r.applyAttrLimits(kvs[i])
}
@ -438,6 +456,24 @@ func (r *Record) applyValueLimits(val log.Value) log.Value {
return val
}
func (r *Record) dedupeBodyCollections(val log.Value) log.Value {
switch val.Kind() {
case log.KindSlice:
sl := val.AsSlice()
for i := range sl {
sl[i] = r.dedupeBodyCollections(sl[i])
}
val = log.SliceValue(sl...)
case log.KindMap:
kvs, _ := dedup(val.AsMap())
for i := range kvs {
kvs[i].Value = r.dedupeBodyCollections(kvs[i].Value)
}
val = log.MapValue(kvs...)
}
return val
}
// truncate returns a truncated version of s such that it contains less than
// the limit number of characters. Truncation is applied by returning the limit
// number of valid characters contained in s.

View file

@ -199,3 +199,33 @@
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.
--------------------------------------------------------------------------------
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -7,6 +7,7 @@ import (
"context"
"errors"
"os"
"strconv"
"strings"
"sync"
@ -17,12 +18,15 @@ import (
// config contains configuration options for a MeterProvider.
type config struct {
res *resource.Resource
readers []Reader
views []View
exemplarFilter exemplar.Filter
res *resource.Resource
readers []Reader
views []View
exemplarFilter exemplar.Filter
cardinalityLimit int
}
const defaultCardinalityLimit = 0
// readerSignals returns a force-flush and shutdown function for a
// MeterProvider to call in their respective options. All Readers c contains
// will have their force-flush and shutdown methods unified into returned
@ -69,8 +73,9 @@ func unifyShutdown(funcs []func(context.Context) error) func(context.Context) er
// newConfig returns a config configured with options.
func newConfig(options []Option) config {
conf := config{
res: resource.Default(),
exemplarFilter: exemplar.TraceBasedFilter,
res: resource.Default(),
exemplarFilter: exemplar.TraceBasedFilter,
cardinalityLimit: cardinalityLimitFromEnv(),
}
for _, o := range meterProviderOptionsFromEnv() {
conf = o.apply(conf)
@ -155,6 +160,21 @@ func WithExemplarFilter(filter exemplar.Filter) Option {
})
}
// WithCardinalityLimit sets the cardinality limit for the MeterProvider.
//
// The cardinality limit is the hard limit on the number of metric datapoints
// that can be collected for a single instrument in a single collect cycle.
//
// Setting this to a zero or negative value means no limit is applied.
func WithCardinalityLimit(limit int) Option {
// For backward compatibility, the environment variable `OTEL_GO_X_CARDINALITY_LIMIT`
// can also be used to set this value.
return optionFunc(func(cfg config) config {
cfg.cardinalityLimit = limit
return cfg
})
}
func meterProviderOptionsFromEnv() []Option {
var opts []Option
// https://github.com/open-telemetry/opentelemetry-specification/blob/d4b241f451674e8f611bb589477680341006ad2b/specification/configuration/sdk-environment-variables.md#exemplar
@ -170,3 +190,17 @@ func meterProviderOptionsFromEnv() []Option {
}
return opts
}
func cardinalityLimitFromEnv() int {
const cardinalityLimitKey = "OTEL_GO_X_CARDINALITY_LIMIT"
v := strings.TrimSpace(os.Getenv(cardinalityLimitKey))
if v == "" {
return defaultCardinalityLimit
}
n, err := strconv.Atoi(v)
if err != nil {
otel.Handle(err)
return defaultCardinalityLimit
}
return n
}

View file

@ -39,6 +39,30 @@
// Meter.RegisterCallback and Registration.Unregister to add and remove
// callbacks without leaking memory.
//
// # Cardinality Limits
//
// Cardinality refers to the number of unique attributes collected. High cardinality can lead to
// excessive memory usage, increased storage costs, and backend performance issues.
//
// Currently, the OpenTelemetry Go Metric SDK does not enforce a cardinality limit by default
// (note that this may change in a future release). Use [WithCardinalityLimit] to set the
// cardinality limit as desired.
//
// New attribute sets are dropped when the cardinality limit is reached. The measurement of
// these sets are aggregated into
// a special attribute set containing attribute.Bool("otel.metric.overflow", true).
// This ensures total metric values (e.g., Sum, Count) remain correct for the
// collection cycle, but information about the specific dropped sets
// is not preserved.
//
// Recommendations:
//
// - Set the limit based on the theoretical maximum combinations or expected
// active combinations. The OpenTelemetry Specification recommends a default of 2000.
// - A too high of a limit increases worst-case memory overhead in the SDK and may cause downstream
// issues for databases that cannot handle high cardinality.
// - A too low of a limit causes loss of attribute detail as more data falls into overflow.
//
// See [go.opentelemetry.io/otel/metric] for more information about
// the metric API.
//

View file

@ -58,10 +58,7 @@ func DefaultExemplarReservoirProviderSelector(agg Aggregation) exemplar.Reservoi
// SimpleFixedSizeExemplarReservoir with a reservoir equal to the
// smaller of the maximum number of buckets configured on the
// aggregation or twenty (e.g. min(20, max_buckets)).
n = int(a.MaxSize)
if n > 20 {
n = 20
}
n = min(int(a.MaxSize), 20)
} else {
// https://github.com/open-telemetry/opentelemetry-specification/blob/e94af89e3d0c01de30127a0f423e912f6cda7bed/specification/metrics/sdk.md#simplefixedsizeexemplarreservoir
// This Exemplar reservoir MAY take a configuration parameter for
@ -69,11 +66,11 @@ func DefaultExemplarReservoirProviderSelector(agg Aggregation) exemplar.Reservoi
// provided, the default size MAY be the number of possible
// concurrent threads (e.g. number of CPUs) to help reduce
// contention. Otherwise, a default size of 1 SHOULD be used.
n = runtime.NumCPU()
if n < 1 {
// Should never be the case, but be defensive.
n = 1
}
//
// Use runtime.GOMAXPROCS instead of runtime.NumCPU to support
// containerized environments that may have less than the total number
// of logical CPUs available on the local machine allocated to it.
n = max(runtime.GOMAXPROCS(0), 1)
}
return exemplar.FixedSizeReservoirProvider(n)

View file

@ -24,11 +24,11 @@ func TraceBasedFilter(ctx context.Context) bool {
}
// AlwaysOnFilter is a [Filter] that always offers measurements.
func AlwaysOnFilter(ctx context.Context) bool {
func AlwaysOnFilter(context.Context) bool {
return true
}
// AlwaysOffFilter is a [Filter] that never offers measurements.
func AlwaysOffFilter(ctx context.Context) bool {
func AlwaysOffFilter(context.Context) bool {
return false
}

View file

@ -14,7 +14,7 @@ import (
// FixedSizeReservoirProvider returns a provider of [FixedSizeReservoir].
func FixedSizeReservoirProvider(k int) ReservoirProvider {
return func(_ attribute.Set) Reservoir {
return func(attribute.Set) Reservoir {
return NewFixedSizeReservoir(k)
}
}
@ -56,7 +56,7 @@ func newFixedSizeReservoir(s *storage) *FixedSizeReservoir {
// randomFloat64 returns, as a float64, a uniform pseudo-random number in the
// open interval (0.0,1.0).
func (r *FixedSizeReservoir) randomFloat64() float64 {
func (*FixedSizeReservoir) randomFloat64() float64 {
// TODO: Use an algorithm that avoids rejection sampling. For example:
//
// const precision = 1 << 53 // 2^53
@ -125,13 +125,11 @@ func (r *FixedSizeReservoir) Offer(ctx context.Context, t time.Time, n Value, a
if int(r.count) < cap(r.store) {
r.store[r.count] = newMeasurement(ctx, t, n, a)
} else {
if r.count == r.next {
// Overwrite a random existing measurement with the one offered.
idx := int(rand.Int64N(int64(cap(r.store))))
r.store[idx] = newMeasurement(ctx, t, n, a)
r.advance()
}
} else if r.count == r.next {
// Overwrite a random existing measurement with the one offered.
idx := int(rand.Int64N(int64(cap(r.store))))
r.store[idx] = newMeasurement(ctx, t, n, a)
r.advance()
}
r.count++
}

Some files were not shown because too many files have changed in this diff Show more