diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d3f0f601b3..d95a7d06aad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,23 +8,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] -### Added - -- Support Go 1.19. - Include compatibility testing and document support. (#3077) -- Upgrade go.opentelemetry.io/proto/otlp from v0.18.0 to v0.19.0 (#3107) -- Add an `Attribute` field to the `Scope` type in `go.opentelemetry.io/otel/sdk/instrumentation`. (#3131) -- Add the `WithScopeAttributes` `TracerOption` to the `go.opentelemetry.io/otel/trace` package. (#3131) -- Add the `WithScopeAttributes` `MeterOption` to the `go.opentelemetry.io/otel/metric` package. (#3132) - ### Changed -- Fix misidentification of OpenTelemetry `SpanKind` in OpenTracing bridge (`go.opentelemetry.io/otel/bridge/opentracing`). (#3096) -- The exponential histogram mapping functions have been updated with - exact upper-inclusive boundary support following the [corresponding - specification change](https://github.com/open-telemetry/opentelemetry-specification/pull/2633). (#2982) -- Attempting to start a span with a nil `context` will no longer cause a panic. (#3110) -- Export scope attributes for all exporters provided by `go.opentelemetry.io/otel/exporters/otlp/otlptrace`. (#3131) - The metric SDK in `go.opentelemetry.io/otel/sdk/metric` is completely refactored to comply with the OpenTelemetry specification. Please see the package documentation for how the new SDK is initialized and configured. (TBD) @@ -57,6 +42,22 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - The `"go.opentelemetry.io/otel/sdk/metric".NewAccumulator` function was removed, see `NewMeterProvider`in the new metric SDK. (TBD) - The deprecated `"go.opentelemetry.io/otel/sdk/metric".AtomicFieldOffsets` function was removed. (TBD) +## [1.10.0] - 2022-09-09 + +### Added + +- Support Go 1.19. (#3077) + Include compatibility testing and document support. (#3077) +- Support the OTLP ExportTracePartialSuccess response; these are passed to the registered error handler. (#3106) +- Upgrade go.opentelemetry.io/proto/otlp from v0.18.0 to v0.19.0 (#3107) + +### Changed + +- Fix misidentification of OpenTelemetry `SpanKind` in OpenTracing bridge (`go.opentelemetry.io/otel/bridge/opentracing`). (#3096) +- Attempting to start a span with a nil `context` will no longer cause a panic. (#3110) +- All exporters will be shutdown even if one reports an error (#3091) +- Ensure valid UTF-8 when truncating over-length attribute values. (#3156) + ## [1.9.0/0.0.3] - 2022-08-01 ### Added @@ -1940,7 +1941,8 @@ It contains api and sdk for trace and meter. - CircleCI build CI manifest files. - CODEOWNERS file to track owners of this project. -[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.9.0...HEAD +[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.10.0...HEAD +[1.10.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.10.0 [1.9.0/0.0.3]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.9.0 [1.8.0/0.31.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.8.0 [1.7.0/0.30.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.7.0 diff --git a/bridge/opencensus/go.mod b/bridge/opencensus/go.mod index 42c24593f9e..4faa85d3607 100644 --- a/bridge/opencensus/go.mod +++ b/bridge/opencensus/go.mod @@ -4,8 +4,8 @@ go 1.17 require ( go.opencensus.io v0.22.6-0.20201102222123-380f4078db9f - go.opentelemetry.io/otel v1.9.0 - go.opentelemetry.io/otel/trace v1.9.0 + go.opentelemetry.io/otel v1.10.0 + go.opentelemetry.io/otel/trace v1.10.0 ) require ( diff --git a/bridge/opencensus/opencensusmetric/go.mod b/bridge/opencensus/opencensusmetric/go.mod index 1f4a9cb153a..2c98a6e1371 100644 --- a/bridge/opencensus/opencensusmetric/go.mod +++ b/bridge/opencensus/opencensusmetric/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( go.opencensus.io v0.23.0 - go.opentelemetry.io/otel v1.9.0 + go.opentelemetry.io/otel v1.10.0 go.opentelemetry.io/otel/metric v0.0.0-00010101000000-000000000000 go.opentelemetry.io/otel/sdk/metric v0.0.0-00010101000000-000000000000 ) @@ -13,7 +13,7 @@ require ( github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect go.opentelemetry.io/otel/sdk v0.0.0-00010101000000-000000000000 // indirect - go.opentelemetry.io/otel/trace v1.9.0 // indirect + go.opentelemetry.io/otel/trace v1.10.0 // indirect golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 // indirect ) diff --git a/bridge/opencensus/test/go.mod b/bridge/opencensus/test/go.mod index 9a40bac93c6..66226d4b6c2 100644 --- a/bridge/opencensus/test/go.mod +++ b/bridge/opencensus/test/go.mod @@ -4,10 +4,10 @@ go 1.17 require ( go.opencensus.io v0.23.0 - go.opentelemetry.io/otel v1.9.0 + go.opentelemetry.io/otel v1.10.0 go.opentelemetry.io/otel/bridge/opencensus v0.31.0 - go.opentelemetry.io/otel/sdk v1.9.0 - go.opentelemetry.io/otel/trace v1.9.0 + go.opentelemetry.io/otel/sdk v1.10.0 + go.opentelemetry.io/otel/trace v1.10.0 ) require ( diff --git a/bridge/opentracing/go.mod b/bridge/opentracing/go.mod index 2dd7e3a935b..c49a89f8dd7 100644 --- a/bridge/opentracing/go.mod +++ b/bridge/opentracing/go.mod @@ -7,8 +7,8 @@ replace go.opentelemetry.io/otel => ../.. require ( github.com/opentracing/opentracing-go v1.2.0 github.com/stretchr/testify v1.7.2 - go.opentelemetry.io/otel v1.9.0 - go.opentelemetry.io/otel/trace v1.9.0 + go.opentelemetry.io/otel v1.10.0 + go.opentelemetry.io/otel/trace v1.10.0 ) require ( diff --git a/example/fib/go.mod b/example/fib/go.mod index 55ca603a603..be627a76236 100644 --- a/example/fib/go.mod +++ b/example/fib/go.mod @@ -3,10 +3,10 @@ module go.opentelemetry.io/otel/example/fib go 1.17 require ( - go.opentelemetry.io/otel v1.9.0 - go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.9.0 - go.opentelemetry.io/otel/sdk v1.9.0 - go.opentelemetry.io/otel/trace v1.9.0 + go.opentelemetry.io/otel v1.10.0 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.10.0 + go.opentelemetry.io/otel/sdk v1.10.0 + go.opentelemetry.io/otel/trace v1.10.0 ) require ( diff --git a/example/jaeger/go.mod b/example/jaeger/go.mod index 8e9f9ff0afc..15ea8347184 100644 --- a/example/jaeger/go.mod +++ b/example/jaeger/go.mod @@ -9,9 +9,9 @@ replace ( ) require ( - go.opentelemetry.io/otel v1.9.0 - go.opentelemetry.io/otel/exporters/jaeger v1.9.0 - go.opentelemetry.io/otel/sdk v1.9.0 + go.opentelemetry.io/otel v1.10.0 + go.opentelemetry.io/otel/exporters/jaeger v1.10.0 + go.opentelemetry.io/otel/sdk v1.10.0 ) require ( @@ -19,7 +19,7 @@ require ( github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/stretchr/objx v0.4.0 // indirect - go.opentelemetry.io/otel/trace v1.9.0 // indirect + go.opentelemetry.io/otel/trace v1.10.0 // indirect golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 // indirect ) diff --git a/example/namedtracer/go.mod b/example/namedtracer/go.mod index 4173fe1974a..41433bff5dd 100644 --- a/example/namedtracer/go.mod +++ b/example/namedtracer/go.mod @@ -9,10 +9,10 @@ replace ( require ( github.com/go-logr/stdr v1.2.2 - go.opentelemetry.io/otel v1.9.0 - go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.9.0 - go.opentelemetry.io/otel/sdk v1.9.0 - go.opentelemetry.io/otel/trace v1.9.0 + go.opentelemetry.io/otel v1.10.0 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.10.0 + go.opentelemetry.io/otel/sdk v1.10.0 + go.opentelemetry.io/otel/trace v1.10.0 ) require ( diff --git a/example/otel-collector/go.mod b/example/otel-collector/go.mod index ba2859c29a0..96b14906a70 100644 --- a/example/otel-collector/go.mod +++ b/example/otel-collector/go.mod @@ -8,10 +8,10 @@ replace ( ) require ( - go.opentelemetry.io/otel v1.9.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.9.0 - go.opentelemetry.io/otel/sdk v1.9.0 - go.opentelemetry.io/otel/trace v1.9.0 + go.opentelemetry.io/otel v1.10.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.10.0 + go.opentelemetry.io/otel/sdk v1.10.0 + go.opentelemetry.io/otel/trace v1.10.0 google.golang.org/grpc v1.46.2 ) @@ -21,8 +21,8 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.9.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.9.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.10.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.10.0 // indirect go.opentelemetry.io/proto/otlp v0.19.0 // indirect golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect diff --git a/example/passthrough/go.mod b/example/passthrough/go.mod index 5843a3bce83..41a68d3bd82 100644 --- a/example/passthrough/go.mod +++ b/example/passthrough/go.mod @@ -3,10 +3,10 @@ module go.opentelemetry.io/otel/example/passthrough go 1.17 require ( - go.opentelemetry.io/otel v1.9.0 - go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.9.0 - go.opentelemetry.io/otel/sdk v1.9.0 - go.opentelemetry.io/otel/trace v1.9.0 + go.opentelemetry.io/otel v1.10.0 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.10.0 + go.opentelemetry.io/otel/sdk v1.10.0 + go.opentelemetry.io/otel/trace v1.10.0 ) require ( diff --git a/example/prometheus/go.mod b/example/prometheus/go.mod index 211189ecaaa..441f03e5112 100644 --- a/example/prometheus/go.mod +++ b/example/prometheus/go.mod @@ -1,10 +1,10 @@ -module github.com/open-telemetry/opentelemetry-go/example/prometheus +module go.opentelemetry.io/otel/example/prometheus go 1.18 require ( github.com/prometheus/client_golang v1.13.0 - go.opentelemetry.io/otel v1.9.0 + go.opentelemetry.io/otel v1.10.0 go.opentelemetry.io/otel/exporters/prometheus v0.31.0 go.opentelemetry.io/otel/metric v0.31.0 go.opentelemetry.io/otel/sdk/metric v0.31.0 @@ -20,8 +20,8 @@ require ( github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect - go.opentelemetry.io/otel/sdk v1.8.0 // indirect - go.opentelemetry.io/otel/trace v1.9.0 // indirect + go.opentelemetry.io/otel/sdk v1.10.0 // indirect + go.opentelemetry.io/otel/trace v1.10.0 // indirect golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect google.golang.org/protobuf v1.28.1 // indirect ) diff --git a/example/zipkin/go.mod b/example/zipkin/go.mod index 5b02b99c85b..5650ba002f4 100644 --- a/example/zipkin/go.mod +++ b/example/zipkin/go.mod @@ -9,10 +9,10 @@ replace ( ) require ( - go.opentelemetry.io/otel v1.9.0 - go.opentelemetry.io/otel/exporters/zipkin v1.9.0 - go.opentelemetry.io/otel/sdk v1.9.0 - go.opentelemetry.io/otel/trace v1.9.0 + go.opentelemetry.io/otel v1.10.0 + go.opentelemetry.io/otel/exporters/zipkin v1.10.0 + go.opentelemetry.io/otel/sdk v1.10.0 + go.opentelemetry.io/otel/trace v1.10.0 ) require ( diff --git a/exporters/README.md b/exporters/README.md new file mode 100644 index 00000000000..0a8c16a07f0 --- /dev/null +++ b/exporters/README.md @@ -0,0 +1,22 @@ +# OpenTelemetry Exporters + +Once the OpenTelemetry SDK has created and processed telemetry, it needs to be exported. +This package contains exporters for this purpose. + +## Exporter Packages + +The following exporter packages are provided with the following OpenTelemetry signal support. + +| Exporter Package | Metrics | Traces | +| :-----------------------------------------------------------------------------: | :-----: | :----: | +| [go.opentelemetry.io/otel/exporters/jaeger](./jaeger) | | ✓ | +| [go.opentelemetry.io/otel/exporters/otlp/otlpmetric](./otlp/otlpmetric) | ✓ | | +| [go.opentelemetry.io/otel/exporters/otlp/otlptrace](./otlp/otlptrace) | | ✓ | +| [go.opentelemetry.io/otel/exporters/prometheus](./prometheus) | ✓ | | +| [go.opentelemetry.io/otel/exporters/stdout/stdoutmetric](./stdout/stdoutmetric) | ✓ | | +| [go.opentelemetry.io/otel/exporters/stdout/stdouttrace](./stdout/stdouttrace) | | ✓ | +| [go.opentelemetry.io/otel/exporters/zipkin](./zipkin) | | ✓ | + +See the [OpenTelemetry registry] for 3rd-part exporters compatible with this project. + +[OpenTelemetry registry]: https://opentelemetry.io/registry/?language=go&component=exporter diff --git a/exporters/jaeger/go.mod b/exporters/jaeger/go.mod index f92b4f75019..c16db4e58e4 100644 --- a/exporters/jaeger/go.mod +++ b/exporters/jaeger/go.mod @@ -5,9 +5,9 @@ go 1.17 require ( github.com/google/go-cmp v0.5.8 github.com/stretchr/testify v1.7.1 - go.opentelemetry.io/otel v1.9.0 - go.opentelemetry.io/otel/sdk v1.9.0 - go.opentelemetry.io/otel/trace v1.9.0 + go.opentelemetry.io/otel v1.10.0 + go.opentelemetry.io/otel/sdk v1.10.0 + go.opentelemetry.io/otel/trace v1.10.0 ) require ( diff --git a/exporters/otlp/internal/partialsuccess.go b/exporters/otlp/internal/partialsuccess.go new file mode 100644 index 00000000000..7994706ab51 --- /dev/null +++ b/exporters/otlp/internal/partialsuccess.go @@ -0,0 +1,68 @@ +// 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 internal // import "go.opentelemetry.io/otel/exporters/otlp/internal" + +import "fmt" + +// PartialSuccessDropKind indicates the kind of partial success error +// received by an OTLP exporter, which corresponds with the signal +// being exported. +type PartialSuccessDropKind string + +const ( + // TracingPartialSuccess indicates that some spans were rejected. + TracingPartialSuccess PartialSuccessDropKind = "spans" + + // MetricsPartialSuccess indicates that some metric data points were rejected. + MetricsPartialSuccess PartialSuccessDropKind = "metric data points" +) + +// PartialSuccess represents the underlying error for all handling +// OTLP partial success messages. Use `errors.Is(err, +// PartialSuccess{})` to test whether an error passed to the OTel +// error handler belongs to this category. +type PartialSuccess struct { + ErrorMessage string + RejectedItems int64 + RejectedKind PartialSuccessDropKind +} + +var _ error = PartialSuccess{} + +// Error implements the error interface. +func (ps PartialSuccess) Error() string { + msg := ps.ErrorMessage + if msg == "" { + msg = "empty message" + } + return fmt.Sprintf("OTLP partial success: %s (%d %s rejected)", msg, ps.RejectedItems, ps.RejectedKind) +} + +// Is supports the errors.Is() interface. +func (ps PartialSuccess) Is(err error) bool { + _, ok := err.(PartialSuccess) + return ok +} + +// PartialSuccessToError produces an error suitable for passing to +// `otel.Handle()` out of the fields in a partial success response, +// independent of which signal produced the outcome. +func PartialSuccessToError(kind PartialSuccessDropKind, itemsRejected int64, errorMessage string) error { + return PartialSuccess{ + ErrorMessage: errorMessage, + RejectedItems: itemsRejected, + RejectedKind: kind, + } +} diff --git a/exporters/otlp/internal/partialsuccess_test.go b/exporters/otlp/internal/partialsuccess_test.go new file mode 100644 index 00000000000..3a7b0f0a6ef --- /dev/null +++ b/exporters/otlp/internal/partialsuccess_test.go @@ -0,0 +1,44 @@ +// 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 internal // import "go.opentelemetry.io/otel/exporters/otlp/internal" + +import ( + "errors" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func requireErrorString(t *testing.T, expect string, err error) { + t.Helper() + require.NotNil(t, err) + require.Error(t, err) + require.True(t, errors.Is(err, PartialSuccess{})) + + const pfx = "OTLP partial success: " + + msg := err.Error() + require.True(t, strings.HasPrefix(msg, pfx)) + require.Equal(t, expect, msg[len(pfx):]) +} + +func TestPartialSuccessFormat(t *testing.T) { + requireErrorString(t, "empty message (0 metric data points rejected)", PartialSuccessToError(MetricsPartialSuccess, 0, "")) + requireErrorString(t, "help help (0 metric data points rejected)", PartialSuccessToError(MetricsPartialSuccess, 0, "help help")) + requireErrorString(t, "what happened (10 metric data points rejected)", PartialSuccessToError(MetricsPartialSuccess, 10, "what happened")) + requireErrorString(t, "what happened (15 spans rejected)", PartialSuccessToError(TracingPartialSuccess, 15, "what happened")) + requireErrorString(t, "empty message (7 log records rejected)", PartialSuccessToError("log records", 7, "")) +} diff --git a/exporters/otlp/otlpmetric/go.mod b/exporters/otlp/otlpmetric/go.mod index 11cb68b06aa..b99be852d34 100644 --- a/exporters/otlp/otlpmetric/go.mod +++ b/exporters/otlp/otlpmetric/go.mod @@ -5,8 +5,8 @@ go 1.18 require ( github.com/google/go-cmp v0.5.8 github.com/stretchr/testify v1.7.1 - go.opentelemetry.io/otel v1.9.0 - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.9.0 + go.opentelemetry.io/otel v1.10.0 + go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.10.0 go.opentelemetry.io/otel/metric v0.0.0-00010101000000-000000000000 go.opentelemetry.io/otel/sdk v0.0.0-00010101000000-000000000000 go.opentelemetry.io/otel/sdk/metric v0.0.0-00010101000000-000000000000 @@ -23,7 +23,7 @@ require ( github.com/golang/protobuf v1.5.2 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - go.opentelemetry.io/otel/trace v1.9.0 // indirect + go.opentelemetry.io/otel/trace v1.10.0 // indirect golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect golang.org/x/text v0.3.5 // indirect diff --git a/exporters/otlp/otlpmetric/otlpmetricgrpc/go.mod b/exporters/otlp/otlpmetric/otlpmetricgrpc/go.mod index 71ea8704bb5..f4051953143 100644 --- a/exporters/otlp/otlpmetric/otlpmetricgrpc/go.mod +++ b/exporters/otlp/otlpmetric/otlpmetricgrpc/go.mod @@ -4,8 +4,8 @@ go 1.18 require ( github.com/stretchr/testify v1.7.1 - go.opentelemetry.io/otel v1.9.0 - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.9.0 + go.opentelemetry.io/otel v1.10.0 + go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.10.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.31.0 go.opentelemetry.io/otel/metric v0.31.0 go.opentelemetry.io/otel/sdk/metric v0.31.0 @@ -24,8 +24,8 @@ require ( github.com/google/go-cmp v0.5.8 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - go.opentelemetry.io/otel/sdk v1.9.0 // indirect - go.opentelemetry.io/otel/trace v1.9.0 // indirect + go.opentelemetry.io/otel/sdk v1.10.0 // indirect + go.opentelemetry.io/otel/trace v1.10.0 // indirect golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect golang.org/x/text v0.3.5 // indirect diff --git a/exporters/otlp/otlpmetric/otlpmetrichttp/go.mod b/exporters/otlp/otlpmetric/otlpmetrichttp/go.mod index 761f37d8a3c..463b978feb6 100644 --- a/exporters/otlp/otlpmetric/otlpmetrichttp/go.mod +++ b/exporters/otlp/otlpmetric/otlpmetrichttp/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( github.com/stretchr/testify v1.7.1 - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.9.0 + go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.10.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.31.0 go.opentelemetry.io/otel/metric v0.31.0 go.opentelemetry.io/otel/sdk/metric v0.31.0 @@ -21,9 +21,9 @@ require ( github.com/google/go-cmp v0.5.8 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - go.opentelemetry.io/otel v1.9.0 // indirect - go.opentelemetry.io/otel/sdk v1.9.0 // indirect - go.opentelemetry.io/otel/trace v1.9.0 // indirect + go.opentelemetry.io/otel v1.10.0 // indirect + go.opentelemetry.io/otel/sdk v1.10.0 // indirect + go.opentelemetry.io/otel/trace v1.10.0 // indirect golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect golang.org/x/text v0.3.5 // indirect diff --git a/exporters/otlp/otlptrace/go.mod b/exporters/otlp/otlptrace/go.mod index 32eb84a92c2..1c89ad3ba5c 100644 --- a/exporters/otlp/otlptrace/go.mod +++ b/exporters/otlp/otlptrace/go.mod @@ -5,10 +5,10 @@ go 1.17 require ( github.com/google/go-cmp v0.5.8 github.com/stretchr/testify v1.7.1 - go.opentelemetry.io/otel v1.9.0 - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.9.0 - go.opentelemetry.io/otel/sdk v1.9.0 - go.opentelemetry.io/otel/trace v1.9.0 + go.opentelemetry.io/otel v1.10.0 + go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.10.0 + go.opentelemetry.io/otel/sdk v1.10.0 + go.opentelemetry.io/otel/trace v1.10.0 go.opentelemetry.io/proto/otlp v0.19.0 google.golang.org/grpc v1.46.2 google.golang.org/protobuf v1.28.0 diff --git a/exporters/otlp/otlptrace/internal/tracetransform/instrumentation.go b/exporters/otlp/otlptrace/internal/tracetransform/instrumentation.go index 4dcddb17809..7aaec38d22a 100644 --- a/exporters/otlp/otlptrace/internal/tracetransform/instrumentation.go +++ b/exporters/otlp/otlptrace/internal/tracetransform/instrumentation.go @@ -24,8 +24,7 @@ func InstrumentationScope(il instrumentation.Scope) *commonpb.InstrumentationSco return nil } return &commonpb.InstrumentationScope{ - Name: il.Name, - Version: il.Version, - Attributes: Iterator(il.Attributes.Iter()), + Name: il.Name, + Version: il.Version, } } diff --git a/exporters/otlp/otlptrace/internal/tracetransform/instrumentation_test.go b/exporters/otlp/otlptrace/internal/tracetransform/instrumentation_test.go deleted file mode 100644 index 634d1dfaf00..00000000000 --- a/exporters/otlp/otlptrace/internal/tracetransform/instrumentation_test.go +++ /dev/null @@ -1,52 +0,0 @@ -// 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 tracetransform // import "go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/tracetransform" - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/sdk/instrumentation" - commonpb "go.opentelemetry.io/proto/otlp/common/v1" -) - -func TestInstrumentationScope(t *testing.T) { - t.Run("Empty", func(t *testing.T) { - assert.Nil(t, InstrumentationScope(instrumentation.Scope{})) - }) - - t.Run("Mapping", func(t *testing.T) { - var ( - name = "instrumentation name" - version = "v0.1.0" - attr = attribute.NewSet(attribute.String("domain", "trace")) - attrPb = Iterator(attr.Iter()) - ) - expected := &commonpb.InstrumentationScope{ - Name: name, - Version: version, - Attributes: attrPb, - } - actual := InstrumentationScope(instrumentation.Scope{ - Name: name, - Version: version, - SchemaURL: "http://this.is.mapped.elsewhere.com", - Attributes: attr, - }) - assert.Equal(t, expected, actual) - }) -} diff --git a/exporters/otlp/otlptrace/otlptracegrpc/client.go b/exporters/otlp/otlptrace/otlptracegrpc/client.go index 6be3fec8626..9d6e1898b14 100644 --- a/exporters/otlp/otlptrace/otlptracegrpc/client.go +++ b/exporters/otlp/otlptrace/otlptracegrpc/client.go @@ -26,6 +26,8 @@ import ( "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/otlp/internal" "go.opentelemetry.io/otel/exporters/otlp/internal/retry" "go.opentelemetry.io/otel/exporters/otlp/otlptrace" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/otlpconfig" @@ -196,9 +198,16 @@ func (c *client) UploadTraces(ctx context.Context, protoSpans []*tracepb.Resourc defer cancel() return c.requestFunc(ctx, func(iCtx context.Context) error { - _, err := c.tsc.Export(iCtx, &coltracepb.ExportTraceServiceRequest{ + resp, err := c.tsc.Export(iCtx, &coltracepb.ExportTraceServiceRequest{ ResourceSpans: protoSpans, }) + if resp != nil && resp.PartialSuccess != nil { + otel.Handle(internal.PartialSuccessToError( + internal.TracingPartialSuccess, + resp.PartialSuccess.RejectedSpans, + resp.PartialSuccess.ErrorMessage, + )) + } // nil is converted to OK. if status.Code(err) == codes.OK { // Success. diff --git a/exporters/otlp/otlptrace/otlptracegrpc/client_test.go b/exporters/otlp/otlptrace/otlptracegrpc/client_test.go index 84e7da801b1..d11111ed126 100644 --- a/exporters/otlp/otlptrace/otlptracegrpc/client_test.go +++ b/exporters/otlp/otlptrace/otlptracegrpc/client_test.go @@ -4,7 +4,7 @@ // 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 +// 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, @@ -30,12 +30,14 @@ import ( "google.golang.org/grpc/encoding/gzip" "google.golang.org/grpc/status" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/exporters/otlp/otlptrace" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/otlptracetest" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" + coltracepb "go.opentelemetry.io/proto/otlp/collector/trace/v1" commonpb "go.opentelemetry.io/proto/otlp/common/v1" ) @@ -386,3 +388,26 @@ func TestEmptyData(t *testing.T) { assert.NoError(t, exp.ExportSpans(ctx, nil)) } + +func TestPartialSuccess(t *testing.T) { + mc := runMockCollectorWithConfig(t, &mockConfig{ + partial: &coltracepb.ExportTracePartialSuccess{ + RejectedSpans: 2, + ErrorMessage: "partially successful", + }, + }) + t.Cleanup(func() { require.NoError(t, mc.stop()) }) + + errors := []error{} + otel.SetErrorHandler(otel.ErrorHandlerFunc(func(err error) { + errors = append(errors, err) + })) + ctx := context.Background() + exp := newGRPCExporter(t, ctx, mc.endpoint) + t.Cleanup(func() { require.NoError(t, exp.Shutdown(ctx)) }) + require.NoError(t, exp.ExportSpans(ctx, roSpans)) + + require.Equal(t, 1, len(errors)) + require.Contains(t, errors[0].Error(), "partially successful") + require.Contains(t, errors[0].Error(), "2 spans rejected") +} diff --git a/exporters/otlp/otlptrace/otlptracegrpc/go.mod b/exporters/otlp/otlptrace/otlptracegrpc/go.mod index 3bff7e4e738..9e444cbe7e3 100644 --- a/exporters/otlp/otlptrace/otlptracegrpc/go.mod +++ b/exporters/otlp/otlptrace/otlptracegrpc/go.mod @@ -4,10 +4,10 @@ go 1.17 require ( github.com/stretchr/testify v1.7.1 - go.opentelemetry.io/otel v1.9.0 - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.9.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.9.0 - go.opentelemetry.io/otel/sdk v1.9.0 + go.opentelemetry.io/otel v1.10.0 + go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.10.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.10.0 + go.opentelemetry.io/otel/sdk v1.10.0 go.opentelemetry.io/proto/otlp v0.19.0 go.uber.org/goleak v1.1.12 google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 @@ -23,7 +23,7 @@ require ( github.com/golang/protobuf v1.5.2 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - go.opentelemetry.io/otel/trace v1.9.0 // indirect + go.opentelemetry.io/otel/trace v1.10.0 // indirect golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect golang.org/x/text v0.3.5 // indirect diff --git a/exporters/otlp/otlptrace/otlptracegrpc/mock_collector_test.go b/exporters/otlp/otlptrace/otlptracegrpc/mock_collector_test.go index d3ebd8357c7..56b65a5d67b 100644 --- a/exporters/otlp/otlptrace/otlptracegrpc/mock_collector_test.go +++ b/exporters/otlp/otlptrace/otlptracegrpc/mock_collector_test.go @@ -36,6 +36,7 @@ func makeMockCollector(t *testing.T, mockConfig *mockConfig) *mockCollector { traceSvc: &mockTraceService{ storage: otlptracetest.NewSpansStorage(), errors: mockConfig.errors, + partial: mockConfig.partial, }, } } @@ -44,6 +45,7 @@ type mockTraceService struct { collectortracepb.UnimplementedTraceServiceServer errors []error + partial *collectortracepb.ExportTracePartialSuccess requests int mu sync.RWMutex storage otlptracetest.SpansStorage @@ -82,7 +84,9 @@ func (mts *mockTraceService) Export(ctx context.Context, exp *collectortracepb.E <-mts.exportBlock } - reply := &collectortracepb.ExportTraceServiceResponse{} + reply := &collectortracepb.ExportTraceServiceResponse{ + PartialSuccess: mts.partial, + } if mts.requests < len(mts.errors) { idx := mts.requests return reply, mts.errors[idx] @@ -106,6 +110,7 @@ type mockCollector struct { type mockConfig struct { errors []error endpoint string + partial *collectortracepb.ExportTracePartialSuccess } var _ collectortracepb.TraceServiceServer = (*mockTraceService)(nil) diff --git a/exporters/otlp/otlptrace/otlptracehttp/client.go b/exporters/otlp/otlptrace/otlptracehttp/client.go index 0c050eb2fa3..745b6541d42 100644 --- a/exporters/otlp/otlptrace/otlptracehttp/client.go +++ b/exporters/otlp/otlptrace/otlptracehttp/client.go @@ -29,6 +29,8 @@ import ( "google.golang.org/protobuf/proto" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/otlp/internal" "go.opentelemetry.io/otel/exporters/otlp/internal/retry" "go.opentelemetry.io/otel/exporters/otlp/otlptrace" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/otlpconfig" @@ -154,28 +156,48 @@ func (d *client) UploadTraces(ctx context.Context, protoSpans []*tracepb.Resourc return err } - var rErr error + if resp != nil && resp.Body != nil { + defer func() { + if err := resp.Body.Close(); err != nil { + otel.Handle(err) + } + }() + } + switch resp.StatusCode { case http.StatusOK: // Success, do not retry. - case http.StatusTooManyRequests, - http.StatusServiceUnavailable: - // Retry-able failure. - rErr = newResponseError(resp.Header) + // Read the partial success message, if any. + var respData bytes.Buffer + if _, err := io.Copy(&respData, resp.Body); err != nil { + return err + } + + if respData.Len() != 0 { + var respProto coltracepb.ExportTraceServiceResponse + if err := proto.Unmarshal(respData.Bytes(), &respProto); err != nil { + return err + } + + if respProto.PartialSuccess != nil { + otel.Handle(internal.PartialSuccessToError( + internal.TracingPartialSuccess, + respProto.PartialSuccess.RejectedSpans, + respProto.PartialSuccess.ErrorMessage, + )) + } + } + return nil - // Going to retry, drain the body to reuse the connection. + case http.StatusTooManyRequests, http.StatusServiceUnavailable: + // Retry-able failures. Drain the body to reuse the connection. if _, err := io.Copy(io.Discard, resp.Body); err != nil { - _ = resp.Body.Close() - return err + otel.Handle(err) } + return newResponseError(resp.Header) default: - rErr = fmt.Errorf("failed to send %s to %s: %s", d.name, request.URL, resp.Status) - } - - if err := resp.Body.Close(); err != nil { - return err + return fmt.Errorf("failed to send %s to %s: %s", d.name, request.URL, resp.Status) } - return rErr }) } diff --git a/exporters/otlp/otlptrace/otlptracehttp/client_test.go b/exporters/otlp/otlptrace/otlptracehttp/client_test.go index d14a6ce806f..bf497bad4be 100644 --- a/exporters/otlp/otlptrace/otlptracehttp/client_test.go +++ b/exporters/otlp/otlptrace/otlptracehttp/client_test.go @@ -25,9 +25,11 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/otlp/otlptrace" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/otlptracetest" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" + coltracepb "go.opentelemetry.io/proto/otlp/collector/trace/v1" ) const ( @@ -348,3 +350,35 @@ func TestStopWhileExporting(t *testing.T) { assert.NoError(t, err) <-doneCh } + +func TestPartialSuccess(t *testing.T) { + mcCfg := mockCollectorConfig{ + Partial: &coltracepb.ExportTracePartialSuccess{ + RejectedSpans: 2, + ErrorMessage: "partially successful", + }, + } + mc := runMockCollector(t, mcCfg) + defer mc.MustStop(t) + driver := otlptracehttp.NewClient( + otlptracehttp.WithEndpoint(mc.Endpoint()), + otlptracehttp.WithInsecure(), + ) + ctx := context.Background() + exporter, err := otlptrace.New(ctx, driver) + require.NoError(t, err) + defer func() { + assert.NoError(t, exporter.Shutdown(context.Background())) + }() + + errors := []error{} + otel.SetErrorHandler(otel.ErrorHandlerFunc(func(err error) { + errors = append(errors, err) + })) + err = exporter.ExportSpans(ctx, otlptracetest.SingleReadOnlySpan()) + assert.NoError(t, err) + + require.Equal(t, 1, len(errors)) + require.Contains(t, errors[0].Error(), "partially successful") + require.Contains(t, errors[0].Error(), "2 spans rejected") +} diff --git a/exporters/otlp/otlptrace/otlptracehttp/go.mod b/exporters/otlp/otlptrace/otlptracehttp/go.mod index da79c3b66d9..798b246a743 100644 --- a/exporters/otlp/otlptrace/otlptracehttp/go.mod +++ b/exporters/otlp/otlptrace/otlptracehttp/go.mod @@ -4,11 +4,11 @@ go 1.17 require ( github.com/stretchr/testify v1.7.1 - go.opentelemetry.io/otel v1.9.0 - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.9.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.9.0 - go.opentelemetry.io/otel/sdk v1.9.0 - go.opentelemetry.io/otel/trace v1.9.0 + go.opentelemetry.io/otel v1.10.0 + go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.10.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.10.0 + go.opentelemetry.io/otel/sdk v1.10.0 + go.opentelemetry.io/otel/trace v1.10.0 go.opentelemetry.io/proto/otlp v0.19.0 google.golang.org/protobuf v1.28.0 ) diff --git a/exporters/otlp/otlptrace/otlptracehttp/mock_collector_test.go b/exporters/otlp/otlptrace/otlptracehttp/mock_collector_test.go index 895b34af4cd..d999c1c8952 100644 --- a/exporters/otlp/otlptrace/otlptracehttp/mock_collector_test.go +++ b/exporters/otlp/otlptrace/otlptracehttp/mock_collector_test.go @@ -46,6 +46,7 @@ type mockCollector struct { injectHTTPStatus []int injectResponseHeader []map[string]string injectContentType string + partial *collectortracepb.ExportTracePartialSuccess delay <-chan struct{} clientTLSConfig *tls.Config @@ -93,7 +94,9 @@ func (c *mockCollector) serveTraces(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusBadRequest) return } - response := collectortracepb.ExportTraceServiceResponse{} + response := collectortracepb.ExportTraceServiceResponse{ + PartialSuccess: c.partial, + } rawResponse, err := proto.Marshal(&response) if err != nil { w.WriteHeader(http.StatusInternalServerError) @@ -207,6 +210,7 @@ type mockCollectorConfig struct { InjectHTTPStatus []int InjectContentType string InjectResponseHeader []map[string]string + Partial *collectortracepb.ExportTracePartialSuccess Delay <-chan struct{} WithTLS bool ExpectedHeaders map[string]string @@ -230,6 +234,7 @@ func runMockCollector(t *testing.T, cfg mockCollectorConfig) *mockCollector { injectHTTPStatus: cfg.InjectHTTPStatus, injectResponseHeader: cfg.InjectResponseHeader, injectContentType: cfg.InjectContentType, + partial: cfg.Partial, delay: cfg.Delay, expectedHeaders: cfg.ExpectedHeaders, } diff --git a/exporters/prometheus/go.mod b/exporters/prometheus/go.mod index 2b1d8e9730b..c06f9ff10a5 100644 --- a/exporters/prometheus/go.mod +++ b/exporters/prometheus/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/prometheus/client_golang v1.13.0 github.com/stretchr/testify v1.7.1 - go.opentelemetry.io/otel v1.9.0 + go.opentelemetry.io/otel v1.10.0 go.opentelemetry.io/otel/metric v0.31.0 go.opentelemetry.io/otel/sdk/metric v0.31.0 ) @@ -22,8 +22,8 @@ require ( github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect - go.opentelemetry.io/otel/sdk v1.8.0 // indirect - go.opentelemetry.io/otel/trace v1.9.0 // indirect + go.opentelemetry.io/otel/sdk v1.10.0 // indirect + go.opentelemetry.io/otel/trace v1.10.0 // indirect golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect diff --git a/exporters/stdout/stdoutmetric/example_test.go b/exporters/stdout/stdoutmetric/example_test.go index 6dcf163c47f..e8ea9310b46 100644 --- a/exporters/stdout/stdoutmetric/example_test.go +++ b/exporters/stdout/stdoutmetric/example_test.go @@ -143,8 +143,7 @@ func Example() { // "Scope": { // "Name": "example", // "Version": "v0.0.1", - // "SchemaURL": "", - // "Attributes": null + // "SchemaURL": "" // }, // "Metrics": [ // { diff --git a/exporters/stdout/stdoutmetric/go.mod b/exporters/stdout/stdoutmetric/go.mod index 880394c7a4d..67edf5fc2ed 100644 --- a/exporters/stdout/stdoutmetric/go.mod +++ b/exporters/stdout/stdoutmetric/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( github.com/stretchr/testify v1.7.1 - go.opentelemetry.io/otel v1.9.0 + go.opentelemetry.io/otel v1.10.0 go.opentelemetry.io/otel/metric v0.0.0-00010101000000-000000000000 go.opentelemetry.io/otel/sdk v0.0.0-00010101000000-000000000000 go.opentelemetry.io/otel/sdk/metric v0.0.0-00010101000000-000000000000 @@ -15,7 +15,7 @@ require ( github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - go.opentelemetry.io/otel/trace v1.9.0 // indirect + go.opentelemetry.io/otel/trace v1.10.0 // indirect golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect ) diff --git a/exporters/stdout/stdouttrace/go.mod b/exporters/stdout/stdouttrace/go.mod index 2ce913ee7c9..b44e0998199 100644 --- a/exporters/stdout/stdouttrace/go.mod +++ b/exporters/stdout/stdouttrace/go.mod @@ -9,9 +9,9 @@ replace ( require ( github.com/stretchr/testify v1.7.1 - go.opentelemetry.io/otel v1.9.0 - go.opentelemetry.io/otel/sdk v1.9.0 - go.opentelemetry.io/otel/trace v1.9.0 + go.opentelemetry.io/otel v1.10.0 + go.opentelemetry.io/otel/sdk v1.10.0 + go.opentelemetry.io/otel/trace v1.10.0 ) require ( diff --git a/exporters/stdout/stdouttrace/trace_test.go b/exporters/stdout/stdouttrace/trace_test.go index 82bd2fcabd7..649312bf697 100644 --- a/exporters/stdout/stdouttrace/trace_test.go +++ b/exporters/stdout/stdouttrace/trace_test.go @@ -186,8 +186,7 @@ func expectedJSON(now time.Time) string { "InstrumentationLibrary": { "Name": "", "Version": "", - "SchemaURL": "", - "Attributes": null + "SchemaURL": "" } } ` diff --git a/exporters/zipkin/go.mod b/exporters/zipkin/go.mod index 67b428a6533..ca6f259a277 100644 --- a/exporters/zipkin/go.mod +++ b/exporters/zipkin/go.mod @@ -6,9 +6,9 @@ require ( github.com/google/go-cmp v0.5.8 github.com/openzipkin/zipkin-go v0.4.0 github.com/stretchr/testify v1.7.1 - go.opentelemetry.io/otel v1.9.0 - go.opentelemetry.io/otel/sdk v1.9.0 - go.opentelemetry.io/otel/trace v1.9.0 + go.opentelemetry.io/otel v1.10.0 + go.opentelemetry.io/otel/sdk v1.10.0 + go.opentelemetry.io/otel/trace v1.10.0 ) require ( diff --git a/go.mod b/go.mod index 1237d40cf6d..76dbbbaec49 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/go-logr/stdr v1.2.2 github.com/google/go-cmp v0.5.8 github.com/stretchr/testify v1.7.1 - go.opentelemetry.io/otel/trace v1.9.0 + go.opentelemetry.io/otel/trace v1.10.0 ) require ( diff --git a/metric/go.mod b/metric/go.mod index 5b6f1c3ad4f..4ce2adacf77 100644 --- a/metric/go.mod +++ b/metric/go.mod @@ -4,7 +4,7 @@ go 1.17 require ( github.com/stretchr/testify v1.7.1 - go.opentelemetry.io/otel v1.9.0 + go.opentelemetry.io/otel v1.10.0 ) require ( @@ -12,7 +12,7 @@ require ( github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - go.opentelemetry.io/otel/trace v1.9.0 // indirect + go.opentelemetry.io/otel/trace v1.10.0 // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect ) diff --git a/sdk/go.mod b/sdk/go.mod index 9f869c2f0b6..6a9bfa8212f 100644 --- a/sdk/go.mod +++ b/sdk/go.mod @@ -8,8 +8,8 @@ require ( github.com/go-logr/logr v1.2.3 github.com/google/go-cmp v0.5.8 github.com/stretchr/testify v1.7.1 - go.opentelemetry.io/otel v1.9.0 - go.opentelemetry.io/otel/trace v1.9.0 + go.opentelemetry.io/otel v1.10.0 + go.opentelemetry.io/otel/trace v1.10.0 golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 ) diff --git a/sdk/instrumentation/scope.go b/sdk/instrumentation/scope.go index 3001b6cc907..09c6d93f6d0 100644 --- a/sdk/instrumentation/scope.go +++ b/sdk/instrumentation/scope.go @@ -14,14 +14,7 @@ package instrumentation // import "go.opentelemetry.io/otel/sdk/instrumentation" -import "go.opentelemetry.io/otel/attribute" - -// Scope represents the instrumentation source of OpenTelemetry data. -// -// Code that uses OpenTelemetry APIs or data-models to produce telemetry needs -// to be identifiable by the receiver of that data. A Scope is used for this -// purpose, it uniquely identifies that code as the source and the extent to -// which it is relevant. +// Scope represents the instrumentation scope. type Scope struct { // Name is the name of the instrumentation scope. This should be the // Go package name of that scope. @@ -30,13 +23,4 @@ type Scope struct { Version string // SchemaURL of the telemetry emitted by the scope. SchemaURL string - // Attributes describe the unique attributes of an instrumentation scope. - // - // These attributes are used to differentiate an instrumentation scope when - // it emits data that belong to different domains. For example, if both - // profiling data and client-side data are emitted as log records from the - // same instrumentation library, they may need to be differentiated by a - // telemetry receiver. In that case, these attributes are used to scope and - // differentiate the data. - Attributes attribute.Set } diff --git a/sdk/metric/go.mod b/sdk/metric/go.mod index b2be037c326..1c96d819855 100644 --- a/sdk/metric/go.mod +++ b/sdk/metric/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/go-logr/logr v1.2.3 github.com/stretchr/testify v1.7.1 - go.opentelemetry.io/otel v1.9.0 + go.opentelemetry.io/otel v1.10.0 go.opentelemetry.io/otel/metric v0.0.0-00010101000000-000000000000 go.opentelemetry.io/otel/sdk v0.0.0-00010101000000-000000000000 ) @@ -14,7 +14,7 @@ require ( github.com/davecgh/go-spew v1.1.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - go.opentelemetry.io/otel/trace v1.9.0 // indirect + go.opentelemetry.io/otel/trace v1.10.0 // indirect golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect ) diff --git a/sdk/trace/provider.go b/sdk/trace/provider.go index 7498017903a..292ea5481bc 100644 --- a/sdk/trace/provider.go +++ b/sdk/trace/provider.go @@ -142,10 +142,9 @@ func (p *TracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.T name = defaultTracerName } is := instrumentation.Scope{ - Name: name, - Version: c.InstrumentationVersion(), - SchemaURL: c.SchemaURL(), - Attributes: c.Attributes(), + Name: name, + Version: c.InstrumentationVersion(), + SchemaURL: c.SchemaURL(), } t, ok := p.namedTracer[is] if !ok { @@ -154,13 +153,7 @@ func (p *TracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.T instrumentationScope: is, } p.namedTracer[is] = t - global.Info( - "Tracer created", - "name", name, - "version", c.InstrumentationVersion(), - "schemaURL", c.SchemaURL(), - "attributes", c.Attributes(), - ) + global.Info("Tracer created", "name", name, "version", c.InstrumentationVersion(), "schemaURL", c.SchemaURL()) } return t } diff --git a/sdk/trace/span.go b/sdk/trace/span.go index 14d0aabfe69..449cf6c2552 100644 --- a/sdk/trace/span.go +++ b/sdk/trace/span.go @@ -20,8 +20,10 @@ import ( "reflect" "runtime" rt "runtime/trace" + "strings" "sync" "time" + "unicode/utf8" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" @@ -294,7 +296,7 @@ func (s *recordingSpan) addOverCapAttrs(limit int, attrs []attribute.KeyValue) { // truncateAttr returns a truncated version of attr. Only string and string // slice attribute values are truncated. String values are truncated to at -// most a length of limit. Each string slice value is truncated in this fasion +// most a length of limit. Each string slice value is truncated in this fashion // (the slice length itself is unaffected). // // No truncation is perfromed for a negative limit. @@ -305,7 +307,7 @@ func truncateAttr(limit int, attr attribute.KeyValue) attribute.KeyValue { switch attr.Value.Type() { case attribute.STRING: if v := attr.Value.AsString(); len(v) > limit { - return attr.Key.String(v[:limit]) + return attr.Key.String(safeTruncate(v, limit)) } case attribute.STRINGSLICE: // Do no mutate the original, make a copy. @@ -324,7 +326,7 @@ func truncateAttr(limit int, attr attribute.KeyValue) attribute.KeyValue { v := trucated.Value.AsStringSlice() for i := range v { if len(v[i]) > limit { - v[i] = v[i][:limit] + v[i] = safeTruncate(v[i], limit) } } return trucated @@ -332,6 +334,34 @@ func truncateAttr(limit int, attr attribute.KeyValue) attribute.KeyValue { return attr } +// safeTruncate truncates the string and guarantees valid UTF-8 is returned. +func safeTruncate(input string, limit int) string { + if trunc, ok := safeTruncateValidUTF8(input, limit); ok { + return trunc + } + trunc, _ := safeTruncateValidUTF8(strings.ToValidUTF8(input, ""), limit) + return trunc +} + +// safeTruncateValidUTF8 returns a copy of the input string safely truncated to +// limit. The truncation is ensured to occur at the bounds of complete UTF-8 +// characters. If invalid encoding of UTF-8 is encountered, input is returned +// with false, otherwise, the truncated input will be returned with true. +func safeTruncateValidUTF8(input string, limit int) (string, bool) { + for cnt := 0; cnt <= limit; { + r, size := utf8.DecodeRuneInString(input[cnt:]) + if r == utf8.RuneError { + return input, false + } + + if cnt+size > limit { + return input[:cnt], true + } + cnt += size + } + return input, true +} + // End ends the span. This method does nothing if the span is already ended or // is not being recorded. // diff --git a/sdk/trace/span_limits_test.go b/sdk/trace/span_limits_test.go index 91199516c56..5e88770ae0f 100644 --- a/sdk/trace/span_limits_test.go +++ b/sdk/trace/span_limits_test.go @@ -168,6 +168,7 @@ func testSpanLimits(t *testing.T, limits SpanLimits) ReadOnlySpan { span.SetAttributes( attribute.String("string", "abc"), attribute.StringSlice("stringSlice", []string{"abc", "def"}), + attribute.String("euro", "€"), // this is a 3-byte rune ) span.AddEvent("event 1", trace.WithAttributes(a...)) span.AddEvent("event 2", trace.WithAttributes(a...)) @@ -186,24 +187,27 @@ func TestSpanLimits(t *testing.T) { attrs := testSpanLimits(t, limits).Attributes() assert.Contains(t, attrs, attribute.String("string", "abc")) assert.Contains(t, attrs, attribute.StringSlice("stringSlice", []string{"abc", "def"})) + assert.Contains(t, attrs, attribute.String("euro", "€")) limits.AttributeValueLengthLimit = 2 attrs = testSpanLimits(t, limits).Attributes() // Ensure string and string slice attributes are truncated. assert.Contains(t, attrs, attribute.String("string", "ab")) assert.Contains(t, attrs, attribute.StringSlice("stringSlice", []string{"ab", "de"})) + assert.Contains(t, attrs, attribute.String("euro", "")) limits.AttributeValueLengthLimit = 0 attrs = testSpanLimits(t, limits).Attributes() assert.Contains(t, attrs, attribute.String("string", "")) assert.Contains(t, attrs, attribute.StringSlice("stringSlice", []string{"", ""})) + assert.Contains(t, attrs, attribute.String("euro", "")) }) t.Run("AttributeCountLimit", func(t *testing.T) { limits := NewSpanLimits() // Unlimited. limits.AttributeCountLimit = -1 - assert.Len(t, testSpanLimits(t, limits).Attributes(), 2) + assert.Len(t, testSpanLimits(t, limits).Attributes(), 3) limits.AttributeCountLimit = 1 assert.Len(t, testSpanLimits(t, limits).Attributes(), 1) diff --git a/sdk/trace/span_test.go b/sdk/trace/span_test.go index 2c7992e457e..2441defae71 100644 --- a/sdk/trace/span_test.go +++ b/sdk/trace/span_test.go @@ -134,6 +134,30 @@ func TestTruncateAttr(t *testing.T) { attr: strSliceAttr, want: strSliceAttr, }, + { + // This tests the ordinary safeTruncate(). + limit: 10, + attr: attribute.String(key, "€€€€"), // 3 bytes each + want: attribute.String(key, "€€€"), + }, + { + // This tests truncation with an invalid UTF-8 input. + // + // Note that after removing the invalid rune, + // the string is over length and still has to + // be truncated on a code point boundary. + limit: 10, + attr: attribute.String(key, "€"[0:2]+"hello€€"), // corrupted first rune, then over limit + want: attribute.String(key, "hello€"), + }, + { + // This tests the fallback to invalidTruncate() + // where after validation the string does not require + // truncation. + limit: 6, + attr: attribute.String(key, "€"[0:2]+"hello"), // corrupted first rune, then not over limit + want: attribute.String(key, "hello"), + }, } for _, test := range tests { diff --git a/sdk/trace/trace_test.go b/sdk/trace/trace_test.go index 8badccc4240..c6adbb77818 100644 --- a/sdk/trace/trace_test.go +++ b/sdk/trace/trace_test.go @@ -911,8 +911,6 @@ func TestSetSpanStatusWithoutMessageWhenStatusIsNotError(t *testing.T) { func cmpDiff(x, y interface{}) string { return cmp.Diff(x, y, cmp.AllowUnexported(snapshot{}), - cmp.AllowUnexported(attribute.Set{}), - cmp.AllowUnexported(attribute.Distinct{}), cmp.AllowUnexported(attribute.Value{}), cmp.AllowUnexported(Event{}), cmp.AllowUnexported(trace.TraceState{})) diff --git a/trace/go.mod b/trace/go.mod index 670e2864c20..d4b34f0cc64 100644 --- a/trace/go.mod +++ b/trace/go.mod @@ -7,7 +7,7 @@ replace go.opentelemetry.io/otel => ../ require ( github.com/google/go-cmp v0.5.8 github.com/stretchr/testify v1.7.1 - go.opentelemetry.io/otel v1.9.0 + go.opentelemetry.io/otel v1.10.0 ) require ( diff --git a/version.go b/version.go index 3de2c94cfe0..806db41c555 100644 --- a/version.go +++ b/version.go @@ -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.9.0" + return "1.10.0" } diff --git a/versions.yaml b/versions.yaml index ec74ef51610..ec2ca16d270 100644 --- a/versions.yaml +++ b/versions.yaml @@ -14,7 +14,7 @@ module-sets: stable-v1: - version: v1.9.0 + version: v1.10.0 modules: - go.opentelemetry.io/otel - go.opentelemetry.io/otel/bridge/opentracing