[chore]: Bump go.opentelemetry.io/otel/sdk from 1.20.0 to 1.24.0
Bumps [go.opentelemetry.io/otel/sdk](https://github.com/open-telemetry/opentelemetry-go) from 1.20.0 to 1.24.0. - [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.20.0...v1.24.0) --- updated-dependencies: - dependency-name: go.opentelemetry.io/otel/sdk dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
parent
d115f9ebc4
commit
93b6093964
8
go.mod
8
go.mod
|
@ -60,14 +60,14 @@ require (
|
|||
github.com/uptrace/bun/extra/bunotel v1.1.16
|
||||
github.com/wagslane/go-password-validator v0.3.0
|
||||
github.com/yuin/goldmark v1.7.0
|
||||
go.opentelemetry.io/otel v1.20.0
|
||||
go.opentelemetry.io/otel v1.24.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.20.0
|
||||
go.opentelemetry.io/otel/exporters/prometheus v0.43.0
|
||||
go.opentelemetry.io/otel/metric v1.20.0
|
||||
go.opentelemetry.io/otel/sdk v1.20.0
|
||||
go.opentelemetry.io/otel/metric v1.24.0
|
||||
go.opentelemetry.io/otel/sdk v1.24.0
|
||||
go.opentelemetry.io/otel/sdk/metric v1.20.0
|
||||
go.opentelemetry.io/otel/trace v1.20.0
|
||||
go.opentelemetry.io/otel/trace v1.24.0
|
||||
go.uber.org/automaxprocs v1.5.3
|
||||
golang.org/x/crypto v0.21.0
|
||||
golang.org/x/image v0.15.0
|
||||
|
|
16
go.sum
16
go.sum
|
@ -735,8 +735,8 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
|||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opentelemetry.io/otel v1.20.0 h1:vsb/ggIY+hUjD/zCAQHpzTmndPqv/ml2ArbsbfBYTAc=
|
||||
go.opentelemetry.io/otel v1.20.0/go.mod h1:oUIGj3D77RwJdM6PPZImDpSZGDvkD9fhesHny69JFrs=
|
||||
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
|
||||
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 h1:DeFD0VgTZ+Cj6hxravYYZE2W4GlneVH81iAOPjZkzk8=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0/go.mod h1:GijYcYmNpX1KazD5JmWGsi4P7dDTTTnfv1UbGn84MnU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0 h1:gvmNvqrPYovvyRmCSygkUDyL8lC5Tl845MLEwqpxhEU=
|
||||
|
@ -745,14 +745,14 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.20.0 h1:CsBiK
|
|||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.20.0/go.mod h1:CMJYNAfooOwSZSAmAeMUV1M+TXld3BiK++z9fqIm2xk=
|
||||
go.opentelemetry.io/otel/exporters/prometheus v0.43.0 h1:Skkl6akzvdWweXX6LLAY29tyFSO6hWZ26uDbVGTDXe8=
|
||||
go.opentelemetry.io/otel/exporters/prometheus v0.43.0/go.mod h1:nZStMoc1H/YJpRjSx9IEX4abBMekORTLQcTUT1CgLkg=
|
||||
go.opentelemetry.io/otel/metric v1.20.0 h1:ZlrO8Hu9+GAhnepmRGhSU7/VkpjrNowxRN9GyKR4wzA=
|
||||
go.opentelemetry.io/otel/metric v1.20.0/go.mod h1:90DRw3nfK4D7Sm/75yQ00gTJxtkBxX+wu6YaNymbpVM=
|
||||
go.opentelemetry.io/otel/sdk v1.20.0 h1:5Jf6imeFZlZtKv9Qbo6qt2ZkmWtdWx/wzcCbNUlAWGM=
|
||||
go.opentelemetry.io/otel/sdk v1.20.0/go.mod h1:rmkSx1cZCm/tn16iWDn1GQbLtsW/LvsdEEFzCSRM6V0=
|
||||
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
|
||||
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
|
||||
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
|
||||
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.20.0 h1:5eD40l/H2CqdKmbSV7iht2KMK0faAIL2pVYzJOWobGk=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.20.0/go.mod h1:AGvpC+YF/jblITiafMTYgvRBUiwi9hZf0EYE2E5XlS8=
|
||||
go.opentelemetry.io/otel/trace v1.20.0 h1:+yxVAPZPbQhbC3OfAkeIVTky6iTFpcr4SiY9om7mXSQ=
|
||||
go.opentelemetry.io/otel/trace v1.20.0/go.mod h1:HJSK7F/hA5RlzpZ0zKDCHCDHm556LCDtKaAo6JmBFUU=
|
||||
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
|
||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
||||
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
|
||||
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
|
||||
go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
|
||||
|
|
|
@ -3,3 +3,5 @@ fo
|
|||
te
|
||||
collison
|
||||
consequentially
|
||||
ans
|
||||
nam
|
||||
|
|
|
@ -14,13 +14,9 @@ go.work.sum
|
|||
gen/
|
||||
|
||||
/example/dice/dice
|
||||
/example/fib/fib
|
||||
/example/fib/traces.txt
|
||||
/example/jaeger/jaeger
|
||||
/example/namedtracer/namedtracer
|
||||
/example/otel-collector/otel-collector
|
||||
/example/opencensus/opencensus
|
||||
/example/passthrough/passthrough
|
||||
/example/prometheus/prometheus
|
||||
/example/view/view
|
||||
/example/zipkin/zipkin
|
||||
|
|
|
@ -8,6 +8,134 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.24.0/0.46.0/0.0.1-alpha] 2024-02-23
|
||||
|
||||
This release is the last to support [Go 1.20].
|
||||
The next release will require at least [Go 1.21].
|
||||
|
||||
### Added
|
||||
|
||||
- Support [Go 1.22]. (#4890)
|
||||
- Add exemplar support to `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc`. (#4900)
|
||||
- Add exemplar support to `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#4900)
|
||||
- The `go.opentelemetry.io/otel/log` module is added.
|
||||
This module includes OpenTelemetry Go's implementation of the Logs Bridge API.
|
||||
This module is in an alpha state, it is subject to breaking changes.
|
||||
See our [versioning policy](./VERSIONING.md) for more info. (#4961)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix registration of multiple callbacks when using the global meter provider from `go.opentelemetry.io/otel`. (#4945)
|
||||
- Fix negative buckets in output of exponential histograms. (#4956)
|
||||
|
||||
## [1.23.1] 2024-02-07
|
||||
|
||||
### Fixed
|
||||
|
||||
- Register all callbacks passed during observable instrument creation instead of just the last one multiple times in `go.opentelemetry.io/otel/sdk/metric`. (#4888)
|
||||
|
||||
## [1.23.0] 2024-02-06
|
||||
|
||||
This release contains the first stable, `v1`, release of the following modules:
|
||||
|
||||
- `go.opentelemetry.io/otel/bridge/opencensus`
|
||||
- `go.opentelemetry.io/otel/bridge/opencensus/test`
|
||||
- `go.opentelemetry.io/otel/example/opencensus`
|
||||
- `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc`
|
||||
- `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`
|
||||
- `go.opentelemetry.io/otel/exporters/stdout/stdoutmetric`
|
||||
|
||||
See our [versioning policy](VERSIONING.md) for more information about these stability guarantees.
|
||||
|
||||
### Added
|
||||
|
||||
- Add `WithEndpointURL` option to the `exporters/otlp/otlpmetric/otlpmetricgrpc`, `exporters/otlp/otlpmetric/otlpmetrichttp`, `exporters/otlp/otlptrace/otlptracegrpc` and `exporters/otlp/otlptrace/otlptracehttp` packages. (#4808)
|
||||
- Experimental exemplar exporting is added to the metric SDK.
|
||||
See [metric documentation](./sdk/metric/internal/x/README.md#exemplars) for more information about this feature and how to enable it. (#4871)
|
||||
- `ErrSchemaURLConflict` is added to `go.opentelemetry.io/otel/sdk/resource`.
|
||||
This error is returned when a merge of two `Resource`s with different (non-empty) schema URL is attempted. (#4876)
|
||||
|
||||
### Changed
|
||||
|
||||
- The `Merge` and `New` functions in `go.opentelemetry.io/otel/sdk/resource` now returns a partial result if there is a schema URL merge conflict.
|
||||
Instead of returning `nil` when two `Resource`s with different (non-empty) schema URLs are merged the merged `Resource`, along with the new `ErrSchemaURLConflict` error, is returned.
|
||||
It is up to the user to decide if they want to use the returned `Resource` or not.
|
||||
It may have desired attributes overwritten or include stale semantic conventions. (#4876)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix `ContainerID` resource detection on systemd when cgroup path has a colon. (#4449)
|
||||
- Fix `go.opentelemetry.io/otel/sdk/metric` to cache instruments to avoid leaking memory when the same instrument is created multiple times. (#4820)
|
||||
- Fix missing `Mix` and `Max` values for `go.opentelemetry.io/otel/exporters/stdout/stdoutmetric` by introducing `MarshalText` and `MarshalJSON` for the `Extrema` type in `go.opentelemetry.io/sdk/metric/metricdata`. (#4827)
|
||||
|
||||
## [1.23.0-rc.1] 2024-01-18
|
||||
|
||||
This is a release candidate for the v1.23.0 release.
|
||||
That release is expected to include the `v1` release of the following modules:
|
||||
|
||||
- `go.opentelemetry.io/otel/bridge/opencensus`
|
||||
- `go.opentelemetry.io/otel/bridge/opencensus/test`
|
||||
- `go.opentelemetry.io/otel/example/opencensus`
|
||||
- `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc`
|
||||
- `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`
|
||||
- `go.opentelemetry.io/otel/exporters/stdout/stdoutmetric`
|
||||
|
||||
See our [versioning policy](VERSIONING.md) for more information about these stability guarantees.
|
||||
|
||||
## [1.22.0/0.45.0] 2024-01-17
|
||||
|
||||
### Added
|
||||
|
||||
- The `go.opentelemetry.io/otel/semconv/v1.22.0` package.
|
||||
The package contains semantic conventions from the `v1.22.0` version of the OpenTelemetry Semantic Conventions. (#4735)
|
||||
- The `go.opentelemetry.io/otel/semconv/v1.23.0` package.
|
||||
The package contains semantic conventions from the `v1.23.0` version of the OpenTelemetry Semantic Conventions. (#4746)
|
||||
- The `go.opentelemetry.io/otel/semconv/v1.23.1` package.
|
||||
The package contains semantic conventions from the `v1.23.1` version of the OpenTelemetry Semantic Conventions. (#4749)
|
||||
- The `go.opentelemetry.io/otel/semconv/v1.24.0` package.
|
||||
The package contains semantic conventions from the `v1.24.0` version of the OpenTelemetry Semantic Conventions. (#4770)
|
||||
- Add `WithResourceAsConstantLabels` option to apply resource attributes for every metric emitted by the Prometheus exporter. (#4733)
|
||||
- Experimental cardinality limiting is added to the metric SDK.
|
||||
See [metric documentation](./sdk/metric/internal/x/README.md#cardinality-limit) for more information about this feature and how to enable it. (#4457)
|
||||
- Add `NewMemberRaw` and `NewKeyValuePropertyRaw` in `go.opentelemetry.io/otel/baggage`. (#4804)
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade all use of `go.opentelemetry.io/otel/semconv` to use `v1.24.0`. (#4754)
|
||||
- Update transformations in `go.opentelemetry.io/otel/exporters/zipkin` to follow `v1.24.0` version of the OpenTelemetry specification. (#4754)
|
||||
- Record synchronous measurements when the passed context is canceled instead of dropping in `go.opentelemetry.io/otel/sdk/metric`.
|
||||
If you do not want to make a measurement when the context is cancelled, you need to handle it yourself (e.g `if ctx.Err() != nil`). (#4671)
|
||||
- Improve `go.opentelemetry.io/otel/trace.TraceState`'s performance. (#4722)
|
||||
- Improve `go.opentelemetry.io/otel/propagation.TraceContext`'s performance. (#4721)
|
||||
- Improve `go.opentelemetry.io/otel/baggage` performance. (#4743)
|
||||
- Improve performance of the `(*Set).Filter` method in `go.opentelemetry.io/otel/attribute` when the passed filter does not filter out any attributes from the set. (#4774)
|
||||
- `Member.String` in `go.opentelemetry.io/otel/baggage` percent-encodes only when necessary. (#4775)
|
||||
- Improve `go.opentelemetry.io/otel/trace.Span`'s performance when adding multiple attributes. (#4818)
|
||||
- `Property.Value` in `go.opentelemetry.io/otel/baggage` now returns a raw string instead of a percent-encoded value. (#4804)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix `Parse` in `go.opentelemetry.io/otel/baggage` to validate member value before percent-decoding. (#4755)
|
||||
- Fix whitespace encoding of `Member.String` in `go.opentelemetry.io/otel/baggage`. (#4756)
|
||||
- Fix observable not registered error when the asynchronous instrument has a drop aggregation in `go.opentelemetry.io/otel/sdk/metric`. (#4772)
|
||||
- Fix baggage item key so that it is not canonicalized in `go.opentelemetry.io/otel/bridge/opentracing`. (#4776)
|
||||
- Fix `go.opentelemetry.io/otel/bridge/opentracing` to properly handle baggage values that requires escaping during propagation. (#4804)
|
||||
- Fix a bug where using multiple readers resulted in incorrect asynchronous counter values in `go.opentelemetry.io/otel/sdk/metric`. (#4742)
|
||||
|
||||
## [1.21.0/0.44.0] 2023-11-16
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove the deprecated `go.opentelemetry.io/otel/bridge/opencensus.NewTracer`. (#4706)
|
||||
- Remove the deprecated `go.opentelemetry.io/otel/exporters/otlp/otlpmetric` module. (#4707)
|
||||
- Remove the deprecated `go.opentelemetry.io/otel/example/view` module. (#4708)
|
||||
- Remove the deprecated `go.opentelemetry.io/otel/example/fib` module. (#4723)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Do not parse non-protobuf responses in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#4719)
|
||||
- Do not parse non-protobuf responses in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`. (#4719)
|
||||
|
||||
## [1.20.0/0.43.0] 2023-11-10
|
||||
|
||||
This release brings a breaking change for custom trace API implementations. Some interfaces (`TracerProvider`, `Tracer`, `Span`) now embed the `go.opentelemetry.io/otel/trace/embedded` types. Implementors need to update their implementations based on what they want the default behavior to be. See the "API Implementations" section of the [trace API] package documentation for more information about how to accomplish this.
|
||||
|
@ -2721,7 +2849,13 @@ 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.20.0...HEAD
|
||||
[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.24.0...HEAD
|
||||
[1.24.0/0.46.0/0.0.1-alpha]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.24.0
|
||||
[1.23.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.23.1
|
||||
[1.23.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.23.0
|
||||
[1.23.0-rc.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.23.0-rc.1
|
||||
[1.22.0/0.45.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.22.0
|
||||
[1.21.0/0.44.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.21.0
|
||||
[1.20.0/0.43.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.20.0
|
||||
[1.19.0/0.42.0/0.0.7]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.19.0
|
||||
[1.19.0-rc.1/0.42.0-rc.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.19.0-rc.1
|
||||
|
@ -2794,6 +2928,8 @@ It contains api and sdk for trace and meter.
|
|||
[0.1.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.1.1
|
||||
[0.1.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.1.0
|
||||
|
||||
[Go 1.22]: https://go.dev/doc/go1.22
|
||||
[Go 1.21]: https://go.dev/doc/go1.21
|
||||
[Go 1.20]: https://go.dev/doc/go1.20
|
||||
[Go 1.19]: https://go.dev/doc/go1.19
|
||||
[Go 1.18]: https://go.dev/doc/go1.18
|
||||
|
|
|
@ -14,4 +14,4 @@
|
|||
|
||||
* @MrAlias @Aneurysm9 @evantorrie @XSAM @dashpole @MadVikingGod @pellared @hanyuancheung @dmathieu
|
||||
|
||||
CODEOWNERS @MrAlias @MadVikingGod @pellared
|
||||
CODEOWNERS @MrAlias @MadVikingGod @pellared @dashpole
|
|
@ -90,6 +90,10 @@ git push <YOUR_FORK> <YOUR_BRANCH_NAME>
|
|||
Open a pull request against the main `opentelemetry-go` repo. Be sure to add the pull
|
||||
request ID to the entry you added to `CHANGELOG.md`.
|
||||
|
||||
Avoid rebasing and force-pushing to your branch to facilitate reviewing the pull request.
|
||||
Rewriting Git history makes it difficult to keep track of iterations during code review.
|
||||
All pull requests are squashed to a single commit upon merge to `main`.
|
||||
|
||||
### How to Receive Comments
|
||||
|
||||
* If the PR is not ready for review, please put `[WIP]` in the title,
|
||||
|
@ -587,25 +591,46 @@ this.
|
|||
|
||||
[^3]: https://github.com/open-telemetry/opentelemetry-go/issues/3548
|
||||
|
||||
### Ignoring context cancellation
|
||||
|
||||
OpenTelemetry API implementations need to ignore the cancellation of the context that are
|
||||
passed when recording a value (e.g. starting a span, recording a measurement, emitting a log).
|
||||
Recording methods should not return an error describing the cancellation state of the context
|
||||
when they complete, nor should they abort any work.
|
||||
|
||||
This rule may not apply if the OpenTelemetry specification defines a timeout mechanism for
|
||||
the method. In that case the context cancellation can be used for the timeout with the
|
||||
restriction that this behavior is documented for the method. Otherwise, timeouts
|
||||
are expected to be handled by the user calling the API, not the implementation.
|
||||
|
||||
Stoppage of the telemetry pipeline is handled by calling the appropriate `Shutdown` method
|
||||
of a provider. It is assumed the context passed from a user is not used for this purpose.
|
||||
|
||||
Outside of the direct recording of telemetry from the API (e.g. exporting telemetry,
|
||||
force flushing telemetry, shutting down a signal provider) the context cancellation
|
||||
should be honored. This means all work done on behalf of the user provided context
|
||||
should be canceled.
|
||||
|
||||
## Approvers and Maintainers
|
||||
|
||||
### Approvers
|
||||
|
||||
- [Evan Torrie](https://github.com/evantorrie), Verizon Media
|
||||
- [Sam Xie](https://github.com/XSAM), Cisco/AppDynamics
|
||||
- [David Ashpole](https://github.com/dashpole), Google
|
||||
- [Chester Cheung](https://github.com/hanyuancheung), Tencent
|
||||
- [Damien Mathieu](https://github.com/dmathieu), Elastic
|
||||
- [Anthony Mirabella](https://github.com/Aneurysm9), AWS
|
||||
|
||||
### Maintainers
|
||||
|
||||
- [David Ashpole](https://github.com/dashpole), Google
|
||||
- [Aaron Clawson](https://github.com/MadVikingGod), LightStep
|
||||
- [Robert Pająk](https://github.com/pellared), Splunk
|
||||
- [Tyler Yahn](https://github.com/MrAlias), Splunk
|
||||
|
||||
### Emeritus
|
||||
|
||||
- [Liz Fong-Jones](https://github.com/lizthegrey), Honeycomb
|
||||
- [Gustavo Silva Paiva](https://github.com/paivagustavo), LightStep
|
||||
- [Josh MacDonald](https://github.com/jmacd), LightStep
|
||||
|
||||
|
|
|
@ -192,7 +192,7 @@ test-coverage: | $(GOCOVMERGE)
|
|||
done; \
|
||||
$(GOCOVMERGE) $$(find . -name coverage.out) > coverage.txt
|
||||
|
||||
# Adding a directory will include all benchmarks in that direcotry if a filter is not specified.
|
||||
# Adding a directory will include all benchmarks in that directory if a filter is not specified.
|
||||
BENCHMARK_TARGETS := sdk/trace
|
||||
.PHONY: benchmark
|
||||
benchmark: $(BENCHMARK_TARGETS:%=benchmark/%)
|
||||
|
@ -315,4 +315,4 @@ add-tags: | $(MULTIMOD)
|
|||
|
||||
.PHONY: lint-markdown
|
||||
lint-markdown:
|
||||
docker run -v "$(CURDIR):$(WORKDIR)" docker://avtodev/markdown-lint:v1 -c $(WORKDIR)/.markdownlint.yaml $(WORKDIR)/**/*.md
|
||||
docker run -v "$(CURDIR):$(WORKDIR)" avtodev/markdown-lint:v1 -c $(WORKDIR)/.markdownlint.yaml $(WORKDIR)/**/*.md
|
||||
|
|
|
@ -11,14 +11,11 @@ It provides a set of APIs to directly measure performance and behavior of your s
|
|||
|
||||
## Project Status
|
||||
|
||||
| Signal | Status |
|
||||
|---------|------------|
|
||||
| Traces | Stable |
|
||||
| Metrics | Stable |
|
||||
| Logs | Design [1] |
|
||||
|
||||
- [1]: Currently the logs signal development is in a design phase ([#4696](https://github.com/open-telemetry/opentelemetry-go/issues/4696)).
|
||||
No Logs Pull Requests are currently being accepted.
|
||||
| Signal | Status |
|
||||
|---------|--------------------|
|
||||
| Traces | Stable |
|
||||
| Metrics | Stable |
|
||||
| Logs | In development[^1] |
|
||||
|
||||
Progress and status specific to this repository is tracked in our
|
||||
[project boards](https://github.com/open-telemetry/opentelemetry-go/projects)
|
||||
|
@ -28,6 +25,8 @@ and
|
|||
Project versioning information and stability guarantees can be found in the
|
||||
[versioning documentation](VERSIONING.md).
|
||||
|
||||
[^1]: https://github.com/orgs/open-telemetry/projects/43
|
||||
|
||||
### Compatibility
|
||||
|
||||
OpenTelemetry-Go ensures compatibility with the current supported versions of
|
||||
|
@ -50,14 +49,19 @@ Currently, this project supports the following environments.
|
|||
|
||||
| OS | Go Version | Architecture |
|
||||
|---------|------------|--------------|
|
||||
| Ubuntu | 1.22 | amd64 |
|
||||
| Ubuntu | 1.21 | amd64 |
|
||||
| Ubuntu | 1.20 | amd64 |
|
||||
| Ubuntu | 1.22 | 386 |
|
||||
| Ubuntu | 1.21 | 386 |
|
||||
| Ubuntu | 1.20 | 386 |
|
||||
| MacOS | 1.22 | amd64 |
|
||||
| MacOS | 1.21 | amd64 |
|
||||
| MacOS | 1.20 | amd64 |
|
||||
| Windows | 1.22 | amd64 |
|
||||
| Windows | 1.21 | amd64 |
|
||||
| Windows | 1.20 | amd64 |
|
||||
| Windows | 1.22 | 386 |
|
||||
| Windows | 1.21 | 386 |
|
||||
| Windows | 1.20 | 386 |
|
||||
|
||||
|
@ -66,7 +70,7 @@ are made for those systems currently.
|
|||
|
||||
## Getting Started
|
||||
|
||||
You can find a getting started guide on [opentelemetry.io](https://opentelemetry.io/docs/go/getting-started/).
|
||||
You can find a getting started guide on [opentelemetry.io](https://opentelemetry.io/docs/languages/go/getting-started/).
|
||||
|
||||
OpenTelemetry's goal is to provide a single set of APIs to capture distributed
|
||||
traces and metrics from your application and send them to an observability
|
||||
|
|
|
@ -123,12 +123,12 @@ Once verified be sure to [make a release for the `contrib` repository](https://g
|
|||
|
||||
### Website Documentation
|
||||
|
||||
Update the [Go instrumentation documentation] in the OpenTelemetry website under [content/en/docs/instrumentation/go].
|
||||
Update the [Go instrumentation documentation] in the OpenTelemetry website under [content/en/docs/languages/go].
|
||||
Importantly, bump any package versions referenced to be the latest one you just released and ensure all code examples still compile and are accurate.
|
||||
|
||||
[OpenTelemetry Semantic Conventions]: https://github.com/open-telemetry/semantic-conventions
|
||||
[Go instrumentation documentation]: https://opentelemetry.io/docs/instrumentation/go/
|
||||
[content/en/docs/instrumentation/go]: https://github.com/open-telemetry/opentelemetry.io/tree/main/content/en/docs/instrumentation/go
|
||||
[Go instrumentation documentation]: https://opentelemetry.io/docs/languages/go/
|
||||
[content/en/docs/languages/go]: https://github.com/open-telemetry/opentelemetry.io/tree/main/content/en/docs/languages/go
|
||||
|
||||
### Demo Repository
|
||||
|
||||
|
|
|
@ -279,52 +279,75 @@ func NewSetWithSortableFiltered(kvs []KeyValue, tmp *Sortable, filter Filter) (S
|
|||
position--
|
||||
kvs[offset], kvs[position] = kvs[position], kvs[offset]
|
||||
}
|
||||
kvs = kvs[position:]
|
||||
|
||||
if filter != nil {
|
||||
return filterSet(kvs[position:], filter)
|
||||
}
|
||||
return Set{
|
||||
equivalent: computeDistinct(kvs[position:]),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// filterSet reorders kvs so that included keys are contiguous at the end of
|
||||
// the slice, while excluded keys precede the included keys.
|
||||
func filterSet(kvs []KeyValue, filter Filter) (Set, []KeyValue) {
|
||||
var excluded []KeyValue
|
||||
|
||||
// Move attributes that do not match the filter so they're adjacent before
|
||||
// calling computeDistinct().
|
||||
distinctPosition := len(kvs)
|
||||
|
||||
// Swap indistinct keys forward and distinct keys toward the
|
||||
// end of the slice.
|
||||
offset := len(kvs) - 1
|
||||
for ; offset >= 0; offset-- {
|
||||
if filter(kvs[offset]) {
|
||||
distinctPosition--
|
||||
kvs[offset], kvs[distinctPosition] = kvs[distinctPosition], kvs[offset]
|
||||
continue
|
||||
if div := filteredToFront(kvs, filter); div != 0 {
|
||||
return Set{equivalent: computeDistinct(kvs[div:])}, kvs[:div]
|
||||
}
|
||||
}
|
||||
excluded = kvs[:distinctPosition]
|
||||
return Set{equivalent: computeDistinct(kvs)}, nil
|
||||
}
|
||||
|
||||
return Set{
|
||||
equivalent: computeDistinct(kvs[distinctPosition:]),
|
||||
}, excluded
|
||||
// filteredToFront filters slice in-place using keep function. All KeyValues that need to
|
||||
// be removed are moved to the front. All KeyValues that need to be kept are
|
||||
// moved (in-order) to the back. The index for the first KeyValue to be kept is
|
||||
// returned.
|
||||
func filteredToFront(slice []KeyValue, keep Filter) int {
|
||||
n := len(slice)
|
||||
j := n
|
||||
for i := n - 1; i >= 0; i-- {
|
||||
if keep(slice[i]) {
|
||||
j--
|
||||
slice[i], slice[j] = slice[j], slice[i]
|
||||
}
|
||||
}
|
||||
return j
|
||||
}
|
||||
|
||||
// Filter returns a filtered copy of this Set. See the documentation for
|
||||
// NewSetWithSortableFiltered for more details.
|
||||
func (l *Set) Filter(re Filter) (Set, []KeyValue) {
|
||||
if re == nil {
|
||||
return Set{
|
||||
equivalent: l.equivalent,
|
||||
}, nil
|
||||
return *l, nil
|
||||
}
|
||||
|
||||
// Note: This could be refactored to avoid the temporary slice
|
||||
// allocation, if it proves to be expensive.
|
||||
return filterSet(l.ToSlice(), re)
|
||||
// Iterate in reverse to the first attribute that will be filtered out.
|
||||
n := l.Len()
|
||||
first := n - 1
|
||||
for ; first >= 0; first-- {
|
||||
kv, _ := l.Get(first)
|
||||
if !re(kv) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// No attributes will be dropped, return the immutable Set l and nil.
|
||||
if first < 0 {
|
||||
return *l, nil
|
||||
}
|
||||
|
||||
// Copy now that we know we need to return a modified set.
|
||||
//
|
||||
// Do not do this in-place on the underlying storage of *Set l. Sets are
|
||||
// immutable and filtering should not change this.
|
||||
slice := l.ToSlice()
|
||||
|
||||
// Don't re-iterate the slice if only slice[0] is filtered.
|
||||
if first == 0 {
|
||||
// It is safe to assume len(slice) >= 1 given we found at least one
|
||||
// attribute above that needs to be filtered out.
|
||||
return Set{equivalent: computeDistinct(slice[1:])}, slice[:1]
|
||||
}
|
||||
|
||||
// Move the filtered slice[first] to the front (preserving order).
|
||||
kv := slice[first]
|
||||
copy(slice[1:first+1], slice[:first])
|
||||
slice[0] = kv
|
||||
|
||||
// Do not re-evaluate re(slice[first+1:]).
|
||||
div := filteredToFront(slice[1:first+1], re) + 1
|
||||
return Set{equivalent: computeDistinct(slice[div:])}, slice[:div]
|
||||
}
|
||||
|
||||
// computeDistinct returns a Distinct using either the fixed- or
|
||||
|
@ -404,7 +427,7 @@ func (l *Set) MarshalJSON() ([]byte, error) {
|
|||
return json.Marshal(l.equivalent.iface)
|
||||
}
|
||||
|
||||
// MarshalLog is the marshaling function used by the logging system to represent this exporter.
|
||||
// MarshalLog is the marshaling function used by the logging system to represent this Set.
|
||||
func (l Set) MarshalLog() interface{} {
|
||||
kvs := make(map[string]string)
|
||||
for _, kv := range l.ToSlice() {
|
||||
|
|
|
@ -18,7 +18,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"go.opentelemetry.io/otel/internal/baggage"
|
||||
|
@ -32,16 +31,6 @@ const (
|
|||
listDelimiter = ","
|
||||
keyValueDelimiter = "="
|
||||
propertyDelimiter = ";"
|
||||
|
||||
keyDef = `([\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5a\x5e-\x7a\x7c\x7e]+)`
|
||||
valueDef = `([\x21\x23-\x2b\x2d-\x3a\x3c-\x5B\x5D-\x7e]*)`
|
||||
keyValueDef = `\s*` + keyDef + `\s*` + keyValueDelimiter + `\s*` + valueDef + `\s*`
|
||||
)
|
||||
|
||||
var (
|
||||
keyRe = regexp.MustCompile(`^` + keyDef + `$`)
|
||||
valueRe = regexp.MustCompile(`^` + valueDef + `$`)
|
||||
propertyRe = regexp.MustCompile(`^(?:\s*` + keyDef + `\s*|` + keyValueDef + `)$`)
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -67,7 +56,7 @@ type Property struct {
|
|||
//
|
||||
// If key is invalid, an error will be returned.
|
||||
func NewKeyProperty(key string) (Property, error) {
|
||||
if !keyRe.MatchString(key) {
|
||||
if !validateKey(key) {
|
||||
return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidKey, key)
|
||||
}
|
||||
|
||||
|
@ -77,14 +66,29 @@ func NewKeyProperty(key string) (Property, error) {
|
|||
|
||||
// NewKeyValueProperty returns a new Property for key with value.
|
||||
//
|
||||
// If key or value are invalid, an error will be returned.
|
||||
// The passed key must be compliant with W3C Baggage specification.
|
||||
// The passed value must be precent-encoded as defined in W3C Baggage specification.
|
||||
//
|
||||
// Notice: Consider using [NewKeyValuePropertyRaw] instead
|
||||
// that does not require precent-encoding of the value.
|
||||
func NewKeyValueProperty(key, value string) (Property, error) {
|
||||
if !keyRe.MatchString(key) {
|
||||
return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidKey, key)
|
||||
}
|
||||
if !valueRe.MatchString(value) {
|
||||
if !validateValue(value) {
|
||||
return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidValue, value)
|
||||
}
|
||||
decodedValue, err := url.PathUnescape(value)
|
||||
if err != nil {
|
||||
return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidValue, value)
|
||||
}
|
||||
return NewKeyValuePropertyRaw(key, decodedValue)
|
||||
}
|
||||
|
||||
// NewKeyValuePropertyRaw returns a new Property for key with value.
|
||||
//
|
||||
// The passed key must be compliant with W3C Baggage specification.
|
||||
func NewKeyValuePropertyRaw(key, value string) (Property, error) {
|
||||
if !validateKey(key) {
|
||||
return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidKey, key)
|
||||
}
|
||||
|
||||
p := Property{
|
||||
key: key,
|
||||
|
@ -106,20 +110,11 @@ func parseProperty(property string) (Property, error) {
|
|||
return newInvalidProperty(), nil
|
||||
}
|
||||
|
||||
match := propertyRe.FindStringSubmatch(property)
|
||||
if len(match) != 4 {
|
||||
p, ok := parsePropertyInternal(property)
|
||||
if !ok {
|
||||
return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidProperty, property)
|
||||
}
|
||||
|
||||
var p Property
|
||||
if match[1] != "" {
|
||||
p.key = match[1]
|
||||
} else {
|
||||
p.key = match[2]
|
||||
p.value = match[3]
|
||||
p.hasValue = true
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
|
@ -130,12 +125,9 @@ func (p Property) validate() error {
|
|||
return fmt.Errorf("invalid property: %w", err)
|
||||
}
|
||||
|
||||
if !keyRe.MatchString(p.key) {
|
||||
if !validateKey(p.key) {
|
||||
return errFunc(fmt.Errorf("%w: %q", errInvalidKey, p.key))
|
||||
}
|
||||
if p.hasValue && !valueRe.MatchString(p.value) {
|
||||
return errFunc(fmt.Errorf("%w: %q", errInvalidValue, p.value))
|
||||
}
|
||||
if !p.hasValue && p.value != "" {
|
||||
return errFunc(errors.New("inconsistent value"))
|
||||
}
|
||||
|
@ -154,11 +146,11 @@ func (p Property) Value() (string, bool) {
|
|||
return p.value, p.hasValue
|
||||
}
|
||||
|
||||
// String encodes Property into a string compliant with the W3C Baggage
|
||||
// String encodes Property into a header string compliant with the W3C Baggage
|
||||
// specification.
|
||||
func (p Property) String() string {
|
||||
if p.hasValue {
|
||||
return fmt.Sprintf("%s%s%v", p.key, keyValueDelimiter, p.value)
|
||||
return fmt.Sprintf("%s%s%v", p.key, keyValueDelimiter, valueEscape(p.value))
|
||||
}
|
||||
return p.key
|
||||
}
|
||||
|
@ -218,7 +210,7 @@ func (p properties) validate() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// String encodes properties into a string compliant with the W3C Baggage
|
||||
// String encodes properties into a header string compliant with the W3C Baggage
|
||||
// specification.
|
||||
func (p properties) String() string {
|
||||
props := make([]string, len(p))
|
||||
|
@ -240,11 +232,28 @@ type Member struct {
|
|||
hasData bool
|
||||
}
|
||||
|
||||
// NewMember returns a new Member from the passed arguments. The key will be
|
||||
// used directly while the value will be url decoded after validation. An error
|
||||
// is returned if the created Member would be invalid according to the W3C
|
||||
// Baggage specification.
|
||||
// NewMemberRaw returns a new Member from the passed arguments.
|
||||
//
|
||||
// The passed key must be compliant with W3C Baggage specification.
|
||||
// The passed value must be precent-encoded as defined in W3C Baggage specification.
|
||||
//
|
||||
// Notice: Consider using [NewMemberRaw] instead
|
||||
// that does not require precent-encoding of the value.
|
||||
func NewMember(key, value string, props ...Property) (Member, error) {
|
||||
if !validateValue(value) {
|
||||
return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, value)
|
||||
}
|
||||
decodedValue, err := url.PathUnescape(value)
|
||||
if err != nil {
|
||||
return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, value)
|
||||
}
|
||||
return NewMemberRaw(key, decodedValue, props...)
|
||||
}
|
||||
|
||||
// NewMemberRaw returns a new Member from the passed arguments.
|
||||
//
|
||||
// The passed key must be compliant with W3C Baggage specification.
|
||||
func NewMemberRaw(key, value string, props ...Property) (Member, error) {
|
||||
m := Member{
|
||||
key: key,
|
||||
value: value,
|
||||
|
@ -254,11 +263,6 @@ func NewMember(key, value string, props ...Property) (Member, error) {
|
|||
if err := m.validate(); err != nil {
|
||||
return newInvalidMember(), err
|
||||
}
|
||||
decodedValue, err := url.PathUnescape(value)
|
||||
if err != nil {
|
||||
return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, value)
|
||||
}
|
||||
m.value = decodedValue
|
||||
return m, nil
|
||||
}
|
||||
|
||||
|
@ -274,11 +278,7 @@ func parseMember(member string) (Member, error) {
|
|||
return newInvalidMember(), fmt.Errorf("%w: %d", errMemberBytes, n)
|
||||
}
|
||||
|
||||
var (
|
||||
key, value string
|
||||
props properties
|
||||
)
|
||||
|
||||
var props properties
|
||||
keyValue, properties, found := strings.Cut(member, propertyDelimiter)
|
||||
if found {
|
||||
// Parse the member properties.
|
||||
|
@ -299,36 +299,34 @@ func parseMember(member string) (Member, error) {
|
|||
}
|
||||
// "Leading and trailing whitespaces are allowed but MUST be trimmed
|
||||
// when converting the header into a data structure."
|
||||
key = strings.TrimSpace(k)
|
||||
var err error
|
||||
value, err = url.PathUnescape(strings.TrimSpace(v))
|
||||
if err != nil {
|
||||
return newInvalidMember(), fmt.Errorf("%w: %q", err, value)
|
||||
}
|
||||
if !keyRe.MatchString(key) {
|
||||
key := strings.TrimSpace(k)
|
||||
if !validateKey(key) {
|
||||
return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidKey, key)
|
||||
}
|
||||
if !valueRe.MatchString(value) {
|
||||
return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, value)
|
||||
|
||||
val := strings.TrimSpace(v)
|
||||
if !validateValue(val) {
|
||||
return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, v)
|
||||
}
|
||||
|
||||
// Decode a precent-encoded value.
|
||||
value, err := url.PathUnescape(val)
|
||||
if err != nil {
|
||||
return newInvalidMember(), fmt.Errorf("%w: %v", errInvalidValue, err)
|
||||
}
|
||||
return Member{key: key, value: value, properties: props, hasData: true}, nil
|
||||
}
|
||||
|
||||
// validate ensures m conforms to the W3C Baggage specification.
|
||||
// A key is just an ASCII string, but a value must be URL encoded UTF-8,
|
||||
// returning an error otherwise.
|
||||
// A key must be an ASCII string, returning an error otherwise.
|
||||
func (m Member) validate() error {
|
||||
if !m.hasData {
|
||||
return fmt.Errorf("%w: %q", errInvalidMember, m)
|
||||
}
|
||||
|
||||
if !keyRe.MatchString(m.key) {
|
||||
if !validateKey(m.key) {
|
||||
return fmt.Errorf("%w: %q", errInvalidKey, m.key)
|
||||
}
|
||||
if !valueRe.MatchString(m.value) {
|
||||
return fmt.Errorf("%w: %q", errInvalidValue, m.value)
|
||||
}
|
||||
return m.properties.validate()
|
||||
}
|
||||
|
||||
|
@ -341,11 +339,13 @@ func (m Member) Value() string { return m.value }
|
|||
// Properties returns a copy of the Member properties.
|
||||
func (m Member) Properties() []Property { return m.properties.Copy() }
|
||||
|
||||
// String encodes Member into a string compliant with the W3C Baggage
|
||||
// String encodes Member into a header string compliant with the W3C Baggage
|
||||
// specification.
|
||||
func (m Member) String() string {
|
||||
// A key is just an ASCII string, but a value is URL encoded UTF-8.
|
||||
s := fmt.Sprintf("%s%s%s", m.key, keyValueDelimiter, url.QueryEscape(m.value))
|
||||
// A key is just an ASCII string. A value is restricted to be
|
||||
// US-ASCII characters excluding CTLs, whitespace,
|
||||
// DQUOTE, comma, semicolon, and backslash.
|
||||
s := fmt.Sprintf("%s%s%s", m.key, keyValueDelimiter, valueEscape(m.value))
|
||||
if len(m.properties) > 0 {
|
||||
s = fmt.Sprintf("%s%s%s", s, propertyDelimiter, m.properties.String())
|
||||
}
|
||||
|
@ -536,9 +536,8 @@ func (b Baggage) Len() int {
|
|||
return len(b.list)
|
||||
}
|
||||
|
||||
// String encodes Baggage into a string compliant with the W3C Baggage
|
||||
// specification. The returned string will be invalid if the Baggage contains
|
||||
// any invalid list-members.
|
||||
// String encodes Baggage into a header string compliant with the W3C Baggage
|
||||
// specification.
|
||||
func (b Baggage) String() string {
|
||||
members := make([]string, 0, len(b.list))
|
||||
for k, v := range b.list {
|
||||
|
@ -550,3 +549,196 @@ func (b Baggage) String() string {
|
|||
}
|
||||
return strings.Join(members, listDelimiter)
|
||||
}
|
||||
|
||||
// parsePropertyInternal attempts to decode a Property from the passed string.
|
||||
// It follows the spec at https://www.w3.org/TR/baggage/#definition.
|
||||
func parsePropertyInternal(s string) (p Property, ok bool) {
|
||||
// For the entire function we will use " key = value " as an example.
|
||||
// Attempting to parse the key.
|
||||
// First skip spaces at the beginning "< >key = value " (they could be empty).
|
||||
index := skipSpace(s, 0)
|
||||
|
||||
// Parse the key: " <key> = value ".
|
||||
keyStart := index
|
||||
keyEnd := index
|
||||
for _, c := range s[keyStart:] {
|
||||
if !validateKeyChar(c) {
|
||||
break
|
||||
}
|
||||
keyEnd++
|
||||
}
|
||||
|
||||
// If we couldn't find any valid key character,
|
||||
// it means the key is either empty or invalid.
|
||||
if keyStart == keyEnd {
|
||||
return
|
||||
}
|
||||
|
||||
// Skip spaces after the key: " key< >= value ".
|
||||
index = skipSpace(s, keyEnd)
|
||||
|
||||
if index == len(s) {
|
||||
// A key can have no value, like: " key ".
|
||||
ok = true
|
||||
p.key = s[keyStart:keyEnd]
|
||||
return
|
||||
}
|
||||
|
||||
// If we have not reached the end and we can't find the '=' delimiter,
|
||||
// it means the property is invalid.
|
||||
if s[index] != keyValueDelimiter[0] {
|
||||
return
|
||||
}
|
||||
|
||||
// Attempting to parse the value.
|
||||
// Match: " key =< >value ".
|
||||
index = skipSpace(s, index+1)
|
||||
|
||||
// Match the value string: " key = <value> ".
|
||||
// A valid property can be: " key =".
|
||||
// Therefore, we don't have to check if the value is empty.
|
||||
valueStart := index
|
||||
valueEnd := index
|
||||
for _, c := range s[valueStart:] {
|
||||
if !validateValueChar(c) {
|
||||
break
|
||||
}
|
||||
valueEnd++
|
||||
}
|
||||
|
||||
// Skip all trailing whitespaces: " key = value< >".
|
||||
index = skipSpace(s, valueEnd)
|
||||
|
||||
// If after looking for the value and skipping whitespaces
|
||||
// we have not reached the end, it means the property is
|
||||
// invalid, something like: " key = value value1".
|
||||
if index != len(s) {
|
||||
return
|
||||
}
|
||||
|
||||
// Decode a precent-encoded value.
|
||||
value, err := url.PathUnescape(s[valueStart:valueEnd])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ok = true
|
||||
p.key = s[keyStart:keyEnd]
|
||||
p.hasValue = true
|
||||
|
||||
p.value = value
|
||||
return
|
||||
}
|
||||
|
||||
func skipSpace(s string, offset int) int {
|
||||
i := offset
|
||||
for ; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if c != ' ' && c != '\t' {
|
||||
break
|
||||
}
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func validateKey(s string) bool {
|
||||
if len(s) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, c := range s {
|
||||
if !validateKeyChar(c) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func validateKeyChar(c int32) bool {
|
||||
return (c >= 0x23 && c <= 0x27) ||
|
||||
(c >= 0x30 && c <= 0x39) ||
|
||||
(c >= 0x41 && c <= 0x5a) ||
|
||||
(c >= 0x5e && c <= 0x7a) ||
|
||||
c == 0x21 ||
|
||||
c == 0x2a ||
|
||||
c == 0x2b ||
|
||||
c == 0x2d ||
|
||||
c == 0x2e ||
|
||||
c == 0x7c ||
|
||||
c == 0x7e
|
||||
}
|
||||
|
||||
func validateValue(s string) bool {
|
||||
for _, c := range s {
|
||||
if !validateValueChar(c) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func validateValueChar(c int32) bool {
|
||||
return c == 0x21 ||
|
||||
(c >= 0x23 && c <= 0x2b) ||
|
||||
(c >= 0x2d && c <= 0x3a) ||
|
||||
(c >= 0x3c && c <= 0x5b) ||
|
||||
(c >= 0x5d && c <= 0x7e)
|
||||
}
|
||||
|
||||
// valueEscape escapes the string so it can be safely placed inside a baggage value,
|
||||
// replacing special characters with %XX sequences as needed.
|
||||
//
|
||||
// The implementation is based on:
|
||||
// https://github.com/golang/go/blob/f6509cf5cdbb5787061b784973782933c47f1782/src/net/url/url.go#L285.
|
||||
func valueEscape(s string) string {
|
||||
hexCount := 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if shouldEscape(c) {
|
||||
hexCount++
|
||||
}
|
||||
}
|
||||
|
||||
if hexCount == 0 {
|
||||
return s
|
||||
}
|
||||
|
||||
var buf [64]byte
|
||||
var t []byte
|
||||
|
||||
required := len(s) + 2*hexCount
|
||||
if required <= len(buf) {
|
||||
t = buf[:required]
|
||||
} else {
|
||||
t = make([]byte, required)
|
||||
}
|
||||
|
||||
j := 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if shouldEscape(s[i]) {
|
||||
const upperhex = "0123456789ABCDEF"
|
||||
t[j] = '%'
|
||||
t[j+1] = upperhex[c>>4]
|
||||
t[j+2] = upperhex[c&15]
|
||||
j += 3
|
||||
} else {
|
||||
t[j] = c
|
||||
j++
|
||||
}
|
||||
}
|
||||
|
||||
return string(t)
|
||||
}
|
||||
|
||||
// shouldEscape returns true if the specified byte should be escaped when
|
||||
// appearing in a baggage value string.
|
||||
func shouldEscape(c byte) bool {
|
||||
if c == '%' {
|
||||
// The percent character must be encoded so that percent-encoding can work.
|
||||
return true
|
||||
}
|
||||
return !validateValueChar(int32(c))
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ transmitted anywhere. An implementation of the OpenTelemetry SDK, like the
|
|||
default SDK implementation (go.opentelemetry.io/otel/sdk), and associated
|
||||
exporters are used to process and transport this data.
|
||||
|
||||
To read the getting started guide, see https://opentelemetry.io/docs/go/getting-started/.
|
||||
To read the getting started guide, see https://opentelemetry.io/docs/languages/go/getting-started/.
|
||||
|
||||
To read more about tracing, see go.opentelemetry.io/otel/trace.
|
||||
|
||||
|
|
|
@ -130,9 +130,11 @@ func (m *meter) setDelegate(provider metric.MeterProvider) {
|
|||
inst.setDelegate(meter)
|
||||
}
|
||||
|
||||
for e := m.registry.Front(); e != nil; e = e.Next() {
|
||||
var n *list.Element
|
||||
for e := m.registry.Front(); e != nil; e = n {
|
||||
r := e.Value.(*registration)
|
||||
r.setDelegate(meter)
|
||||
n = e.Next()
|
||||
m.registry.Remove(e)
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ func SetTracerProvider(tp trace.TracerProvider) {
|
|||
// to itself.
|
||||
Error(
|
||||
errors.New("no delegate configured in tracer provider"),
|
||||
"Setting tracer provider to it's current value. No delegate will be configured",
|
||||
"Setting tracer provider to its current value. No delegate will be configured",
|
||||
)
|
||||
return
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ func SetTextMapPropagator(p propagation.TextMapPropagator) {
|
|||
// delegate to itself.
|
||||
Error(
|
||||
errors.New("no delegate configured in text map propagator"),
|
||||
"Setting text map propagator to it's current value. No delegate will be configured",
|
||||
"Setting text map propagator to its current value. No delegate will be configured",
|
||||
)
|
||||
return
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ func SetMeterProvider(mp metric.MeterProvider) {
|
|||
// to itself.
|
||||
Error(
|
||||
errors.New("no delegate configured in meter provider"),
|
||||
"Setting meter provider to it's current value. No delegate will be configured",
|
||||
"Setting meter provider to its current value. No delegate will be configured",
|
||||
)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import (
|
|||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
@ -28,6 +28,7 @@ const (
|
|||
maxVersion = 254
|
||||
traceparentHeader = "traceparent"
|
||||
tracestateHeader = "tracestate"
|
||||
delimiter = "-"
|
||||
)
|
||||
|
||||
// TraceContext is a propagator that supports the W3C Trace Context format
|
||||
|
@ -41,8 +42,8 @@ const (
|
|||
type TraceContext struct{}
|
||||
|
||||
var (
|
||||
_ TextMapPropagator = TraceContext{}
|
||||
traceCtxRegExp = regexp.MustCompile("^(?P<version>[0-9a-f]{2})-(?P<traceID>[a-f0-9]{32})-(?P<spanID>[a-f0-9]{16})-(?P<traceFlags>[a-f0-9]{2})(?:-.*)?$")
|
||||
_ TextMapPropagator = TraceContext{}
|
||||
versionPart = fmt.Sprintf("%.2X", supportedVersion)
|
||||
)
|
||||
|
||||
// Inject set tracecontext from the Context into the carrier.
|
||||
|
@ -59,12 +60,19 @@ func (tc TraceContext) Inject(ctx context.Context, carrier TextMapCarrier) {
|
|||
// Clear all flags other than the trace-context supported sampling bit.
|
||||
flags := sc.TraceFlags() & trace.FlagsSampled
|
||||
|
||||
h := fmt.Sprintf("%.2x-%s-%s-%s",
|
||||
supportedVersion,
|
||||
sc.TraceID(),
|
||||
sc.SpanID(),
|
||||
flags)
|
||||
carrier.Set(traceparentHeader, h)
|
||||
var sb strings.Builder
|
||||
sb.Grow(2 + 32 + 16 + 2 + 3)
|
||||
_, _ = sb.WriteString(versionPart)
|
||||
traceID := sc.TraceID()
|
||||
spanID := sc.SpanID()
|
||||
flagByte := [1]byte{byte(flags)}
|
||||
var buf [32]byte
|
||||
for _, src := range [][]byte{traceID[:], spanID[:], flagByte[:]} {
|
||||
_ = sb.WriteByte(delimiter[0])
|
||||
n := hex.Encode(buf[:], src)
|
||||
_, _ = sb.Write(buf[:n])
|
||||
}
|
||||
carrier.Set(traceparentHeader, sb.String())
|
||||
}
|
||||
|
||||
// Extract reads tracecontext from the carrier into a returned Context.
|
||||
|
@ -86,21 +94,8 @@ func (tc TraceContext) extract(carrier TextMapCarrier) trace.SpanContext {
|
|||
return trace.SpanContext{}
|
||||
}
|
||||
|
||||
matches := traceCtxRegExp.FindStringSubmatch(h)
|
||||
|
||||
if len(matches) == 0 {
|
||||
return trace.SpanContext{}
|
||||
}
|
||||
|
||||
if len(matches) < 5 { // four subgroups plus the overall match
|
||||
return trace.SpanContext{}
|
||||
}
|
||||
|
||||
if len(matches[1]) != 2 {
|
||||
return trace.SpanContext{}
|
||||
}
|
||||
ver, err := hex.DecodeString(matches[1])
|
||||
if err != nil {
|
||||
var ver [1]byte
|
||||
if !extractPart(ver[:], &h, 2) {
|
||||
return trace.SpanContext{}
|
||||
}
|
||||
version := int(ver[0])
|
||||
|
@ -108,36 +103,24 @@ func (tc TraceContext) extract(carrier TextMapCarrier) trace.SpanContext {
|
|||
return trace.SpanContext{}
|
||||
}
|
||||
|
||||
if version == 0 && len(matches) != 5 { // four subgroups plus the overall match
|
||||
return trace.SpanContext{}
|
||||
}
|
||||
|
||||
if len(matches[2]) != 32 {
|
||||
return trace.SpanContext{}
|
||||
}
|
||||
|
||||
var scc trace.SpanContextConfig
|
||||
|
||||
scc.TraceID, err = trace.TraceIDFromHex(matches[2][:32])
|
||||
if err != nil {
|
||||
if !extractPart(scc.TraceID[:], &h, 32) {
|
||||
return trace.SpanContext{}
|
||||
}
|
||||
if !extractPart(scc.SpanID[:], &h, 16) {
|
||||
return trace.SpanContext{}
|
||||
}
|
||||
|
||||
if len(matches[3]) != 16 {
|
||||
var opts [1]byte
|
||||
if !extractPart(opts[:], &h, 2) {
|
||||
return trace.SpanContext{}
|
||||
}
|
||||
scc.SpanID, err = trace.SpanIDFromHex(matches[3])
|
||||
if err != nil {
|
||||
if version == 0 && (h != "" || opts[0] > 2) {
|
||||
// version 0 not allow extra
|
||||
// version 0 not allow other flag
|
||||
return trace.SpanContext{}
|
||||
}
|
||||
|
||||
if len(matches[4]) != 2 {
|
||||
return trace.SpanContext{}
|
||||
}
|
||||
opts, err := hex.DecodeString(matches[4])
|
||||
if err != nil || len(opts) < 1 || (version == 0 && opts[0] > 2) {
|
||||
return trace.SpanContext{}
|
||||
}
|
||||
// Clear all flags other than the trace-context supported sampling bit.
|
||||
scc.TraceFlags = trace.TraceFlags(opts[0]) & trace.FlagsSampled
|
||||
|
||||
|
@ -155,6 +138,29 @@ func (tc TraceContext) extract(carrier TextMapCarrier) trace.SpanContext {
|
|||
return sc
|
||||
}
|
||||
|
||||
// upperHex detect hex is upper case Unicode characters.
|
||||
func upperHex(v string) bool {
|
||||
for _, c := range v {
|
||||
if c >= 'A' && c <= 'F' {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func extractPart(dst []byte, h *string, n int) bool {
|
||||
part, left, _ := strings.Cut(*h, delimiter)
|
||||
*h = left
|
||||
// hex.Decode decodes unsupported upper-case characters, so exclude explicitly.
|
||||
if len(part) != n || upperHex(part) {
|
||||
return false
|
||||
}
|
||||
if p, err := hex.Decode(dst, []byte(part)); err != nil || p != n/2 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Fields returns the keys who's values are set with Inject.
|
||||
func (tc TraceContext) Fields() []string {
|
||||
return []string{traceparentHeader, tracestateHeader}
|
||||
|
|
|
@ -41,8 +41,20 @@ type Detector interface {
|
|||
// must never be done outside of a new major release.
|
||||
}
|
||||
|
||||
// Detect calls all input detectors sequentially and merges each result with the previous one.
|
||||
// It returns the merged error too.
|
||||
// Detect returns a new [Resource] merged from all the Resources each of the
|
||||
// detectors produces. Each of the detectors are called sequentially, in the
|
||||
// order they are passed, merging the produced resource into the previous.
|
||||
//
|
||||
// This may return a partial Resource along with an error containing
|
||||
// [ErrPartialResource] if that error is returned from a detector. It may also
|
||||
// return a merge-conflicting Resource along with an error containing
|
||||
// [ErrSchemaURLConflict] if merging Resources from different detectors results
|
||||
// in a schema URL conflict. It is up to the caller to determine if this
|
||||
// returned Resource should be used or not.
|
||||
//
|
||||
// If one of the detectors returns an error that is not [ErrPartialResource],
|
||||
// the resource produced by the detector will not be merged and the returned
|
||||
// error will wrap that detector's error.
|
||||
func Detect(ctx context.Context, detectors ...Detector) (*Resource, error) {
|
||||
r := new(Resource)
|
||||
return r, detect(ctx, r, detectors)
|
||||
|
@ -50,6 +62,10 @@ func Detect(ctx context.Context, detectors ...Detector) (*Resource, error) {
|
|||
|
||||
// detect runs all detectors using ctx and merges the result into res. This
|
||||
// assumes res is allocated and not nil, it will panic otherwise.
|
||||
//
|
||||
// If the detectors or merging resources produces any errors (i.e.
|
||||
// [ErrPartialResource] [ErrSchemaURLConflict]), a single error wrapping all of
|
||||
// these errors will be returned. Otherwise, nil is returned.
|
||||
func detect(ctx context.Context, res *Resource, detectors []Detector) error {
|
||||
var (
|
||||
r *Resource
|
||||
|
@ -78,6 +94,11 @@ func detect(ctx context.Context, res *Resource, detectors []Detector) error {
|
|||
if len(errs) == 0 {
|
||||
return nil
|
||||
}
|
||||
if errors.Is(errs, ErrSchemaURLConflict) {
|
||||
// If there has been a merge conflict, ensure the resource has no
|
||||
// schema URL.
|
||||
res.schemaURL = ""
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import (
|
|||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/sdk"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
|
||||
)
|
||||
|
||||
type (
|
||||
|
|
|
@ -22,14 +22,14 @@ import (
|
|||
"os"
|
||||
"regexp"
|
||||
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
|
||||
)
|
||||
|
||||
type containerIDProvider func() (string, error)
|
||||
|
||||
var (
|
||||
containerID containerIDProvider = getContainerIDFromCGroup
|
||||
cgroupContainerIDRe = regexp.MustCompile(`^.*/(?:.*-)?([0-9a-f]+)(?:\.|\s*$)`)
|
||||
cgroupContainerIDRe = regexp.MustCompile(`^.*/(?:.*[-:])?([0-9a-f]+)(?:\.|\s*$)`)
|
||||
)
|
||||
|
||||
type cgroupContainerIDDetector struct{}
|
||||
|
|
|
@ -23,7 +23,7 @@ import (
|
|||
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -19,7 +19,7 @@ import (
|
|||
"errors"
|
||||
"strings"
|
||||
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
|
||||
)
|
||||
|
||||
type hostIDProvider func() (string, error)
|
||||
|
|
|
@ -19,7 +19,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
|
||||
)
|
||||
|
||||
type osDescriptionProvider func() (string, error)
|
||||
|
|
|
@ -22,7 +22,7 @@ import (
|
|||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
|
||||
)
|
||||
|
||||
type (
|
||||
|
|
|
@ -17,6 +17,7 @@ package resource // import "go.opentelemetry.io/otel/sdk/resource"
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
|
@ -40,9 +41,20 @@ var (
|
|||
defaultResourceOnce sync.Once
|
||||
)
|
||||
|
||||
var errMergeConflictSchemaURL = errors.New("cannot merge resource due to conflicting Schema URL")
|
||||
// ErrSchemaURLConflict is an error returned when two Resources are merged
|
||||
// together that contain different, non-empty, schema URLs.
|
||||
var ErrSchemaURLConflict = errors.New("conflicting Schema URL")
|
||||
|
||||
// New returns a Resource combined from the user-provided detectors.
|
||||
// New returns a [Resource] built using opts.
|
||||
//
|
||||
// This may return a partial Resource along with an error containing
|
||||
// [ErrPartialResource] if options that provide a [Detector] are used and that
|
||||
// error is returned from one or more of the Detectors. It may also return a
|
||||
// merge-conflict Resource along with an error containing
|
||||
// [ErrSchemaURLConflict] if merging Resources from the opts results in a
|
||||
// schema URL conflict (see [Resource.Merge] for more information). It is up to
|
||||
// the caller to determine if this returned Resource should be used or not
|
||||
// based on these errors.
|
||||
func New(ctx context.Context, opts ...Option) (*Resource, error) {
|
||||
cfg := config{}
|
||||
for _, opt := range opts {
|
||||
|
@ -98,7 +110,7 @@ func (r *Resource) String() string {
|
|||
return r.attrs.Encoded(attribute.DefaultEncoder())
|
||||
}
|
||||
|
||||
// MarshalLog is the marshaling function used by the logging system to represent this exporter.
|
||||
// MarshalLog is the marshaling function used by the logging system to represent this Resource.
|
||||
func (r *Resource) MarshalLog() interface{} {
|
||||
return struct {
|
||||
Attributes attribute.Set
|
||||
|
@ -146,16 +158,29 @@ func (r *Resource) Equal(eq *Resource) bool {
|
|||
return r.Equivalent() == eq.Equivalent()
|
||||
}
|
||||
|
||||
// Merge creates a new resource by combining resource a and b.
|
||||
// Merge creates a new [Resource] by merging a and b.
|
||||
//
|
||||
// If there are common keys between resource a and b, then the value
|
||||
// from resource b will overwrite the value from resource a, even
|
||||
// if resource b's value is empty.
|
||||
// If there are common keys between a and b, then the value from b will
|
||||
// overwrite the value from a, even if b's value is empty.
|
||||
//
|
||||
// The SchemaURL of the resources will be merged according to the spec rules:
|
||||
// https://github.com/open-telemetry/opentelemetry-specification/blob/v1.20.0/specification/resource/sdk.md#merge
|
||||
// If the resources have different non-empty schemaURL an empty resource and an error
|
||||
// will be returned.
|
||||
// The SchemaURL of the resources will be merged according to the
|
||||
// [OpenTelemetry specification rules]:
|
||||
//
|
||||
// - If a's schema URL is empty then the returned Resource's schema URL will
|
||||
// be set to the schema URL of b,
|
||||
// - Else if b's schema URL is empty then the returned Resource's schema URL
|
||||
// will be set to the schema URL of a,
|
||||
// - Else if the schema URLs of a and b are the same then that will be the
|
||||
// schema URL of the returned Resource,
|
||||
// - Else this is a merging error. If the resources have different,
|
||||
// non-empty, schema URLs an error containing [ErrSchemaURLConflict] will
|
||||
// be returned with the merged Resource. The merged Resource will have an
|
||||
// empty schema URL. It may be the case that some unintended attributes
|
||||
// have been overwritten or old semantic conventions persisted in the
|
||||
// returned Resource. It is up to the caller to determine if this returned
|
||||
// Resource should be used or not.
|
||||
//
|
||||
// [OpenTelemetry specification rules]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.20.0/specification/resource/sdk.md#merge
|
||||
func Merge(a, b *Resource) (*Resource, error) {
|
||||
if a == nil && b == nil {
|
||||
return Empty(), nil
|
||||
|
@ -167,19 +192,6 @@ func Merge(a, b *Resource) (*Resource, error) {
|
|||
return a, nil
|
||||
}
|
||||
|
||||
// Merge the schema URL.
|
||||
var schemaURL string
|
||||
switch true {
|
||||
case a.schemaURL == "":
|
||||
schemaURL = b.schemaURL
|
||||
case b.schemaURL == "":
|
||||
schemaURL = a.schemaURL
|
||||
case a.schemaURL == b.schemaURL:
|
||||
schemaURL = a.schemaURL
|
||||
default:
|
||||
return Empty(), errMergeConflictSchemaURL
|
||||
}
|
||||
|
||||
// Note: 'b' attributes will overwrite 'a' with last-value-wins in attribute.Key()
|
||||
// Meaning this is equivalent to: append(a.Attributes(), b.Attributes()...)
|
||||
mi := attribute.NewMergeIterator(b.Set(), a.Set())
|
||||
|
@ -187,8 +199,23 @@ func Merge(a, b *Resource) (*Resource, error) {
|
|||
for mi.Next() {
|
||||
combine = append(combine, mi.Attribute())
|
||||
}
|
||||
merged := NewWithAttributes(schemaURL, combine...)
|
||||
return merged, nil
|
||||
|
||||
switch {
|
||||
case a.schemaURL == "":
|
||||
return NewWithAttributes(b.schemaURL, combine...), nil
|
||||
case b.schemaURL == "":
|
||||
return NewWithAttributes(a.schemaURL, combine...), nil
|
||||
case a.schemaURL == b.schemaURL:
|
||||
return NewWithAttributes(a.schemaURL, combine...), nil
|
||||
}
|
||||
// Return the merged resource with an appropriate error. It is up to
|
||||
// the user to decide if the returned resource can be used or not.
|
||||
return NewSchemaless(combine...), fmt.Errorf(
|
||||
"%w: %s and %s",
|
||||
ErrSchemaURLConflict,
|
||||
a.schemaURL,
|
||||
b.schemaURL,
|
||||
)
|
||||
}
|
||||
|
||||
// Empty returns an instance of Resource with no attributes. It is
|
||||
|
|
|
@ -406,7 +406,7 @@ func (bsp *batchSpanProcessor) enqueueDrop(ctx context.Context, sd ReadOnlySpan)
|
|||
return false
|
||||
}
|
||||
|
||||
// MarshalLog is the marshaling function used by the logging system to represent this exporter.
|
||||
// MarshalLog is the marshaling function used by the logging system to represent this Span Processor.
|
||||
func (bsp *batchSpanProcessor) MarshalLog() interface{} {
|
||||
return struct {
|
||||
Type string
|
||||
|
|
|
@ -55,7 +55,7 @@ type tracerProviderConfig struct {
|
|||
resource *resource.Resource
|
||||
}
|
||||
|
||||
// MarshalLog is the marshaling function used by the logging system to represent this exporter.
|
||||
// MarshalLog is the marshaling function used by the logging system to represent this Provider.
|
||||
func (cfg tracerProviderConfig) MarshalLog() interface{} {
|
||||
return struct {
|
||||
SpanProcessors []SpanProcessor
|
||||
|
|
|
@ -30,7 +30,7 @@ import (
|
|||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
"go.opentelemetry.io/otel/sdk/internal"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"go.opentelemetry.io/otel/trace/embedded"
|
||||
)
|
||||
|
@ -208,6 +208,16 @@ func (s *recordingSpan) SetStatus(code codes.Code, description string) {
|
|||
s.status = status
|
||||
}
|
||||
|
||||
// ensureAttributesCapacity inlines functionality from slices.Grow
|
||||
// so that we can avoid needing to import golang.org/x/exp for go1.20.
|
||||
// Once support for go1.20 is dropped, we can use slices.Grow available since go1.21 instead.
|
||||
// Tracking issue: https://github.com/open-telemetry/opentelemetry-go/issues/4819.
|
||||
func (s *recordingSpan) ensureAttributesCapacity(minCapacity int) {
|
||||
if n := minCapacity - cap(s.attributes); n > 0 {
|
||||
s.attributes = append(s.attributes[:cap(s.attributes)], make([]attribute.KeyValue, n)...)[:len(s.attributes)]
|
||||
}
|
||||
}
|
||||
|
||||
// SetAttributes sets attributes of this span.
|
||||
//
|
||||
// If a key from attributes already exists the value associated with that key
|
||||
|
@ -242,6 +252,7 @@ func (s *recordingSpan) SetAttributes(attributes ...attribute.KeyValue) {
|
|||
|
||||
// Otherwise, add without deduplication. When attributes are read they
|
||||
// will be deduplicated, optimizing the operation.
|
||||
s.ensureAttributesCapacity(len(s.attributes) + len(attributes))
|
||||
for _, a := range attributes {
|
||||
if !a.Valid() {
|
||||
// Drop all invalid attributes.
|
||||
|
@ -277,6 +288,12 @@ func (s *recordingSpan) addOverCapAttrs(limit int, attrs []attribute.KeyValue) {
|
|||
|
||||
// Now that s.attributes is deduplicated, adding unique attributes up to
|
||||
// the capacity of s will not over allocate s.attributes.
|
||||
if sum := len(attrs) + len(s.attributes); sum < limit {
|
||||
// After support for go1.20 is dropped, simplify if-else to min(sum, limit).
|
||||
s.ensureAttributesCapacity(sum)
|
||||
} else {
|
||||
s.ensureAttributesCapacity(limit)
|
||||
}
|
||||
for _, a := range attrs {
|
||||
if !a.Valid() {
|
||||
// Drop all invalid attributes.
|
||||
|
|
|
@ -16,5 +16,5 @@ package sdk // import "go.opentelemetry.io/otel/sdk"
|
|||
|
||||
// Version is the current release version of the OpenTelemetry SDK in use.
|
||||
func Version() string {
|
||||
return "1.20.0"
|
||||
return "1.24.0"
|
||||
}
|
||||
|
|
|
@ -15,6 +15,6 @@
|
|||
// Package semconv implements OpenTelemetry semantic conventions.
|
||||
//
|
||||
// OpenTelemetry semantic conventions are agreed standardized naming
|
||||
// patterns for OpenTelemetry things. This package represents the conventions
|
||||
// as of the v1.21.0 version of the OpenTelemetry specification.
|
||||
// patterns for OpenTelemetry things. This package represents the v1.21.0
|
||||
// version of the OpenTelemetry semantic conventions.
|
||||
package semconv // import "go.opentelemetry.io/otel/semconv/v1.21.0"
|
||||
|
|
4398
vendor/go.opentelemetry.io/otel/semconv/v1.24.0/attribute_group.go
generated
vendored
Normal file
4398
vendor/go.opentelemetry.io/otel/semconv/v1.24.0/attribute_group.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,20 @@
|
|||
// Copyright The OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package semconv implements OpenTelemetry semantic conventions.
|
||||
//
|
||||
// OpenTelemetry semantic conventions are agreed standardized naming
|
||||
// patterns for OpenTelemetry things. This package represents the v1.24.0
|
||||
// version of the OpenTelemetry semantic conventions.
|
||||
package semconv // import "go.opentelemetry.io/otel/semconv/v1.24.0"
|
|
@ -0,0 +1,211 @@
|
|||
// Copyright The OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated from semantic convention specification. DO NOT EDIT.
|
||||
|
||||
package semconv // import "go.opentelemetry.io/otel/semconv/v1.24.0"
|
||||
|
||||
import "go.opentelemetry.io/otel/attribute"
|
||||
|
||||
// This event represents an occurrence of a lifecycle transition on the iOS
|
||||
// platform.
|
||||
const (
|
||||
// IosStateKey is the attribute Key conforming to the "ios.state" semantic
|
||||
// conventions. It represents the this attribute represents the state the
|
||||
// application has transitioned into at the occurrence of the event.
|
||||
//
|
||||
// Type: Enum
|
||||
// RequirementLevel: Required
|
||||
// Stability: experimental
|
||||
// Note: The iOS lifecycle states are defined in the [UIApplicationDelegate
|
||||
// documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902),
|
||||
// and from which the `OS terminology` column values are derived.
|
||||
IosStateKey = attribute.Key("ios.state")
|
||||
)
|
||||
|
||||
var (
|
||||
// The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`
|
||||
IosStateActive = IosStateKey.String("active")
|
||||
// The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`
|
||||
IosStateInactive = IosStateKey.String("inactive")
|
||||
// The app is now in the background. This value is associated with UIKit notification `applicationDidEnterBackground`
|
||||
IosStateBackground = IosStateKey.String("background")
|
||||
// The app is now in the foreground. This value is associated with UIKit notification `applicationWillEnterForeground`
|
||||
IosStateForeground = IosStateKey.String("foreground")
|
||||
// The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`
|
||||
IosStateTerminate = IosStateKey.String("terminate")
|
||||
)
|
||||
|
||||
// This event represents an occurrence of a lifecycle transition on the Android
|
||||
// platform.
|
||||
const (
|
||||
// AndroidStateKey is the attribute Key conforming to the "android.state"
|
||||
// semantic conventions. It represents the this attribute represents the
|
||||
// state the application has transitioned into at the occurrence of the
|
||||
// event.
|
||||
//
|
||||
// Type: Enum
|
||||
// RequirementLevel: Required
|
||||
// Stability: experimental
|
||||
// Note: The Android lifecycle states are defined in [Activity lifecycle
|
||||
// callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc),
|
||||
// and from which the `OS identifiers` are derived.
|
||||
AndroidStateKey = attribute.Key("android.state")
|
||||
)
|
||||
|
||||
var (
|
||||
// Any time before Activity.onResume() or, if the app has no Activity, Context.startService() has been called in the app for the first time
|
||||
AndroidStateCreated = AndroidStateKey.String("created")
|
||||
// Any time after Activity.onPause() or, if the app has no Activity, Context.stopService() has been called when the app was in the foreground state
|
||||
AndroidStateBackground = AndroidStateKey.String("background")
|
||||
// Any time after Activity.onResume() or, if the app has no Activity, Context.startService() has been called when the app was in either the created or background states
|
||||
AndroidStateForeground = AndroidStateKey.String("foreground")
|
||||
)
|
||||
|
||||
// This semantic convention defines the attributes used to represent a feature
|
||||
// flag evaluation as an event.
|
||||
const (
|
||||
// FeatureFlagKeyKey is the attribute Key conforming to the
|
||||
// "feature_flag.key" semantic conventions. It represents the unique
|
||||
// identifier of the feature flag.
|
||||
//
|
||||
// Type: string
|
||||
// RequirementLevel: Required
|
||||
// Stability: experimental
|
||||
// Examples: 'logo-color'
|
||||
FeatureFlagKeyKey = attribute.Key("feature_flag.key")
|
||||
|
||||
// FeatureFlagProviderNameKey is the attribute Key conforming to the
|
||||
// "feature_flag.provider_name" semantic conventions. It represents the
|
||||
// name of the service provider that performs the flag evaluation.
|
||||
//
|
||||
// Type: string
|
||||
// RequirementLevel: Recommended
|
||||
// Stability: experimental
|
||||
// Examples: 'Flag Manager'
|
||||
FeatureFlagProviderNameKey = attribute.Key("feature_flag.provider_name")
|
||||
|
||||
// FeatureFlagVariantKey is the attribute Key conforming to the
|
||||
// "feature_flag.variant" semantic conventions. It represents the sHOULD be
|
||||
// a semantic identifier for a value. If one is unavailable, a stringified
|
||||
// version of the value can be used.
|
||||
//
|
||||
// Type: string
|
||||
// RequirementLevel: Recommended
|
||||
// Stability: experimental
|
||||
// Examples: 'red', 'true', 'on'
|
||||
// Note: A semantic identifier, commonly referred to as a variant, provides
|
||||
// a means
|
||||
// for referring to a value without including the value itself. This can
|
||||
// provide additional context for understanding the meaning behind a value.
|
||||
// For example, the variant `red` maybe be used for the value `#c05543`.
|
||||
//
|
||||
// A stringified version of the value can be used in situations where a
|
||||
// semantic identifier is unavailable. String representation of the value
|
||||
// should be determined by the implementer.
|
||||
FeatureFlagVariantKey = attribute.Key("feature_flag.variant")
|
||||
)
|
||||
|
||||
// FeatureFlagKey returns an attribute KeyValue conforming to the
|
||||
// "feature_flag.key" semantic conventions. It represents the unique identifier
|
||||
// of the feature flag.
|
||||
func FeatureFlagKey(val string) attribute.KeyValue {
|
||||
return FeatureFlagKeyKey.String(val)
|
||||
}
|
||||
|
||||
// FeatureFlagProviderName returns an attribute KeyValue conforming to the
|
||||
// "feature_flag.provider_name" semantic conventions. It represents the name of
|
||||
// the service provider that performs the flag evaluation.
|
||||
func FeatureFlagProviderName(val string) attribute.KeyValue {
|
||||
return FeatureFlagProviderNameKey.String(val)
|
||||
}
|
||||
|
||||
// FeatureFlagVariant returns an attribute KeyValue conforming to the
|
||||
// "feature_flag.variant" semantic conventions. It represents the sHOULD be a
|
||||
// semantic identifier for a value. If one is unavailable, a stringified
|
||||
// version of the value can be used.
|
||||
func FeatureFlagVariant(val string) attribute.KeyValue {
|
||||
return FeatureFlagVariantKey.String(val)
|
||||
}
|
||||
|
||||
// RPC received/sent message.
|
||||
const (
|
||||
// MessageCompressedSizeKey is the attribute Key conforming to the
|
||||
// "message.compressed_size" semantic conventions. It represents the
|
||||
// compressed size of the message in bytes.
|
||||
//
|
||||
// Type: int
|
||||
// RequirementLevel: Optional
|
||||
// Stability: experimental
|
||||
MessageCompressedSizeKey = attribute.Key("message.compressed_size")
|
||||
|
||||
// MessageIDKey is the attribute Key conforming to the "message.id"
|
||||
// semantic conventions. It represents the mUST be calculated as two
|
||||
// different counters starting from `1` one for sent messages and one for
|
||||
// received message.
|
||||
//
|
||||
// Type: int
|
||||
// RequirementLevel: Optional
|
||||
// Stability: experimental
|
||||
// Note: This way we guarantee that the values will be consistent between
|
||||
// different implementations.
|
||||
MessageIDKey = attribute.Key("message.id")
|
||||
|
||||
// MessageTypeKey is the attribute Key conforming to the "message.type"
|
||||
// semantic conventions. It represents the whether this is a received or
|
||||
// sent message.
|
||||
//
|
||||
// Type: Enum
|
||||
// RequirementLevel: Optional
|
||||
// Stability: experimental
|
||||
MessageTypeKey = attribute.Key("message.type")
|
||||
|
||||
// MessageUncompressedSizeKey is the attribute Key conforming to the
|
||||
// "message.uncompressed_size" semantic conventions. It represents the
|
||||
// uncompressed size of the message in bytes.
|
||||
//
|
||||
// Type: int
|
||||
// RequirementLevel: Optional
|
||||
// Stability: experimental
|
||||
MessageUncompressedSizeKey = attribute.Key("message.uncompressed_size")
|
||||
)
|
||||
|
||||
var (
|
||||
// sent
|
||||
MessageTypeSent = MessageTypeKey.String("SENT")
|
||||
// received
|
||||
MessageTypeReceived = MessageTypeKey.String("RECEIVED")
|
||||
)
|
||||
|
||||
// MessageCompressedSize returns an attribute KeyValue conforming to the
|
||||
// "message.compressed_size" semantic conventions. It represents the compressed
|
||||
// size of the message in bytes.
|
||||
func MessageCompressedSize(val int) attribute.KeyValue {
|
||||
return MessageCompressedSizeKey.Int(val)
|
||||
}
|
||||
|
||||
// MessageID returns an attribute KeyValue conforming to the "message.id"
|
||||
// semantic conventions. It represents the mUST be calculated as two different
|
||||
// counters starting from `1` one for sent messages and one for received
|
||||
// message.
|
||||
func MessageID(val int) attribute.KeyValue {
|
||||
return MessageIDKey.Int(val)
|
||||
}
|
||||
|
||||
// MessageUncompressedSize returns an attribute KeyValue conforming to the
|
||||
// "message.uncompressed_size" semantic conventions. It represents the
|
||||
// uncompressed size of the message in bytes.
|
||||
func MessageUncompressedSize(val int) attribute.KeyValue {
|
||||
return MessageUncompressedSizeKey.Int(val)
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright The OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package semconv // import "go.opentelemetry.io/otel/semconv/v1.24.0"
|
||||
|
||||
const (
|
||||
// ExceptionEventName is the name of the Span event representing an exception.
|
||||
ExceptionEventName = "exception"
|
||||
)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,20 @@
|
|||
// Copyright The OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package semconv // import "go.opentelemetry.io/otel/semconv/v1.24.0"
|
||||
|
||||
// SchemaURL is the schema URL that matches the version of the semantic conventions
|
||||
// that this package defines. Semconv packages starting from v1.4.0 must declare
|
||||
// non-empty schema URL in the form https://opentelemetry.io/schemas/<version>
|
||||
const SchemaURL = "https://opentelemetry.io/schemas/1.24.0"
|
File diff suppressed because it is too large
Load Diff
|
@ -17,20 +17,14 @@ package trace // import "go.opentelemetry.io/otel/trace"
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
maxListMembers = 32
|
||||
|
||||
listDelimiter = ","
|
||||
|
||||
// based on the W3C Trace Context specification, see
|
||||
// https://www.w3.org/TR/trace-context-1/#tracestate-header
|
||||
noTenantKeyFormat = `[a-z][_0-9a-z\-\*\/]*`
|
||||
withTenantKeyFormat = `[a-z0-9][_0-9a-z\-\*\/]*@[a-z][_0-9a-z\-\*\/]*`
|
||||
valueFormat = `[\x20-\x2b\x2d-\x3c\x3e-\x7e]*[\x21-\x2b\x2d-\x3c\x3e-\x7e]`
|
||||
listDelimiters = ","
|
||||
memberDelimiter = "="
|
||||
|
||||
errInvalidKey errorConst = "invalid tracestate key"
|
||||
errInvalidValue errorConst = "invalid tracestate value"
|
||||
|
@ -39,43 +33,128 @@ const (
|
|||
errDuplicate errorConst = "duplicate list-member in tracestate"
|
||||
)
|
||||
|
||||
var (
|
||||
noTenantKeyRe = regexp.MustCompile(`^` + noTenantKeyFormat + `$`)
|
||||
withTenantKeyRe = regexp.MustCompile(`^` + withTenantKeyFormat + `$`)
|
||||
valueRe = regexp.MustCompile(`^` + valueFormat + `$`)
|
||||
memberRe = regexp.MustCompile(`^\s*((?:` + noTenantKeyFormat + `)|(?:` + withTenantKeyFormat + `))=(` + valueFormat + `)\s*$`)
|
||||
)
|
||||
|
||||
type member struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
// according to (chr = %x20 / (nblk-char = %x21-2B / %x2D-3C / %x3E-7E) )
|
||||
// means (chr = %x20-2B / %x2D-3C / %x3E-7E) .
|
||||
func checkValueChar(v byte) bool {
|
||||
return v >= '\x20' && v <= '\x7e' && v != '\x2c' && v != '\x3d'
|
||||
}
|
||||
|
||||
// according to (nblk-chr = %x21-2B / %x2D-3C / %x3E-7E) .
|
||||
func checkValueLast(v byte) bool {
|
||||
return v >= '\x21' && v <= '\x7e' && v != '\x2c' && v != '\x3d'
|
||||
}
|
||||
|
||||
// based on the W3C Trace Context specification
|
||||
//
|
||||
// value = (0*255(chr)) nblk-chr
|
||||
// nblk-chr = %x21-2B / %x2D-3C / %x3E-7E
|
||||
// chr = %x20 / nblk-chr
|
||||
//
|
||||
// see https://www.w3.org/TR/trace-context-1/#value
|
||||
func checkValue(val string) bool {
|
||||
n := len(val)
|
||||
if n == 0 || n > 256 {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < n-1; i++ {
|
||||
if !checkValueChar(val[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return checkValueLast(val[n-1])
|
||||
}
|
||||
|
||||
func checkKeyRemain(key string) bool {
|
||||
// ( lcalpha / DIGIT / "_" / "-"/ "*" / "/" )
|
||||
for _, v := range key {
|
||||
if isAlphaNum(byte(v)) {
|
||||
continue
|
||||
}
|
||||
switch v {
|
||||
case '_', '-', '*', '/':
|
||||
continue
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// according to
|
||||
//
|
||||
// simple-key = lcalpha (0*255( lcalpha / DIGIT / "_" / "-"/ "*" / "/" ))
|
||||
// system-id = lcalpha (0*13( lcalpha / DIGIT / "_" / "-"/ "*" / "/" ))
|
||||
//
|
||||
// param n is remain part length, should be 255 in simple-key or 13 in system-id.
|
||||
func checkKeyPart(key string, n int) bool {
|
||||
if len(key) == 0 {
|
||||
return false
|
||||
}
|
||||
first := key[0] // key's first char
|
||||
ret := len(key[1:]) <= n
|
||||
ret = ret && first >= 'a' && first <= 'z'
|
||||
return ret && checkKeyRemain(key[1:])
|
||||
}
|
||||
|
||||
func isAlphaNum(c byte) bool {
|
||||
if c >= 'a' && c <= 'z' {
|
||||
return true
|
||||
}
|
||||
return c >= '0' && c <= '9'
|
||||
}
|
||||
|
||||
// according to
|
||||
//
|
||||
// tenant-id = ( lcalpha / DIGIT ) 0*240( lcalpha / DIGIT / "_" / "-"/ "*" / "/" )
|
||||
//
|
||||
// param n is remain part length, should be 240 exactly.
|
||||
func checkKeyTenant(key string, n int) bool {
|
||||
if len(key) == 0 {
|
||||
return false
|
||||
}
|
||||
return isAlphaNum(key[0]) && len(key[1:]) <= n && checkKeyRemain(key[1:])
|
||||
}
|
||||
|
||||
// based on the W3C Trace Context specification
|
||||
//
|
||||
// key = simple-key / multi-tenant-key
|
||||
// simple-key = lcalpha (0*255( lcalpha / DIGIT / "_" / "-"/ "*" / "/" ))
|
||||
// multi-tenant-key = tenant-id "@" system-id
|
||||
// tenant-id = ( lcalpha / DIGIT ) (0*240( lcalpha / DIGIT / "_" / "-"/ "*" / "/" ))
|
||||
// system-id = lcalpha (0*13( lcalpha / DIGIT / "_" / "-"/ "*" / "/" ))
|
||||
// lcalpha = %x61-7A ; a-z
|
||||
//
|
||||
// see https://www.w3.org/TR/trace-context-1/#tracestate-header.
|
||||
func checkKey(key string) bool {
|
||||
tenant, system, ok := strings.Cut(key, "@")
|
||||
if !ok {
|
||||
return checkKeyPart(key, 255)
|
||||
}
|
||||
return checkKeyTenant(tenant, 240) && checkKeyPart(system, 13)
|
||||
}
|
||||
|
||||
func newMember(key, value string) (member, error) {
|
||||
if len(key) > 256 {
|
||||
return member{}, fmt.Errorf("%w: %s", errInvalidKey, key)
|
||||
if !checkKey(key) {
|
||||
return member{}, errInvalidKey
|
||||
}
|
||||
if !noTenantKeyRe.MatchString(key) {
|
||||
if !withTenantKeyRe.MatchString(key) {
|
||||
return member{}, fmt.Errorf("%w: %s", errInvalidKey, key)
|
||||
}
|
||||
atIndex := strings.LastIndex(key, "@")
|
||||
if atIndex > 241 || len(key)-1-atIndex > 14 {
|
||||
return member{}, fmt.Errorf("%w: %s", errInvalidKey, key)
|
||||
}
|
||||
}
|
||||
if len(value) > 256 || !valueRe.MatchString(value) {
|
||||
return member{}, fmt.Errorf("%w: %s", errInvalidValue, value)
|
||||
if !checkValue(value) {
|
||||
return member{}, errInvalidValue
|
||||
}
|
||||
return member{Key: key, Value: value}, nil
|
||||
}
|
||||
|
||||
func parseMember(m string) (member, error) {
|
||||
matches := memberRe.FindStringSubmatch(m)
|
||||
if len(matches) != 3 {
|
||||
key, val, ok := strings.Cut(m, memberDelimiter)
|
||||
if !ok {
|
||||
return member{}, fmt.Errorf("%w: %s", errInvalidMember, m)
|
||||
}
|
||||
result, e := newMember(matches[1], matches[2])
|
||||
key = strings.TrimLeft(key, " \t")
|
||||
val = strings.TrimRight(val, " \t")
|
||||
result, e := newMember(key, val)
|
||||
if e != nil {
|
||||
return member{}, fmt.Errorf("%w: %s", errInvalidMember, m)
|
||||
}
|
||||
|
@ -85,7 +164,7 @@ func parseMember(m string) (member, error) {
|
|||
// String encodes member into a string compliant with the W3C Trace Context
|
||||
// specification.
|
||||
func (m member) String() string {
|
||||
return fmt.Sprintf("%s=%s", m.Key, m.Value)
|
||||
return m.Key + "=" + m.Value
|
||||
}
|
||||
|
||||
// TraceState provides additional vendor-specific trace identification
|
||||
|
@ -109,8 +188,8 @@ var _ json.Marshaler = TraceState{}
|
|||
// ParseTraceState attempts to decode a TraceState from the passed
|
||||
// string. It returns an error if the input is invalid according to the W3C
|
||||
// Trace Context specification.
|
||||
func ParseTraceState(tracestate string) (TraceState, error) {
|
||||
if tracestate == "" {
|
||||
func ParseTraceState(ts string) (TraceState, error) {
|
||||
if ts == "" {
|
||||
return TraceState{}, nil
|
||||
}
|
||||
|
||||
|
@ -120,7 +199,9 @@ func ParseTraceState(tracestate string) (TraceState, error) {
|
|||
|
||||
var members []member
|
||||
found := make(map[string]struct{})
|
||||
for _, memberStr := range strings.Split(tracestate, listDelimiter) {
|
||||
for ts != "" {
|
||||
var memberStr string
|
||||
memberStr, ts, _ = strings.Cut(ts, listDelimiters)
|
||||
if len(memberStr) == 0 {
|
||||
continue
|
||||
}
|
||||
|
@ -153,11 +234,29 @@ func (ts TraceState) MarshalJSON() ([]byte, error) {
|
|||
// Trace Context specification. The returned string will be invalid if the
|
||||
// TraceState contains any invalid members.
|
||||
func (ts TraceState) String() string {
|
||||
members := make([]string, len(ts.list))
|
||||
for i, m := range ts.list {
|
||||
members[i] = m.String()
|
||||
if len(ts.list) == 0 {
|
||||
return ""
|
||||
}
|
||||
return strings.Join(members, listDelimiter)
|
||||
var n int
|
||||
n += len(ts.list) // member delimiters: '='
|
||||
n += len(ts.list) - 1 // list delimiters: ','
|
||||
for _, mem := range ts.list {
|
||||
n += len(mem.Key)
|
||||
n += len(mem.Value)
|
||||
}
|
||||
|
||||
var sb strings.Builder
|
||||
sb.Grow(n)
|
||||
_, _ = sb.WriteString(ts.list[0].Key)
|
||||
_ = sb.WriteByte('=')
|
||||
_, _ = sb.WriteString(ts.list[0].Value)
|
||||
for i := 1; i < len(ts.list); i++ {
|
||||
_ = sb.WriteByte(listDelimiters[0])
|
||||
_, _ = sb.WriteString(ts.list[i].Key)
|
||||
_ = sb.WriteByte('=')
|
||||
_, _ = sb.WriteString(ts.list[i].Value)
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// Get returns the value paired with key from the corresponding TraceState
|
||||
|
@ -189,15 +288,25 @@ func (ts TraceState) Insert(key, value string) (TraceState, error) {
|
|||
if err != nil {
|
||||
return ts, err
|
||||
}
|
||||
|
||||
cTS := ts.Delete(key)
|
||||
if cTS.Len()+1 <= maxListMembers {
|
||||
cTS.list = append(cTS.list, member{})
|
||||
n := len(ts.list)
|
||||
found := n
|
||||
for i := range ts.list {
|
||||
if ts.list[i].Key == key {
|
||||
found = i
|
||||
}
|
||||
}
|
||||
cTS := TraceState{}
|
||||
if found == n && n < maxListMembers {
|
||||
cTS.list = make([]member, n+1)
|
||||
} else {
|
||||
cTS.list = make([]member, n)
|
||||
}
|
||||
// When the number of members exceeds capacity, drop the "right-most".
|
||||
copy(cTS.list[1:], cTS.list)
|
||||
cTS.list[0] = m
|
||||
|
||||
// When the number of members exceeds capacity, drop the "right-most".
|
||||
copy(cTS.list[1:], ts.list[0:found])
|
||||
if found < n {
|
||||
copy(cTS.list[1+found:], ts.list[found+1:])
|
||||
}
|
||||
return cTS, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -16,5 +16,5 @@ package otel // import "go.opentelemetry.io/otel"
|
|||
|
||||
// Version is the current release version of OpenTelemetry in use.
|
||||
func Version() string {
|
||||
return "1.20.0"
|
||||
return "1.24.0"
|
||||
}
|
||||
|
|
|
@ -14,20 +14,25 @@
|
|||
|
||||
module-sets:
|
||||
stable-v1:
|
||||
version: v1.20.0
|
||||
version: v1.24.0
|
||||
modules:
|
||||
- go.opentelemetry.io/otel
|
||||
- go.opentelemetry.io/otel/bridge/opencensus
|
||||
- go.opentelemetry.io/otel/bridge/opencensus/test
|
||||
- go.opentelemetry.io/otel/bridge/opentracing
|
||||
- go.opentelemetry.io/otel/bridge/opentracing/test
|
||||
- go.opentelemetry.io/otel/example/dice
|
||||
- go.opentelemetry.io/otel/example/fib
|
||||
- go.opentelemetry.io/otel/example/namedtracer
|
||||
- go.opentelemetry.io/otel/example/opencensus
|
||||
- go.opentelemetry.io/otel/example/otel-collector
|
||||
- go.opentelemetry.io/otel/example/passthrough
|
||||
- go.opentelemetry.io/otel/example/zipkin
|
||||
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc
|
||||
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp
|
||||
- go.opentelemetry.io/otel/exporters/otlp/otlptrace
|
||||
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc
|
||||
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp
|
||||
- go.opentelemetry.io/otel/exporters/stdout/stdoutmetric
|
||||
- go.opentelemetry.io/otel/exporters/stdout/stdouttrace
|
||||
- go.opentelemetry.io/otel/exporters/zipkin
|
||||
- go.opentelemetry.io/otel/metric
|
||||
|
@ -35,18 +40,14 @@ module-sets:
|
|||
- go.opentelemetry.io/otel/sdk/metric
|
||||
- go.opentelemetry.io/otel/trace
|
||||
experimental-metrics:
|
||||
version: v0.43.0
|
||||
version: v0.46.0
|
||||
modules:
|
||||
- go.opentelemetry.io/otel/bridge/opencensus
|
||||
- go.opentelemetry.io/otel/bridge/opencensus/test
|
||||
- go.opentelemetry.io/otel/example/opencensus
|
||||
- go.opentelemetry.io/otel/example/prometheus
|
||||
- go.opentelemetry.io/otel/example/view
|
||||
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric
|
||||
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc
|
||||
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp
|
||||
- go.opentelemetry.io/otel/exporters/prometheus
|
||||
- go.opentelemetry.io/otel/exporters/stdout/stdoutmetric
|
||||
experimental-logs:
|
||||
version: v0.0.1-alpha
|
||||
modules:
|
||||
- go.opentelemetry.io/otel/log
|
||||
experimental-schema:
|
||||
version: v0.0.7
|
||||
modules:
|
||||
|
|
|
@ -912,7 +912,7 @@ go.mongodb.org/mongo-driver/bson/bsonrw
|
|||
go.mongodb.org/mongo-driver/bson/bsontype
|
||||
go.mongodb.org/mongo-driver/bson/primitive
|
||||
go.mongodb.org/mongo-driver/x/bsonx/bsoncore
|
||||
# go.opentelemetry.io/otel v1.20.0
|
||||
# go.opentelemetry.io/otel v1.24.0
|
||||
## explicit; go 1.20
|
||||
go.opentelemetry.io/otel
|
||||
go.opentelemetry.io/otel/attribute
|
||||
|
@ -930,6 +930,7 @@ go.opentelemetry.io/otel/semconv/v1.12.0
|
|||
go.opentelemetry.io/otel/semconv/v1.20.0
|
||||
go.opentelemetry.io/otel/semconv/v1.20.0/httpconv
|
||||
go.opentelemetry.io/otel/semconv/v1.21.0
|
||||
go.opentelemetry.io/otel/semconv/v1.24.0
|
||||
go.opentelemetry.io/otel/semconv/v1.7.0
|
||||
# go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0
|
||||
## explicit; go 1.20
|
||||
|
@ -952,12 +953,12 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/retry
|
|||
# go.opentelemetry.io/otel/exporters/prometheus v0.43.0
|
||||
## explicit; go 1.20
|
||||
go.opentelemetry.io/otel/exporters/prometheus
|
||||
# go.opentelemetry.io/otel/metric v1.20.0
|
||||
# go.opentelemetry.io/otel/metric v1.24.0
|
||||
## explicit; go 1.20
|
||||
go.opentelemetry.io/otel/metric
|
||||
go.opentelemetry.io/otel/metric/embedded
|
||||
go.opentelemetry.io/otel/metric/noop
|
||||
# go.opentelemetry.io/otel/sdk v1.20.0
|
||||
# go.opentelemetry.io/otel/sdk v1.24.0
|
||||
## explicit; go 1.20
|
||||
go.opentelemetry.io/otel/sdk
|
||||
go.opentelemetry.io/otel/sdk/instrumentation
|
||||
|
@ -971,7 +972,7 @@ go.opentelemetry.io/otel/sdk/metric
|
|||
go.opentelemetry.io/otel/sdk/metric/internal
|
||||
go.opentelemetry.io/otel/sdk/metric/internal/aggregate
|
||||
go.opentelemetry.io/otel/sdk/metric/metricdata
|
||||
# go.opentelemetry.io/otel/trace v1.20.0
|
||||
# go.opentelemetry.io/otel/trace v1.24.0
|
||||
## explicit; go 1.20
|
||||
go.opentelemetry.io/otel/trace
|
||||
go.opentelemetry.io/otel/trace/embedded
|
||||
|
|
Loading…
Reference in New Issue