diff --git a/.github/dependabot.yml b/.github/dependabot.yml index a143996ab84..7c563372091 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -76,6 +76,16 @@ updates: schedule: day: sunday interval: weekly + - + package-ecosystem: gomod + directory: /example/opencensus + labels: + - dependencies + - go + - "Skip Changelog" + schedule: + day: sunday + interval: weekly - package-ecosystem: gomod directory: /example/otel-collector diff --git a/.github/workflows/protogen.yml b/.github/workflows/protogen.yml index a82d841efda..8b8f641170c 100644 --- a/.github/workflows/protogen.yml +++ b/.github/workflows/protogen.yml @@ -14,8 +14,8 @@ jobs: - uses: actions/setup-go@v2 with: go-version: '^1.14.0' - - run: sudo apt-get -y install pax - - run: make -f Makefile.proto protobuf + - run: sudo apt-get -y install rsync wget unzip + - run: make -f Makefile.proto protobuf clean - uses: stefanzweifel/git-auto-commit-action@v4 id: commit-changes with: diff --git a/.gitignore b/.gitignore index cbef19714a7..90bd682fde4 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ gen/ /example/http/server/server /example/jaeger/jaeger /example/namedtracer/namedtracer +/example/opencensus/opencensus /example/prometheus/prometheus /example/zipkin/zipkin /example/otel-collector/otel-collector diff --git a/CHANGELOG.md b/CHANGELOG.md index 241633b10dc..f004ec1d788 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,56 +10,101 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Added -- `EventOption` and the related `NewEventConfig` function are added to the `go.opentelemetry.io/otel` package to configure Span events. (#1254) -- A `TextMapPropagator` and associated `TextMapCarrier` are added to the `go.opentelemetry.io/otel/oteltest` package to test TextMap type propagators and their use. (#1259) -- `SpanContextFromContext` returns `SpanContext` from context. (#1255) +- Add the `ReadOnlySpan` and `ReadWriteSpan` interfaces to provide better control for accessing span data. (#1360) - `MetricsLabelsEnricher` type is added to `go.opentelemetry.io/otel/sdk/metric` package. (#1271) - `WithMetricsLabelsEnricher` config option is added to `go.opentelemetry.io/otel/sdk/push` and `go.opentelemetry.io/otel/sdk/pull` packages to allow providing a function to enrich metrics labels based on context. (#1271) + +### Changed + +- Rename `export.SpanData` to `export.SpanSnapshot` and use it only for exporting spans. (#1360) +- Store the parent's full `SpanContext` rather than just its span ID in the `span` struct. (#1360) +- Improve span duration accuracy. (#1360) + +### Removed + +- Remove `errUninitializedSpan` as its only usage is now obsolete. (#1360) + +## [0.15.0] - 2020-12-10 + +### Added + +- The `WithIDGenerator` `TracerProviderOption` is added to the `go.opentelemetry.io/otel/trace` package to configure an `IDGenerator` for the `TracerProvider`. (#1363) + +### Changed + +- The Zipkin exporter now uses the Span status code to determine. (#1328) +- `NewExporter` and `Start` functions in `go.opentelemetry.io/otel/exporters/otlp` now receive `context.Context` as a first parameter. (#1357) +- Move the OpenCensus example into `example` directory. (#1359) +- Moved the SDK's `internal.IDGenerator` interface in to the `sdk/trace` package to enable support for externally-defined ID generators. (#1363) +- Bump `github.com/google/go-cmp` from 0.5.3 to 0.5.4 (#1374) +- Bump `github.com/golangci/golangci-lint` in `/internal/tools` (#1375) + + +### Fixed + +- Metric SDK `SumObserver` and `UpDownSumObserver` instruments correctness fixes. (#1381) + +## [0.14.0] - 2020-11-19 + +### Added + +- An `EventOption` and the related `NewEventConfig` function are added to the `go.opentelemetry.io/otel` package to configure Span events. (#1254) +- A `TextMapPropagator` and associated `TextMapCarrier` are added to the `go.opentelemetry.io/otel/oteltest` package to test `TextMap` type propagators and their use. (#1259) +- `SpanContextFromContext` returns `SpanContext` from context. (#1255) - Add an opencensus to opentelemetry tracing bridge. (#1305) +- `DeploymentEnvironmentKey` added to `go.opentelemetry.io/otel/semconv` package. (#1323) +- Add an OpenCensus to OpenTelemetry tracing bridge. (#1305) +- Add a parent context argument to `SpanProcessor.OnStart` to follow the specification. (#1333) +- Add missing tests for `sdk/trace/attributes_map.go`. (#1337) ### Changed - Move the `go.opentelemetry.io/otel/api/trace` package into `go.opentelemetry.io/otel/trace` with the following changes. (#1229) (#1307) - `ID` has been renamed to `TraceID`. - `IDFromHex` has been renamed to `TraceIDFromHex`. - - `ErrorOption` has been changed to an interface to conform with project design standards which included adding a `NewErrorConfig` function. - `EmptySpanContext` is removed. - Move the `go.opentelemetry.io/otel/api/trace/tracetest` package into `go.opentelemetry.io/otel/oteltest`. (#1229) - OTLP Exporter updates: - - supports OTLP v0.5.0 (#1230) + - supports OTLP v0.6.0 (#1230, #1354) - supports configurable aggregation temporality (default: Cumulative, optional: Stateless). (#1296) - The Sampler is now called on local child spans. (#1233) - The `Kind` type from the `go.opentelemetry.io/otel/api/metric` package was renamed to `InstrumentKind` to more specifically describe what it is and avoid semantic ambiguity. (#1240) - The `MetricKind` method of the `Descriptor` type in the `go.opentelemetry.io/otel/api/metric` package was renamed to `Descriptor.InstrumentKind`. This matches the returned type and fixes misuse of the term metric. (#1240) - Move test harness from the `go.opentelemetry.io/otel/api/apitest` package into `go.opentelemetry.io/otel/oteltest`. (#1241) -- Rename `MergeItererator` to `MergeIterator` in the `go.opentelemetry.io/otel/label` package. (#1244) - Move the `go.opentelemetry.io/otel/api/metric/metrictest` package into `go.opentelemetry.io/oteltest` as part of #964. (#1252) - Move the `go.opentelemetry.io/otel/api/metric` package into `go.opentelemetry.io/otel/metric` as part of #1303. (#1321) -- Move the `go.opentelemetry.io/otel/api/metric/registry` package into `go.opentelemetry.io/otel/metric/registry as a part of #1303. (#1316) +- Move the `go.opentelemetry.io/otel/api/metric/registry` package into `go.opentelemetry.io/otel/metric/registry` as a part of #1303. (#1316) - Move the `Number` type (together with related functions) from `go.opentelemetry.io/otel/api/metric` package into `go.opentelemetry.io/otel/metric/number` as a part of #1303. (#1316) - The function signature of the Span `AddEvent` method in `go.opentelemetry.io/otel` is updated to no longer take an unused context and instead take a required name and a variable number of `EventOption`s. (#1254) - The function signature of the Span `RecordError` method in `go.opentelemetry.io/otel` is updated to no longer take an unused context and instead take a required error value and a variable number of `EventOption`s. (#1254) -- Move the `go.opentelemetry.io/otel/api/global` package to `go.opentelemetry.io/otel/global`. (#1262) +- Move the `go.opentelemetry.io/otel/api/global` package to `go.opentelemetry.io/otel`. (#1262) (#1330) +- Move the `Version` function from `go.opentelemetry.io/otel/sdk` to `go.opentelemetry.io/otel`. (#1330) - Rename correlation context header from `"otcorrelations"` to `"baggage"` to match the OpenTelemetry specification. (#1267) -- Fix `Code.UnmarshalJSON` to work with valid json only. (#1276) +- Fix `Code.UnmarshalJSON` to work with valid JSON only. (#1276) - The `resource.New()` method changes signature to support builtin attributes and functional options, including `telemetry.sdk.*` and `host.name` semantic conventions; the former method is renamed `resource.NewWithAttributes`. (#1235) -- The prometheus exporter now exports non-monotonic counters (i.e. `UpDownCounter`s) as gauges. (#1210) +- The Prometheus exporter now exports non-monotonic counters (i.e. `UpDownCounter`s) as gauges. (#1210) - Correct the `Span.End` method documentation in the `otel` API to state updates are not allowed on a span after it has ended. (#1310) - Updated span collection limits for attribute, event and link counts to 1000 (#1318) +- Renamed `semconv.HTTPUrlKey` to `semconv.HTTPURLKey`. (#1338) ### Removed - The `ErrInvalidHexID`, `ErrInvalidTraceIDLength`, `ErrInvalidSpanIDLength`, `ErrInvalidSpanIDLength`, or `ErrNilSpanID` from the `go.opentelemetry.io/otel` package are unexported now. (#1243) - The `AddEventWithTimestamp` method on the `Span` interface in `go.opentelemetry.io/otel` is removed due to its redundancy. - It is replaced by using the `AddEvent` method with a `WithTimestamp` option. (#1254) -- Structs `MockSpan` and `MockTracer` are removed from `go.opentelemetry.io/otel/oteltest`. `Tracer` and `Span` from the same module should be used in their place instead. (#1306) + It is replaced by using the `AddEvent` method with a `WithTimestamp` option. (#1254) +- The `MockSpan` and `MockTracer` types are removed from `go.opentelemetry.io/otel/oteltest`. + `Tracer` and `Span` from the same module should be used in their place instead. (#1306) +- `WorkerCount` option is removed from `go.opentelemetry.io/otel/exporters/otlp`. (#1350) ### Fixed +- Rename `MergeItererator` to `MergeIterator` in the `go.opentelemetry.io/otel/label` package. (#1244) - The `go.opentelemetry.io/otel/api/global` packages global TextMapPropagator now delegates functionality to a globally set delegate for all previously returned propagators. (#1258) - Fix condition in `label.Any`. (#1299) +- Fix global `TracerProvider` to pass options to its configured provider. (#1329) +- Fix missing handler for `ExactKind` aggregator in OTLP metrics transformer (#1309) ## [0.13.0] - 2020-10-08 @@ -73,13 +118,13 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Changed - Set default propagator to no-op propagator. (#1184) -- The `HTTPSupplier`, `HTTPExtractor`, `HTTPInjector`, and `HTTPPropagator` from the `go.opentelemetry.io/otel/api/propagation` package were replaced with unified `TextMapCarrier` and `TextMapPropagator` in the `go.opentelemetry.io/otel` package. (#1212) +- The `HTTPSupplier`, `HTTPExtractor`, `HTTPInjector`, and `HTTPPropagator` from the `go.opentelemetry.io/otel/api/propagation` package were replaced with unified `TextMapCarrier` and `TextMapPropagator` in the `go.opentelemetry.io/otel/propagation` package. (#1212) (#1325) - The `New` function from the `go.opentelemetry.io/otel/api/propagation` package was replaced with `NewCompositeTextMapPropagator` in the `go.opentelemetry.io/otel` package. (#1212) - The status codes of the `go.opentelemetry.io/otel/codes` package have been updated to match the latest OpenTelemetry specification. They now are `Unset`, `Error`, and `Ok`. They no longer track the gRPC codes. (#1214) - The `StatusCode` field of the `SpanData` struct in the `go.opentelemetry.io/otel/sdk/export/trace` package now uses the codes package from this package instead of the gRPC project. (#1214) -- Move the `go.opentelemetry.io/otel/api/baggage` package into `go.opentelemetry.io/otel/propagators`. (#1217) +- Move the `go.opentelemetry.io/otel/api/baggage` package into `go.opentelemetry.io/otel/baggage`. (#1217) (#1325) - A `Shutdown` method of `SpanProcessor` and all its implementations receives a context and returns an error. (#1264) ### Fixed @@ -952,7 +997,9 @@ It contains api and sdk for trace and meter. - CODEOWNERS file to track owners of this project. -[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v0.13.0...HEAD +[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v0.15.0...HEAD +[0.15.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.15.0 +[0.14.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.14.0 [0.13.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.13.0 [0.12.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.12.0 [0.11.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.11.0 diff --git a/Makefile b/Makefile index 85506a3b36d..130be713a82 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ TOOLS_MOD_DIR := ./internal/tools # All source code and documents. Used in spell check. ALL_DOCS := $(shell find . -name '*.md' -type f | sort) # All directories with go.mod files related to opentelemetry library. Used for building, testing and linting. -ALL_GO_MOD_DIRS := $(filter-out $(TOOLS_MOD_DIR), $(shell find . -type f -name 'go.mod' -exec dirname {} \; | sort)) +ALL_GO_MOD_DIRS := $(filter-out $(TOOLS_MOD_DIR), $(shell find . -type f -name 'go.mod' -exec dirname {} \; | egrep -v '^./example' | sort)) $(shell find ./example -type f -name 'go.mod' -exec dirname {} \; | sort) ALL_COVERAGE_MOD_DIRS := $(shell find . -type f -name 'go.mod' -exec dirname {} \; | egrep -v '^./example|^$(TOOLS_MOD_DIR)' | sort) # Mac OS Catalina 10.5.x doesn't support 386. Hence skip 386 test diff --git a/Makefile.proto b/Makefile.proto index 417c3b31c47..5e51af3a5c9 100644 --- a/Makefile.proto +++ b/Makefile.proto @@ -13,60 +13,117 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# This Makefile.proto has rules to generate *.pb.go files in -# `exporters/otlp/internal/opentelemetry-proto-gen` from the .proto files in -# `exporters/otlp/internal/opentelemetry-proto` using protoc with a go plugin. +# This Makefile.proto has rules to generate go code for otlp +# exporter. It does it by copying the proto files from +# `exporters/otlp/internal/opentelemetry-proto` (which is a +# submodule that needs to be checked out) into `gen/proto`, changing +# the go_package option to a valid string, generating the go files and +# finally copying the files into the module. The files are not +# generated in place, because protoc generates a too-deep directory +# structure. # -# The protoc binary and other tools are sourced from a docker image -# `PROTOC_IMAGE`. +# Currently, all the generated code is in +# `exporters/otlp/internal/opentelemetry-proto-gen`. # -# Prereqs: The archiving utility `pax` is installed. +# Prereqs: wget (for downloading the zip file with protoc binary), +# unzip (for unpacking the archive), rsync (for copying back the +# generated files). -PROTOC_IMAGE := namely/protoc-all:1.29_2 -PROTOBUF_VERSION := v1 -OTEL_PROTO_SUBMODULE := exporters/otlp/internal/opentelemetry-proto -PROTOBUF_GEN_DIR := exporters/otlp/internal/opentelemetry-proto-gen -PROTOBUF_TEMP_DIR := gen/pb-go -PROTO_SOURCE_DIR := gen/proto -SUBMODULE_PROTO_FILES := $(wildcard $(OTEL_PROTO_SUBMODULE)/opentelemetry/proto/*/$(PROTOBUF_VERSION)/*.proto \ - $(OTEL_PROTO_SUBMODULE)/opentelemetry/proto/collector/*/$(PROTOBUF_VERSION)/*.proto) -SOURCE_PROTO_FILES := $(subst $(OTEL_PROTO_SUBMODULE),$(PROTO_SOURCE_DIR),$(SUBMODULE_PROTO_FILES)) +PROTOC_VERSION := 3.14.0 -default: protobuf +TOOLS_DIR := $(abspath ./.tools) +TOOLS_MOD_DIR := ./internal/tools +PROTOBUF_VERSION := v1 +OTEL_PROTO_SUBMODULE := exporters/otlp/internal/opentelemetry-proto +GEN_TEMP_DIR := gen +SUBMODULE_PROTO_FILES := $(wildcard $(OTEL_PROTO_SUBMODULE)/opentelemetry/proto/*/$(PROTOBUF_VERSION)/*.proto) $(wildcard $(OTEL_PROTO_SUBMODULE)/opentelemetry/proto/collector/*/$(PROTOBUF_VERSION)/*.proto) -.PHONY: protobuf protobuf-source gen-protobuf copy-protobufs -protobuf: protobuf-source gen-protobuf copy-protobufs +ifeq ($(strip $(SUBMODULE_PROTO_FILES)),) +$(error Submodule at $(OTEL_PROTO_SUBMODULE) is not checked out, use "git submodule update --init") +endif -protobuf-source: $(SOURCE_PROTO_FILES) | $(PROTO_SOURCE_DIR)/ +PROTOBUF_GEN_DIR := exporters/otlp/internal/opentelemetry-proto-gen +PROTOBUF_TEMP_DIR := $(GEN_TEMP_DIR)/pb-go +PROTO_SOURCE_DIR := $(GEN_TEMP_DIR)/proto +SOURCE_PROTO_FILES := $(subst $(OTEL_PROTO_SUBMODULE),$(PROTO_SOURCE_DIR),$(SUBMODULE_PROTO_FILES)) -# Changes go_package in .proto file to point to repo-local location -define exec-replace-pkgname -sed 's,go_package = "github.com/open-telemetry/opentelemetry-proto/gen/go,go_package = "go.opentelemetry.io/otel/exporters/otlp/internal/opentelemetry-proto-gen,' < $(1) > $(2) +.DEFAULT_GOAL := protobuf -endef +UNAME_S := $(shell uname -s) +UNAME_M := $(shell uname -m) + +ifeq ($(UNAME_S),Linux) + +PROTOC_OS := linux +PROTOC_ARCH := $(UNAME_M) + +else ifeq ($(UNAME_S),Darwin) + +PROTOC_OS := osx +PROTOC_ARCH := x86_64 + +endif -# replace opentelemetry-proto package name by go.opentelemetry.io/otel specific version -$(SOURCE_PROTO_FILES): $(PROTO_SOURCE_DIR)/%.proto: $(OTEL_PROTO_SUBMODULE)/%.proto - @mkdir -p $(@D) - $(call exec-replace-pkgname,$<,$@) +PROTOC_ZIP_URL := https://github.com/protocolbuffers/protobuf/releases/download/v$(PROTOC_VERSION)/protoc-$(PROTOC_VERSION)-$(PROTOC_OS)-$(PROTOC_ARCH).zip -# Command to run protoc using docker image -define exec-protoc-all -docker run -v `pwd`:/defs $(PROTOC_IMAGE) $(1) +$(TOOLS_DIR)/PROTOC_$(PROTOC_VERSION): + @rm -f "$(TOOLS_DIR)"/PROTOC_* && \ + touch "$@" +# Depend on a versioned file (like PROTOC_3.14.0), so when version +# gets bumped, we will depend on a nonexistent file and thus download +# a newer version. +$(TOOLS_DIR)/protoc/bin/protoc: $(TOOLS_DIR)/PROTOC_$(PROTOC_VERSION) + echo "Fetching protoc $(PROTOC_VERSION)" && \ + rm -rf $(TOOLS_DIR)/protoc && \ + wget -O $(TOOLS_DIR)/protoc.zip $(PROTOC_ZIP_URL) && \ + unzip $(TOOLS_DIR)/protoc.zip -d $(TOOLS_DIR)/protoc-tmp && \ + rm $(TOOLS_DIR)/protoc.zip && \ + touch $(TOOLS_DIR)/protoc-tmp/bin/protoc && \ + mv $(TOOLS_DIR)/protoc-tmp $(TOOLS_DIR)/protoc + +$(TOOLS_DIR)/protoc-gen-gogofast: $(TOOLS_MOD_DIR)/go.mod $(TOOLS_MOD_DIR)/go.sum $(TOOLS_MOD_DIR)/tools.go + cd $(TOOLS_MOD_DIR) && \ + go build -o $(TOOLS_DIR)/protoc-gen-gogofast github.com/gogo/protobuf/protoc-gen-gogofast && \ + go mod tidy + +# Return a sed expression for replacing the go_package option in proto +# file with a one that's valid for us. +# +# Example: $(call get-sed-expr,$(PROTOBUF_GEN_DIR)) +define get-sed-expr +'s,go_package = "github.com/open-telemetry/opentelemetry-proto/gen/go,go_package = "go.opentelemetry.io/otel/$(1),' endef -gen-protobuf: $(SOURCE_PROTO_FILES) | $(PROTOBUF_GEN_DIR)/ - $(foreach file,$(subst ${PROTO_SOURCE_DIR}/,,$(SOURCE_PROTO_FILES)),$(call exec-protoc-all, -i $(PROTO_SOURCE_DIR) -f ${file} -l gogo -o ${PROTOBUF_TEMP_DIR})) +.PHONY: protobuf +protobuf: protobuf-source gen-protobuf copy-protobufs + +.PHONY: protobuf-source +protobuf-source: $(SOURCE_PROTO_FILES) + +# This copies proto files from submodule into $(PROTO_SOURCE_DIR), +# thus satisfying the $(SOURCE_PROTO_FILES) prerequisite. The copies +# have their package name replaced by go.opentelemetry.io/otel. +$(PROTO_SOURCE_DIR)/%.proto: $(OTEL_PROTO_SUBMODULE)/%.proto + @ \ + mkdir -p $(@D); \ + sed -e $(call get-sed-expr,$(PROTOBUF_GEN_DIR)) "$<" >"$@.tmp"; \ + mv "$@.tmp" "$@" -# requires `pax` to be installed, as it has consistent options for both BSD (Darwin) and Linux -copy-protobufs: | $(PROTOBUF_GEN_DIR)/ - find ./$(PROTOBUF_TEMP_DIR)/go.opentelemetry.io/otel/$(PROTOBUF_GEN_DIR) -type f -print0 | \ - pax -0 -s ',^./$(PROTOBUF_TEMP_DIR)/go.opentelemetry.io/otel/$(PROTOBUF_GEN_DIR),,' -rw ./$(PROTOBUF_GEN_DIR) +.PHONY: gen-protobuf +gen-protobuf: $(SOURCE_PROTO_FILES) $(TOOLS_DIR)/protoc-gen-gogofast $(TOOLS_DIR)/protoc/bin/protoc + @ \ + mkdir -p "$(PROTOBUF_TEMP_DIR)"; \ + set -e; for f in $^; do \ + if [[ "$${f}" == $(TOOLS_DIR)/* ]]; then continue; fi; \ + echo "protoc $${f#"$(PROTO_SOURCE_DIR)/"}"; \ + PATH="$(TOOLS_DIR):$${PATH}" $(TOOLS_DIR)/protoc/bin/protoc --proto_path="$(PROTO_SOURCE_DIR)" --gogofast_out="plugins=grpc:$(PROTOBUF_TEMP_DIR)" "$${f}"; \ + done -$(PROTO_SOURCE_DIR)/ $(PROTOBUF_GEN_DIR)/: - mkdir -p $@ +.PHONY: copy-protobufs +copy-protobufs: + @rsync -a $(PROTOBUF_TEMP_DIR)/go.opentelemetry.io/otel/exporters . .PHONY: clean clean: - rm -rf ./gen + rm -rf $(GEN_TEMP_DIR) diff --git a/baggage.go b/baggage/baggage.go similarity index 67% rename from baggage.go rename to baggage/baggage.go index f9c4dc5cfa4..66b8416f1f3 100644 --- a/baggage.go +++ b/baggage/baggage.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package otel // import "go.opentelemetry.io/otel" +package baggage // import "go.opentelemetry.io/otel/baggage" import ( "context" @@ -21,8 +21,8 @@ import ( "go.opentelemetry.io/otel/label" ) -// Baggage returns a copy of the baggage in ctx. -func Baggage(ctx context.Context) label.Set { +// Set returns a copy of the set of baggage key-values in ctx. +func Set(ctx context.Context) label.Set { // TODO (MrAlias, #1222): The underlying storage, the Map, shares many of // the functional elements of the label.Set. These should be unified so // this conversion is unnecessary and there is no performance hit calling @@ -36,32 +36,32 @@ func Baggage(ctx context.Context) label.Set { return label.NewSet(values...) } -// BaggageValue returns the value related to key in the baggage of ctx. If no +// Value returns the value related to key in the baggage of ctx. If no // value is set, the returned label.Value will be an uninitialized zero-value // with type INVALID. -func BaggageValue(ctx context.Context, key label.Key) label.Value { +func Value(ctx context.Context, key label.Key) label.Value { v, _ := baggage.MapFromContext(ctx).Value(key) return v } -// ContextWithBaggageValues returns a copy of parent with pairs updated in the baggage. -func ContextWithBaggageValues(parent context.Context, pairs ...label.KeyValue) context.Context { +// ContextWithValues returns a copy of parent with pairs updated in the baggage. +func ContextWithValues(parent context.Context, pairs ...label.KeyValue) context.Context { m := baggage.MapFromContext(parent).Apply(baggage.MapUpdate{ MultiKV: pairs, }) return baggage.ContextWithMap(parent, m) } -// ContextWithoutBaggageValues returns a copy of parent in which the values related +// ContextWithoutValues returns a copy of parent in which the values related // to keys have been removed from the baggage. -func ContextWithoutBaggageValues(parent context.Context, keys ...label.Key) context.Context { +func ContextWithoutValues(parent context.Context, keys ...label.Key) context.Context { m := baggage.MapFromContext(parent).Apply(baggage.MapUpdate{ DropMultiK: keys, }) return baggage.ContextWithMap(parent, m) } -// ContextWithoutBaggage returns a copy of parent without baggage. -func ContextWithoutBaggage(parent context.Context) context.Context { +// ContextWithEmpty returns a copy of parent without baggage. +func ContextWithEmpty(parent context.Context) context.Context { return baggage.ContextWithNoCorrelationData(parent) } diff --git a/baggage_test.go b/baggage/baggage_test.go similarity index 66% rename from baggage_test.go rename to baggage/baggage_test.go index 3d53b24da2e..f87c3b2b64d 100644 --- a/baggage_test.go +++ b/baggage/baggage_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package otel +package baggage import ( "context" @@ -26,59 +26,59 @@ func TestBaggage(t *testing.T) { ctx := context.Background() ctx = baggage.ContextWithMap(ctx, baggage.NewEmptyMap()) - b := Baggage(ctx) + b := Set(ctx) if b.Len() != 0 { t.Fatalf("empty baggage returned a set with %d elements", b.Len()) } first, second, third := label.Key("first"), label.Key("second"), label.Key("third") - ctx = ContextWithBaggageValues(ctx, first.Bool(true), second.String("2")) + ctx = ContextWithValues(ctx, first.Bool(true), second.String("2")) m := baggage.MapFromContext(ctx) v, ok := m.Value(first) if !ok { - t.Fatal("WithBaggageValues failed to set first value") + t.Fatal("WithValues failed to set first value") } if !v.AsBool() { - t.Fatal("WithBaggageValues failed to set first correct value") + t.Fatal("WithValues failed to set first correct value") } v, ok = m.Value(second) if !ok { - t.Fatal("WithBaggageValues failed to set second value") + t.Fatal("WithValues failed to set second value") } if v.AsString() != "2" { - t.Fatal("WithBaggageValues failed to set second correct value") + t.Fatal("WithValues failed to set second correct value") } _, ok = m.Value(third) if ok { - t.Fatal("WithBaggageValues set an unexpected third value") + t.Fatal("WithValues set an unexpected third value") } - b = Baggage(ctx) + b = Set(ctx) if b.Len() != 2 { t.Fatalf("Baggage returned a set with %d elements, want 2", b.Len()) } - v = BaggageValue(ctx, first) + v = Value(ctx, first) if v.Type() != label.BOOL || !v.AsBool() { - t.Fatal("BaggageValue failed to get correct first value") + t.Fatal("Value failed to get correct first value") } - v = BaggageValue(ctx, second) + v = Value(ctx, second) if v.Type() != label.STRING || v.AsString() != "2" { - t.Fatal("BaggageValue failed to get correct second value") + t.Fatal("Value failed to get correct second value") } - ctx = ContextWithoutBaggageValues(ctx, first) + ctx = ContextWithoutValues(ctx, first) m = baggage.MapFromContext(ctx) _, ok = m.Value(first) if ok { - t.Fatal("WithoutBaggageValues failed to remove a baggage value") + t.Fatal("WithoutValues failed to remove a baggage value") } _, ok = m.Value(second) if !ok { - t.Fatal("WithoutBaggageValues removed incorrect value") + t.Fatal("WithoutValues removed incorrect value") } - ctx = ContextWithoutBaggage(ctx) + ctx = ContextWithEmpty(ctx) m = baggage.MapFromContext(ctx) if m.Len() != 0 { t.Fatal("WithoutBaggage failed to clear baggage") diff --git a/baggage/doc.go b/baggage/doc.go new file mode 100644 index 00000000000..4ac3fccee6c --- /dev/null +++ b/baggage/doc.go @@ -0,0 +1,24 @@ +// 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 baggage provides functionality for storing and retrieving +baggage items in Go context. For propagating the baggage, see the +go.opentelemetry.io/otel/propagation package. + +This package is currently in a pre-GA phase. Backwards incompatible changes +may be introduced in subsequent minor version releases as we work to track the +evolving OpenTelemetry specification and user feedback. +*/ +package baggage // import "go.opentelemetry.io/otel/baggage" diff --git a/bridge/opencensus/README.md b/bridge/opencensus/README.md new file mode 100644 index 00000000000..85c3ddbc69d --- /dev/null +++ b/bridge/opencensus/README.md @@ -0,0 +1,72 @@ +# OpenCensus Bridge + +The OpenCensus Bridge helps facilitate the migration of an application from OpenCensus to OpenTelemetry. + +## The Problem: Mixing OpenCensus and OpenTelemetry libraries + +In a perfect world, one would simply migrate their entire go application --including custom instrumentation, libraries, and exporters-- from OpenCensus to OpenTelemetry all at once. In the real world, dependency constraints, third-party ownership of libraries, or other reasons may require mixing OpenCensus and OpenTelemetry libraries in a single application. + +However, if you create the following spans in a go application: + +```golang +ctx, ocSpan := opencensus.StartSpan(context.Background(), "OuterSpan") +defer ocSpan.End() +ctx, otSpan := opentelemetryTracer.Start(ctx, "MiddleSpan") +defer otSpan.End() +ctx, ocSpan := opencensus.StartSpan(ctx, "InnerSpan") +defer ocSpan.End() +``` + +OpenCensus reports (to OpenCensus exporters): + +``` +[--------OuterSpan------------] + [----InnerSpan------] +``` + +OpenTelemetry reports (to OpenTelemetry exporters): + +``` + [-----MiddleSpan--------] +``` + +Instead, I would prefer (to a single set of exporters): + +``` +[--------OuterSpan------------] + [-----MiddleSpan--------] + [----InnerSpan------] +``` + +### The bridge solution + +The bridge implements the OpenCensus trace API using OpenTelemetry. This would cause, for example, a span recorded with OpenCensus' `StartSpan()` method to be equivalent to recording a span using OpenTelemetry's `tracer.Start()` method. Funneling all tracing API calls to OpenTelemetry APIs results in the desired unified span hierarchy. + +### User Journey + +1. Instantiate OpenTelemetry SDK and Exporters +2. Override OpenCensus' DefaultTracer with the bridge +3. Migrate libraries from OpenCensus to OpenTelemetry +4. Remove OpenCensus Exporters + +To override OpenCensus' DefaultTracer with the bridge: +```golang +import ( + octrace "go.opencensus.io/trace" + "go.opentelemetry.io/otel/bridge/opencensus" + "go.opentelemetry.io/otel" +) + +tracer := otel.GetTracerProvider().Tracer("bridge") +octrace.DefaultTracer = opencensus.NewTracer(tracer) +``` + +Be sure to set the `Tracer` name to your instrumentation package name instead of `"bridge"`. + +### Incompatibilities + +OpenCensus and OpenTelemetry APIs are not entirely compatible. If the bridge finds any incompatibilities, it will log them. Incompatibilities include: + +* Custom OpenCensus Samplers specified during StartSpan are ignored. +* Links cannot be added to OpenCensus spans. +* OpenTelemetry Debug or Deferred trace flags are dropped after an OpenCensus span is created. diff --git a/bridge/opencensus/bridge.go b/bridge/opencensus/bridge.go index 3c4e2840b25..aabcbf1774e 100644 --- a/bridge/opencensus/bridge.go +++ b/bridge/opencensus/bridge.go @@ -20,8 +20,9 @@ import ( octrace "go.opencensus.io/trace" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/bridge/opencensus/utils" "go.opentelemetry.io/otel/codes" - "go.opentelemetry.io/otel/global" "go.opentelemetry.io/otel/label" "go.opentelemetry.io/otel/trace" ) @@ -60,7 +61,7 @@ func convertStartOptions(optFns []octrace.StartOption, name string) []trace.Span } if ocOpts.Sampler != nil { - global.Handle(fmt.Errorf("ignoring custom sampler for span %q created by OpenCensus because OpenTelemetry does not support creating a span with a custom sampler", name)) + otel.Handle(fmt.Errorf("ignoring custom sampler for span %q created by OpenCensus because OpenTelemetry does not support creating a span with a custom sampler", name)) } return otOpts } @@ -68,7 +69,7 @@ func convertStartOptions(optFns []octrace.StartOption, name string) []trace.Span func (o *otelTracer) StartSpanWithRemoteParent(ctx context.Context, name string, parent octrace.SpanContext, s ...octrace.StartOption) (context.Context, *octrace.Span) { // make sure span context is zero'd out so we use the remote parent ctx = trace.ContextWithSpan(ctx, nil) - ctx = trace.ContextWithRemoteSpanContext(ctx, ocSpanContextToOTel(parent)) + ctx = trace.ContextWithRemoteSpanContext(ctx, utils.OCSpanContextToOTel(parent)) return o.StartSpan(ctx, name, s...) } @@ -81,7 +82,7 @@ func (o *otelTracer) NewContext(parent context.Context, s *octrace.Span) context if otSpan, ok := s.Internal().(*span); ok { return trace.ContextWithSpan(parent, otSpan.otSpan) } - global.Handle(fmt.Errorf("unable to create context with span %q, since it was created using a different tracer", s.String())) + otel.Handle(fmt.Errorf("unable to create context with span %q, since it was created using a different tracer", s.String())) return parent } @@ -98,7 +99,7 @@ func (s *span) End() { } func (s *span) SpanContext() octrace.SpanContext { - return otelSpanContextToOc(s.otSpan.SpanContext()) + return utils.OTelSpanContextToOC(s.otSpan.SpanContext()) } func (s *span) SetName(name string) { @@ -181,37 +182,9 @@ func (s *span) AddMessageReceiveEvent(messageID, uncompressedByteSize, compresse } func (s *span) AddLink(l octrace.Link) { - global.Handle(fmt.Errorf("ignoring OpenCensus link %+v for span %q because OpenTelemetry doesn't support setting links after creation", l, s.String())) + otel.Handle(fmt.Errorf("ignoring OpenCensus link %+v for span %q because OpenTelemetry doesn't support setting links after creation", l, s.String())) } func (s *span) String() string { return fmt.Sprintf("span %s", s.otSpan.SpanContext().SpanID.String()) } - -func otelSpanContextToOc(sc trace.SpanContext) octrace.SpanContext { - if sc.IsDebug() || sc.IsDeferred() { - global.Handle(fmt.Errorf("ignoring OpenTelemetry Debug or Deferred trace flags for span %q because they are not supported by OpenCensus", sc.SpanID)) - } - var to octrace.TraceOptions - if sc.IsSampled() { - // OpenCensus doesn't expose functions to directly set sampled - to = 0x1 - } - return octrace.SpanContext{ - TraceID: octrace.TraceID(sc.TraceID), - SpanID: octrace.SpanID(sc.SpanID), - TraceOptions: to, - } -} - -func ocSpanContextToOTel(sc octrace.SpanContext) trace.SpanContext { - var traceFlags byte - if sc.IsSampled() { - traceFlags = trace.FlagsSampled - } - return trace.SpanContext{ - TraceID: trace.TraceID(sc.TraceID), - SpanID: trace.SpanID(sc.SpanID), - TraceFlags: traceFlags, - } -} diff --git a/bridge/opencensus/bridge_test.go b/bridge/opencensus/bridge_test.go index a2cdb5d562c..91b334066e0 100644 --- a/bridge/opencensus/bridge_test.go +++ b/bridge/opencensus/bridge_test.go @@ -20,6 +20,7 @@ import ( octrace "go.opencensus.io/trace" + "go.opentelemetry.io/otel/bridge/opencensus/utils" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/label" "go.opentelemetry.io/otel/oteltest" @@ -101,7 +102,7 @@ func TestStartSpanWithRemoteParent(t *testing.T) { ctx := context.Background() ctx, parent := tracer.Start(ctx, "OpenTelemetrySpan1") - _, span := octrace.StartSpanWithRemoteParent(ctx, "OpenCensusSpan", otelSpanContextToOc(parent.SpanContext())) + _, span := octrace.StartSpanWithRemoteParent(ctx, "OpenCensusSpan", utils.OTelSpanContextToOC(parent.SpanContext())) span.End() spans := sr.Completed() diff --git a/global/doc.go b/bridge/opencensus/doc.go similarity index 63% rename from global/doc.go rename to bridge/opencensus/doc.go index b0c0f248dfc..1705e102b80 100644 --- a/global/doc.go +++ b/bridge/opencensus/doc.go @@ -12,9 +12,5 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package global provides global providers, propagators and more. -// -// This package is currently in a pre-GA phase. Backwards incompatible changes -// may be introduced in subsequent minor version releases as we work to track -// the evolving OpenTelemetry specification and user feedback. -package global // import "go.opentelemetry.io/otel/global" +// Package opencensus provides a migration bridge forwarding the OpenCensus API to the OpenTelemetry SDK. +package opencensus // import "go.opentelemetry.io/otel/bridge/opencensus" diff --git a/bridge/opencensus/go.mod b/bridge/opencensus/go.mod index a9960958414..3cb27e07fd5 100644 --- a/bridge/opencensus/go.mod +++ b/bridge/opencensus/go.mod @@ -1,10 +1,10 @@ -module go.opentelemetry.io/opentelemetry-go/bridge/opencensus +module go.opentelemetry.io/otel/bridge/opencensus -go 1.15 +go 1.14 require ( go.opencensus.io v0.22.6-0.20201102222123-380f4078db9f - go.opentelemetry.io/otel v0.13.0 + go.opentelemetry.io/otel v0.15.0 ) replace go.opentelemetry.io/otel => ../.. diff --git a/bridge/opencensus/go.sum b/bridge/opencensus/go.sum index 3d2eb5226b8..57a8a6fff2c 100644 --- a/bridge/opencensus/go.sum +++ b/bridge/opencensus/go.sum @@ -10,8 +10,8 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/bridge/opencensus/utils/utils.go b/bridge/opencensus/utils/utils.go new file mode 100644 index 00000000000..e12a5450dd5 --- /dev/null +++ b/bridge/opencensus/utils/utils.go @@ -0,0 +1,57 @@ +// 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 utils // import "go.opentelemetry.io/otel/bridge/opencensus/utils" + +import ( + "fmt" + + octrace "go.opencensus.io/trace" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" +) + +// OTelSpanContextToOC converts from an OpenTelemetry SpanContext to an +// OpenCensus SpanContext, and handles any incompatibilities with the global +// error handler. +func OTelSpanContextToOC(sc trace.SpanContext) octrace.SpanContext { + if sc.IsDebug() || sc.IsDeferred() { + otel.Handle(fmt.Errorf("ignoring OpenTelemetry Debug or Deferred trace flags for span %q because they are not supported by OpenCensus", sc.SpanID)) + } + var to octrace.TraceOptions + if sc.IsSampled() { + // OpenCensus doesn't expose functions to directly set sampled + to = 0x1 + } + return octrace.SpanContext{ + TraceID: octrace.TraceID(sc.TraceID), + SpanID: octrace.SpanID(sc.SpanID), + TraceOptions: to, + } +} + +// OCSpanContextToOTel converts from an OpenCensus SpanContext to an +// OpenTelemetry SpanContext. +func OCSpanContextToOTel(sc octrace.SpanContext) trace.SpanContext { + var traceFlags byte + if sc.IsSampled() { + traceFlags = trace.FlagsSampled + } + return trace.SpanContext{ + TraceID: trace.TraceID(sc.TraceID), + SpanID: trace.SpanID(sc.SpanID), + TraceFlags: traceFlags, + } +} diff --git a/bridge/opencensus/utils/utils_test.go b/bridge/opencensus/utils/utils_test.go new file mode 100644 index 00000000000..b2174450306 --- /dev/null +++ b/bridge/opencensus/utils/utils_test.go @@ -0,0 +1,138 @@ +// 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 utils + +import ( + "testing" + + "go.opencensus.io/trace/tracestate" + + octrace "go.opencensus.io/trace" + + "go.opentelemetry.io/otel/trace" +) + +func TestOTelSpanContextToOC(t *testing.T) { + for _, tc := range []struct { + description string + input trace.SpanContext + expected octrace.SpanContext + }{ + { + description: "empty", + }, + { + description: "sampled", + input: trace.SpanContext{ + TraceID: trace.TraceID([16]byte{1}), + SpanID: trace.SpanID([8]byte{2}), + TraceFlags: trace.FlagsSampled, + }, + expected: octrace.SpanContext{ + TraceID: octrace.TraceID([16]byte{1}), + SpanID: octrace.SpanID([8]byte{2}), + TraceOptions: octrace.TraceOptions(0x1), + }, + }, + { + description: "not sampled", + input: trace.SpanContext{ + TraceID: trace.TraceID([16]byte{1}), + SpanID: trace.SpanID([8]byte{2}), + }, + expected: octrace.SpanContext{ + TraceID: octrace.TraceID([16]byte{1}), + SpanID: octrace.SpanID([8]byte{2}), + TraceOptions: octrace.TraceOptions(0), + }, + }, + { + description: "debug flag", + input: trace.SpanContext{ + TraceID: trace.TraceID([16]byte{1}), + SpanID: trace.SpanID([8]byte{2}), + TraceFlags: trace.FlagsDebug, + }, + expected: octrace.SpanContext{ + TraceID: octrace.TraceID([16]byte{1}), + SpanID: octrace.SpanID([8]byte{2}), + TraceOptions: octrace.TraceOptions(0), + }, + }, + } { + t.Run(tc.description, func(t *testing.T) { + output := OTelSpanContextToOC(tc.input) + if output != tc.expected { + t.Fatalf("Got %+v spancontext, exepected %+v.", output, tc.expected) + } + }) + } +} + +func TestOCSpanContextToOTel(t *testing.T) { + for _, tc := range []struct { + description string + input octrace.SpanContext + expected trace.SpanContext + }{ + { + description: "empty", + }, + { + description: "sampled", + input: octrace.SpanContext{ + TraceID: octrace.TraceID([16]byte{1}), + SpanID: octrace.SpanID([8]byte{2}), + TraceOptions: octrace.TraceOptions(0x1), + }, + expected: trace.SpanContext{ + TraceID: trace.TraceID([16]byte{1}), + SpanID: trace.SpanID([8]byte{2}), + TraceFlags: trace.FlagsSampled, + }, + }, + { + description: "not sampled", + input: octrace.SpanContext{ + TraceID: octrace.TraceID([16]byte{1}), + SpanID: octrace.SpanID([8]byte{2}), + TraceOptions: octrace.TraceOptions(0), + }, + expected: trace.SpanContext{ + TraceID: trace.TraceID([16]byte{1}), + SpanID: trace.SpanID([8]byte{2}), + }, + }, + { + description: "trace state is ignored", + input: octrace.SpanContext{ + TraceID: octrace.TraceID([16]byte{1}), + SpanID: octrace.SpanID([8]byte{2}), + Tracestate: &tracestate.Tracestate{}, + }, + expected: trace.SpanContext{ + TraceID: trace.TraceID([16]byte{1}), + SpanID: trace.SpanID([8]byte{2}), + }, + }, + } { + t.Run(tc.description, func(t *testing.T) { + output := OCSpanContextToOTel(tc.input) + if output != tc.expected { + t.Fatalf("Got %+v spancontext, exepected %+v.", output, tc.expected) + } + }) + } +} diff --git a/bridge/opentracing/bridge.go b/bridge/opentracing/bridge.go index 87449f5caaf..5e6e29aa97a 100644 --- a/bridge/opentracing/bridge.go +++ b/bridge/opentracing/bridge.go @@ -26,15 +26,14 @@ import ( otlog "github.com/opentracing/opentracing-go/log" "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/bridge/opentracing/migration" "go.opentelemetry.io/otel/codes" - otelglobal "go.opentelemetry.io/otel/global" "go.opentelemetry.io/otel/internal/baggage" "go.opentelemetry.io/otel/internal/trace/noop" otelparent "go.opentelemetry.io/otel/internal/trace/parent" "go.opentelemetry.io/otel/label" + "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" - - "go.opentelemetry.io/otel/bridge/opentracing/migration" ) type bridgeSpanContext struct { @@ -294,7 +293,7 @@ type BridgeTracer struct { warningHandler BridgeWarningHandler warnOnce sync.Once - propagator otel.TextMapPropagator + propagator propagation.TextMapPropagator } var _ ot.Tracer = &BridgeTracer{} @@ -321,7 +320,7 @@ func (t *BridgeTracer) SetWarningHandler(handler BridgeWarningHandler) { t.warningHandler = handler } -// SetWarningHandler overrides the underlying OpenTelemetry +// SetOpenTelemetryTracer overrides the underlying OpenTelemetry // tracer. The passed tracer should know how to operate in the // environment that uses OpenTracing API. func (t *BridgeTracer) SetOpenTelemetryTracer(tracer trace.Tracer) { @@ -329,7 +328,7 @@ func (t *BridgeTracer) SetOpenTelemetryTracer(tracer trace.Tracer) { t.setTracer.isSet = true } -func (t *BridgeTracer) SetTextMapPropagator(propagator otel.TextMapPropagator) { +func (t *BridgeTracer) SetTextMapPropagator(propagator propagation.TextMapPropagator) { t.propagator = propagator } @@ -651,9 +650,9 @@ func (t *BridgeTracer) Extract(format interface{}, carrier interface{}) (ot.Span return bridgeSC, nil } -func (t *BridgeTracer) getPropagator() otel.TextMapPropagator { +func (t *BridgeTracer) getPropagator() propagation.TextMapPropagator { if t.propagator != nil { return t.propagator } - return otelglobal.TextMapPropagator() + return otel.GetTextMapPropagator() } diff --git a/bridge/opentracing/go.mod b/bridge/opentracing/go.mod index 5b01357b267..08b9d1874e8 100644 --- a/bridge/opentracing/go.mod +++ b/bridge/opentracing/go.mod @@ -6,5 +6,5 @@ replace go.opentelemetry.io/otel => ../.. require ( github.com/opentracing/opentracing-go v1.2.0 - go.opentelemetry.io/otel v0.13.0 + go.opentelemetry.io/otel v0.15.0 ) diff --git a/bridge/opentracing/go.sum b/bridge/opentracing/go.sum index f154add47b3..d24ca0c3d56 100644 --- a/bridge/opentracing/go.sum +++ b/bridge/opentracing/go.sum @@ -1,7 +1,7 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/bridge/opentracing/mix_test.go b/bridge/opentracing/mix_test.go index b6814ae648f..140e8eaa3e8 100644 --- a/bridge/opentracing/mix_test.go +++ b/bridge/opentracing/mix_test.go @@ -21,7 +21,7 @@ import ( ot "github.com/opentracing/opentracing-go" - otelglobal "go.opentelemetry.io/otel/global" + "go.opentelemetry.io/otel" otelbaggage "go.opentelemetry.io/otel/internal/baggage" "go.opentelemetry.io/otel/label" "go.opentelemetry.io/otel/trace" @@ -130,7 +130,7 @@ func TestMixedAPIs(t *testing.T) { t.Log(msg) }) - otelglobal.SetTracerProvider(otelProvider) + otel.SetTracerProvider(otelProvider) ot.SetGlobalTracer(otTracer) tc.setup(t, mockOtelTracer) @@ -440,7 +440,7 @@ func (tm *tracerMessTest) setup(t *testing.T, tracer *internal.MockTracer) { func (tm *tracerMessTest) check(t *testing.T, tracer *internal.MockTracer) { globalOtTracer := ot.GlobalTracer() - globalOtelTracer := otelglobal.Tracer("") + globalOtelTracer := otel.Tracer("") if len(tm.recordedOTSpanTracers) != 3 { t.Errorf("Expected 3 recorded OpenTracing tracers from spans, got %d", len(tm.recordedOTSpanTracers)) } @@ -684,7 +684,7 @@ func min(a, b int) int { } func runOtelOTOtel(t *testing.T, ctx context.Context, name string, callback func(*testing.T, context.Context) context.Context) { - tr := otelglobal.Tracer("") + tr := otel.Tracer("") ctx, span := tr.Start(ctx, fmt.Sprintf("%s_Otel_OTOtel", name), trace.WithSpanKind(trace.SpanKindClient)) defer span.End() ctx = callback(t, ctx) @@ -701,7 +701,7 @@ func runOtelOTOtel(t *testing.T, ctx context.Context, name string, callback func } func runOTOtelOT(t *testing.T, ctx context.Context, name string, callback func(*testing.T, context.Context) context.Context) { - tr := otelglobal.Tracer("") + tr := otel.Tracer("") span, ctx := ot.StartSpanFromContext(ctx, fmt.Sprintf("%s_OT_OtelOT", name), ot.Tag{Key: "span.kind", Value: "client"}) defer span.Finish() ctx = callback(t, ctx) diff --git a/codes/codes.go b/codes/codes.go index 7440e79aff0..064a9279fd1 100644 --- a/codes/codes.go +++ b/codes/codes.go @@ -12,14 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package codes defines the canonical error codes used by OpenTelemetry. -// -// This package is currently in a pre-GA phase. Backwards incompatible changes -// may be introduced in subsequent minor version releases as we work to track -// the evolving OpenTelemetry specification and user feedback. -// -// It conforms to [the OpenTelemetry -// specification](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/api.md#statuscanonicalcode). package codes // import "go.opentelemetry.io/otel/codes" import ( diff --git a/codes/doc.go b/codes/doc.go new file mode 100644 index 00000000000..368f8818fd0 --- /dev/null +++ b/codes/doc.go @@ -0,0 +1,25 @@ +// 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 codes defines the canonical error codes used by OpenTelemetry. + +This package is currently in a pre-GA phase. Backwards incompatible changes +may be introduced in subsequent minor version releases as we work to track +the evolving OpenTelemetry specification and user feedback. + +It conforms to [the OpenTelemetry +specification](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/api.md#statuscanonicalcode). +*/ +package codes // import "go.opentelemetry.io/otel/codes" diff --git a/doc.go b/doc.go index 9a4e206297c..953ab998d47 100644 --- a/doc.go +++ b/doc.go @@ -13,7 +13,8 @@ // limitations under the License. /* -Package otel provides an implementation of the OpenTelemetry API. +Package otel provides global access to the OpenTelemetry API. The subpackages of +the otel package provide an implementation of the OpenTelemetry API. This package is currently in a pre-GA phase. Backwards incompatible changes may be introduced in subsequent minor version releases as we work to track the @@ -25,99 +26,11 @@ 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. -Tracing +To read more about tracing, see go.opentelemetry.io/otel/trace. -To participate in distributed traces a Span needs to be created for the -operation being performed as part of a traced workflow. It its simplest form: +To read more about metrics, see go.opentelemetry.io/otel/metric. - var tracer otel.Tracer - - func init() { - tracer = global.Tracer("instrumentation/package/name") - } - - func operation(ctx context.Context) { - var span trace.Span - ctx, span = tracer.Start(ctx, "operation") - defer span.End() - // ... - } - -A Tracer is unique to the instrumentation and is used to create Spans. -Instrumentation should be designed to accept a TracerProvider from which it -can create its own unique Tracer. Alternatively, the registered global -TracerProvider from the go.opentelemetry.io/otel/global package can be used as -a default. - - const ( - name = "instrumentation/package/name" - version = "0.1.0" - ) - - type Instrumentation struct { - tracer otel.Tracer - } - - func NewInstrumentation(tp otel.TracerProvider) *Instrumentation { - if tp == nil { - tp := global.TracerProvider() - } - return &Instrumentation{ - tracer: tp.Tracer(name, otel.WithTracerVersion(version)), - } - } - - func operation(ctx context.Context, inst *Instrumentation) { - var span trace.Span - ctx, span = inst.tracer.Start(ctx, "operation") - defer span.End() - // ... - } - -Metric Measurements - -Measurements can be made about an operation being performed or the state of a -system in general. These measurements can be crucial to the reliable operation -of code and provide valuable insights about the inner workings of a system. - -Measurements are made using instruments provided by this package. The type of -instrument used will depend on the type of measurement being made and of what -part of a system is being measured. - -Instruments are categorized as Synchronous or Asynchronous and independently -as Adding or Grouping. Synchronous instruments are called by the user with a -Context. Asynchronous instruments are called by the SDK during collection. -Additive instruments are semantically intended for capturing a sum. Grouping -instruments are intended for capturing a distribution. - -Additive instruments may be monotonic, in which case they are non-decreasing -and naturally define a rate. - -The synchronous instrument names are: - - Counter: additive, monotonic - UpDownCounter: additive - ValueRecorder: grouping - -and the asynchronous instruments are: - - SumObserver: additive, monotonic - UpDownSumObserver: additive - ValueObserver: grouping - -All instruments are provided with support for either float64 or int64 input -values. - -An instrument is created using a Meter. Additionally, a Meter is used to -record batches of synchronous measurements or asynchronous observations. A -Meter is obtained using a MeterProvider. A Meter, like a Tracer, is unique to -the instrumentation it instruments and must be named and versioned when -created with a MeterProvider with the name and version of the instrumentation -library. - -Instrumentation should be designed to accept a MeterProvider from which it can -create its own unique Meter. Alternatively, the registered global -MeterProvider from the go.opentelemetry.io/otel/api/global package can be used -as a default. +To read more about propagation, see go.opentelemetry.io/otel/propagation and +go.opentelemetry.io/otel/baggage. */ package otel // import "go.opentelemetry.io/otel" diff --git a/example/basic/go.mod b/example/basic/go.mod index c23043b7e1b..98d07903061 100644 --- a/example/basic/go.mod +++ b/example/basic/go.mod @@ -9,7 +9,7 @@ replace ( ) require ( - go.opentelemetry.io/otel v0.13.0 - go.opentelemetry.io/otel/exporters/stdout v0.13.0 - go.opentelemetry.io/otel/sdk v0.13.0 + go.opentelemetry.io/otel v0.15.0 + go.opentelemetry.io/otel/exporters/stdout v0.15.0 + go.opentelemetry.io/otel/sdk v0.15.0 ) diff --git a/example/basic/go.sum b/example/basic/go.sum index 1680073b00e..ae3c891c195 100644 --- a/example/basic/go.sum +++ b/example/basic/go.sum @@ -4,8 +4,8 @@ github.com/benbjohnson/clock v1.0.3 h1:vkLuvpK4fmtSCuo60+yC63p7y0BmQ8gm5ZXGuBCJy github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/example/basic/main.go b/example/basic/main.go index 93d6fa042c2..20193dad43c 100644 --- a/example/basic/main.go +++ b/example/basic/main.go @@ -19,11 +19,11 @@ import ( "log" "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/baggage" "go.opentelemetry.io/otel/exporters/stdout" - "go.opentelemetry.io/otel/global" "go.opentelemetry.io/otel/label" "go.opentelemetry.io/otel/metric" - "go.opentelemetry.io/otel/propagators" + "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/sdk/metric/controller/push" "go.opentelemetry.io/otel/sdk/metric/processor/basic" "go.opentelemetry.io/otel/sdk/metric/selector/simple" @@ -59,13 +59,13 @@ func main() { ) pusher.Start() defer pusher.Stop() - global.SetTracerProvider(tp) - global.SetMeterProvider(pusher.MeterProvider()) + otel.SetTracerProvider(tp) + otel.SetMeterProvider(pusher.MeterProvider()) // set global propagator to baggage (the default is no-op). - global.SetTextMapPropagator(propagators.Baggage{}) - tracer := global.Tracer("ex.com/basic") - meter := global.Meter("ex.com/basic") + otel.SetTextMapPropagator(propagation.Baggage{}) + tracer := otel.Tracer("ex.com/basic") + meter := otel.Meter("ex.com/basic") commonLabels := []label.KeyValue{lemonsKey.Int(10), label.String("A", "1"), label.String("B", "2"), label.String("C", "3")} @@ -79,7 +79,7 @@ func main() { valuerecorderTwo := metric.Must(meter).NewFloat64ValueRecorder("ex.com.two") ctx := context.Background() - ctx = otel.ContextWithBaggageValues(ctx, fooKey.String("foo1"), barKey.String("bar1")) + ctx = baggage.ContextWithValues(ctx, fooKey.String("foo1"), barKey.String("bar1")) valuerecorder := valuerecorderTwo.Bind(commonLabels...) defer valuerecorder.Unbind() @@ -94,7 +94,7 @@ func main() { meter.RecordBatch( // Note: call-site variables added as context Entries: - otel.ContextWithBaggageValues(ctx, anotherKey.String("xyz")), + baggage.ContextWithValues(ctx, anotherKey.String("xyz")), commonLabels, valuerecorderTwo.Measurement(2.0), diff --git a/example/jaeger/go.mod b/example/jaeger/go.mod index bd142538063..439aebd585c 100644 --- a/example/jaeger/go.mod +++ b/example/jaeger/go.mod @@ -9,7 +9,7 @@ replace ( ) require ( - go.opentelemetry.io/otel v0.13.0 - go.opentelemetry.io/otel/exporters/trace/jaeger v0.13.0 - go.opentelemetry.io/otel/sdk v0.13.0 + go.opentelemetry.io/otel v0.15.0 + go.opentelemetry.io/otel/exporters/trace/jaeger v0.15.0 + go.opentelemetry.io/otel/sdk v0.15.0 ) diff --git a/example/jaeger/go.sum b/example/jaeger/go.sum index 53d77185452..aaa87c97e12 100644 --- a/example/jaeger/go.sum +++ b/example/jaeger/go.sum @@ -89,6 +89,8 @@ github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= diff --git a/example/jaeger/main.go b/example/jaeger/main.go index f1be40b7935..7af58754dc7 100644 --- a/example/jaeger/main.go +++ b/example/jaeger/main.go @@ -20,7 +20,7 @@ import ( "context" "log" - "go.opentelemetry.io/otel/global" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/label" "go.opentelemetry.io/otel/exporters/trace/jaeger" @@ -53,7 +53,7 @@ func main() { flush := initTracer() defer flush() - tr := global.Tracer("component-main") + tr := otel.Tracer("component-main") ctx, span := tr.Start(ctx, "foo") defer span.End() @@ -61,7 +61,7 @@ func main() { } func bar(ctx context.Context) { - tr := global.Tracer("component-bar") + tr := otel.Tracer("component-bar") _, span := tr.Start(ctx, "bar") defer span.End() diff --git a/example/namedtracer/foo/foo.go b/example/namedtracer/foo/foo.go index c8ee668c604..ed2e668dcac 100644 --- a/example/namedtracer/foo/foo.go +++ b/example/namedtracer/foo/foo.go @@ -17,7 +17,7 @@ package foo // import "go.opentelemetry.io/otel/example/namedtracer/foo" import ( "context" - "go.opentelemetry.io/otel/global" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/label" "go.opentelemetry.io/otel/trace" ) @@ -31,7 +31,7 @@ var ( func SubOperation(ctx context.Context) error { // Using global provider. Alternative is to have application provide a getter // for its component to get the instance of the provider. - tr := global.Tracer("example/namedtracer/foo") + tr := otel.Tracer("example/namedtracer/foo") var span trace.Span _, span = tr.Start(ctx, "Sub operation...") diff --git a/example/namedtracer/go.mod b/example/namedtracer/go.mod index ddd0f90ba16..c2b1cf76aa6 100644 --- a/example/namedtracer/go.mod +++ b/example/namedtracer/go.mod @@ -9,7 +9,7 @@ replace ( ) require ( - go.opentelemetry.io/otel v0.13.0 - go.opentelemetry.io/otel/exporters/stdout v0.13.0 - go.opentelemetry.io/otel/sdk v0.13.0 + go.opentelemetry.io/otel v0.15.0 + go.opentelemetry.io/otel/exporters/stdout v0.15.0 + go.opentelemetry.io/otel/sdk v0.15.0 ) diff --git a/example/namedtracer/go.sum b/example/namedtracer/go.sum index 1680073b00e..ae3c891c195 100644 --- a/example/namedtracer/go.sum +++ b/example/namedtracer/go.sum @@ -4,8 +4,8 @@ github.com/benbjohnson/clock v1.0.3 h1:vkLuvpK4fmtSCuo60+yC63p7y0BmQ8gm5ZXGuBCJy github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/example/namedtracer/main.go b/example/namedtracer/main.go index 75995ee75cc..471b44ed2e6 100644 --- a/example/namedtracer/main.go +++ b/example/namedtracer/main.go @@ -19,9 +19,9 @@ import ( "log" "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/baggage" "go.opentelemetry.io/otel/example/namedtracer/foo" "go.opentelemetry.io/otel/exporters/stdout" - "go.opentelemetry.io/otel/global" "go.opentelemetry.io/otel/label" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" @@ -52,7 +52,7 @@ func initTracer() { ), sdktrace.WithSpanProcessor(bsp), ) - global.SetTracerProvider(tp) + otel.SetTracerProvider(tp) } func main() { @@ -63,7 +63,7 @@ func main() { tracer := tp.Tracer("example/namedtracer/main") ctx := context.Background() defer func() { _ = tp.Shutdown(ctx) }() - ctx = otel.ContextWithBaggageValues(ctx, fooKey.String("foo1"), barKey.String("bar1")) + ctx = baggage.ContextWithValues(ctx, fooKey.String("foo1"), barKey.String("bar1")) var span trace.Span ctx, span = tracer.Start(ctx, "operation") diff --git a/example/opencensus/go.mod b/example/opencensus/go.mod new file mode 100644 index 00000000000..70c49202889 --- /dev/null +++ b/example/opencensus/go.mod @@ -0,0 +1,18 @@ +module go.opentelemetry.io/otel/example/opencensus + +go 1.14 + +replace ( + go.opentelemetry.io/otel => ../.. + go.opentelemetry.io/otel/bridge/opencensus => ../../bridge/opencensus + go.opentelemetry.io/otel/exporters/stdout => ../../exporters/stdout + go.opentelemetry.io/otel/sdk => ../../sdk +) + +require ( + go.opencensus.io v0.22.6-0.20201102222123-380f4078db9f + go.opentelemetry.io/otel v0.15.0 + go.opentelemetry.io/otel/bridge/opencensus v0.15.0 + go.opentelemetry.io/otel/exporters/stdout v0.15.0 + go.opentelemetry.io/otel/sdk v0.15.0 +) diff --git a/example/opencensus/go.sum b/example/opencensus/go.sum new file mode 100644 index 00000000000..0f352e86792 --- /dev/null +++ b/example/opencensus/go.sum @@ -0,0 +1,65 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/DataDog/sketches-go v0.0.1 h1:RtG+76WKgZuz6FIaGsjoPePmadDBkuD/KC6+ZWu78b8= +github.com/DataDog/sketches-go v0.0.1/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60= +github.com/benbjohnson/clock v1.0.3 h1:vkLuvpK4fmtSCuo60+yC63p7y0BmQ8gm5ZXGuBCJyXg= +github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +go.opencensus.io v0.22.6-0.20201102222123-380f4078db9f h1:IUmbcoP9XyEXW+R9AbrZgDvaYVfTbISN92Y5RIV+Mx4= +go.opencensus.io v0.22.6-0.20201102222123-380f4078db9f/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/example/opencensus/main.go b/example/opencensus/main.go new file mode 100644 index 00000000000..8e1b828ac88 --- /dev/null +++ b/example/opencensus/main.go @@ -0,0 +1,58 @@ +// 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 main // import "go.opentelemetry.io/otel/bridge/opencensus/examples/simple" + +import ( + "context" + "log" + + octrace "go.opencensus.io/trace" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/bridge/opencensus" + "go.opentelemetry.io/otel/exporters/stdout" + sdktrace "go.opentelemetry.io/otel/sdk/trace" +) + +func main() { + ctx := context.Background() + + log.Println("Configuring OpenCensus. Not Registering any OpenCensus exporters.") + octrace.ApplyConfig(octrace.Config{DefaultSampler: octrace.AlwaysSample()}) + + log.Println("Registering OpenTelemetry stdout exporter.") + otExporter, err := stdout.NewExporter(stdout.WithPrettyPrint()) + if err != nil { + log.Fatal(err) + } + tp := sdktrace.NewTracerProvider(sdktrace.WithSyncer(otExporter)) + otel.SetTracerProvider(tp) + + log.Println("Installing the OpenCensus bridge to make OpenCensus libraries write spans using OpenTelemetry.") + tracer := tp.Tracer("simple") + octrace.DefaultTracer = opencensus.NewTracer(tracer) + + log.Println("Creating OpenCensus span, which should be printed out using the OpenTelemetry stdout exporter.\n-- It should have no parent, since it is the first span.") + ctx, outerOCSpan := octrace.StartSpan(ctx, "OpenCensusOuterSpan") + outerOCSpan.End() + + log.Println("Creating OpenTelemetry span\n-- It should have the OpenCensus span as a parent, since the OpenCensus span was written with using OpenTelemetry APIs.") + ctx, otspan := tracer.Start(ctx, "OpenTelemetrySpan") + otspan.End() + + log.Println("Creating OpenCensus span, which should be printed out using the OpenTelemetry stdout exporter.\n-- It should have the OpenTelemetry span as a parent, since it was written using OpenTelemetry APIs") + _, innerOCSpan := octrace.StartSpan(ctx, "OpenCensusInnerSpan") + innerOCSpan.End() +} diff --git a/example/otel-collector/README.md b/example/otel-collector/README.md index 5a2157a6901..b00baf15838 100644 --- a/example/otel-collector/README.md +++ b/example/otel-collector/README.md @@ -7,7 +7,7 @@ The complete flow is: ``` -----> Jaeger (trace) -App + SDK ---> OpenTelemtry Collector ---| +App + SDK ---> OpenTelemetry Collector ---| -----> Prometheus (metrics) ``` diff --git a/example/otel-collector/go.mod b/example/otel-collector/go.mod index d73becfe397..57746df3795 100644 --- a/example/otel-collector/go.mod +++ b/example/otel-collector/go.mod @@ -9,8 +9,8 @@ replace ( ) require ( - go.opentelemetry.io/otel v0.13.0 - go.opentelemetry.io/otel/exporters/otlp v0.13.0 - go.opentelemetry.io/otel/sdk v0.13.0 + go.opentelemetry.io/otel v0.15.0 + go.opentelemetry.io/otel/exporters/otlp v0.15.0 + go.opentelemetry.io/otel/sdk v0.15.0 google.golang.org/grpc v1.32.0 ) diff --git a/example/otel-collector/go.sum b/example/otel-collector/go.sum index 0e57b4604c7..b6ddbb33ead 100644 --- a/example/otel-collector/go.sum +++ b/example/otel-collector/go.sum @@ -32,8 +32,8 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= diff --git a/example/otel-collector/main.go b/example/otel-collector/main.go index 732a31e165e..a2452f87485 100644 --- a/example/otel-collector/main.go +++ b/example/otel-collector/main.go @@ -25,11 +25,11 @@ import ( "google.golang.org/grpc" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/otlp" - "go.opentelemetry.io/otel/global" "go.opentelemetry.io/otel/label" "go.opentelemetry.io/otel/metric" - "go.opentelemetry.io/otel/propagators" + "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/sdk/metric/controller/push" "go.opentelemetry.io/otel/sdk/metric/processor/basic" "go.opentelemetry.io/otel/sdk/metric/selector/simple" @@ -49,7 +49,7 @@ func initProvider() func() { // `localhost:30080` address. Otherwise, replace `localhost` with the // address of your cluster. If you run the app inside k8s, then you can // probably connect directly to the service through dns - exp, err := otlp.NewExporter( + exp, err := otlp.NewExporter(ctx, otlp.WithInsecure(), otlp.WithAddress("localhost:30080"), otlp.WithGRPCDialOption(grpc.WithBlock()), // useful for testing @@ -81,9 +81,9 @@ func initProvider() func() { ) // set global propagator to tracecontext (the default is no-op). - global.SetTextMapPropagator(propagators.TraceContext{}) - global.SetTracerProvider(tracerProvider) - global.SetMeterProvider(pusher.MeterProvider()) + otel.SetTextMapPropagator(propagation.TraceContext{}) + otel.SetTracerProvider(tracerProvider) + otel.SetMeterProvider(pusher.MeterProvider()) pusher.Start() return func() { @@ -99,8 +99,8 @@ func main() { shutdown := initProvider() defer shutdown() - tracer := global.Tracer("test-tracer") - meter := global.Meter("test-meter") + tracer := otel.Tracer("test-tracer") + meter := otel.Meter("test-meter") // labels represent additional key-value descriptors that can be bound to a // metric observer or recorder. diff --git a/example/prometheus/go.mod b/example/prometheus/go.mod index 4fc56c66bae..d5a94e775ea 100644 --- a/example/prometheus/go.mod +++ b/example/prometheus/go.mod @@ -9,6 +9,6 @@ replace ( ) require ( - go.opentelemetry.io/otel v0.13.0 - go.opentelemetry.io/otel/exporters/metric/prometheus v0.13.0 + go.opentelemetry.io/otel v0.15.0 + go.opentelemetry.io/otel/exporters/metric/prometheus v0.15.0 ) diff --git a/example/prometheus/go.sum b/example/prometheus/go.sum index f9ba40180fd..5ad64efdd1b 100644 --- a/example/prometheus/go.sum +++ b/example/prometheus/go.sum @@ -34,8 +34,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= diff --git a/example/prometheus/main.go b/example/prometheus/main.go index b3208da51d4..54f2209e4e4 100644 --- a/example/prometheus/main.go +++ b/example/prometheus/main.go @@ -22,8 +22,8 @@ import ( "sync" "time" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/metric/prometheus" - "go.opentelemetry.io/otel/global" "go.opentelemetry.io/otel/label" "go.opentelemetry.io/otel/metric" ) @@ -48,7 +48,7 @@ func initMeter() { func main() { initMeter() - meter := global.Meter("ex.com/basic") + meter := otel.Meter("ex.com/basic") observerLock := new(sync.RWMutex) observerValueToReport := new(float64) observerLabelsToReport := new([]label.KeyValue) diff --git a/example/zipkin/go.mod b/example/zipkin/go.mod index a0ee3cc5dee..b4b1e160ff1 100644 --- a/example/zipkin/go.mod +++ b/example/zipkin/go.mod @@ -9,7 +9,7 @@ replace ( ) require ( - go.opentelemetry.io/otel v0.13.0 - go.opentelemetry.io/otel/exporters/trace/zipkin v0.13.0 - go.opentelemetry.io/otel/sdk v0.13.0 + go.opentelemetry.io/otel v0.15.0 + go.opentelemetry.io/otel/exporters/trace/zipkin v0.15.0 + go.opentelemetry.io/otel/sdk v0.15.0 ) diff --git a/example/zipkin/go.sum b/example/zipkin/go.sum index 604b91818f0..d226056d1ae 100644 --- a/example/zipkin/go.sum +++ b/example/zipkin/go.sum @@ -38,8 +38,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= diff --git a/example/zipkin/main.go b/example/zipkin/main.go index 202253ee923..15266b78763 100644 --- a/example/zipkin/main.go +++ b/example/zipkin/main.go @@ -23,8 +23,7 @@ import ( "os" "time" - "go.opentelemetry.io/otel/global" - + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/trace/zipkin" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) @@ -57,7 +56,7 @@ func main() { ctx := context.Background() - tr := global.TracerProvider().Tracer("component-main") + tr := otel.GetTracerProvider().Tracer("component-main") ctx, span := tr.Start(ctx, "foo") <-time.After(6 * time.Millisecond) bar(ctx) @@ -69,7 +68,7 @@ func main() { } func bar(ctx context.Context) { - tr := global.TracerProvider().Tracer("component-bar") + tr := otel.GetTracerProvider().Tracer("component-bar") _, span := tr.Start(ctx, "bar") <-time.After(6 * time.Millisecond) span.End() diff --git a/exporters/metric/prometheus/go.mod b/exporters/metric/prometheus/go.mod index 86e51041716..04acb8b4427 100644 --- a/exporters/metric/prometheus/go.mod +++ b/exporters/metric/prometheus/go.mod @@ -10,6 +10,6 @@ replace ( require ( github.com/prometheus/client_golang v1.7.1 github.com/stretchr/testify v1.6.1 - go.opentelemetry.io/otel v0.13.0 - go.opentelemetry.io/otel/sdk v0.13.0 + go.opentelemetry.io/otel v0.15.0 + go.opentelemetry.io/otel/sdk v0.15.0 ) diff --git a/exporters/metric/prometheus/go.sum b/exporters/metric/prometheus/go.sum index f9ba40180fd..5ad64efdd1b 100644 --- a/exporters/metric/prometheus/go.sum +++ b/exporters/metric/prometheus/go.sum @@ -34,8 +34,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= diff --git a/exporters/metric/prometheus/prometheus.go b/exporters/metric/prometheus/prometheus.go index 811b82c4674..a12a8ff3c48 100644 --- a/exporters/metric/prometheus/prometheus.go +++ b/exporters/metric/prometheus/prometheus.go @@ -23,7 +23,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" - "go.opentelemetry.io/otel/global" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/label" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric/number" @@ -135,7 +135,7 @@ func InstallNewPipeline(config Config, options ...pull.Option) (*Exporter, error if err != nil { return nil, err } - global.SetMeterProvider(exp.MeterProvider()) + otel.SetMeterProvider(exp.MeterProvider()) return exp, nil } @@ -209,7 +209,7 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) { ctrl := c.exp.Controller() if err := ctrl.Collect(context.Background()); err != nil { - global.Handle(err) + otel.Handle(err) } err := ctrl.ForEach(c.exp, func(record export.Record) error { @@ -254,7 +254,7 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) { return nil }) if err != nil { - global.Handle(err) + otel.Handle(err) } } diff --git a/exporters/otlp/alignment_test.go b/exporters/otlp/alignment_test.go index f20a0bd1b2d..276625637a1 100644 --- a/exporters/otlp/alignment_test.go +++ b/exporters/otlp/alignment_test.go @@ -26,8 +26,8 @@ import ( func TestMain(m *testing.M) { fields := []ottest.FieldOffset{ { - Name: "Exporter.lastConnectErrPtr", - Offset: unsafe.Offsetof(Exporter{}.lastConnectErrPtr), + Name: "grpcConnection.lastConnectErrPtr", + Offset: unsafe.Offsetof(grpcConnection{}.lastConnectErrPtr), }, } if !ottest.Aligned8Byte(fields, os.Stderr) { diff --git a/exporters/otlp/connection.go b/exporters/otlp/connection.go index 48c799c80e2..283d6d42d55 100644 --- a/exporters/otlp/connection.go +++ b/exporters/otlp/connection.go @@ -15,52 +15,113 @@ package otlp // import "go.opentelemetry.io/otel/exporters/otlp" import ( + "context" + "fmt" "math/rand" + "sync" "sync/atomic" "time" "unsafe" + + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" ) -func (e *Exporter) lastConnectError() error { - errPtr := (*error)(atomic.LoadPointer(&e.lastConnectErrPtr)) +type grpcConnection struct { + // Ensure pointer is 64-bit aligned for atomic operations on both 32 and 64 bit machines. + lastConnectErrPtr unsafe.Pointer + + // mu protects the connection as it is accessed by the + // exporter goroutines and background connection goroutine + mu sync.Mutex + cc *grpc.ClientConn + + // these fields are read-only after constructor is finished + c config + metadata metadata.MD + newConnectionHandler func(cc *grpc.ClientConn) error + + // these channels are created once + disconnectedCh chan bool + backgroundConnectionDoneCh chan struct{} + stopCh chan struct{} + + // this is for tests, so they can replace the closing + // routine without a worry of modifying some global variable + // or changing it back to original after the test is done + closeBackgroundConnectionDoneCh func(ch chan struct{}) +} + +func newGRPCConnection(c config, handler func(cc *grpc.ClientConn) error) *grpcConnection { + conn := new(grpcConnection) + conn.newConnectionHandler = handler + if c.collectorAddr == "" { + c.collectorAddr = fmt.Sprintf("%s:%d", DefaultCollectorHost, DefaultCollectorPort) + } + conn.c = c + if len(conn.c.headers) > 0 { + conn.metadata = metadata.New(conn.c.headers) + } + conn.closeBackgroundConnectionDoneCh = func(ch chan struct{}) { + close(ch) + } + return conn +} + +func (oc *grpcConnection) startConnection(ctx context.Context) { + oc.stopCh = make(chan struct{}) + oc.disconnectedCh = make(chan bool) + oc.backgroundConnectionDoneCh = make(chan struct{}) + + if err := oc.connect(ctx); err == nil { + oc.setStateConnected() + } else { + oc.setStateDisconnected(err) + } + go oc.indefiniteBackgroundConnection() +} + +func (oc *grpcConnection) lastConnectError() error { + errPtr := (*error)(atomic.LoadPointer(&oc.lastConnectErrPtr)) if errPtr == nil { return nil } return *errPtr } -func (e *Exporter) saveLastConnectError(err error) { +func (oc *grpcConnection) saveLastConnectError(err error) { var errPtr *error if err != nil { errPtr = &err } - atomic.StorePointer(&e.lastConnectErrPtr, unsafe.Pointer(errPtr)) + atomic.StorePointer(&oc.lastConnectErrPtr, unsafe.Pointer(errPtr)) } -func (e *Exporter) setStateDisconnected(err error) { - e.saveLastConnectError(err) +func (oc *grpcConnection) setStateDisconnected(err error) { + oc.saveLastConnectError(err) select { - case e.disconnectedCh <- true: + case oc.disconnectedCh <- true: default: } + _ = oc.newConnectionHandler(nil) } -func (e *Exporter) setStateConnected() { - e.saveLastConnectError(nil) +func (oc *grpcConnection) setStateConnected() { + oc.saveLastConnectError(nil) } -func (e *Exporter) connected() bool { - return e.lastConnectError() == nil +func (oc *grpcConnection) connected() bool { + return oc.lastConnectError() == nil } const defaultConnReattemptPeriod = 10 * time.Second -func (e *Exporter) indefiniteBackgroundConnection() { +func (oc *grpcConnection) indefiniteBackgroundConnection() { defer func() { - e.backgroundConnectionDoneCh <- true + oc.closeBackgroundConnectionDoneCh(oc.backgroundConnectionDoneCh) }() - connReattemptPeriod := e.c.reconnectionPeriod + connReattemptPeriod := oc.c.reconnectionPeriod if connReattemptPeriod <= 0 { connReattemptPeriod = defaultConnReattemptPeriod } @@ -79,17 +140,26 @@ func (e *Exporter) indefiniteBackgroundConnection() { // 2. Otherwise block until we are disconnected, and // then retry connecting select { - case <-e.stopCh: + case <-oc.stopCh: return - case <-e.disconnectedCh: + case <-oc.disconnectedCh: + // Quickly check if we haven't stopped at the + // same time. + select { + case <-oc.stopCh: + return + + default: + } + // Normal scenario that we'll wait for } - if err := e.connect(); err == nil { - e.setStateConnected() + if err := oc.connect(context.Background()); err == nil { + oc.setStateConnected() } else { - e.setStateDisconnected(err) + oc.setStateDisconnected(err) } // Apply some jitter to avoid lockstep retrials of other @@ -97,17 +167,110 @@ func (e *Exporter) indefiniteBackgroundConnection() { // innocent DDOS, by clogging the machine's resources and network. jitter := time.Duration(rng.Int63n(maxJitterNanos)) select { - case <-e.stopCh: + case <-oc.stopCh: return case <-time.After(connReattemptPeriod + jitter): } } } -func (e *Exporter) connect() error { - cc, err := e.dialToCollector() +func (oc *grpcConnection) connect(ctx context.Context) error { + cc, err := oc.dialToCollector(ctx) if err != nil { return err } - return e.enableConnections(cc) + oc.setConnection(cc) + return oc.newConnectionHandler(cc) +} + +// setConnection sets cc as the client connection and returns true if +// the connection state changed. +func (oc *grpcConnection) setConnection(cc *grpc.ClientConn) bool { + oc.mu.Lock() + defer oc.mu.Unlock() + + // If previous clientConn is same as the current then just return. + // This doesn't happen right now as this func is only called with new ClientConn. + // It is more about future-proofing. + if oc.cc == cc { + return false + } + + // If the previous clientConn was non-nil, close it + if oc.cc != nil { + _ = oc.cc.Close() + } + oc.cc = cc + return true +} + +func (oc *grpcConnection) dialToCollector(ctx context.Context) (*grpc.ClientConn, error) { + addr := oc.c.collectorAddr + + dialOpts := []grpc.DialOption{} + if oc.c.grpcServiceConfig != "" { + dialOpts = append(dialOpts, grpc.WithDefaultServiceConfig(oc.c.grpcServiceConfig)) + } + if oc.c.clientCredentials != nil { + dialOpts = append(dialOpts, grpc.WithTransportCredentials(oc.c.clientCredentials)) + } else if oc.c.canDialInsecure { + dialOpts = append(dialOpts, grpc.WithInsecure()) + } + if oc.c.compressor != "" { + dialOpts = append(dialOpts, grpc.WithDefaultCallOptions(grpc.UseCompressor(oc.c.compressor))) + } + if len(oc.c.grpcDialOptions) != 0 { + dialOpts = append(dialOpts, oc.c.grpcDialOptions...) + } + + ctx, cancel := oc.contextWithStop(ctx) + defer cancel() + ctx = oc.contextWithMetadata(ctx) + return grpc.DialContext(ctx, addr, dialOpts...) +} + +func (oc *grpcConnection) contextWithMetadata(ctx context.Context) context.Context { + if oc.metadata.Len() > 0 { + return metadata.NewOutgoingContext(ctx, oc.metadata) + } + return ctx +} + +func (oc *grpcConnection) shutdown(ctx context.Context) error { + close(oc.stopCh) + // Ensure that the backgroundConnector returns + select { + case <-oc.backgroundConnectionDoneCh: + case <-ctx.Done(): + return ctx.Err() + } + + close(oc.disconnectedCh) + + oc.mu.Lock() + cc := oc.cc + oc.cc = nil + oc.mu.Unlock() + + if cc != nil { + return cc.Close() + } + + return nil +} + +func (oc *grpcConnection) contextWithStop(ctx context.Context) (context.Context, context.CancelFunc) { + // Unify the parent context Done signal with the connection's + // stop channel. + ctx, cancel := context.WithCancel(ctx) + go func(ctx context.Context, cancel context.CancelFunc) { + select { + case <-ctx.Done(): + // Nothing to do, either cancelled or deadline + // happened. + case <-oc.stopCh: + cancel() + } + }(ctx, cancel) + return ctx, cancel } diff --git a/exporters/otlp/example_test.go b/exporters/otlp/example_test.go index e3bae99cf60..a34811e25e2 100644 --- a/exporters/otlp/example_test.go +++ b/exporters/otlp/example_test.go @@ -22,21 +22,22 @@ import ( "google.golang.org/grpc/credentials" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/otlp" - "go.opentelemetry.io/otel/global" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) func Example_insecure() { - exp, err := otlp.NewExporter(otlp.WithInsecure()) + ctx := context.Background() + exp, err := otlp.NewExporter(ctx, otlp.WithInsecure()) if err != nil { log.Fatalf("Failed to create the collector exporter: %v", err) } defer func() { - ctx, cancel := context.WithTimeout(context.Background(), time.Second) + ctx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() if err := exp.Shutdown(ctx); err != nil { - global.Handle(err) + otel.Handle(err) } }() @@ -49,12 +50,12 @@ func Example_insecure() { sdktrace.WithMaxExportBatchSize(10), ), ) - global.SetTracerProvider(tp) + otel.SetTracerProvider(tp) - tracer := global.Tracer("test-tracer") + tracer := otel.Tracer("test-tracer") // Then use the OpenTelemetry tracing library, like we normally would. - ctx, span := tracer.Start(context.Background(), "CollectorExporter-Example") + ctx, span := tracer.Start(ctx, "CollectorExporter-Example") defer span.End() for i := 0; i < 10; i++ { @@ -72,15 +73,16 @@ func Example_withTLS() { log.Fatalf("failed to create gRPC client TLS credentials: %v", err) } - exp, err := otlp.NewExporter(otlp.WithTLSCredentials(creds)) + ctx := context.Background() + exp, err := otlp.NewExporter(ctx, otlp.WithTLSCredentials(creds)) if err != nil { log.Fatalf("failed to create the collector exporter: %v", err) } defer func() { - ctx, cancel := context.WithTimeout(context.Background(), time.Second) + ctx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() if err := exp.Shutdown(ctx); err != nil { - global.Handle(err) + otel.Handle(err) } }() @@ -93,12 +95,12 @@ func Example_withTLS() { sdktrace.WithMaxExportBatchSize(10), ), ) - global.SetTracerProvider(tp) + otel.SetTracerProvider(tp) - tracer := global.Tracer("test-tracer") + tracer := otel.Tracer("test-tracer") // Then use the OpenTelemetry tracing library, like we normally would. - ctx, span := tracer.Start(context.Background(), "Securely-Talking-To-Collector-Span") + ctx, span := tracer.Start(ctx, "Securely-Talking-To-Collector-Span") defer span.End() for i := 0; i < 10; i++ { diff --git a/exporters/otlp/go.mod b/exporters/otlp/go.mod index 4a4f097e22f..5f30f92e938 100644 --- a/exporters/otlp/go.mod +++ b/exporters/otlp/go.mod @@ -10,10 +10,10 @@ replace ( require ( github.com/gogo/protobuf v1.3.1 github.com/golang/protobuf v1.4.2 // indirect - github.com/google/go-cmp v0.5.2 + github.com/google/go-cmp v0.5.4 github.com/stretchr/testify v1.6.1 - go.opentelemetry.io/otel v0.13.0 - go.opentelemetry.io/otel/sdk v0.13.0 + go.opentelemetry.io/otel v0.15.0 + go.opentelemetry.io/otel/sdk v0.15.0 golang.org/x/net v0.0.0-20191002035440-2ec189313ef0 // indirect google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884 // indirect google.golang.org/grpc v1.32.0 diff --git a/exporters/otlp/go.sum b/exporters/otlp/go.sum index b9f8e227791..467779a83ee 100644 --- a/exporters/otlp/go.sum +++ b/exporters/otlp/go.sum @@ -31,8 +31,8 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= diff --git a/exporters/otlp/internal/opentelemetry-proto b/exporters/otlp/internal/opentelemetry-proto index 313a868be25..59c488bfb8f 160000 --- a/exporters/otlp/internal/opentelemetry-proto +++ b/exporters/otlp/internal/opentelemetry-proto @@ -1 +1 @@ -Subproject commit 313a868be259dce6c6516dd417d3ad5fd3321acf +Subproject commit 59c488bfb8fb6d0458ad6425758b70259ff4a2bd diff --git a/exporters/otlp/internal/opentelemetry-proto-gen/collector/trace/v1/trace_config.pb.go b/exporters/otlp/internal/opentelemetry-proto-gen/collector/trace/v1/trace_config.pb.go index da1bb875198..4b88106bf6e 100644 --- a/exporters/otlp/internal/opentelemetry-proto-gen/collector/trace/v1/trace_config.pb.go +++ b/exporters/otlp/internal/opentelemetry-proto-gen/collector/trace/v1/trace_config.pb.go @@ -62,7 +62,7 @@ type TraceConfig struct { // // Types that are valid to be assigned to Sampler: // *TraceConfig_ConstantSampler - // *TraceConfig_ProbabilitySampler + // *TraceConfig_TraceIdRatioBased // *TraceConfig_RateLimitingSampler Sampler isTraceConfig_Sampler `protobuf_oneof:"sampler"` // The global default max number of attributes per span. @@ -122,15 +122,15 @@ type isTraceConfig_Sampler interface { type TraceConfig_ConstantSampler struct { ConstantSampler *ConstantSampler `protobuf:"bytes,1,opt,name=constant_sampler,json=constantSampler,proto3,oneof" json:"constant_sampler,omitempty"` } -type TraceConfig_ProbabilitySampler struct { - ProbabilitySampler *ProbabilitySampler `protobuf:"bytes,2,opt,name=probability_sampler,json=probabilitySampler,proto3,oneof" json:"probability_sampler,omitempty"` +type TraceConfig_TraceIdRatioBased struct { + TraceIdRatioBased *TraceIdRatioBased `protobuf:"bytes,2,opt,name=trace_id_ratio_based,json=traceIdRatioBased,proto3,oneof" json:"trace_id_ratio_based,omitempty"` } type TraceConfig_RateLimitingSampler struct { RateLimitingSampler *RateLimitingSampler `protobuf:"bytes,3,opt,name=rate_limiting_sampler,json=rateLimitingSampler,proto3,oneof" json:"rate_limiting_sampler,omitempty"` } func (*TraceConfig_ConstantSampler) isTraceConfig_Sampler() {} -func (*TraceConfig_ProbabilitySampler) isTraceConfig_Sampler() {} +func (*TraceConfig_TraceIdRatioBased) isTraceConfig_Sampler() {} func (*TraceConfig_RateLimitingSampler) isTraceConfig_Sampler() {} func (m *TraceConfig) GetSampler() isTraceConfig_Sampler { @@ -147,9 +147,9 @@ func (m *TraceConfig) GetConstantSampler() *ConstantSampler { return nil } -func (m *TraceConfig) GetProbabilitySampler() *ProbabilitySampler { - if x, ok := m.GetSampler().(*TraceConfig_ProbabilitySampler); ok { - return x.ProbabilitySampler +func (m *TraceConfig) GetTraceIdRatioBased() *TraceIdRatioBased { + if x, ok := m.GetSampler().(*TraceConfig_TraceIdRatioBased); ok { + return x.TraceIdRatioBased } return nil } @@ -200,7 +200,7 @@ func (m *TraceConfig) GetMaxNumberOfAttributesPerLink() int64 { func (*TraceConfig) XXX_OneofWrappers() []interface{} { return []interface{}{ (*TraceConfig_ConstantSampler)(nil), - (*TraceConfig_ProbabilitySampler)(nil), + (*TraceConfig_TraceIdRatioBased)(nil), (*TraceConfig_RateLimitingSampler)(nil), } } @@ -253,28 +253,28 @@ func (m *ConstantSampler) GetDecision() ConstantSampler_ConstantDecision { return ConstantSampler_ALWAYS_OFF } -// Sampler that tries to uniformly sample traces with a given probability. -// The probability of sampling a trace is equal to that of the specified probability. -type ProbabilitySampler struct { - // The desired probability of sampling. Must be within [0.0, 1.0]. - SamplingProbability float64 `protobuf:"fixed64,1,opt,name=samplingProbability,proto3" json:"samplingProbability,omitempty"` +// Sampler that tries to uniformly sample traces with a given ratio. +// The ratio of sampling a trace is equal to that of the specified ratio. +type TraceIdRatioBased struct { + // The desired ratio of sampling. Must be within [0.0, 1.0]. + SamplingRatio float64 `protobuf:"fixed64,1,opt,name=samplingRatio,proto3" json:"samplingRatio,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } -func (m *ProbabilitySampler) Reset() { *m = ProbabilitySampler{} } -func (m *ProbabilitySampler) String() string { return proto.CompactTextString(m) } -func (*ProbabilitySampler) ProtoMessage() {} -func (*ProbabilitySampler) Descriptor() ([]byte, []int) { +func (m *TraceIdRatioBased) Reset() { *m = TraceIdRatioBased{} } +func (m *TraceIdRatioBased) String() string { return proto.CompactTextString(m) } +func (*TraceIdRatioBased) ProtoMessage() {} +func (*TraceIdRatioBased) Descriptor() ([]byte, []int) { return fileDescriptor_5936aa8fa6443e6f, []int{2} } -func (m *ProbabilitySampler) XXX_Unmarshal(b []byte) error { +func (m *TraceIdRatioBased) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *ProbabilitySampler) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *TraceIdRatioBased) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_ProbabilitySampler.Marshal(b, m, deterministic) + return xxx_messageInfo_TraceIdRatioBased.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -284,21 +284,21 @@ func (m *ProbabilitySampler) XXX_Marshal(b []byte, deterministic bool) ([]byte, return b[:n], nil } } -func (m *ProbabilitySampler) XXX_Merge(src proto.Message) { - xxx_messageInfo_ProbabilitySampler.Merge(m, src) +func (m *TraceIdRatioBased) XXX_Merge(src proto.Message) { + xxx_messageInfo_TraceIdRatioBased.Merge(m, src) } -func (m *ProbabilitySampler) XXX_Size() int { +func (m *TraceIdRatioBased) XXX_Size() int { return m.Size() } -func (m *ProbabilitySampler) XXX_DiscardUnknown() { - xxx_messageInfo_ProbabilitySampler.DiscardUnknown(m) +func (m *TraceIdRatioBased) XXX_DiscardUnknown() { + xxx_messageInfo_TraceIdRatioBased.DiscardUnknown(m) } -var xxx_messageInfo_ProbabilitySampler proto.InternalMessageInfo +var xxx_messageInfo_TraceIdRatioBased proto.InternalMessageInfo -func (m *ProbabilitySampler) GetSamplingProbability() float64 { +func (m *TraceIdRatioBased) GetSamplingRatio() float64 { if m != nil { - return m.SamplingProbability + return m.SamplingRatio } return 0 } @@ -356,7 +356,7 @@ func init() { proto.RegisterEnum("opentelemetry.proto.trace.v1.ConstantSampler_ConstantDecision", ConstantSampler_ConstantDecision_name, ConstantSampler_ConstantDecision_value) proto.RegisterType((*TraceConfig)(nil), "opentelemetry.proto.trace.v1.TraceConfig") proto.RegisterType((*ConstantSampler)(nil), "opentelemetry.proto.trace.v1.ConstantSampler") - proto.RegisterType((*ProbabilitySampler)(nil), "opentelemetry.proto.trace.v1.ProbabilitySampler") + proto.RegisterType((*TraceIdRatioBased)(nil), "opentelemetry.proto.trace.v1.TraceIdRatioBased") proto.RegisterType((*RateLimitingSampler)(nil), "opentelemetry.proto.trace.v1.RateLimitingSampler") } @@ -365,41 +365,42 @@ func init() { } var fileDescriptor_5936aa8fa6443e6f = []byte{ - // 538 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0xcd, 0x6e, 0xd3, 0x4e, - 0x14, 0xc5, 0x3b, 0xcd, 0xbf, 0x5f, 0xb7, 0x6a, 0xeb, 0xff, 0x44, 0x45, 0x16, 0xaa, 0x42, 0xf1, - 0x86, 0x6c, 0x12, 0x37, 0x65, 0x81, 0xc4, 0x02, 0x29, 0x69, 0x1b, 0x58, 0x44, 0x69, 0xe4, 0x46, - 0x42, 0x84, 0x85, 0xe5, 0xb8, 0x37, 0xd6, 0x88, 0xf1, 0x8c, 0x19, 0x4f, 0xa3, 0xf4, 0x01, 0x78, - 0x0d, 0x5e, 0x82, 0x97, 0x60, 0xc9, 0x23, 0xa0, 0x3c, 0x09, 0xf2, 0x24, 0x38, 0x9f, 0x8d, 0xc4, - 0x6e, 0xee, 0x3d, 0x3e, 0xbf, 0x33, 0x63, 0x5f, 0x0f, 0xb8, 0x32, 0x41, 0xa1, 0x91, 0x63, 0x8c, - 0x5a, 0x3d, 0xba, 0x89, 0x92, 0x5a, 0xba, 0x5a, 0x05, 0x21, 0xba, 0xc3, 0xda, 0x64, 0xe1, 0x87, - 0x52, 0x0c, 0x58, 0x54, 0x35, 0x1a, 0x3d, 0x5b, 0x30, 0x4c, 0x9a, 0x55, 0xf3, 0x5c, 0x75, 0x58, - 0x73, 0xbe, 0xed, 0xc0, 0x61, 0x37, 0x2b, 0xae, 0x8c, 0x87, 0xf6, 0xc0, 0x0a, 0xa5, 0x48, 0x75, - 0x20, 0xb4, 0x9f, 0x06, 0x71, 0xc2, 0x51, 0xd9, 0xe4, 0x9c, 0x94, 0x0f, 0x2f, 0x2b, 0xd5, 0x4d, - 0xa0, 0xea, 0xd5, 0xd4, 0x75, 0x37, 0x31, 0x7d, 0xd8, 0xf2, 0x4e, 0xc2, 0xc5, 0x16, 0x0d, 0xa1, - 0x98, 0x28, 0xd9, 0x0f, 0xfa, 0x8c, 0x33, 0xfd, 0x98, 0xe3, 0xb7, 0x0d, 0xfe, 0x62, 0x33, 0xbe, - 0x33, 0x33, 0xce, 0x12, 0x68, 0xb2, 0xd2, 0xa5, 0x11, 0x9c, 0xaa, 0x40, 0xa3, 0xcf, 0x59, 0xcc, - 0x34, 0x13, 0x51, 0x1e, 0x53, 0x30, 0x31, 0xb5, 0xcd, 0x31, 0x5e, 0xa0, 0xb1, 0x35, 0x75, 0xce, - 0x72, 0x8a, 0x6a, 0xb5, 0x4d, 0xdf, 0x80, 0x1d, 0x07, 0x23, 0x5f, 0x3c, 0xc4, 0x7d, 0x54, 0xbe, - 0x1c, 0xf8, 0x81, 0xd6, 0x8a, 0xf5, 0x1f, 0x34, 0xa6, 0xf6, 0x7f, 0xe7, 0xa4, 0x5c, 0xf0, 0x4e, - 0xe3, 0x60, 0xd4, 0x36, 0xf2, 0xed, 0xa0, 0x9e, 0x8b, 0xf4, 0x2d, 0x3c, 0x5f, 0x34, 0x6a, 0x16, - 0xe3, 0xbd, 0x8f, 0x43, 0x14, 0x3a, 0xb5, 0x77, 0x8c, 0xf5, 0xd9, 0x9c, 0xb5, 0x9b, 0xc9, 0x37, - 0x46, 0xa5, 0x5d, 0x28, 0x3f, 0x15, 0xea, 0x27, 0xa8, 0xe6, 0x51, 0xf6, 0xae, 0x21, 0x39, 0x6b, - 0x37, 0xd1, 0x41, 0x35, 0xc3, 0xd2, 0x0a, 0x14, 0x17, 0xa9, 0x9c, 0x89, 0x2f, 0xa9, 0xbd, 0x67, - 0x00, 0xd6, 0x1c, 0xa0, 0x95, 0xf5, 0xe9, 0x7b, 0x78, 0xb9, 0x71, 0x13, 0x99, 0xdb, 0xde, 0x37, - 0xe6, 0xb3, 0xa7, 0xd2, 0x33, 0x52, 0xe3, 0x00, 0xf6, 0xa6, 0x5f, 0xc7, 0xf9, 0x41, 0xe0, 0x64, - 0x69, 0x84, 0x68, 0x0f, 0xf6, 0xef, 0x31, 0x64, 0x29, 0x93, 0xc2, 0xcc, 0xe0, 0xf1, 0xe5, 0xbb, - 0x7f, 0x9a, 0xc1, 0xbc, 0xbe, 0x9e, 0x52, 0xbc, 0x9c, 0xe7, 0x5c, 0x83, 0xb5, 0xac, 0xd2, 0x63, - 0x80, 0x7a, 0xeb, 0x63, 0xfd, 0xd3, 0x9d, 0x7f, 0xdb, 0x6c, 0x5a, 0x5b, 0xf4, 0x08, 0x0e, 0xfe, - 0xd6, 0x6d, 0x8b, 0xd0, 0xff, 0xe1, 0x68, 0x5a, 0x76, 0xea, 0xde, 0x4d, 0xbb, 0x6b, 0x6d, 0x3b, - 0x4d, 0xa0, 0xab, 0x83, 0x49, 0x2f, 0xa0, 0x68, 0x8e, 0xc5, 0x44, 0x34, 0xa7, 0x9a, 0x23, 0x10, - 0x6f, 0x9d, 0xe4, 0xbc, 0x82, 0xe2, 0x9a, 0xc9, 0xa3, 0x16, 0x14, 0xbe, 0x26, 0xa9, 0x31, 0x16, - 0xbc, 0x6c, 0xd9, 0xf8, 0x4e, 0x7e, 0x8e, 0x4b, 0xe4, 0xd7, 0xb8, 0x44, 0x7e, 0x8f, 0x4b, 0x04, - 0x5e, 0x30, 0xb9, 0xf1, 0x8d, 0x34, 0xac, 0xb9, 0x7f, 0xbb, 0x93, 0x49, 0x1d, 0xd2, 0xfb, 0x1c, - 0x2d, 0x9b, 0x98, 0x74, 0xa5, 0x46, 0xee, 0xe2, 0x28, 0x91, 0x4a, 0xa3, 0x4a, 0x5d, 0xa9, 0x79, - 0xe2, 0x32, 0xa1, 0x51, 0x89, 0x80, 0x2f, 0x5e, 0x39, 0x15, 0x13, 0x51, 0x89, 0x50, 0xb8, 0xa1, - 0xe4, 0x1c, 0x43, 0x2d, 0x55, 0x7e, 0x01, 0xf5, 0x77, 0x8d, 0xfa, 0xfa, 0x4f, 0x00, 0x00, 0x00, - 0xff, 0xff, 0x7f, 0x94, 0x6e, 0x93, 0xa7, 0x04, 0x00, 0x00, + // 548 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0xdf, 0x6e, 0x12, 0x41, + 0x14, 0xc6, 0xbb, 0xc5, 0xfe, 0x3b, 0x4d, 0xdb, 0x65, 0xb0, 0x66, 0x63, 0x1a, 0xac, 0x1b, 0x13, + 0xb9, 0x81, 0x0d, 0xf5, 0xc2, 0xe8, 0x85, 0x09, 0xf4, 0x8f, 0x35, 0x21, 0x94, 0x6c, 0x49, 0x8c, + 0x78, 0x31, 0x19, 0x96, 0xc3, 0x66, 0xe2, 0xee, 0xcc, 0x3a, 0x3b, 0x25, 0x78, 0xef, 0x73, 0xf8, + 0x12, 0xbe, 0x84, 0x97, 0x3e, 0x82, 0xe1, 0x49, 0xcc, 0x0e, 0x48, 0x59, 0xda, 0x92, 0x78, 0x37, + 0xe7, 0xfb, 0xf8, 0x7d, 0xe7, 0x0c, 0x1c, 0x06, 0x3c, 0x99, 0xa0, 0xd0, 0x18, 0x61, 0x8c, 0x5a, + 0x7d, 0xf3, 0x12, 0x25, 0xb5, 0xf4, 0xb4, 0x62, 0x01, 0x7a, 0xa3, 0xfa, 0xf4, 0x40, 0x03, 0x29, + 0x86, 0x3c, 0xac, 0x19, 0x8f, 0x1c, 0xe5, 0x80, 0xa9, 0x58, 0x33, 0x9f, 0xab, 0x8d, 0xea, 0xee, + 0xf7, 0x0d, 0xd8, 0xed, 0x66, 0xc5, 0xa9, 0x61, 0x48, 0x0f, 0xec, 0x40, 0x8a, 0x54, 0x33, 0xa1, + 0x69, 0xca, 0xe2, 0x24, 0x42, 0xe5, 0x58, 0xc7, 0x56, 0x65, 0xf7, 0xa4, 0x5a, 0x5b, 0x15, 0x54, + 0x3b, 0x9d, 0x51, 0xd7, 0x53, 0xe8, 0x72, 0xcd, 0x3f, 0x08, 0xf2, 0x12, 0xe9, 0xc3, 0xe3, 0xe9, + 0x7c, 0x7c, 0x40, 0x15, 0xd3, 0x5c, 0xd2, 0x3e, 0x4b, 0x71, 0xe0, 0xac, 0x9b, 0x7c, 0x6f, 0x75, + 0xbe, 0x19, 0xf2, 0xc3, 0xc0, 0xcf, 0xb8, 0x66, 0x86, 0x5d, 0xae, 0xf9, 0x45, 0xbd, 0x2c, 0x92, + 0x10, 0x0e, 0x15, 0xd3, 0x48, 0x23, 0x1e, 0x73, 0xcd, 0x45, 0x38, 0xbf, 0x44, 0xc1, 0x34, 0xa9, + 0xaf, 0x6e, 0xe2, 0x33, 0x8d, 0xad, 0x19, 0x79, 0x7b, 0x91, 0x92, 0xba, 0x2b, 0x93, 0xd7, 0xe0, + 0xc4, 0x6c, 0x4c, 0xc5, 0x4d, 0xdc, 0x47, 0x45, 0xe5, 0x90, 0x32, 0xad, 0x15, 0xef, 0xdf, 0x68, + 0x4c, 0x9d, 0x47, 0xc7, 0x56, 0xa5, 0xe0, 0x1f, 0xc6, 0x6c, 0xdc, 0x36, 0xf6, 0xd5, 0xb0, 0x31, + 0x37, 0xc9, 0x5b, 0x78, 0x9a, 0x07, 0x35, 0x8f, 0x71, 0x40, 0x71, 0x84, 0x42, 0xa7, 0xce, 0x86, + 0x41, 0x9f, 0x2c, 0xa0, 0xdd, 0xcc, 0x3e, 0x37, 0x2e, 0xe9, 0x42, 0xe5, 0xa1, 0xa6, 0x34, 0x41, + 0xb5, 0x18, 0xe5, 0x6c, 0x9a, 0x24, 0xf7, 0xde, 0x21, 0x3a, 0xa8, 0x6e, 0x63, 0x49, 0x15, 0x4a, + 0xf9, 0xd4, 0x88, 0x8b, 0x2f, 0xa9, 0xb3, 0x65, 0x02, 0xec, 0x85, 0x80, 0x56, 0xa6, 0x93, 0xf7, + 0xf0, 0x7c, 0xe5, 0x10, 0x19, 0xed, 0x6c, 0x1b, 0xf8, 0xe8, 0xa1, 0xee, 0x59, 0x52, 0x73, 0x07, + 0xb6, 0x66, 0xbf, 0x8e, 0xfb, 0xd3, 0x82, 0x83, 0xa5, 0x0d, 0x22, 0x3d, 0xd8, 0x1e, 0x60, 0xc0, + 0x53, 0x2e, 0x85, 0x59, 0xc1, 0xfd, 0x93, 0x77, 0xff, 0xb5, 0x82, 0xf3, 0xfa, 0x6c, 0x96, 0xe2, + 0xcf, 0xf3, 0xdc, 0x33, 0xb0, 0x97, 0x5d, 0xb2, 0x0f, 0xd0, 0x68, 0x7d, 0x6c, 0x7c, 0xba, 0xa6, + 0x57, 0x17, 0x17, 0xf6, 0x1a, 0xd9, 0x83, 0x9d, 0x7f, 0x75, 0xdb, 0xb6, 0x48, 0x11, 0xf6, 0x66, + 0x65, 0xa7, 0xe1, 0x9f, 0xb7, 0xbb, 0xf6, 0xba, 0xfb, 0x06, 0x8a, 0x77, 0xd6, 0x92, 0xbc, 0x80, + 0x3d, 0x73, 0x2b, 0x2e, 0x42, 0xa3, 0x9a, 0xd9, 0x2d, 0x3f, 0x2f, 0xba, 0x2f, 0xa1, 0x74, 0xcf, + 0xb2, 0x11, 0x1b, 0x0a, 0x5f, 0x93, 0xd4, 0x20, 0x05, 0x3f, 0x3b, 0x36, 0x7f, 0x58, 0xbf, 0x26, + 0x65, 0xeb, 0xf7, 0xa4, 0x6c, 0xfd, 0x99, 0x94, 0x2d, 0x78, 0xc6, 0xe5, 0xca, 0x2f, 0xa1, 0x69, + 0x2f, 0xfc, 0x9b, 0x3b, 0x99, 0xd5, 0xb1, 0x7a, 0x9f, 0xc3, 0x65, 0x88, 0x4b, 0x4f, 0x6a, 0x8c, + 0x3c, 0x1c, 0x27, 0x52, 0x69, 0x54, 0xa9, 0x27, 0x75, 0x94, 0x78, 0x5c, 0x68, 0x54, 0x82, 0x45, + 0xf9, 0x47, 0xa6, 0x6a, 0x5a, 0x54, 0x43, 0x14, 0x5e, 0x20, 0xa3, 0x08, 0x03, 0x2d, 0xd5, 0xfc, + 0xc9, 0xe9, 0x6f, 0x1a, 0xf7, 0xd5, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x69, 0x02, 0x09, 0x0c, + 0x99, 0x04, 0x00, 0x00, } func (m *TraceConfig) Marshal() (dAtA []byte, err error) { @@ -484,16 +485,16 @@ func (m *TraceConfig_ConstantSampler) MarshalToSizedBuffer(dAtA []byte) (int, er } return len(dAtA) - i, nil } -func (m *TraceConfig_ProbabilitySampler) MarshalTo(dAtA []byte) (int, error) { +func (m *TraceConfig_TraceIdRatioBased) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *TraceConfig_ProbabilitySampler) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *TraceConfig_TraceIdRatioBased) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) - if m.ProbabilitySampler != nil { + if m.TraceIdRatioBased != nil { { - size, err := m.ProbabilitySampler.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.TraceIdRatioBased.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -558,7 +559,7 @@ func (m *ConstantSampler) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *ProbabilitySampler) Marshal() (dAtA []byte, err error) { +func (m *TraceIdRatioBased) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -568,12 +569,12 @@ func (m *ProbabilitySampler) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *ProbabilitySampler) MarshalTo(dAtA []byte) (int, error) { +func (m *TraceIdRatioBased) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *ProbabilitySampler) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *TraceIdRatioBased) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -582,9 +583,9 @@ func (m *ProbabilitySampler) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } - if m.SamplingProbability != 0 { + if m.SamplingRatio != 0 { i -= 8 - encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.SamplingProbability)))) + encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.SamplingRatio)))) i-- dAtA[i] = 0x9 } @@ -676,14 +677,14 @@ func (m *TraceConfig_ConstantSampler) Size() (n int) { } return n } -func (m *TraceConfig_ProbabilitySampler) Size() (n int) { +func (m *TraceConfig_TraceIdRatioBased) Size() (n int) { if m == nil { return 0 } var l int _ = l - if m.ProbabilitySampler != nil { - l = m.ProbabilitySampler.Size() + if m.TraceIdRatioBased != nil { + l = m.TraceIdRatioBased.Size() n += 1 + l + sovTraceConfig(uint64(l)) } return n @@ -715,13 +716,13 @@ func (m *ConstantSampler) Size() (n int) { return n } -func (m *ProbabilitySampler) Size() (n int) { +func (m *TraceIdRatioBased) Size() (n int) { if m == nil { return 0 } var l int _ = l - if m.SamplingProbability != 0 { + if m.SamplingRatio != 0 { n += 9 } if m.XXX_unrecognized != nil { @@ -817,7 +818,7 @@ func (m *TraceConfig) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProbabilitySampler", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field TraceIdRatioBased", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -844,11 +845,11 @@ func (m *TraceConfig) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &ProbabilitySampler{} + v := &TraceIdRatioBased{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Sampler = &TraceConfig_ProbabilitySampler{v} + m.Sampler = &TraceConfig_TraceIdRatioBased{v} iNdEx = postIndex case 3: if wireType != 2 { @@ -1078,7 +1079,7 @@ func (m *ConstantSampler) Unmarshal(dAtA []byte) error { } return nil } -func (m *ProbabilitySampler) Unmarshal(dAtA []byte) error { +func (m *TraceIdRatioBased) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1101,15 +1102,15 @@ func (m *ProbabilitySampler) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ProbabilitySampler: wiretype end group for non-group") + return fmt.Errorf("proto: TraceIdRatioBased: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ProbabilitySampler: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: TraceIdRatioBased: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 1 { - return fmt.Errorf("proto: wrong wireType = %d for field SamplingProbability", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field SamplingRatio", wireType) } var v uint64 if (iNdEx + 8) > l { @@ -1117,7 +1118,7 @@ func (m *ProbabilitySampler) Unmarshal(dAtA []byte) error { } v = uint64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:])) iNdEx += 8 - m.SamplingProbability = float64(math.Float64frombits(v)) + m.SamplingRatio = float64(math.Float64frombits(v)) default: iNdEx = preIndex skippy, err := skipTraceConfig(dAtA[iNdEx:]) diff --git a/exporters/otlp/internal/opentelemetry-proto-gen/trace/v1/trace.pb.go b/exporters/otlp/internal/opentelemetry-proto-gen/trace/v1/trace.pb.go index c1580319253..4c02a065b6f 100644 --- a/exporters/otlp/internal/opentelemetry-proto-gen/trace/v1/trace.pb.go +++ b/exporters/otlp/internal/opentelemetry-proto-gen/trace/v1/trace.pb.go @@ -78,68 +78,100 @@ func (Span_SpanKind) EnumDescriptor() ([]byte, []int) { return fileDescriptor_5c407ac9c675a601, []int{2, 0} } -// StatusCode mirrors the codes defined at -// https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/api-tracing.md#statuscanonicalcode +type Status_DeprecatedStatusCode int32 + +const ( + Status_DEPRECATED_STATUS_CODE_OK Status_DeprecatedStatusCode = 0 + Status_DEPRECATED_STATUS_CODE_CANCELLED Status_DeprecatedStatusCode = 1 + Status_DEPRECATED_STATUS_CODE_UNKNOWN_ERROR Status_DeprecatedStatusCode = 2 + Status_DEPRECATED_STATUS_CODE_INVALID_ARGUMENT Status_DeprecatedStatusCode = 3 + Status_DEPRECATED_STATUS_CODE_DEADLINE_EXCEEDED Status_DeprecatedStatusCode = 4 + Status_DEPRECATED_STATUS_CODE_NOT_FOUND Status_DeprecatedStatusCode = 5 + Status_DEPRECATED_STATUS_CODE_ALREADY_EXISTS Status_DeprecatedStatusCode = 6 + Status_DEPRECATED_STATUS_CODE_PERMISSION_DENIED Status_DeprecatedStatusCode = 7 + Status_DEPRECATED_STATUS_CODE_RESOURCE_EXHAUSTED Status_DeprecatedStatusCode = 8 + Status_DEPRECATED_STATUS_CODE_FAILED_PRECONDITION Status_DeprecatedStatusCode = 9 + Status_DEPRECATED_STATUS_CODE_ABORTED Status_DeprecatedStatusCode = 10 + Status_DEPRECATED_STATUS_CODE_OUT_OF_RANGE Status_DeprecatedStatusCode = 11 + Status_DEPRECATED_STATUS_CODE_UNIMPLEMENTED Status_DeprecatedStatusCode = 12 + Status_DEPRECATED_STATUS_CODE_INTERNAL_ERROR Status_DeprecatedStatusCode = 13 + Status_DEPRECATED_STATUS_CODE_UNAVAILABLE Status_DeprecatedStatusCode = 14 + Status_DEPRECATED_STATUS_CODE_DATA_LOSS Status_DeprecatedStatusCode = 15 + Status_DEPRECATED_STATUS_CODE_UNAUTHENTICATED Status_DeprecatedStatusCode = 16 +) + +var Status_DeprecatedStatusCode_name = map[int32]string{ + 0: "DEPRECATED_STATUS_CODE_OK", + 1: "DEPRECATED_STATUS_CODE_CANCELLED", + 2: "DEPRECATED_STATUS_CODE_UNKNOWN_ERROR", + 3: "DEPRECATED_STATUS_CODE_INVALID_ARGUMENT", + 4: "DEPRECATED_STATUS_CODE_DEADLINE_EXCEEDED", + 5: "DEPRECATED_STATUS_CODE_NOT_FOUND", + 6: "DEPRECATED_STATUS_CODE_ALREADY_EXISTS", + 7: "DEPRECATED_STATUS_CODE_PERMISSION_DENIED", + 8: "DEPRECATED_STATUS_CODE_RESOURCE_EXHAUSTED", + 9: "DEPRECATED_STATUS_CODE_FAILED_PRECONDITION", + 10: "DEPRECATED_STATUS_CODE_ABORTED", + 11: "DEPRECATED_STATUS_CODE_OUT_OF_RANGE", + 12: "DEPRECATED_STATUS_CODE_UNIMPLEMENTED", + 13: "DEPRECATED_STATUS_CODE_INTERNAL_ERROR", + 14: "DEPRECATED_STATUS_CODE_UNAVAILABLE", + 15: "DEPRECATED_STATUS_CODE_DATA_LOSS", + 16: "DEPRECATED_STATUS_CODE_UNAUTHENTICATED", +} + +var Status_DeprecatedStatusCode_value = map[string]int32{ + "DEPRECATED_STATUS_CODE_OK": 0, + "DEPRECATED_STATUS_CODE_CANCELLED": 1, + "DEPRECATED_STATUS_CODE_UNKNOWN_ERROR": 2, + "DEPRECATED_STATUS_CODE_INVALID_ARGUMENT": 3, + "DEPRECATED_STATUS_CODE_DEADLINE_EXCEEDED": 4, + "DEPRECATED_STATUS_CODE_NOT_FOUND": 5, + "DEPRECATED_STATUS_CODE_ALREADY_EXISTS": 6, + "DEPRECATED_STATUS_CODE_PERMISSION_DENIED": 7, + "DEPRECATED_STATUS_CODE_RESOURCE_EXHAUSTED": 8, + "DEPRECATED_STATUS_CODE_FAILED_PRECONDITION": 9, + "DEPRECATED_STATUS_CODE_ABORTED": 10, + "DEPRECATED_STATUS_CODE_OUT_OF_RANGE": 11, + "DEPRECATED_STATUS_CODE_UNIMPLEMENTED": 12, + "DEPRECATED_STATUS_CODE_INTERNAL_ERROR": 13, + "DEPRECATED_STATUS_CODE_UNAVAILABLE": 14, + "DEPRECATED_STATUS_CODE_DATA_LOSS": 15, + "DEPRECATED_STATUS_CODE_UNAUTHENTICATED": 16, +} + +func (x Status_DeprecatedStatusCode) String() string { + return proto.EnumName(Status_DeprecatedStatusCode_name, int32(x)) +} + +func (Status_DeprecatedStatusCode) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_5c407ac9c675a601, []int{3, 0} +} + +// For the semantics of status codes see +// https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/api.md#set-status type Status_StatusCode int32 const ( - Status_STATUS_CODE_OK Status_StatusCode = 0 - Status_STATUS_CODE_CANCELLED Status_StatusCode = 1 - Status_STATUS_CODE_UNKNOWN_ERROR Status_StatusCode = 2 - Status_STATUS_CODE_INVALID_ARGUMENT Status_StatusCode = 3 - Status_STATUS_CODE_DEADLINE_EXCEEDED Status_StatusCode = 4 - Status_STATUS_CODE_NOT_FOUND Status_StatusCode = 5 - Status_STATUS_CODE_ALREADY_EXISTS Status_StatusCode = 6 - Status_STATUS_CODE_PERMISSION_DENIED Status_StatusCode = 7 - Status_STATUS_CODE_RESOURCE_EXHAUSTED Status_StatusCode = 8 - Status_STATUS_CODE_FAILED_PRECONDITION Status_StatusCode = 9 - Status_STATUS_CODE_ABORTED Status_StatusCode = 10 - Status_STATUS_CODE_OUT_OF_RANGE Status_StatusCode = 11 - Status_STATUS_CODE_UNIMPLEMENTED Status_StatusCode = 12 - Status_STATUS_CODE_INTERNAL_ERROR Status_StatusCode = 13 - Status_STATUS_CODE_UNAVAILABLE Status_StatusCode = 14 - Status_STATUS_CODE_DATA_LOSS Status_StatusCode = 15 - Status_STATUS_CODE_UNAUTHENTICATED Status_StatusCode = 16 + // The default status. + Status_STATUS_CODE_UNSET Status_StatusCode = 0 + // The Span has been validated by an Application developers or Operator to have + // completed successfully. + Status_STATUS_CODE_OK Status_StatusCode = 1 + // The Span contains an error. + Status_STATUS_CODE_ERROR Status_StatusCode = 2 ) var Status_StatusCode_name = map[int32]string{ - 0: "STATUS_CODE_OK", - 1: "STATUS_CODE_CANCELLED", - 2: "STATUS_CODE_UNKNOWN_ERROR", - 3: "STATUS_CODE_INVALID_ARGUMENT", - 4: "STATUS_CODE_DEADLINE_EXCEEDED", - 5: "STATUS_CODE_NOT_FOUND", - 6: "STATUS_CODE_ALREADY_EXISTS", - 7: "STATUS_CODE_PERMISSION_DENIED", - 8: "STATUS_CODE_RESOURCE_EXHAUSTED", - 9: "STATUS_CODE_FAILED_PRECONDITION", - 10: "STATUS_CODE_ABORTED", - 11: "STATUS_CODE_OUT_OF_RANGE", - 12: "STATUS_CODE_UNIMPLEMENTED", - 13: "STATUS_CODE_INTERNAL_ERROR", - 14: "STATUS_CODE_UNAVAILABLE", - 15: "STATUS_CODE_DATA_LOSS", - 16: "STATUS_CODE_UNAUTHENTICATED", + 0: "STATUS_CODE_UNSET", + 1: "STATUS_CODE_OK", + 2: "STATUS_CODE_ERROR", } var Status_StatusCode_value = map[string]int32{ - "STATUS_CODE_OK": 0, - "STATUS_CODE_CANCELLED": 1, - "STATUS_CODE_UNKNOWN_ERROR": 2, - "STATUS_CODE_INVALID_ARGUMENT": 3, - "STATUS_CODE_DEADLINE_EXCEEDED": 4, - "STATUS_CODE_NOT_FOUND": 5, - "STATUS_CODE_ALREADY_EXISTS": 6, - "STATUS_CODE_PERMISSION_DENIED": 7, - "STATUS_CODE_RESOURCE_EXHAUSTED": 8, - "STATUS_CODE_FAILED_PRECONDITION": 9, - "STATUS_CODE_ABORTED": 10, - "STATUS_CODE_OUT_OF_RANGE": 11, - "STATUS_CODE_UNIMPLEMENTED": 12, - "STATUS_CODE_INTERNAL_ERROR": 13, - "STATUS_CODE_UNAVAILABLE": 14, - "STATUS_CODE_DATA_LOSS": 15, - "STATUS_CODE_UNAUTHENTICATED": 16, + "STATUS_CODE_UNSET": 0, + "STATUS_CODE_OK": 1, + "STATUS_CODE_ERROR": 2, } func (x Status_StatusCode) String() string { @@ -147,7 +179,7 @@ func (x Status_StatusCode) String() string { } func (Status_StatusCode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_5c407ac9c675a601, []int{3, 0} + return fileDescriptor_5c407ac9c675a601, []int{3, 1} } // A collection of InstrumentationLibrarySpans from a Resource. @@ -359,9 +391,8 @@ type Span struct { // dropped_links_count is the number of dropped links after the maximum size was // enforced. If this value is 0, then no links were dropped. DroppedLinksCount uint32 `protobuf:"varint,14,opt,name=dropped_links_count,json=droppedLinksCount,proto3" json:"dropped_links_count,omitempty"` - // An optional final status for this span. Semantically when Status - // wasn't set it is means span ended without errors and assume - // Status.Ok (code = 0). + // An optional final status for this span. Semantically when Status isn't set, it means + // span's status code is unset, i.e. assume STATUS_CODE_UNSET (code = 0). Status *Status `protobuf:"bytes,15,opt,name=status,proto3" json:"status,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -678,14 +709,20 @@ func (m *Span_Link) GetDroppedAttributesCount() uint32 { // The Status type defines a logical error model that is suitable for different // programming environments, including REST APIs and RPC APIs. type Status struct { - // The status code. This is optional field. It is safe to assume 0 (OK) - // when not set. - Code Status_StatusCode `protobuf:"varint,1,opt,name=code,proto3,enum=opentelemetry.proto.trace.v1.Status_StatusCode" json:"code,omitempty"` + // The deprecated status code. This is an optional field. + // + // This field is deprecated and is replaced by the `code` field below. See backward + // compatibility notes below. According to our stability guarantees this field + // will be removed in 12 months, on Oct 22, 2021. All usage of old senders and + // receivers that do not understand the `code` field MUST be phased out by then. + DeprecatedCode Status_DeprecatedStatusCode `protobuf:"varint,1,opt,name=deprecated_code,json=deprecatedCode,proto3,enum=opentelemetry.proto.trace.v1.Status_DeprecatedStatusCode" json:"deprecated_code,omitempty"` // Deprecated: Do not use. // A developer-facing human readable error message. - Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` + // The status code. + Code Status_StatusCode `protobuf:"varint,3,opt,name=code,proto3,enum=opentelemetry.proto.trace.v1.Status_StatusCode" json:"code,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Status) Reset() { *m = Status{} } @@ -721,11 +758,12 @@ func (m *Status) XXX_DiscardUnknown() { var xxx_messageInfo_Status proto.InternalMessageInfo -func (m *Status) GetCode() Status_StatusCode { +// Deprecated: Do not use. +func (m *Status) GetDeprecatedCode() Status_DeprecatedStatusCode { if m != nil { - return m.Code + return m.DeprecatedCode } - return Status_STATUS_CODE_OK + return Status_DEPRECATED_STATUS_CODE_OK } func (m *Status) GetMessage() string { @@ -735,8 +773,16 @@ func (m *Status) GetMessage() string { return "" } +func (m *Status) GetCode() Status_StatusCode { + if m != nil { + return m.Code + } + return Status_STATUS_CODE_UNSET +} + func init() { proto.RegisterEnum("opentelemetry.proto.trace.v1.Span_SpanKind", Span_SpanKind_name, Span_SpanKind_value) + proto.RegisterEnum("opentelemetry.proto.trace.v1.Status_DeprecatedStatusCode", Status_DeprecatedStatusCode_name, Status_DeprecatedStatusCode_value) proto.RegisterEnum("opentelemetry.proto.trace.v1.Status_StatusCode", Status_StatusCode_name, Status_StatusCode_value) proto.RegisterType((*ResourceSpans)(nil), "opentelemetry.proto.trace.v1.ResourceSpans") proto.RegisterType((*InstrumentationLibrarySpans)(nil), "opentelemetry.proto.trace.v1.InstrumentationLibrarySpans") @@ -751,75 +797,80 @@ func init() { } var fileDescriptor_5c407ac9c675a601 = []byte{ - // 1088 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x4f, 0x6f, 0xe3, 0xc4, - 0x1b, 0x5e, 0xb7, 0x4e, 0xda, 0x7d, 0xdb, 0x66, 0xbd, 0xb3, 0xfb, 0xdb, 0xba, 0xff, 0xf3, 0x0b, - 0x2b, 0x11, 0x58, 0x6d, 0x42, 0x8b, 0x90, 0x16, 0x09, 0x04, 0xae, 0x3d, 0xed, 0x5a, 0x75, 0xed, - 0x30, 0xb6, 0xcb, 0xc2, 0xc5, 0x72, 0x9b, 0x51, 0x65, 0x35, 0x19, 0x47, 0xb6, 0x53, 0xb5, 0x07, - 0xbe, 0x02, 0x37, 0x0e, 0x48, 0x7c, 0x1c, 0x24, 0x38, 0x72, 0xe1, 0x8a, 0x50, 0xbf, 0x08, 0x68, - 0xc6, 0x4e, 0x1b, 0x87, 0x36, 0xdd, 0x4b, 0x2f, 0xc9, 0xcc, 0xfb, 0x3e, 0xcf, 0xfb, 0xbc, 0xff, - 0x46, 0x09, 0x34, 0xe3, 0x01, 0x65, 0x19, 0xed, 0xd1, 0x3e, 0xcd, 0x92, 0xcb, 0xf6, 0x20, 0x89, - 0xb3, 0xb8, 0x9d, 0x25, 0xe1, 0x09, 0x6d, 0x9f, 0x6f, 0xe7, 0x87, 0x96, 0x30, 0xa2, 0xf5, 0x12, - 0x32, 0x37, 0xb6, 0x72, 0xc0, 0xf9, 0xf6, 0xea, 0xc7, 0xb7, 0xc5, 0x39, 0x89, 0xfb, 0xfd, 0x98, - 0xf1, 0x40, 0xf9, 0x29, 0x27, 0xad, 0xb6, 0x6e, 0xc3, 0x26, 0x34, 0x8d, 0x87, 0x49, 0x2e, 0x3b, - 0x3a, 0xe7, 0xf8, 0xc6, 0x9f, 0x12, 0x2c, 0x91, 0xc2, 0xe4, 0x0e, 0x42, 0x96, 0x22, 0x0c, 0xf3, - 0x23, 0x8c, 0x2a, 0xd5, 0xa5, 0xe6, 0xc2, 0xce, 0x47, 0xad, 0xdb, 0xd2, 0xbb, 0x0e, 0x74, 0xbe, - 0xdd, 0x1a, 0x45, 0x20, 0xd7, 0x54, 0xf4, 0x03, 0x6c, 0x44, 0x2c, 0xcd, 0x92, 0x61, 0x9f, 0xb2, - 0x2c, 0xcc, 0xa2, 0x98, 0x05, 0xbd, 0xe8, 0x38, 0x09, 0x93, 0xcb, 0x20, 0xe5, 0x3a, 0xea, 0x4c, - 0x7d, 0xb6, 0xb9, 0xb0, 0xf3, 0x79, 0x6b, 0x5a, 0xe9, 0x2d, 0xb3, 0x1c, 0xc2, 0xca, 0x23, 0x88, - 0x44, 0xc9, 0x5a, 0x74, 0xb7, 0xb3, 0xf1, 0x9b, 0x04, 0x6b, 0x53, 0xc8, 0x88, 0xc1, 0xf2, 0x1d, - 0xe9, 0x15, 0x45, 0x7f, 0x76, 0x6b, 0x62, 0x45, 0xaf, 0xef, 0xcc, 0x8c, 0xbc, 0xb8, 0x3d, 0x29, - 0xf4, 0x06, 0x2a, 0xe3, 0x65, 0x37, 0xa6, 0x97, 0xcd, 0x73, 0x24, 0x39, 0xa1, 0xf1, 0x0b, 0x80, - 0xcc, 0xef, 0x68, 0x05, 0xe6, 0x05, 0x20, 0x88, 0xba, 0x22, 0xc7, 0x45, 0x32, 0x27, 0xee, 0x66, - 0x17, 0x2d, 0xc3, 0x1c, 0x07, 0x73, 0xcf, 0x8c, 0xf0, 0x54, 0xf9, 0xd5, 0xec, 0xa2, 0x2d, 0x58, - 0xc8, 0x39, 0x69, 0x16, 0x66, 0x54, 0x9d, 0xad, 0x4b, 0xcd, 0xc7, 0x04, 0x84, 0xc9, 0xe5, 0x16, - 0xf4, 0x12, 0x6a, 0x83, 0x30, 0xa1, 0x2c, 0x0b, 0x46, 0x01, 0x64, 0x11, 0x60, 0x31, 0xb7, 0xba, - 0x79, 0x18, 0x04, 0x32, 0x0b, 0xfb, 0x54, 0xad, 0x08, 0xbe, 0x38, 0xa3, 0xaf, 0x40, 0x3e, 0x8b, - 0x58, 0x57, 0xad, 0xd6, 0xa5, 0x66, 0x6d, 0xe7, 0xd5, 0xfd, 0x05, 0x89, 0x8f, 0x83, 0x88, 0x75, - 0x89, 0x20, 0xa2, 0x36, 0x3c, 0x4f, 0xb3, 0x30, 0xc9, 0x82, 0x2c, 0xea, 0xd3, 0x60, 0xc8, 0xa2, - 0x8b, 0x80, 0x85, 0x2c, 0x56, 0xe7, 0xea, 0x52, 0xb3, 0x4a, 0x9e, 0x0a, 0x9f, 0x17, 0xf5, 0xa9, - 0xcf, 0xa2, 0x0b, 0x3b, 0x64, 0x31, 0x7a, 0x05, 0x88, 0xb2, 0xee, 0x24, 0x7c, 0x5e, 0xc0, 0x9f, - 0x50, 0xd6, 0x2d, 0x81, 0xf7, 0x01, 0xc2, 0x2c, 0x4b, 0xa2, 0xe3, 0x61, 0x46, 0x53, 0xf5, 0xb1, - 0xe8, 0xfa, 0x87, 0xf7, 0xcc, 0xf4, 0x80, 0x5e, 0x1e, 0x85, 0xbd, 0x21, 0x25, 0x63, 0x54, 0xf4, - 0x06, 0xd4, 0x6e, 0x12, 0x0f, 0x06, 0xb4, 0x1b, 0xdc, 0x58, 0x83, 0x93, 0x78, 0xc8, 0x32, 0x15, - 0xea, 0x52, 0x73, 0x89, 0xbc, 0x28, 0xfc, 0xda, 0xb5, 0x5b, 0xe7, 0x5e, 0xf4, 0x35, 0x54, 0xe9, - 0x39, 0x65, 0x59, 0xaa, 0x2e, 0x08, 0xf9, 0xe6, 0x7b, 0xf4, 0x08, 0x73, 0x02, 0x29, 0x78, 0xe8, - 0x13, 0x78, 0x3e, 0xd2, 0xce, 0x2d, 0x85, 0xee, 0xa2, 0xd0, 0x45, 0x85, 0x4f, 0x70, 0x0a, 0xcd, - 0x2f, 0xa1, 0xd2, 0x8b, 0xd8, 0x59, 0xaa, 0x2e, 0x4d, 0xa9, 0xb8, 0x2c, 0x69, 0x45, 0xec, 0x8c, - 0xe4, 0x2c, 0xd4, 0x82, 0x67, 0x23, 0x41, 0x61, 0x28, 0xf4, 0x6a, 0x42, 0xef, 0x69, 0xe1, 0xe2, - 0x84, 0x42, 0xee, 0x0b, 0xa8, 0xf2, 0xcd, 0x1a, 0xa6, 0xea, 0x13, 0xf1, 0x6a, 0x5e, 0xde, 0xa3, - 0x27, 0xb0, 0xa4, 0xe0, 0xac, 0xfe, 0x2a, 0x41, 0x45, 0x24, 0xcf, 0xd7, 0x70, 0x62, 0xac, 0x92, - 0x18, 0xeb, 0x62, 0x36, 0x3e, 0xd3, 0xd1, 0x1a, 0xce, 0x8c, 0xad, 0x61, 0x79, 0xce, 0xb3, 0x0f, - 0x33, 0x67, 0x79, 0xda, 0x9c, 0x57, 0xff, 0x92, 0x40, 0xe6, 0x3d, 0x79, 0x98, 0x17, 0x5a, 0x2e, - 0x50, 0x7e, 0x98, 0x02, 0x2b, 0xd3, 0x0a, 0x6c, 0xfc, 0x2c, 0xc1, 0xfc, 0xe8, 0xf1, 0xa2, 0x15, - 0xf8, 0x9f, 0xdb, 0xd1, 0xec, 0xe0, 0xc0, 0xb4, 0x8d, 0xc0, 0xb7, 0xdd, 0x0e, 0xd6, 0xcd, 0x3d, - 0x13, 0x1b, 0xca, 0x23, 0xf4, 0x02, 0xd0, 0x8d, 0xcb, 0xb4, 0x3d, 0x4c, 0x6c, 0xcd, 0x52, 0x24, - 0xf4, 0x1c, 0x94, 0x1b, 0xbb, 0x8b, 0xc9, 0x11, 0x26, 0xca, 0x4c, 0xd9, 0xaa, 0x5b, 0x26, 0xb6, - 0x3d, 0x65, 0xb6, 0x1c, 0xa3, 0x43, 0x1c, 0xc3, 0xd7, 0x31, 0x51, 0xe4, 0xb2, 0x5d, 0x77, 0x6c, - 0xd7, 0x3f, 0xc4, 0x44, 0xa9, 0x34, 0xfe, 0x91, 0xa1, 0x9a, 0xaf, 0x15, 0xd2, 0x41, 0x3e, 0x89, - 0xbb, 0xf9, 0xaf, 0x56, 0x6d, 0xa7, 0xfd, 0x3e, 0xab, 0x58, 0x7c, 0xe9, 0x71, 0x97, 0x12, 0x41, - 0x46, 0x2a, 0xcc, 0xf5, 0x69, 0x9a, 0x86, 0xa7, 0xa3, 0x35, 0x1b, 0x5d, 0x1b, 0x3f, 0xc9, 0x00, - 0x37, 0x70, 0x84, 0xa0, 0xe6, 0x7a, 0x9a, 0xe7, 0xbb, 0x81, 0xee, 0x18, 0x38, 0x70, 0x0e, 0x94, - 0x47, 0xa2, 0x37, 0x63, 0x36, 0x5d, 0xb3, 0x75, 0x6c, 0x59, 0xd8, 0x50, 0x24, 0xb4, 0x01, 0x2b, - 0xe3, 0x2e, 0xdf, 0x3e, 0xb0, 0x9d, 0x6f, 0xed, 0x00, 0x13, 0xe2, 0xf0, 0x66, 0xd4, 0x61, 0x7d, - 0xdc, 0x6d, 0xda, 0x47, 0x9a, 0x65, 0x1a, 0x81, 0x46, 0xf6, 0xfd, 0xc3, 0xbc, 0x31, 0xff, 0x87, - 0x8d, 0x71, 0x84, 0x81, 0x35, 0xc3, 0x32, 0x6d, 0x1c, 0xe0, 0x77, 0x3a, 0xc6, 0x06, 0x36, 0x14, - 0x79, 0x52, 0xde, 0x76, 0xbc, 0x60, 0xcf, 0xf1, 0x6d, 0x43, 0xa9, 0xa0, 0x4d, 0x58, 0x1d, 0x77, - 0x69, 0x16, 0xc1, 0x9a, 0xf1, 0x5d, 0x80, 0xdf, 0x99, 0xae, 0xe7, 0x2a, 0xd5, 0xc9, 0xe8, 0x1d, - 0x4c, 0x0e, 0x4d, 0xd7, 0x35, 0x1d, 0x3b, 0x30, 0xb0, 0xcd, 0xa7, 0x3b, 0x87, 0x1a, 0xb0, 0x39, - 0x0e, 0x21, 0xd8, 0x75, 0x7c, 0xa2, 0xf3, 0x04, 0xde, 0x6a, 0xbe, 0xeb, 0x61, 0x43, 0x99, 0x47, - 0x1f, 0xc0, 0xd6, 0x38, 0x66, 0x4f, 0x33, 0x2d, 0xcc, 0xc7, 0x88, 0x75, 0xc7, 0x36, 0x4c, 0xcf, - 0x74, 0x6c, 0xe5, 0x31, 0x5a, 0x86, 0x67, 0xa5, 0x5c, 0x76, 0x1d, 0xc2, 0xd9, 0x80, 0xd6, 0x41, - 0x2d, 0xb5, 0xd4, 0xf7, 0x02, 0x67, 0x2f, 0x20, 0x9a, 0xbd, 0x8f, 0x95, 0x85, 0xff, 0x76, 0xd0, - 0x3c, 0xec, 0x58, 0x98, 0x77, 0x07, 0x1b, 0xca, 0xe2, 0x64, 0x85, 0xa3, 0xf5, 0x2b, 0x3a, 0xbc, - 0x84, 0xd6, 0x60, 0xb9, 0x4c, 0xd7, 0x8e, 0x34, 0xd3, 0xd2, 0x76, 0x2d, 0xac, 0xd4, 0x26, 0x3b, - 0x67, 0x68, 0x9e, 0x16, 0x58, 0x8e, 0xeb, 0x2a, 0x4f, 0xd0, 0x16, 0xac, 0x4d, 0xf0, 0x7c, 0xef, - 0x2d, 0xb6, 0x3d, 0x53, 0xd7, 0xb8, 0xb0, 0xb2, 0xfb, 0xa3, 0xf4, 0xfb, 0xd5, 0xa6, 0xf4, 0xc7, - 0xd5, 0xa6, 0xf4, 0xf7, 0xd5, 0xa6, 0x04, 0x5b, 0x51, 0x3c, 0x75, 0xf3, 0x76, 0xc1, 0xe3, 0xa7, - 0x0e, 0x37, 0x76, 0xa4, 0xef, 0xbf, 0x39, 0x9d, 0x84, 0x47, 0x71, 0x3b, 0xce, 0x68, 0xaf, 0x4d, - 0x2f, 0x06, 0x71, 0x92, 0xd1, 0x24, 0x6d, 0xc7, 0x59, 0x6f, 0xd0, 0x8e, 0x58, 0x46, 0x13, 0x16, - 0xf6, 0xda, 0x25, 0xf4, 0x6b, 0x11, 0xfc, 0xf5, 0x29, 0x65, 0xd7, 0xff, 0x2c, 0x8f, 0xab, 0xc2, - 0xf6, 0xe9, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xcd, 0xf7, 0xd2, 0xe8, 0x80, 0x0a, 0x00, 0x00, + // 1160 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x41, 0x6f, 0xdc, 0x44, + 0x14, 0xae, 0x93, 0xdd, 0x4d, 0xfa, 0x92, 0x6c, 0xdc, 0x21, 0x6d, 0xdd, 0x94, 0xa6, 0xab, 0x25, + 0xb4, 0xdb, 0x96, 0xee, 0xd2, 0x22, 0xa4, 0x22, 0x81, 0xc0, 0xb1, 0x27, 0xad, 0x15, 0xc7, 0x5e, + 0xc6, 0x76, 0x28, 0x5c, 0x46, 0x6e, 0x3c, 0x54, 0x56, 0x77, 0xc7, 0x2b, 0x7b, 0x36, 0x6a, 0x0f, + 0xfc, 0x05, 0xee, 0x48, 0xfc, 0x1c, 0x24, 0x38, 0x72, 0xe1, 0xc2, 0x01, 0xa1, 0xfe, 0x0e, 0x0e, + 0xc8, 0x63, 0x6f, 0x92, 0x8d, 0x62, 0xa7, 0x97, 0x5e, 0xa2, 0xf1, 0xf7, 0xbe, 0xef, 0x7d, 0xef, + 0xcd, 0x7b, 0xa3, 0x0d, 0xf4, 0x92, 0x09, 0xe3, 0x82, 0x8d, 0xd8, 0x98, 0x89, 0xf4, 0xcd, 0x60, + 0x92, 0x26, 0x22, 0x19, 0x88, 0x34, 0x3c, 0x64, 0x83, 0xa3, 0x47, 0xc5, 0xa1, 0x2f, 0x41, 0xf4, + 0xe1, 0x1c, 0xb3, 0x00, 0xfb, 0x05, 0xe1, 0xe8, 0xd1, 0xe6, 0xfd, 0xf3, 0xf2, 0x1c, 0x26, 0xe3, + 0x71, 0xc2, 0xf3, 0x44, 0xc5, 0xa9, 0x10, 0x6d, 0xf6, 0xcf, 0xe3, 0xa6, 0x2c, 0x4b, 0xa6, 0x69, + 0x61, 0x3b, 0x3b, 0x17, 0xfc, 0xee, 0x5f, 0x0a, 0xac, 0x91, 0x12, 0xf2, 0x26, 0x21, 0xcf, 0x10, + 0x86, 0xe5, 0x19, 0x47, 0x53, 0x3a, 0x4a, 0x6f, 0xe5, 0xf1, 0xbd, 0xfe, 0x79, 0xe5, 0x1d, 0x27, + 0x3a, 0x7a, 0xd4, 0x9f, 0x65, 0x20, 0xc7, 0x52, 0xf4, 0x13, 0xdc, 0x8a, 0x79, 0x26, 0xd2, 0xe9, + 0x98, 0x71, 0x11, 0x8a, 0x38, 0xe1, 0x74, 0x14, 0xbf, 0x48, 0xc3, 0xf4, 0x0d, 0xcd, 0x72, 0x1f, + 0x6d, 0xa1, 0xb3, 0xd8, 0x5b, 0x79, 0xfc, 0x45, 0xbf, 0xae, 0xf5, 0xbe, 0x35, 0x9f, 0xc2, 0x2e, + 0x32, 0xc8, 0x42, 0xc9, 0xcd, 0xb8, 0x3a, 0xd8, 0xfd, 0x5d, 0x81, 0x9b, 0x35, 0x62, 0xc4, 0xe1, + 0x7a, 0x45, 0x79, 0x65, 0xd3, 0x9f, 0x9f, 0x5b, 0x58, 0x79, 0xd7, 0x95, 0x95, 0x91, 0x6b, 0xe7, + 0x17, 0x85, 0x9e, 0x40, 0xf3, 0x74, 0xdb, 0xdd, 0xfa, 0xb6, 0xf3, 0x1a, 0x49, 0x21, 0xe8, 0xfe, + 0x0a, 0xd0, 0xc8, 0xbf, 0xd1, 0x0d, 0x58, 0x96, 0x04, 0x1a, 0x47, 0xb2, 0xc6, 0x55, 0xb2, 0x24, + 0xbf, 0xad, 0x08, 0x5d, 0x87, 0xa5, 0x9c, 0x9c, 0x47, 0x16, 0x64, 0xa4, 0x95, 0x7f, 0x5a, 0x11, + 0xba, 0x0d, 0x2b, 0x85, 0x26, 0x13, 0xa1, 0x60, 0xda, 0x62, 0x47, 0xe9, 0x5d, 0x26, 0x20, 0x21, + 0x2f, 0x47, 0xd0, 0x36, 0xb4, 0x27, 0x61, 0xca, 0xb8, 0xa0, 0xb3, 0x04, 0x0d, 0x99, 0x60, 0xb5, + 0x40, 0xbd, 0x22, 0x0d, 0x82, 0x06, 0x0f, 0xc7, 0x4c, 0x6b, 0x4a, 0xbd, 0x3c, 0xa3, 0xaf, 0xa1, + 0xf1, 0x2a, 0xe6, 0x91, 0xd6, 0xea, 0x28, 0xbd, 0xf6, 0xe3, 0x07, 0x17, 0x37, 0x24, 0xff, 0xec, + 0xc5, 0x3c, 0x22, 0x52, 0x88, 0x06, 0xb0, 0x91, 0x89, 0x30, 0x15, 0x54, 0xc4, 0x63, 0x46, 0xa7, + 0x3c, 0x7e, 0x4d, 0x79, 0xc8, 0x13, 0x6d, 0xa9, 0xa3, 0xf4, 0x5a, 0xe4, 0x8a, 0x8c, 0xf9, 0xf1, + 0x98, 0x05, 0x3c, 0x7e, 0xed, 0x84, 0x3c, 0x41, 0x0f, 0x00, 0x31, 0x1e, 0x9d, 0xa5, 0x2f, 0x4b, + 0xfa, 0x3a, 0xe3, 0xd1, 0x1c, 0xf9, 0x29, 0x40, 0x28, 0x44, 0x1a, 0xbf, 0x98, 0x0a, 0x96, 0x69, + 0x97, 0xe5, 0xad, 0xdf, 0xbd, 0x60, 0xa6, 0x7b, 0xec, 0xcd, 0x41, 0x38, 0x9a, 0x32, 0x72, 0x4a, + 0x8a, 0x9e, 0x80, 0x16, 0xa5, 0xc9, 0x64, 0xc2, 0x22, 0x7a, 0x82, 0xd2, 0xc3, 0x64, 0xca, 0x85, + 0x06, 0x1d, 0xa5, 0xb7, 0x46, 0xae, 0x95, 0x71, 0xfd, 0x38, 0x6c, 0xe4, 0x51, 0xf4, 0x0d, 0xb4, + 0xd8, 0x11, 0xe3, 0x22, 0xd3, 0x56, 0xa4, 0x7d, 0xef, 0x1d, 0xee, 0x08, 0xe7, 0x02, 0x52, 0xea, + 0xd0, 0xa7, 0xb0, 0x31, 0xf3, 0x2e, 0x90, 0xd2, 0x77, 0x55, 0xfa, 0xa2, 0x32, 0x26, 0x35, 0xa5, + 0xe7, 0x57, 0xd0, 0x1c, 0xc5, 0xfc, 0x55, 0xa6, 0xad, 0xd5, 0x74, 0x3c, 0x6f, 0x69, 0xc7, 0xfc, + 0x15, 0x29, 0x54, 0xa8, 0x0f, 0x1f, 0xcc, 0x0c, 0x25, 0x50, 0xfa, 0xb5, 0xa5, 0xdf, 0x95, 0x32, + 0x94, 0x0b, 0x4a, 0xbb, 0x2f, 0xa1, 0x95, 0x6f, 0xd6, 0x34, 0xd3, 0xd6, 0xe5, 0xab, 0xd9, 0xbe, + 0xc0, 0x4f, 0x72, 0x49, 0xa9, 0xd9, 0xfc, 0x4d, 0x81, 0xa6, 0x2c, 0x3e, 0x5f, 0xc3, 0x33, 0x63, + 0x55, 0xe4, 0x58, 0x57, 0xc5, 0xe9, 0x99, 0xce, 0xd6, 0x70, 0xe1, 0xd4, 0x1a, 0xce, 0xcf, 0x79, + 0xf1, 0xfd, 0xcc, 0xb9, 0x51, 0x37, 0xe7, 0xcd, 0x7f, 0x14, 0x68, 0xe4, 0x77, 0xf2, 0x7e, 0x5e, + 0xe8, 0x7c, 0x83, 0x8d, 0xf7, 0xd3, 0x60, 0xb3, 0xae, 0xc1, 0xee, 0x2f, 0x0a, 0x2c, 0xcf, 0x1e, + 0x2f, 0xba, 0x01, 0x57, 0xbd, 0xa1, 0xee, 0xd0, 0x3d, 0xcb, 0x31, 0x69, 0xe0, 0x78, 0x43, 0x6c, + 0x58, 0xbb, 0x16, 0x36, 0xd5, 0x4b, 0xe8, 0x1a, 0xa0, 0x93, 0x90, 0xe5, 0xf8, 0x98, 0x38, 0xba, + 0xad, 0x2a, 0x68, 0x03, 0xd4, 0x13, 0xdc, 0xc3, 0xe4, 0x00, 0x13, 0x75, 0x61, 0x1e, 0x35, 0x6c, + 0x0b, 0x3b, 0xbe, 0xba, 0x38, 0x9f, 0x63, 0x48, 0x5c, 0x33, 0x30, 0x30, 0x51, 0x1b, 0xf3, 0xb8, + 0xe1, 0x3a, 0x5e, 0xb0, 0x8f, 0x89, 0xda, 0xec, 0xfe, 0xb7, 0x04, 0xad, 0x62, 0xad, 0xd0, 0x8f, + 0xb0, 0x1e, 0xb1, 0x49, 0xca, 0x0e, 0x43, 0xc1, 0x22, 0x7a, 0x98, 0x44, 0xc5, 0x0f, 0x58, 0xfb, + 0xa2, 0x1f, 0x99, 0x42, 0xde, 0x37, 0x8f, 0xb5, 0x05, 0x60, 0x24, 0x11, 0xdb, 0x59, 0xd0, 0x14, + 0xd2, 0x3e, 0xc9, 0x9a, 0x63, 0x48, 0x83, 0xa5, 0x31, 0xcb, 0xb2, 0xf0, 0xe5, 0x6c, 0x13, 0x67, + 0x9f, 0xc8, 0x80, 0x86, 0xb4, 0x5d, 0x94, 0xb6, 0x83, 0x77, 0xb2, 0x3d, 0x31, 0x23, 0x52, 0xdc, + 0xfd, 0xbb, 0x09, 0x1b, 0xe7, 0xd5, 0x82, 0x6e, 0xc1, 0x0d, 0x13, 0x0f, 0x09, 0x36, 0x74, 0x1f, + 0x9b, 0xd4, 0xf3, 0x75, 0x3f, 0xf0, 0xa8, 0xe1, 0x9a, 0x98, 0xba, 0x7b, 0xea, 0x25, 0xb4, 0x0d, + 0x9d, 0x8a, 0xb0, 0xa1, 0x3b, 0x06, 0xb6, 0x6d, 0x6c, 0xaa, 0x0a, 0xea, 0xc1, 0x76, 0x05, 0x2b, + 0x70, 0xf6, 0x1c, 0xf7, 0x3b, 0x87, 0x62, 0x42, 0xdc, 0x7c, 0x3e, 0x0f, 0xe0, 0x6e, 0x05, 0xd3, + 0x72, 0x0e, 0x74, 0xdb, 0x32, 0xa9, 0x4e, 0x9e, 0x06, 0xfb, 0xc5, 0xd8, 0x3e, 0x81, 0x5e, 0x05, + 0xd9, 0xc4, 0xba, 0x69, 0x5b, 0x0e, 0xa6, 0xf8, 0xb9, 0x81, 0xb1, 0x89, 0x4d, 0xb5, 0x51, 0x53, + 0xaa, 0xe3, 0xfa, 0x74, 0xd7, 0x0d, 0x1c, 0x53, 0x6d, 0xa2, 0x7b, 0xf0, 0x71, 0x05, 0x4b, 0xb7, + 0x09, 0xd6, 0xcd, 0xef, 0x29, 0x7e, 0x6e, 0x79, 0xbe, 0xa7, 0xb6, 0x6a, 0xec, 0x87, 0x98, 0xec, + 0x5b, 0x9e, 0x67, 0xb9, 0x0e, 0x35, 0xb1, 0x93, 0xef, 0xe9, 0x12, 0x7a, 0x08, 0xf7, 0x2a, 0xd8, + 0x04, 0x7b, 0x6e, 0x40, 0x8c, 0xbc, 0xd8, 0x67, 0x7a, 0xe0, 0xf9, 0xd8, 0x54, 0x97, 0x51, 0x1f, + 0xee, 0x57, 0xd0, 0x77, 0x75, 0xcb, 0xc6, 0xf9, 0x9a, 0x62, 0xc3, 0x75, 0x4c, 0xcb, 0xb7, 0x5c, + 0x47, 0xbd, 0x8c, 0xba, 0xb0, 0x55, 0x55, 0xf7, 0x8e, 0x4b, 0xf2, 0x9c, 0x80, 0xee, 0xc2, 0x47, + 0x55, 0xb3, 0x0c, 0x7c, 0xea, 0xee, 0x52, 0xa2, 0x3b, 0x4f, 0xb1, 0xba, 0x52, 0x3b, 0x2f, 0x6b, + 0x7f, 0x68, 0xe3, 0x7c, 0x00, 0xd8, 0x54, 0x57, 0x6b, 0xae, 0x6b, 0xf6, 0x14, 0xcb, 0xd1, 0xae, + 0xa1, 0x3b, 0xd0, 0xad, 0x4c, 0xaa, 0x1f, 0xe8, 0x96, 0xad, 0xef, 0xd8, 0x58, 0x6d, 0xd7, 0xcc, + 0xc9, 0xd4, 0x7d, 0x9d, 0xda, 0xae, 0xe7, 0xa9, 0xeb, 0xe8, 0x3e, 0xdc, 0xa9, 0xce, 0x16, 0xf8, + 0xcf, 0xb0, 0xe3, 0x5b, 0x32, 0xa6, 0xaa, 0x5d, 0x07, 0xe0, 0xd4, 0x46, 0x5f, 0x85, 0x2b, 0xf3, + 0x74, 0x0f, 0xfb, 0xea, 0x25, 0x84, 0xa0, 0x7d, 0x66, 0xbb, 0x95, 0xb3, 0xd4, 0x72, 0x49, 0x77, + 0x7e, 0x56, 0xfe, 0x78, 0xbb, 0xa5, 0xfc, 0xf9, 0x76, 0x4b, 0xf9, 0xf7, 0xed, 0x96, 0x02, 0xb7, + 0xe3, 0xa4, 0xf6, 0xd1, 0xed, 0x80, 0x9f, 0x9f, 0x86, 0x39, 0x38, 0x54, 0x7e, 0xf8, 0xf6, 0xe5, + 0x59, 0x7a, 0x9c, 0x0c, 0x12, 0xc1, 0x46, 0x03, 0xf6, 0x7a, 0x92, 0xa4, 0x82, 0xa5, 0xd9, 0x20, + 0x11, 0xa3, 0xc9, 0x20, 0xe6, 0x82, 0xa5, 0x3c, 0x1c, 0x0d, 0xe6, 0xd8, 0x0f, 0x65, 0xf2, 0x87, + 0x2f, 0x19, 0x3f, 0xfe, 0xb7, 0xfe, 0x45, 0x4b, 0x62, 0x9f, 0xfd, 0x1f, 0x00, 0x00, 0xff, 0xff, + 0xc6, 0x22, 0x3f, 0x48, 0xfd, 0x0b, 0x00, 0x00, } func (m *ResourceSpans) Marshal() (dAtA []byte, err error) { @@ -1226,6 +1277,11 @@ func (m *Status) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.Code != 0 { + i = encodeVarintTrace(dAtA, i, uint64(m.Code)) + i-- + dAtA[i] = 0x18 + } if len(m.Message) > 0 { i -= len(m.Message) copy(dAtA[i:], m.Message) @@ -1233,8 +1289,8 @@ func (m *Status) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x12 } - if m.Code != 0 { - i = encodeVarintTrace(dAtA, i, uint64(m.Code)) + if m.DeprecatedCode != 0 { + i = encodeVarintTrace(dAtA, i, uint64(m.DeprecatedCode)) i-- dAtA[i] = 0x8 } @@ -1435,13 +1491,16 @@ func (m *Status) Size() (n int) { } var l int _ = l - if m.Code != 0 { - n += 1 + sovTrace(uint64(m.Code)) + if m.DeprecatedCode != 0 { + n += 1 + sovTrace(uint64(m.DeprecatedCode)) } l = len(m.Message) if l > 0 { n += 1 + l + sovTrace(uint64(l)) } + if m.Code != 0 { + n += 1 + sovTrace(uint64(m.Code)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -2543,9 +2602,9 @@ func (m *Status) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Code", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field DeprecatedCode", wireType) } - m.Code = 0 + m.DeprecatedCode = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTrace @@ -2555,7 +2614,7 @@ func (m *Status) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Code |= Status_StatusCode(b&0x7F) << shift + m.DeprecatedCode |= Status_DeprecatedStatusCode(b&0x7F) << shift if b < 0x80 { break } @@ -2592,6 +2651,25 @@ func (m *Status) Unmarshal(dAtA []byte) error { } m.Message = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Code", wireType) + } + m.Code = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTrace + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Code |= Status_StatusCode(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTrace(dAtA[iNdEx:]) diff --git a/exporters/otlp/internal/transform/metric.go b/exporters/otlp/internal/transform/metric.go index 20b063c389e..ad0432a6391 100644 --- a/exporters/otlp/internal/transform/metric.go +++ b/exporters/otlp/internal/transform/metric.go @@ -289,11 +289,71 @@ func Record(exportSelector export.ExportKindSelector, r export.Record) (*metricp } return gaugePoint(r, value, time.Time{}, tm) + case aggregation.ExactKind: + e, ok := agg.(aggregation.Points) + if !ok { + return nil, fmt.Errorf("%w: %T", ErrIncompatibleAgg, agg) + } + pts, err := e.Points() + if err != nil { + return nil, err + } + + return gaugeArray(r, pts) + default: return nil, fmt.Errorf("%w: %T", ErrUnimplementedAgg, agg) } } +func gaugeArray(record export.Record, points []number.Number) (*metricpb.Metric, error) { + desc := record.Descriptor() + m := &metricpb.Metric{ + Name: desc.Name(), + Description: desc.Description(), + Unit: string(desc.Unit()), + } + + switch n := desc.NumberKind(); n { + case number.Int64Kind: + var pts []*metricpb.IntDataPoint + for _, p := range points { + pts = append(pts, &metricpb.IntDataPoint{ + Labels: nil, + StartTimeUnixNano: toNanos(record.StartTime()), + TimeUnixNano: toNanos(record.EndTime()), + Value: p.CoerceToInt64(n), + }) + } + m.Data = &metricpb.Metric_IntGauge{ + IntGauge: &metricpb.IntGauge{ + DataPoints: pts, + }, + } + + case number.Float64Kind: + var pts []*metricpb.DoubleDataPoint + for _, p := range points { + pts = append(pts, &metricpb.DoubleDataPoint{ + Labels: nil, + StartTimeUnixNano: toNanos(record.StartTime()), + TimeUnixNano: toNanos(record.EndTime()), + Value: p.CoerceToFloat64(n), + }) + } + m.Data = &metricpb.Metric_DoubleGauge{ + DoubleGauge: &metricpb.DoubleGauge{ + DataPoints: pts, + }, + } + + default: + return nil, fmt.Errorf("%w: %v", ErrUnknownValueType, n) + } + + return m, nil +} + func gaugePoint(record export.Record, num number.Number, start, end time.Time) (*metricpb.Metric, error) { desc := record.Descriptor() labels := record.Labels() diff --git a/exporters/otlp/internal/transform/metric_test.go b/exporters/otlp/internal/transform/metric_test.go index d732fb1e996..f6fa64e58f3 100644 --- a/exporters/otlp/internal/transform/metric_test.go +++ b/exporters/otlp/internal/transform/metric_test.go @@ -32,7 +32,7 @@ import ( export "go.opentelemetry.io/otel/sdk/export/metric" "go.opentelemetry.io/otel/sdk/export/metric/aggregation" "go.opentelemetry.io/otel/sdk/export/metric/metrictest" - "go.opentelemetry.io/otel/sdk/metric/aggregator/array" + arrAgg "go.opentelemetry.io/otel/sdk/metric/aggregator/array" "go.opentelemetry.io/otel/sdk/metric/aggregator/lastvalue" lvAgg "go.opentelemetry.io/otel/sdk/metric/aggregator/lastvalue" "go.opentelemetry.io/otel/sdk/metric/aggregator/minmaxsumcount" @@ -243,6 +243,58 @@ func TestLastValueIntDataPoints(t *testing.T) { } } +func TestExactIntDataPoints(t *testing.T) { + desc := metric.NewDescriptor("", metric.ValueRecorderInstrumentKind, number.Int64Kind) + labels := label.NewSet() + e, ckpt := metrictest.Unslice2(arrAgg.New(2)) + assert.NoError(t, e.Update(context.Background(), number.Number(100), &desc)) + require.NoError(t, e.SynchronizedMove(ckpt, &desc)) + record := export.NewRecord(&desc, &labels, nil, ckpt.Aggregation(), intervalStart, intervalEnd) + p, ok := ckpt.(aggregation.Points) + require.True(t, ok, "ckpt is not an aggregation.Points: %T", ckpt) + pts, err := p.Points() + require.NoError(t, err) + + if m, err := gaugeArray(record, pts); assert.NoError(t, err) { + assert.Equal(t, []*metricpb.IntDataPoint{{ + Value: 100, + StartTimeUnixNano: toNanos(intervalStart), + TimeUnixNano: toNanos(intervalEnd), + }}, m.GetIntGauge().DataPoints) + assert.Nil(t, m.GetIntHistogram()) + assert.Nil(t, m.GetIntSum()) + assert.Nil(t, m.GetDoubleGauge()) + assert.Nil(t, m.GetDoubleHistogram()) + assert.Nil(t, m.GetDoubleSum()) + } +} + +func TestExactFloatDataPoints(t *testing.T) { + desc := metric.NewDescriptor("", metric.ValueRecorderInstrumentKind, number.Float64Kind) + labels := label.NewSet() + e, ckpt := metrictest.Unslice2(arrAgg.New(2)) + assert.NoError(t, e.Update(context.Background(), number.NewFloat64Number(100), &desc)) + require.NoError(t, e.SynchronizedMove(ckpt, &desc)) + record := export.NewRecord(&desc, &labels, nil, ckpt.Aggregation(), intervalStart, intervalEnd) + p, ok := ckpt.(aggregation.Points) + require.True(t, ok, "ckpt is not an aggregation.Points: %T", ckpt) + pts, err := p.Points() + require.NoError(t, err) + + if m, err := gaugeArray(record, pts); assert.NoError(t, err) { + assert.Equal(t, []*metricpb.DoubleDataPoint{{ + Value: 100, + StartTimeUnixNano: toNanos(intervalStart), + TimeUnixNano: toNanos(intervalEnd), + }}, m.GetDoubleGauge().DataPoints) + assert.Nil(t, m.GetIntHistogram()) + assert.Nil(t, m.GetIntSum()) + assert.Nil(t, m.GetIntGauge()) + assert.Nil(t, m.GetDoubleHistogram()) + assert.Nil(t, m.GetDoubleSum()) + } +} + func TestSumErrUnknownValueType(t *testing.T) { desc := metric.NewDescriptor("", metric.ValueRecorderInstrumentKind, number.Kind(-1)) labels := label.NewSet() @@ -357,11 +409,11 @@ func TestRecordAggregatorIncompatibleErrors(t *testing.T) { require.Nil(t, mpb) require.True(t, errors.Is(err, ErrIncompatibleAgg)) - mpb, err = makeMpb(aggregation.ExactKind, &array.New(1)[0]) + mpb, err = makeMpb(aggregation.ExactKind, &lastvalue.New(1)[0]) require.Error(t, err) require.Nil(t, mpb) - require.True(t, errors.Is(err, ErrUnimplementedAgg)) + require.True(t, errors.Is(err, ErrIncompatibleAgg)) } func TestRecordAggregatorUnexpectedErrors(t *testing.T) { diff --git a/exporters/otlp/internal/transform/span.go b/exporters/otlp/internal/transform/span.go index 78420739c45..7e575a6d14d 100644 --- a/exporters/otlp/internal/transform/span.go +++ b/exporters/otlp/internal/transform/span.go @@ -28,8 +28,9 @@ const ( maxMessageEventsPerSpan = 128 ) -// SpanData transforms a slice of SpanData into a slice of OTLP ResourceSpans. -func SpanData(sdl []*export.SpanData) []*tracepb.ResourceSpans { +// SpanData transforms a slice of SpanSnapshot into a slice of OTLP +// ResourceSpans. +func SpanData(sdl []*export.SpanSnapshot) []*tracepb.ResourceSpans { if len(sdl) == 0 { return nil } @@ -95,7 +96,7 @@ func SpanData(sdl []*export.SpanData) []*tracepb.ResourceSpans { } // span transforms a Span into an OTLP span. -func span(sd *export.SpanData) *tracepb.Span { +func span(sd *export.SpanSnapshot) *tracepb.Span { if sd == nil { return nil } @@ -129,7 +130,7 @@ func status(status codes.Code, message string) *tracepb.Status { var c tracepb.Status_StatusCode switch status { case codes.Error: - c = tracepb.Status_STATUS_CODE_UNKNOWN_ERROR + c = tracepb.Status_STATUS_CODE_ERROR default: c = tracepb.Status_STATUS_CODE_OK } diff --git a/exporters/otlp/internal/transform/span_test.go b/exporters/otlp/internal/transform/span_test.go index 8a339d7427c..1a80a18946a 100644 --- a/exporters/otlp/internal/transform/span_test.go +++ b/exporters/otlp/internal/transform/span_test.go @@ -172,7 +172,7 @@ func TestStatus(t *testing.T) { { codes.Error, "test Error", - tracepb.Status_STATUS_CODE_UNKNOWN_ERROR, + tracepb.Status_STATUS_CODE_ERROR, }, } { expected := &tracepb.Status{Code: test.otlpStatus, Message: test.message} @@ -199,7 +199,7 @@ func TestSpanData(t *testing.T) { // March 31, 2020 5:01:26 1234nanos (UTC) startTime := time.Unix(1585674086, 1234) endTime := startTime.Add(10 * time.Second) - spanData := &export.SpanData{ + spanData := &export.SpanSnapshot{ SpanContext: trace.SpanContext{ TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}, SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8}, @@ -279,7 +279,7 @@ func TestSpanData(t *testing.T) { DroppedLinksCount: 3, } - got := SpanData([]*export.SpanData{spanData}) + got := SpanData([]*export.SpanSnapshot{spanData}) require.Len(t, got, 1) assert.Equal(t, got[0].GetResource(), Resource(spanData.Resource)) @@ -296,7 +296,7 @@ func TestSpanData(t *testing.T) { // Empty parent span ID should be treated as root span. func TestRootSpanData(t *testing.T) { - sd := SpanData([]*export.SpanData{{}}) + sd := SpanData([]*export.SpanSnapshot{{}}) require.Len(t, sd, 1) rs := sd[0] got := rs.GetInstrumentationLibrarySpans()[0].GetSpans()[0].GetParentSpanId() @@ -306,5 +306,5 @@ func TestRootSpanData(t *testing.T) { } func TestSpanDataNilResource(t *testing.T) { - assert.NotPanics(t, func() { SpanData([]*export.SpanData{{}}) }) + assert.NotPanics(t, func() { SpanData([]*export.SpanSnapshot{{}}) }) } diff --git a/exporters/otlp/options.go b/exporters/otlp/options.go index 737f56b8c08..3fdb9b64d92 100644 --- a/exporters/otlp/options.go +++ b/exporters/otlp/options.go @@ -30,10 +30,6 @@ const ( // DefaultCollectorHost is the host address the Exporter will attempt // connect to if no collector address is provided. DefaultCollectorHost string = "localhost" - // DefaultNumWorkers is the number of goroutines the Exporter will use when - // processing telemetry. - DefaultNumWorkers uint = 1 - // DefaultGRPCServiceConfig is the gRPC service config used if none is // provided by the user. // @@ -84,20 +80,9 @@ type config struct { grpcDialOptions []grpc.DialOption headers map[string]string clientCredentials credentials.TransportCredentials - numWorkers uint exportKindSelector metricsdk.ExportKindSelector } -// WorkerCount sets the number of Goroutines to use when processing telemetry. -func WorkerCount(n uint) ExporterOption { - if n == 0 { - n = DefaultNumWorkers - } - return func(cfg *config) { - cfg.numWorkers = n - } -} - // WithInsecure disables client transport security for the exporter's gRPC connection // just like grpc.WithInsecure() https://pkg.go.dev/google.golang.org/grpc#WithInsecure // does. Note, by default, client security is required unless WithInsecure is used. diff --git a/exporters/otlp/otlp.go b/exporters/otlp/otlp.go index 8c60aeb8e5f..d040781e07c 100644 --- a/exporters/otlp/otlp.go +++ b/exporters/otlp/otlp.go @@ -20,12 +20,9 @@ package otlp // import "go.opentelemetry.io/otel/exporters/otlp" import ( "context" "errors" - "fmt" "sync" - "unsafe" "google.golang.org/grpc" - "google.golang.org/grpc/metadata" colmetricpb "go.opentelemetry.io/otel/exporters/otlp/internal/opentelemetry-proto-gen/collector/metrics/v1" coltracepb "go.opentelemetry.io/otel/exporters/otlp/internal/opentelemetry-proto-gen/collector/trace/v1" @@ -43,21 +40,16 @@ type Exporter struct { // mu protects the non-atomic and non-channel variables mu sync.RWMutex // senderMu protects the concurrent unsafe sends on the shared gRPC client connection. - senderMu sync.Mutex - started bool - traceExporter coltracepb.TraceServiceClient - metricExporter colmetricpb.MetricsServiceClient - grpcClientConn *grpc.ClientConn - lastConnectErrPtr unsafe.Pointer + senderMu sync.Mutex + started bool + traceExporter coltracepb.TraceServiceClient + metricExporter colmetricpb.MetricsServiceClient + cc *grpcConnection - startOnce sync.Once - stopCh chan bool - disconnectedCh chan bool + startOnce sync.Once + stopOnce sync.Once - backgroundConnectionDoneCh chan bool - - c config - metadata metadata.MD + exportKindSelector metricsdk.ExportKindSelector } var _ tracesdk.SpanExporter = (*Exporter)(nil) @@ -67,7 +59,6 @@ var _ metricsdk.Exporter = (*Exporter)(nil) // any ExporterOptions provided. func newConfig(opts ...ExporterOption) config { cfg := config{ - numWorkers: DefaultNumWorkers, grpcServiceConfig: DefaultGRPCServiceConfig, // Note: the default ExportKindSelector is specified @@ -82,9 +73,9 @@ func newConfig(opts ...ExporterOption) config { } // NewExporter constructs a new Exporter and starts it. -func NewExporter(opts ...ExporterOption) (*Exporter, error) { +func NewExporter(ctx context.Context, opts ...ExporterOption) (*Exporter, error) { exp := NewUnstartedExporter(opts...) - if err := exp.Start(); err != nil { + if err := exp.Start(ctx); err != nil { return nil, err } return exp, nil @@ -93,19 +84,29 @@ func NewExporter(opts ...ExporterOption) (*Exporter, error) { // NewUnstartedExporter constructs a new Exporter and does not start it. func NewUnstartedExporter(opts ...ExporterOption) *Exporter { e := new(Exporter) - e.c = newConfig(opts...) - if len(e.c.headers) > 0 { - e.metadata = metadata.New(e.c.headers) - } + cfg := newConfig(opts...) + e.exportKindSelector = cfg.exportKindSelector + e.cc = newGRPCConnection(cfg, e.handleNewConnection) return e } +func (e *Exporter) handleNewConnection(cc *grpc.ClientConn) error { + e.mu.Lock() + defer e.mu.Unlock() + if cc != nil { + e.metricExporter = colmetricpb.NewMetricsServiceClient(cc) + e.traceExporter = coltracepb.NewTraceServiceClient(cc) + } else { + e.metricExporter = nil + e.traceExporter = nil + } + return nil +} + var ( - errAlreadyStarted = errors.New("already started") - errNotStarted = errors.New("not started") - errDisconnected = errors.New("exporter disconnected") - errStopped = errors.New("exporter stopped") - errContextCanceled = errors.New("context canceled") + errNoClient = errors.New("no client") + errAlreadyStarted = errors.New("already started") + errDisconnected = errors.New("exporter disconnected") ) // Start dials to the collector, establishing a connection to it. It also @@ -113,108 +114,25 @@ var ( // messages that consist of the node identifier. Start invokes a background // connector that will reattempt connections to the collector periodically // if the connection dies. -func (e *Exporter) Start() error { +func (e *Exporter) Start(ctx context.Context) error { var err = errAlreadyStarted e.startOnce.Do(func() { e.mu.Lock() e.started = true - e.disconnectedCh = make(chan bool, 1) - e.stopCh = make(chan bool) - e.backgroundConnectionDoneCh = make(chan bool) e.mu.Unlock() - // An optimistic first connection attempt to ensure that - // applications under heavy load can immediately process - // data. See https://github.com/census-ecosystem/opencensus-go-exporter-ocagent/pull/63 - if err := e.connect(); err == nil { - e.setStateConnected() - } else { - e.setStateDisconnected(err) - } - go e.indefiniteBackgroundConnection() - err = nil + e.cc.startConnection(ctx) }) return err } -func (e *Exporter) prepareCollectorAddress() string { - if e.c.collectorAddr != "" { - return e.c.collectorAddr - } - return fmt.Sprintf("%s:%d", DefaultCollectorHost, DefaultCollectorPort) -} - -func (e *Exporter) enableConnections(cc *grpc.ClientConn) error { - e.mu.RLock() - started := e.started - e.mu.RUnlock() - - if !started { - return errNotStarted - } - - e.mu.Lock() - // If previous clientConn is same as the current then just return. - // This doesn't happen right now as this func is only called with new ClientConn. - // It is more about future-proofing. - if e.grpcClientConn == cc { - e.mu.Unlock() - return nil - } - // If the previous clientConn was non-nil, close it - if e.grpcClientConn != nil { - _ = e.grpcClientConn.Close() - } - e.grpcClientConn = cc - e.traceExporter = coltracepb.NewTraceServiceClient(cc) - e.metricExporter = colmetricpb.NewMetricsServiceClient(cc) - e.mu.Unlock() - - return nil -} - -func (e *Exporter) contextWithMetadata(ctx context.Context) context.Context { - if e.metadata.Len() > 0 { - return metadata.NewOutgoingContext(ctx, e.metadata) - } - return ctx -} - -func (e *Exporter) dialToCollector() (*grpc.ClientConn, error) { - addr := e.prepareCollectorAddress() - - dialOpts := []grpc.DialOption{} - if e.c.grpcServiceConfig != "" { - dialOpts = append(dialOpts, grpc.WithDefaultServiceConfig(e.c.grpcServiceConfig)) - } - if e.c.clientCredentials != nil { - dialOpts = append(dialOpts, grpc.WithTransportCredentials(e.c.clientCredentials)) - } else if e.c.canDialInsecure { - dialOpts = append(dialOpts, grpc.WithInsecure()) - } - if e.c.compressor != "" { - dialOpts = append(dialOpts, grpc.WithDefaultCallOptions(grpc.UseCompressor(e.c.compressor))) - } - if len(e.c.grpcDialOptions) != 0 { - dialOpts = append(dialOpts, e.c.grpcDialOptions...) - } - - ctx := e.contextWithMetadata(context.Background()) - return grpc.DialContext(ctx, addr, dialOpts...) -} - -// closeStopCh is used to wrap the exporters stopCh channel closing for testing. -var closeStopCh = func(stopCh chan bool) { - close(stopCh) -} - // Shutdown closes all connections and releases resources currently being used // by the exporter. If the exporter is not started this does nothing. func (e *Exporter) Shutdown(ctx context.Context) error { e.mu.RLock() - cc := e.grpcClientConn + cc := e.cc started := e.started e.mu.RUnlock() @@ -223,23 +141,16 @@ func (e *Exporter) Shutdown(ctx context.Context) error { } var err error - if cc != nil { + + e.stopOnce.Do(func() { // Clean things up before checking this error. - err = cc.Close() - } + err = cc.shutdown(ctx) - // At this point we can change the state variable started - e.mu.Lock() - e.started = false - e.mu.Unlock() - closeStopCh(e.stopCh) - - // Ensure that the backgroundConnector returns - select { - case <-e.backgroundConnectionDoneCh: - case <-ctx.Done(): - return ctx.Err() - } + // At this point we can change the state variable started + e.mu.Lock() + e.started = false + e.mu.Unlock() + }) return err } @@ -248,78 +159,75 @@ func (e *Exporter) Shutdown(ctx context.Context) error { // interface. It transforms and batches metric Records into OTLP Metrics and // transmits them to the configured collector. func (e *Exporter) Export(parent context.Context, cps metricsdk.CheckpointSet) error { - // Unify the parent context Done signal with the exporter stopCh. - ctx, cancel := context.WithCancel(parent) + ctx, cancel := e.cc.contextWithStop(parent) defer cancel() - go func(ctx context.Context, cancel context.CancelFunc) { - select { - case <-ctx.Done(): - case <-e.stopCh: - cancel() - } - }(ctx, cancel) - rms, err := transform.CheckpointSet(ctx, e, cps, e.c.numWorkers) + // Hardcode the number of worker goroutines to 1. We later will + // need to see if there's a way to adjust that number for longer + // running operations. + rms, err := transform.CheckpointSet(ctx, e, cps, 1) if err != nil { return err } - if !e.connected() { + if !e.cc.connected() { return errDisconnected } - select { - case <-e.stopCh: - return errStopped - case <-ctx.Done(): - return errContextCanceled - default: + err = func() error { e.senderMu.Lock() - _, err := e.metricExporter.Export(e.contextWithMetadata(ctx), &colmetricpb.ExportMetricsServiceRequest{ + defer e.senderMu.Unlock() + if e.metricExporter == nil { + return errNoClient + } + _, err := e.metricExporter.Export(e.cc.contextWithMetadata(ctx), &colmetricpb.ExportMetricsServiceRequest{ ResourceMetrics: rms, }) - e.senderMu.Unlock() - if err != nil { - return err - } + return err + }() + if err != nil { + e.cc.setStateDisconnected(err) } - return nil + return err } // ExportKindFor reports back to the OpenTelemetry SDK sending this Exporter // metric telemetry that it needs to be provided in a cumulative format. func (e *Exporter) ExportKindFor(desc *metric.Descriptor, kind aggregation.Kind) metricsdk.ExportKind { - return e.c.exportKindSelector.ExportKindFor(desc, kind) + return e.exportKindSelector.ExportKindFor(desc, kind) } -// ExportSpans exports a batch of SpanData. -func (e *Exporter) ExportSpans(ctx context.Context, sds []*tracesdk.SpanData) error { - return e.uploadTraces(ctx, sds) +// ExportSpans exports a batch of SpanSnapshot. +func (e *Exporter) ExportSpans(ctx context.Context, ss []*tracesdk.SpanSnapshot) error { + return e.uploadTraces(ctx, ss) } -func (e *Exporter) uploadTraces(ctx context.Context, sdl []*tracesdk.SpanData) error { - select { - case <-e.stopCh: +func (e *Exporter) uploadTraces(ctx context.Context, ss []*tracesdk.SpanSnapshot) error { + ctx, cancel := e.cc.contextWithStop(ctx) + defer cancel() + + if !e.cc.connected() { return nil - default: - if !e.connected() { - return nil - } + } - protoSpans := transform.SpanData(sdl) - if len(protoSpans) == 0 { - return nil - } + protoSpans := transform.SpanData(ss) + if len(protoSpans) == 0 { + return nil + } + err := func() error { e.senderMu.Lock() - _, err := e.traceExporter.Export(e.contextWithMetadata(ctx), &coltracepb.ExportTraceServiceRequest{ + defer e.senderMu.Unlock() + if e.traceExporter == nil { + return errNoClient + } + _, err := e.traceExporter.Export(e.cc.contextWithMetadata(ctx), &coltracepb.ExportTraceServiceRequest{ ResourceSpans: protoSpans, }) - e.senderMu.Unlock() - if err != nil { - e.setStateDisconnected(err) - return err - } + return err + }() + if err != nil { + e.cc.setStateDisconnected(err) } - return nil + return err } diff --git a/exporters/otlp/otlp_integration_test.go b/exporters/otlp/otlp_integration_test.go index 70f32c46571..c452bcfa1e0 100644 --- a/exporters/otlp/otlp_integration_test.go +++ b/exporters/otlp/otlp_integration_test.go @@ -72,12 +72,13 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption) } opts = append(opts, additionalOpts...) - exp, err := otlp.NewExporter(opts...) + ctx := context.Background() + exp, err := otlp.NewExporter(ctx, opts...) if err != nil { t.Fatalf("failed to create a new collector exporter: %v", err) } defer func() { - ctx, cancel := context.WithTimeout(context.Background(), time.Second) + ctx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() if err := exp.Shutdown(ctx); err != nil { panic(err) @@ -110,11 +111,11 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption) // Now create few spans m := 4 for i := 0; i < m; i++ { - _, span := tr1.Start(context.Background(), "AlwaysSample") + _, span := tr1.Start(ctx, "AlwaysSample") span.SetAttributes(label.Int64("i", int64(i))) span.End() - _, span = tr2.Start(context.Background(), "AlwaysSample") + _, span = tr2.Start(ctx, "AlwaysSample") span.SetAttributes(label.Int64("i", int64(i))) span.End() } @@ -124,7 +125,6 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption) pusher := push.New(processor, exp) pusher.Start() - ctx := context.Background() meter := pusher.MeterProvider().Meter("test-meter") labels := []label.KeyValue{label.Bool("test", true)} @@ -190,7 +190,7 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption) <-time.After(40 * time.Millisecond) // Now shutdown the exporter - ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond) + ctx, cancel := context.WithTimeout(ctx, time.Millisecond) defer cancel() if err := exp.Shutdown(ctx); err != nil { t.Fatalf("failed to stop the exporter: %v", err) @@ -307,31 +307,33 @@ func TestNewExporter_invokeStartThenStopManyTimes(t *testing.T) { _ = mc.stop() }() - exp, err := otlp.NewExporter(otlp.WithInsecure(), + ctx := context.Background() + exp, err := otlp.NewExporter(ctx, + otlp.WithInsecure(), otlp.WithReconnectionPeriod(50*time.Millisecond), otlp.WithAddress(mc.address)) if err != nil { t.Fatalf("error creating exporter: %v", err) } defer func() { - if err := exp.Shutdown(context.Background()); err != nil { + if err := exp.Shutdown(ctx); err != nil { panic(err) } }() // Invoke Start numerous times, should return errAlreadyStarted for i := 0; i < 10; i++ { - if err := exp.Start(); err == nil || !strings.Contains(err.Error(), "already started") { + if err := exp.Start(ctx); err == nil || !strings.Contains(err.Error(), "already started") { t.Fatalf("#%d unexpected Start error: %v", i, err) } } - if err := exp.Shutdown(context.Background()); err != nil { + if err := exp.Shutdown(ctx); err != nil { t.Fatalf("failed to Shutdown the exporter: %v", err) } // Invoke Shutdown numerous times for i := 0; i < 10; i++ { - if err := exp.Shutdown(context.Background()); err != nil { + if err := exp.Shutdown(ctx); err != nil { t.Fatalf(`#%d got error (%v) expected none`, i, err) } } @@ -341,14 +343,16 @@ func TestNewExporter_collectorConnectionDiesThenReconnects(t *testing.T) { mc := runMockCol(t) reconnectionPeriod := 20 * time.Millisecond - exp, err := otlp.NewExporter(otlp.WithInsecure(), + ctx := context.Background() + exp, err := otlp.NewExporter(ctx, + otlp.WithInsecure(), otlp.WithAddress(mc.address), otlp.WithReconnectionPeriod(reconnectionPeriod)) if err != nil { t.Fatalf("Unexpected error: %v", err) } defer func() { - _ = exp.Shutdown(context.Background()) + _ = exp.Shutdown(ctx) }() // We'll now stop the collector right away to simulate a connection @@ -363,7 +367,7 @@ func TestNewExporter_collectorConnectionDiesThenReconnects(t *testing.T) { // No endpoint up. require.Error( t, - exp.ExportSpans(context.Background(), []*exporttrace.SpanData{{Name: "in the midst"}}), + exp.ExportSpans(ctx, []*exporttrace.SpanSnapshot{{Name: "in the midst"}}), "transport: Error while dialing dial tcp %s: connect: connection refused", mc.address, ) @@ -377,11 +381,11 @@ func TestNewExporter_collectorConnectionDiesThenReconnects(t *testing.T) { n := 10 for i := 0; i < n; i++ { - require.NoError(t, exp.ExportSpans(context.Background(), []*exporttrace.SpanData{{Name: "Resurrected"}})) + require.NoError(t, exp.ExportSpans(ctx, []*exporttrace.SpanSnapshot{{Name: "Resurrected"}})) } nmaSpans := nmc.getSpans() - // Expecting 10 spanData that were sampled, given that + // Expecting 10 SpanSnapshots that were sampled, given that if g, w := len(nmaSpans), n; g != w { t.Fatalf("Round #%d: Connected collector: spans: got %d want %d", j, g, w) } @@ -412,13 +416,15 @@ func TestNewExporter_collectorOnBadConnection(t *testing.T) { _, collectorPortStr, _ := net.SplitHostPort(ln.Addr().String()) address := fmt.Sprintf("localhost:%s", collectorPortStr) - exp, err := otlp.NewExporter(otlp.WithInsecure(), + ctx := context.Background() + exp, err := otlp.NewExporter(ctx, + otlp.WithInsecure(), otlp.WithReconnectionPeriod(50*time.Millisecond), otlp.WithAddress(address)) if err != nil { t.Fatalf("Despite an indefinite background reconnection, got error: %v", err) } - _ = exp.Shutdown(context.Background()) + _ = exp.Shutdown(ctx) } func TestNewExporter_withAddress(t *testing.T) { @@ -432,11 +438,12 @@ func TestNewExporter_withAddress(t *testing.T) { otlp.WithReconnectionPeriod(50*time.Millisecond), otlp.WithAddress(mc.address)) + ctx := context.Background() defer func() { - _ = exp.Shutdown(context.Background()) + _ = exp.Shutdown(ctx) }() - if err := exp.Start(); err != nil { + if err := exp.Start(ctx); err != nil { t.Fatalf("Unexpected Start error: %v", err) } } @@ -447,16 +454,17 @@ func TestNewExporter_withHeaders(t *testing.T) { _ = mc.stop() }() - exp, _ := otlp.NewExporter( + ctx := context.Background() + exp, _ := otlp.NewExporter(ctx, otlp.WithInsecure(), otlp.WithReconnectionPeriod(50*time.Millisecond), otlp.WithAddress(mc.address), otlp.WithHeaders(map[string]string{"header1": "value1"}), ) - require.NoError(t, exp.ExportSpans(context.Background(), []*exporttrace.SpanData{{Name: "in the midst"}})) + require.NoError(t, exp.ExportSpans(ctx, []*exporttrace.SpanSnapshot{{Name: "in the midst"}})) defer func() { - _ = exp.Shutdown(context.Background()) + _ = exp.Shutdown(ctx) }() headers := mc.getHeaders() @@ -473,14 +481,15 @@ func TestNewExporter_withMultipleAttributeTypes(t *testing.T) { <-time.After(5 * time.Millisecond) - exp, _ := otlp.NewExporter( + ctx := context.Background() + exp, _ := otlp.NewExporter(ctx, otlp.WithInsecure(), otlp.WithReconnectionPeriod(50*time.Millisecond), otlp.WithAddress(mc.address), ) defer func() { - _ = exp.Shutdown(context.Background()) + _ = exp.Shutdown(ctx) }() tp := sdktrace.NewTracerProvider( @@ -492,7 +501,7 @@ func TestNewExporter_withMultipleAttributeTypes(t *testing.T) { sdktrace.WithMaxExportBatchSize(10), ), ) - defer func() { _ = tp.Shutdown(context.Background()) }() + defer func() { _ = tp.Shutdown(ctx) }() tr := tp.Tracer("test-tracer") testKvs := []label.KeyValue{ @@ -504,7 +513,7 @@ func TestNewExporter_withMultipleAttributeTypes(t *testing.T) { label.Bool("Bool", true), label.String("String", "test"), } - _, span := tr.Start(context.Background(), "AlwaysSample") + _, span := tr.Start(ctx, "AlwaysSample") span.SetAttributes(testKvs...) span.End() @@ -520,7 +529,7 @@ func TestNewExporter_withMultipleAttributeTypes(t *testing.T) { <-time.After(40 * time.Millisecond) // Now shutdown the exporter - ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond) + ctx, cancel := context.WithTimeout(ctx, time.Millisecond) defer cancel() if err := exp.Shutdown(ctx); err != nil { t.Fatalf("failed to stop the exporter: %v", err) diff --git a/exporters/otlp/otlp_metric_test.go b/exporters/otlp/otlp_metric_test.go index c4ebca4c905..120b88ad8eb 100644 --- a/exporters/otlp/otlp_metric_test.go +++ b/exporters/otlp/otlp_metric_test.go @@ -767,15 +767,7 @@ func TestStatelessExportKind(t *testing.T) { // What works single-threaded should work multi-threaded func runMetricExportTests(t *testing.T, opts []ExporterOption, rs []record, expected []metricpb.ResourceMetrics) { - t.Run("1 goroutine", func(t *testing.T) { - runMetricExportTest(t, NewUnstartedExporter(append(opts[:len(opts):len(opts)], WorkerCount(1))...), rs, expected) - }) - t.Run("20 goroutines", func(t *testing.T) { - runMetricExportTest(t, NewUnstartedExporter(append(opts[:len(opts):len(opts)], WorkerCount(20))...), rs, expected) - }) -} - -func runMetricExportTest(t *testing.T, exp *Exporter, rs []record, expected []metricpb.ResourceMetrics) { + exp := NewUnstartedExporter(opts...) msc := &metricsServiceClientStub{} exp.metricExporter = msc exp.started = true diff --git a/exporters/otlp/otlp_span_test.go b/exporters/otlp/otlp_span_test.go index 2e0e71b3462..e967e507d17 100644 --- a/exporters/otlp/otlp_span_test.go +++ b/exporters/otlp/otlp_span_test.go @@ -68,19 +68,19 @@ func TestExportSpans(t *testing.T) { endTime := startTime.Add(10 * time.Second) for _, test := range []struct { - sd []*tracesdk.SpanData + sd []*tracesdk.SpanSnapshot want []tracepb.ResourceSpans }{ { - []*tracesdk.SpanData(nil), + []*tracesdk.SpanSnapshot(nil), []tracepb.ResourceSpans(nil), }, { - []*tracesdk.SpanData{}, + []*tracesdk.SpanSnapshot{}, []tracepb.ResourceSpans(nil), }, { - []*tracesdk.SpanData{ + []*tracesdk.SpanSnapshot{ { SpanContext: trace.SpanContext{ TraceID: trace.TraceID([16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}), @@ -341,7 +341,7 @@ func TestExportSpans(t *testing.T) { }, }, Status: &tracepb.Status{ - Code: tracepb.Status_STATUS_CODE_UNKNOWN_ERROR, + Code: tracepb.Status_STATUS_CODE_ERROR, Message: "Unauthenticated", }, }, diff --git a/exporters/otlp/otlp_test.go b/exporters/otlp/otlp_test.go index d2e808ebf65..afcb28ddfea 100644 --- a/exporters/otlp/otlp_test.go +++ b/exporters/otlp/otlp_test.go @@ -17,26 +17,24 @@ package otlp import ( "context" "errors" + "sync" "testing" "time" ) func TestExporterShutdownHonorsTimeout(t *testing.T) { - orig := closeStopCh ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) - defer func() { - cancel() - closeStopCh = orig - }() - closeStopCh = func(stopCh chan bool) { + defer cancel() + + e := NewUnstartedExporter() + orig := e.cc.closeBackgroundConnectionDoneCh + e.cc.closeBackgroundConnectionDoneCh = func(ch chan struct{}) { go func() { <-ctx.Done() - close(stopCh) + orig(ch) }() } - - e := NewUnstartedExporter() - if err := e.Start(); err != nil { + if err := e.Start(ctx); err != nil { t.Fatalf("failed to start exporter: %v", err) } @@ -50,21 +48,18 @@ func TestExporterShutdownHonorsTimeout(t *testing.T) { } func TestExporterShutdownHonorsCancel(t *testing.T) { - orig := closeStopCh ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) - defer func() { - cancel() - closeStopCh = orig - }() - closeStopCh = func(stopCh chan bool) { + defer cancel() + + e := NewUnstartedExporter() + orig := e.cc.closeBackgroundConnectionDoneCh + e.cc.closeBackgroundConnectionDoneCh = func(ch chan struct{}) { go func() { <-ctx.Done() - close(stopCh) + orig(ch) }() } - - e := NewUnstartedExporter() - if err := e.Start(); err != nil { + if err := e.Start(ctx); err != nil { t.Fatalf("failed to start exporter: %v", err) } @@ -83,7 +78,7 @@ func TestExporterShutdownNoError(t *testing.T) { defer cancel() e := NewUnstartedExporter() - if err := e.Start(); err != nil { + if err := e.Start(ctx); err != nil { t.Fatalf("failed to start exporter: %v", err) } @@ -91,3 +86,30 @@ func TestExporterShutdownNoError(t *testing.T) { t.Errorf("shutdown errored: expected nil, got %v", err) } } + +func TestExporterShutdownManyTimes(t *testing.T) { + ctx := context.Background() + e, err := NewExporter(ctx) + if err != nil { + t.Fatalf("failed to start an exporter: %v", err) + } + ch := make(chan struct{}) + wg := sync.WaitGroup{} + const num int = 20 + wg.Add(num) + errs := make([]error, num) + for i := 0; i < num; i++ { + go func(idx int) { + defer wg.Done() + <-ch + errs[idx] = e.Shutdown(ctx) + }(i) + } + close(ch) + wg.Wait() + for _, err := range errs { + if err != nil { + t.Fatalf("failed to shutdown exporter: %v", err) + } + } +} diff --git a/exporters/stdout/example_test.go b/exporters/stdout/example_test.go index 21a061ba2c0..e537f71e4d2 100644 --- a/exporters/stdout/example_test.go +++ b/exporters/stdout/example_test.go @@ -18,8 +18,8 @@ import ( "context" "log" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/stdout" - "go.opentelemetry.io/otel/global" "go.opentelemetry.io/otel/label" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" @@ -31,12 +31,12 @@ const ( ) var ( - tracer = global.TracerProvider().Tracer( + tracer = otel.GetTracerProvider().Tracer( instrumentationName, trace.WithInstrumentationVersion(instrumentationVersion), ) - meter = global.MeterProvider().Meter( + meter = otel.GetMeterProvider().Meter( instrumentationName, metric.WithInstrumentationVersion(instrumentationVersion), ) diff --git a/exporters/stdout/exporter.go b/exporters/stdout/exporter.go index 493a71a525a..21a64c022cd 100644 --- a/exporters/stdout/exporter.go +++ b/exporters/stdout/exporter.go @@ -15,7 +15,7 @@ package stdout // import "go.opentelemetry.io/otel/exporters/stdout" import ( - "go.opentelemetry.io/otel/global" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/sdk/export/metric" exporttrace "go.opentelemetry.io/otel/sdk/export/trace" "go.opentelemetry.io/otel/sdk/metric/controller/push" @@ -87,7 +87,7 @@ func InstallNewPipeline(exportOpts []Option, pushOpts []push.Option) (*push.Cont if err != nil { return controller, err } - global.SetTracerProvider(tracerProvider) - global.SetMeterProvider(controller.MeterProvider()) + otel.SetTracerProvider(tracerProvider) + otel.SetMeterProvider(controller.MeterProvider()) return controller, err } diff --git a/exporters/stdout/go.mod b/exporters/stdout/go.mod index 9bf96e406aa..28829e51856 100644 --- a/exporters/stdout/go.mod +++ b/exporters/stdout/go.mod @@ -9,6 +9,6 @@ replace ( require ( github.com/stretchr/testify v1.6.1 - go.opentelemetry.io/otel v0.13.0 - go.opentelemetry.io/otel/sdk v0.13.0 + go.opentelemetry.io/otel v0.15.0 + go.opentelemetry.io/otel/sdk v0.15.0 ) diff --git a/exporters/stdout/go.sum b/exporters/stdout/go.sum index 1680073b00e..ae3c891c195 100644 --- a/exporters/stdout/go.sum +++ b/exporters/stdout/go.sum @@ -4,8 +4,8 @@ github.com/benbjohnson/clock v1.0.3 h1:vkLuvpK4fmtSCuo60+yC63p7y0BmQ8gm5ZXGuBCJy github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/exporters/stdout/trace.go b/exporters/stdout/trace.go index 85a595dbca3..a80e35d174e 100644 --- a/exporters/stdout/trace.go +++ b/exporters/stdout/trace.go @@ -31,8 +31,8 @@ type traceExporter struct { stopped bool } -// ExportSpans writes SpanData in json format to stdout. -func (e *traceExporter) ExportSpans(ctx context.Context, data []*trace.SpanData) error { +// ExportSpans writes SpanSnapshots in json format to stdout. +func (e *traceExporter) ExportSpans(ctx context.Context, ss []*trace.SpanSnapshot) error { e.stoppedMu.RLock() stopped := e.stopped e.stoppedMu.RUnlock() @@ -40,10 +40,10 @@ func (e *traceExporter) ExportSpans(ctx context.Context, data []*trace.SpanData) return nil } - if e.config.DisableTraceExport || len(data) == 0 { + if e.config.DisableTraceExport || len(ss) == 0 { return nil } - out, err := e.marshal(data) + out, err := e.marshal(ss) if err != nil { return err } diff --git a/exporters/stdout/trace_test.go b/exporters/stdout/trace_test.go index 83df6fe4ab4..ed2f4f31030 100644 --- a/exporters/stdout/trace_test.go +++ b/exporters/stdout/trace_test.go @@ -46,7 +46,7 @@ func TestExporter_ExportSpan(t *testing.T) { doubleValue := 123.456 resource := resource.NewWithAttributes(label.String("rk1", "rv11")) - testSpan := &export.SpanData{ + testSpan := &export.SpanSnapshot{ SpanContext: trace.SpanContext{ TraceID: traceID, SpanID: spanID, @@ -67,7 +67,7 @@ func TestExporter_ExportSpan(t *testing.T) { StatusMessage: "interesting", Resource: resource, } - if err := ex.ExportSpans(context.Background(), []*export.SpanData{testSpan}); err != nil { + if err := ex.ExportSpans(context.Background(), []*export.SpanSnapshot{testSpan}); err != nil { t.Fatal(err) } diff --git a/exporters/trace/jaeger/env.go b/exporters/trace/jaeger/env.go index ecf2fd7bdfa..d2f7fe284c5 100644 --- a/exporters/trace/jaeger/env.go +++ b/exporters/trace/jaeger/env.go @@ -20,7 +20,7 @@ import ( "strconv" "strings" - "go.opentelemetry.io/otel/global" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/label" ) @@ -81,7 +81,7 @@ func ProcessFromEnv() Process { if e := os.Getenv(envTags); e != "" { tags, err := parseTags(e) if err != nil { - global.Handle(err) + otel.Handle(err) } else { p.Tags = tags } diff --git a/exporters/trace/jaeger/go.mod b/exporters/trace/jaeger/go.mod index 6ee37106496..deb27449bde 100644 --- a/exporters/trace/jaeger/go.mod +++ b/exporters/trace/jaeger/go.mod @@ -9,9 +9,9 @@ replace ( require ( github.com/apache/thrift v0.13.0 - github.com/google/go-cmp v0.5.2 + github.com/google/go-cmp v0.5.4 github.com/stretchr/testify v1.6.1 - go.opentelemetry.io/otel v0.13.0 - go.opentelemetry.io/otel/sdk v0.13.0 + go.opentelemetry.io/otel v0.15.0 + go.opentelemetry.io/otel/sdk v0.15.0 google.golang.org/api v0.32.0 ) diff --git a/exporters/trace/jaeger/go.sum b/exporters/trace/jaeger/go.sum index 9386b3cb4e8..5ef4eb0bcd1 100644 --- a/exporters/trace/jaeger/go.sum +++ b/exporters/trace/jaeger/go.sum @@ -89,6 +89,8 @@ github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= diff --git a/exporters/trace/jaeger/jaeger.go b/exporters/trace/jaeger/jaeger.go index 05df3cd5df2..cfd3f71ebee 100644 --- a/exporters/trace/jaeger/jaeger.go +++ b/exporters/trace/jaeger/jaeger.go @@ -22,9 +22,9 @@ import ( "google.golang.org/api/support/bundler" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/codes" gen "go.opentelemetry.io/otel/exporters/trace/jaeger/internal/gen-go/jaeger" - "go.opentelemetry.io/otel/global" "go.opentelemetry.io/otel/label" export "go.opentelemetry.io/otel/sdk/export/trace" sdktrace "go.opentelemetry.io/otel/sdk/trace" @@ -129,7 +129,7 @@ func NewRawExporter(endpointOption EndpointOption, opts ...Option) (*Exporter, e } bundler := bundler.NewBundler((*gen.Span)(nil), func(bundle interface{}) { if err := e.upload(bundle.([]*gen.Span)); err != nil { - global.Handle(err) + otel.Handle(err) } }) @@ -182,7 +182,7 @@ func InstallNewPipeline(endpointOption EndpointOption, opts ...Option) (func(), return nil, err } - global.SetTracerProvider(tp) + otel.SetTracerProvider(tp) return flushFn, nil } @@ -210,8 +210,8 @@ type Exporter struct { var _ export.SpanExporter = (*Exporter)(nil) -// ExportSpans exports SpanData to Jaeger. -func (e *Exporter) ExportSpans(ctx context.Context, spans []*export.SpanData) error { +// ExportSpans exports SpanSnapshots to Jaeger. +func (e *Exporter) ExportSpans(ctx context.Context, ss []*export.SpanSnapshot) error { e.stoppedMu.RLock() stopped := e.stopped e.stoppedMu.RUnlock() @@ -219,9 +219,9 @@ func (e *Exporter) ExportSpans(ctx context.Context, spans []*export.SpanData) er return nil } - for _, span := range spans { + for _, span := range ss { // TODO(jbd): Handle oversized bundlers. - err := e.bundler.Add(spanDataToThrift(span), 1) + err := e.bundler.Add(spanSnapshotToThrift(span), 1) if err != nil { return fmt.Errorf("failed to bundle %q: %w", span.Name, err) } @@ -260,9 +260,9 @@ func (e *Exporter) Shutdown(ctx context.Context) error { return nil } -func spanDataToThrift(data *export.SpanData) *gen.Span { - tags := make([]*gen.Tag, 0, len(data.Attributes)) - for _, kv := range data.Attributes { +func spanSnapshotToThrift(ss *export.SpanSnapshot) *gen.Span { + tags := make([]*gen.Tag, 0, len(ss.Attributes)) + for _, kv := range ss.Attributes { tag := keyValueToTag(kv) if tag != nil { tags = append(tags, tag) @@ -273,14 +273,14 @@ func spanDataToThrift(data *export.SpanData) *gen.Span { // semantic. Should resources be appended before span // attributes, above, to allow span attributes to // overwrite resource attributes? - if data.Resource != nil { - for iter := data.Resource.Iter(); iter.Next(); { + if ss.Resource != nil { + for iter := ss.Resource.Iter(); iter.Next(); { if tag := keyValueToTag(iter.Attribute()); tag != nil { tags = append(tags, tag) } } } - if il := data.InstrumentationLibrary; il.Name != "" { + if il := ss.InstrumentationLibrary; il.Name != "" { tags = append(tags, getStringTag(keyInstrumentationLibraryName, il.Name)) if il.Version != "" { tags = append(tags, getStringTag(keyInstrumentationLibraryVersion, il.Version)) @@ -288,19 +288,19 @@ func spanDataToThrift(data *export.SpanData) *gen.Span { } tags = append(tags, - getInt64Tag("status.code", int64(data.StatusCode)), - getStringTag("status.message", data.StatusMessage), - getStringTag("span.kind", data.SpanKind.String()), + getInt64Tag("status.code", int64(ss.StatusCode)), + getStringTag("status.message", ss.StatusMessage), + getStringTag("span.kind", ss.SpanKind.String()), ) // Ensure that if Status.Code is not OK, that we set the "error" tag on the Jaeger span. // See Issue https://github.com/census-instrumentation/opencensus-go/issues/1041 - if data.StatusCode != codes.Ok && data.StatusCode != codes.Unset { + if ss.StatusCode != codes.Ok && ss.StatusCode != codes.Unset { tags = append(tags, getBoolTag("error", true)) } var logs []*gen.Log - for _, a := range data.MessageEvents { + for _, a := range ss.MessageEvents { fields := make([]*gen.Tag, 0, len(a.Attributes)) for _, kv := range a.Attributes { tag := keyValueToTag(kv) @@ -316,7 +316,7 @@ func spanDataToThrift(data *export.SpanData) *gen.Span { } var refs []*gen.SpanRef - for _, link := range data.Links { + for _, link := range ss.Links { refs = append(refs, &gen.SpanRef{ TraceIdHigh: int64(binary.BigEndian.Uint64(link.TraceID[0:8])), TraceIdLow: int64(binary.BigEndian.Uint64(link.TraceID[8:16])), @@ -328,14 +328,14 @@ func spanDataToThrift(data *export.SpanData) *gen.Span { } return &gen.Span{ - TraceIdHigh: int64(binary.BigEndian.Uint64(data.SpanContext.TraceID[0:8])), - TraceIdLow: int64(binary.BigEndian.Uint64(data.SpanContext.TraceID[8:16])), - SpanId: int64(binary.BigEndian.Uint64(data.SpanContext.SpanID[:])), - ParentSpanId: int64(binary.BigEndian.Uint64(data.ParentSpanID[:])), - OperationName: data.Name, // TODO: if span kind is added then add prefix "Sent"/"Recv" - Flags: int32(data.SpanContext.TraceFlags), - StartTime: data.StartTime.UnixNano() / 1000, - Duration: data.EndTime.Sub(data.StartTime).Nanoseconds() / 1000, + TraceIdHigh: int64(binary.BigEndian.Uint64(ss.SpanContext.TraceID[0:8])), + TraceIdLow: int64(binary.BigEndian.Uint64(ss.SpanContext.TraceID[8:16])), + SpanId: int64(binary.BigEndian.Uint64(ss.SpanContext.SpanID[:])), + ParentSpanId: int64(binary.BigEndian.Uint64(ss.ParentSpanID[:])), + OperationName: ss.Name, // TODO: if span kind is added then add prefix "Sent"/"Recv" + Flags: int32(ss.SpanContext.TraceFlags), + StartTime: ss.StartTime.UnixNano() / 1000, + Duration: ss.EndTime.Sub(ss.StartTime).Nanoseconds() / 1000, Tags: tags, Logs: logs, References: refs, diff --git a/exporters/trace/jaeger/jaeger_test.go b/exporters/trace/jaeger/jaeger_test.go index 7c2eaeb6ffd..eea460b18c8 100644 --- a/exporters/trace/jaeger/jaeger_test.go +++ b/exporters/trace/jaeger/jaeger_test.go @@ -28,9 +28,9 @@ import ( "github.com/stretchr/testify/require" "google.golang.org/api/support/bundler" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/codes" gen "go.opentelemetry.io/otel/exporters/trace/jaeger/internal/gen-go/jaeger" - "go.opentelemetry.io/otel/global" ottest "go.opentelemetry.io/otel/internal/testing" "go.opentelemetry.io/otel/label" export "go.opentelemetry.io/otel/sdk/export/trace" @@ -81,9 +81,9 @@ func TestInstallNewPipeline(t *testing.T) { defer fn() assert.NoError(t, err) - assert.IsType(t, tc.expectedProvider, global.TracerProvider()) + assert.IsType(t, tc.expectedProvider, otel.GetTracerProvider()) - global.SetTracerProvider(nil) + otel.SetTracerProvider(nil) }) } } @@ -144,7 +144,7 @@ func TestNewExportPipeline(t *testing.T) { defer fn() assert.NoError(t, err) - assert.NotEqual(t, tp, global.TracerProvider()) + assert.NotEqual(t, tp, otel.GetTracerProvider()) assert.IsType(t, tc.expectedProviderType, tp) if tc.testSpanSampling { @@ -342,8 +342,8 @@ func TestExporter_ExportSpan(t *testing.T) { sdktrace.WithConfig(sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}), sdktrace.WithSyncer(exp), ) - global.SetTracerProvider(tp) - _, span := global.Tracer("test-tracer").Start(context.Background(), "test-span") + otel.SetTracerProvider(tp) + _, span := otel.Tracer("test-tracer").Start(context.Background(), "test-span") span.End() assert.True(t, span.SpanContext().IsValid()) @@ -353,7 +353,7 @@ func TestExporter_ExportSpan(t *testing.T) { assert.True(t, len(tc.spansUploaded) == 1) } -func Test_spanDataToThrift(t *testing.T) { +func Test_spanSnapshotToThrift(t *testing.T) { now := time.Now() traceID, _ := trace.TraceIDFromHex("0102030405060708090a0b0c0d0e0f10") spanID, _ := trace.SpanIDFromHex("0102030405060708") @@ -376,12 +376,12 @@ func Test_spanDataToThrift(t *testing.T) { tests := []struct { name string - data *export.SpanData + data *export.SpanSnapshot want *gen.Span }{ { name: "no parent", - data: &export.SpanData{ + data: &export.SpanSnapshot{ SpanContext: trace.SpanContext{ TraceID: traceID, SpanID: spanID, @@ -465,7 +465,7 @@ func Test_spanDataToThrift(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := spanDataToThrift(tt.data) + got := spanSnapshotToThrift(tt.data) sort.Slice(got.Tags, func(i, j int) bool { return got.Tags[i].Key < got.Tags[j].Key }) diff --git a/exporters/trace/zipkin/go.mod b/exporters/trace/zipkin/go.mod index 5fef1fbfeb1..0725caea395 100644 --- a/exporters/trace/zipkin/go.mod +++ b/exporters/trace/zipkin/go.mod @@ -8,9 +8,9 @@ replace ( ) require ( - github.com/google/go-cmp v0.5.2 + github.com/google/go-cmp v0.5.4 github.com/openzipkin/zipkin-go v0.2.5 github.com/stretchr/testify v1.6.1 - go.opentelemetry.io/otel v0.13.0 - go.opentelemetry.io/otel/sdk v0.13.0 + go.opentelemetry.io/otel v0.15.0 + go.opentelemetry.io/otel/sdk v0.15.0 ) diff --git a/exporters/trace/zipkin/go.sum b/exporters/trace/zipkin/go.sum index 1e58540e291..4bffaf98aa9 100644 --- a/exporters/trace/zipkin/go.sum +++ b/exporters/trace/zipkin/go.sum @@ -38,8 +38,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= diff --git a/exporters/trace/zipkin/model.go b/exporters/trace/zipkin/model.go index e9d264b68aa..fe5454b40aa 100644 --- a/exporters/trace/zipkin/model.go +++ b/exporters/trace/zipkin/model.go @@ -31,7 +31,7 @@ const ( keyInstrumentationLibraryVersion = "otel.instrumentation_library.version" ) -func toZipkinSpanModels(batch []*export.SpanData, serviceName string) []zkmodel.SpanModel { +func toZipkinSpanModels(batch []*export.SpanSnapshot, serviceName string) []zkmodel.SpanModel { models := make([]zkmodel.SpanModel, 0, len(batch)) for _, data := range batch { models = append(models, toZipkinSpanModel(data, serviceName)) @@ -39,7 +39,7 @@ func toZipkinSpanModels(batch []*export.SpanData, serviceName string) []zkmodel. return models } -func toZipkinSpanModel(data *export.SpanData, serviceName string) zkmodel.SpanModel { +func toZipkinSpanModel(data *export.SpanSnapshot, serviceName string) zkmodel.SpanModel { return zkmodel.SpanModel{ SpanContext: toZipkinSpanContext(data), Name: data.Name, @@ -56,7 +56,7 @@ func toZipkinSpanModel(data *export.SpanData, serviceName string) zkmodel.SpanMo } } -func toZipkinSpanContext(data *export.SpanData) zkmodel.SpanContext { +func toZipkinSpanContext(data *export.SpanSnapshot) zkmodel.SpanContext { return zkmodel.SpanContext{ TraceID: toZipkinTraceID(data.SpanContext.TraceID), ID: toZipkinID(data.SpanContext.SpanID), @@ -145,7 +145,7 @@ var extraZipkinTags = []string{ keyInstrumentationLibraryVersion, } -func toZipkinTags(data *export.SpanData) map[string]string { +func toZipkinTags(data *export.SpanSnapshot) map[string]string { m := make(map[string]string, len(data.Attributes)+len(extraZipkinTags)) for _, kv := range data.Attributes { m[(string)(kv.Key)] = kv.Value.Emit() diff --git a/exporters/trace/zipkin/model_test.go b/exporters/trace/zipkin/model_test.go index ef0123341c8..51ec10214c1 100644 --- a/exporters/trace/zipkin/model_test.go +++ b/exporters/trace/zipkin/model_test.go @@ -32,7 +32,7 @@ import ( ) func TestModelConversion(t *testing.T) { - inputBatch := []*export.SpanData{ + inputBatch := []*export.SpanSnapshot{ // typical span data { SpanContext: trace.SpanContext{ @@ -671,12 +671,12 @@ func Test_toZipkinTags(t *testing.T) { tests := []struct { name string - data *export.SpanData + data *export.SpanSnapshot want map[string]string }{ { name: "attributes", - data: &export.SpanData{ + data: &export.SpanSnapshot{ Attributes: []label.KeyValue{ label.String("key", keyValue), label.Float64("double", doubleValue), @@ -695,7 +695,7 @@ func Test_toZipkinTags(t *testing.T) { }, { name: "no attributes", - data: &export.SpanData{}, + data: &export.SpanSnapshot{}, want: map[string]string{ "otel.status_code": codes.Unset.String(), "otel.status_description": "", @@ -703,7 +703,7 @@ func Test_toZipkinTags(t *testing.T) { }, { name: "omit-noerror", - data: &export.SpanData{ + data: &export.SpanSnapshot{ Attributes: []label.KeyValue{ label.Bool("error", false), }, @@ -715,7 +715,7 @@ func Test_toZipkinTags(t *testing.T) { }, { name: "statusCode", - data: &export.SpanData{ + data: &export.SpanSnapshot{ Attributes: []label.KeyValue{ label.String("key", keyValue), label.Bool("error", true), @@ -732,7 +732,7 @@ func Test_toZipkinTags(t *testing.T) { }, { name: "instrLib-empty", - data: &export.SpanData{ + data: &export.SpanSnapshot{ InstrumentationLibrary: instrumentation.Library{}, }, want: map[string]string{ @@ -742,7 +742,7 @@ func Test_toZipkinTags(t *testing.T) { }, { name: "instrLib-noversion", - data: &export.SpanData{ + data: &export.SpanSnapshot{ Attributes: []label.KeyValue{}, InstrumentationLibrary: instrumentation.Library{ Name: instrLibName, @@ -756,7 +756,7 @@ func Test_toZipkinTags(t *testing.T) { }, { name: "instrLib-with-version", - data: &export.SpanData{ + data: &export.SpanSnapshot{ Attributes: []label.KeyValue{}, InstrumentationLibrary: instrumentation.Library{ Name: instrLibName, diff --git a/exporters/trace/zipkin/zipkin.go b/exporters/trace/zipkin/zipkin.go index bf779794463..63b3a3e9d9f 100644 --- a/exporters/trace/zipkin/zipkin.go +++ b/exporters/trace/zipkin/zipkin.go @@ -20,18 +20,19 @@ import ( "encoding/json" "errors" "fmt" + "io" "io/ioutil" "log" "net/http" "net/url" "sync" - "go.opentelemetry.io/otel/global" + "go.opentelemetry.io/otel" export "go.opentelemetry.io/otel/sdk/export/trace" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) -// Exporter exports SpanData to the zipkin collector. It implements +// Exporter exports SpanSnapshots to the zipkin collector. It implements // the SpanBatcher interface, so it needs to be used together with the // WithBatcher option when setting up the exporter pipeline. type Exporter struct { @@ -112,14 +113,14 @@ func NewRawExporter(collectorURL, serviceName string, opts ...Option) (*Exporter // NewExportPipeline sets up a complete export pipeline // with the recommended setup for trace provider func NewExportPipeline(collectorURL, serviceName string, opts ...Option) (*sdktrace.TracerProvider, error) { - exp, err := NewRawExporter(collectorURL, serviceName, opts...) + exporter, err := NewRawExporter(collectorURL, serviceName, opts...) if err != nil { return nil, err } - tp := sdktrace.NewTracerProvider(sdktrace.WithBatcher(exp)) - if exp.o.config != nil { - tp.ApplyConfig(*exp.o.config) + tp := sdktrace.NewTracerProvider(sdktrace.WithBatcher(exporter)) + if exporter.o.config != nil { + tp.ApplyConfig(*exporter.o.config) } return tp, err @@ -133,12 +134,12 @@ func InstallNewPipeline(collectorURL, serviceName string, opts ...Option) error return err } - global.SetTracerProvider(tp) + otel.SetTracerProvider(tp) return nil } -// ExportSpans exports SpanData to a Zipkin receiver. -func (e *Exporter) ExportSpans(ctx context.Context, batch []*export.SpanData) error { +// ExportSpans exports SpanSnapshots to a Zipkin receiver. +func (e *Exporter) ExportSpans(ctx context.Context, ss []*export.SpanSnapshot) error { e.stoppedMu.RLock() stopped := e.stopped e.stoppedMu.RUnlock() @@ -147,11 +148,11 @@ func (e *Exporter) ExportSpans(ctx context.Context, batch []*export.SpanData) er return nil } - if len(batch) == 0 { + if len(ss) == 0 { e.logf("no spans to export") return nil } - models := toZipkinSpanModels(batch, e.serviceName) + models := toZipkinSpanModels(ss, e.serviceName) body, err := json.Marshal(models) if err != nil { return e.errf("failed to serialize zipkin models to JSON: %v", err) @@ -166,19 +167,21 @@ func (e *Exporter) ExportSpans(ctx context.Context, batch []*export.SpanData) er if err != nil { return e.errf("request to %s failed: %v", e.url, err) } - e.logf("zipkin responded with status %d", resp.StatusCode) + defer resp.Body.Close() - _, err = ioutil.ReadAll(resp.Body) + // Zipkin API returns a 202 on success and the content of the body isn't interesting + // but it is still being read because according to https://golang.org/pkg/net/http/#Response + // > The default HTTP client's Transport may not reuse HTTP/1.x "keep-alive" TCP connections + // > if the Body is not read to completion and closed. + _, err = io.Copy(ioutil.Discard, resp.Body) if err != nil { - // Best effort to clean up here. - resp.Body.Close() return e.errf("failed to read response body: %v", err) } - err = resp.Body.Close() - if err != nil { - return e.errf("failed to close response body: %v", err) + if resp.StatusCode != http.StatusAccepted { + return e.errf("failed to send spans to zipkin server with status %d", resp.StatusCode) } + return nil } diff --git a/exporters/trace/zipkin/zipkin_test.go b/exporters/trace/zipkin/zipkin_test.go index a8d45a56036..cf04112a5aa 100644 --- a/exporters/trace/zipkin/zipkin_test.go +++ b/exporters/trace/zipkin/zipkin_test.go @@ -30,8 +30,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/codes" - "go.opentelemetry.io/otel/global" export "go.opentelemetry.io/otel/sdk/export/trace" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" @@ -48,7 +48,7 @@ func TestInstallNewPipeline(t *testing.T) { serviceName, ) assert.NoError(t, err) - assert.IsType(t, &sdktrace.TracerProvider{}, global.TracerProvider()) + assert.IsType(t, &sdktrace.TracerProvider{}, otel.GetTracerProvider()) } func TestNewExportPipeline(t *testing.T) { @@ -90,7 +90,7 @@ func TestNewExportPipeline(t *testing.T) { tc.options..., ) assert.NoError(t, err) - assert.NotEqual(t, tp, global.TracerProvider()) + assert.NotEqual(t, tp, otel.GetTracerProvider()) if tc.testSpanSampling { _, span := tp.Tracer("zipkin test").Start(context.Background(), tc.name) @@ -192,6 +192,7 @@ func (c *mockZipkinCollector) handler(w http.ResponseWriter, r *http.Request) { c.lock.Lock() defer c.lock.Unlock() c.models = append(c.models, models...) + w.WriteHeader(http.StatusAccepted) } func (c *mockZipkinCollector) Close() { @@ -238,7 +239,7 @@ func logStoreLogger(s *logStore) *log.Logger { } func TestExportSpans(t *testing.T) { - spans := []*export.SpanData{ + spans := []*export.SpanSnapshot{ // parent { SpanContext: trace.SpanContext{ @@ -340,9 +341,8 @@ func TestExportSpans(t *testing.T) { ctx := context.Background() require.Len(t, ls.Messages, 0) require.NoError(t, exporter.ExportSpans(ctx, spans[0:1])) - require.Len(t, ls.Messages, 2) + require.Len(t, ls.Messages, 1) require.Contains(t, ls.Messages[0], "send a POST request") - require.Contains(t, ls.Messages[1], "zipkin responded") ls.Messages = nil require.NoError(t, exporter.ExportSpans(ctx, nil)) require.Len(t, ls.Messages, 1) @@ -350,7 +350,6 @@ func TestExportSpans(t *testing.T) { ls.Messages = nil require.NoError(t, exporter.ExportSpans(ctx, spans[1:2])) require.Contains(t, ls.Messages[0], "send a POST request") - require.Contains(t, ls.Messages[1], "zipkin responded") checkFunc := func() bool { return collector.ModelsLen() == len(models) } diff --git a/global/propagation.go b/global/propagation.go deleted file mode 100644 index 3fe10e08619..00000000000 --- a/global/propagation.go +++ /dev/null @@ -1,31 +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 global // import "go.opentelemetry.io/otel/global" - -import ( - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/global/internal" -) - -// TextMapPropagator returns the global TextMapPropagator. If none has been -// set, a No-Op TextMapPropagator is returned. -func TextMapPropagator() otel.TextMapPropagator { - return internal.TextMapPropagator() -} - -// SetTextMapPropagator sets propagator as the global TSetTextMapPropagator. -func SetTextMapPropagator(propagator otel.TextMapPropagator) { - internal.SetTextMapPropagator(propagator) -} diff --git a/go.mod b/go.mod index 95f9aa4e150..1847746362e 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,6 @@ module go.opentelemetry.io/otel go 1.14 require ( - github.com/google/go-cmp v0.5.2 + github.com/google/go-cmp v0.5.4 github.com/stretchr/testify v1.6.1 ) diff --git a/go.sum b/go.sum index bf1148d5ea5..76002a62e42 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/global/handler.go b/handler.go similarity index 81% rename from global/handler.go rename to handler.go index 0e1b3d1e05c..27e1caa30d9 100644 --- a/global/handler.go +++ b/handler.go @@ -12,15 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -package global // import "go.opentelemetry.io/otel/global" +package otel // import "go.opentelemetry.io/otel" import ( "log" "os" "sync" "sync/atomic" - - "go.opentelemetry.io/otel" ) var ( @@ -37,7 +35,7 @@ var ( delegateErrorHandlerOnce sync.Once // Comiple time check that loggingErrorHandler implements ErrorHandler. - _ otel.ErrorHandler = (*loggingErrorHandler)(nil) + _ ErrorHandler = (*loggingErrorHandler)(nil) ) // loggingErrorHandler logs all errors to STDERR. @@ -48,7 +46,7 @@ type loggingErrorHandler struct { } // setDelegate sets the ErrorHandler delegate if one is not already set. -func (h *loggingErrorHandler) setDelegate(d otel.ErrorHandler) { +func (h *loggingErrorHandler) setDelegate(d ErrorHandler) { if h.delegate.Load() != nil { // Delegate already registered return @@ -56,26 +54,26 @@ func (h *loggingErrorHandler) setDelegate(d otel.ErrorHandler) { h.delegate.Store(d) } -// Handle implements otel.ErrorHandler. +// Handle implements ErrorHandler. func (h *loggingErrorHandler) Handle(err error) { if d := h.delegate.Load(); d != nil { - d.(otel.ErrorHandler).Handle(err) + d.(ErrorHandler).Handle(err) return } h.l.Print(err) } -// ErrorHandler returns the global ErrorHandler instance. If no ErrorHandler +// GetErrorHandler returns the global ErrorHandler instance. If no ErrorHandler // instance has been set (`SetErrorHandler`), the default ErrorHandler which // logs errors to STDERR is returned. -func ErrorHandler() otel.ErrorHandler { +func GetErrorHandler() ErrorHandler { return globalErrorHandler } // SetErrorHandler sets the global ErrorHandler to be h. -func SetErrorHandler(h otel.ErrorHandler) { +func SetErrorHandler(h ErrorHandler) { delegateErrorHandlerOnce.Do(func() { - current := ErrorHandler() + current := GetErrorHandler() if current == h { return } @@ -87,5 +85,5 @@ func SetErrorHandler(h otel.ErrorHandler) { // Handle is a convience function for ErrorHandler().Handle(err) func Handle(err error) { - ErrorHandler().Handle(err) + GetErrorHandler().Handle(err) } diff --git a/global/handler_test.go b/handler_test.go similarity index 98% rename from global/handler_test.go rename to handler_test.go index 5713e0b8d36..1aba19c5d81 100644 --- a/global/handler_test.go +++ b/handler_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package global +package otel import ( "bytes" @@ -66,7 +66,7 @@ func (s *HandlerTestSuite) SetupTest() { func (s *HandlerTestSuite) TestGlobalHandler() { errs := []string{"one", "two"} - ErrorHandler().Handle(errors.New(errs[0])) + GetErrorHandler().Handle(errors.New(errs[0])) Handle(errors.New(errs[1])) s.Assert().Equal(errs, s.errLogger.Got()) } diff --git a/global/internal/benchmark_test.go b/internal/global/benchmark_test.go similarity index 78% rename from global/internal/benchmark_test.go rename to internal/global/benchmark_test.go index 0a33ba281e3..f4d4e060cf6 100644 --- a/global/internal/benchmark_test.go +++ b/internal/global/benchmark_test.go @@ -12,24 +12,24 @@ // See the License for the specific language governing permissions and // limitations under the License. -package internal_test +package global_test import ( "context" "testing" - "go.opentelemetry.io/otel/global" - "go.opentelemetry.io/otel/global/internal" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/internal/global" "go.opentelemetry.io/otel/label" ) func BenchmarkGlobalInt64CounterAddNoSDK(b *testing.B) { // Compare with BenchmarkGlobalInt64CounterAddWithSDK() in - // ../../../sdk/metric/benchmark_test.go to see the overhead of the + // ../../sdk/metric/benchmark_test.go to see the overhead of the // global no-op system against a registered SDK. - internal.ResetForTest() + global.ResetForTest() ctx := context.Background() - sdk := global.Meter("test") + sdk := otel.Meter("test") labs := []label.KeyValue{label.String("A", "B")} cnt := Must(sdk).NewInt64Counter("int64.counter") @@ -42,9 +42,9 @@ func BenchmarkGlobalInt64CounterAddNoSDK(b *testing.B) { func BenchmarkStartEndSpanNoSDK(b *testing.B) { // Compare with BenchmarkStartEndSpan() in - // ../../../sdk/trace/benchmark_test.go. - internal.ResetForTest() - t := global.Tracer("Benchmark StartEndSpan") + // ../../sdk/trace/benchmark_test.go. + global.ResetForTest() + t := otel.Tracer("Benchmark StartEndSpan") ctx := context.Background() b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/global/internal/internal_test.go b/internal/global/internal_test.go similarity index 90% rename from global/internal/internal_test.go rename to internal/global/internal_test.go index 13cd72be0ff..dae5bc5ae38 100644 --- a/global/internal/internal_test.go +++ b/internal/global/internal_test.go @@ -12,19 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -package internal_test +package global_test import ( "os" "testing" - "go.opentelemetry.io/otel/global/internal" + "go.opentelemetry.io/otel/internal/global" ottest "go.opentelemetry.io/otel/internal/testing" ) // Ensure struct alignment prior to running tests. func TestMain(m *testing.M) { - fieldsMap := internal.AtomicFieldOffsets() + fieldsMap := global.AtomicFieldOffsets() fields := make([]ottest.FieldOffset, 0, len(fieldsMap)) for name, offset := range fieldsMap { fields = append(fields, ottest.FieldOffset{ diff --git a/global/internal/meter.go b/internal/global/meter.go similarity index 99% rename from global/internal/meter.go rename to internal/global/meter.go index afe0f41835f..8b288df780f 100644 --- a/global/internal/meter.go +++ b/internal/global/meter.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package internal +package global import ( "context" diff --git a/global/internal/meter_test.go b/internal/global/meter_test.go similarity index 90% rename from global/internal/meter_test.go rename to internal/global/meter_test.go index 70147d0dc4c..5d4fbc88a5b 100644 --- a/global/internal/meter_test.go +++ b/internal/global/meter_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package internal_test +package global_test import ( "context" @@ -21,8 +21,8 @@ import ( "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/global" - "go.opentelemetry.io/otel/global/internal" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/internal/global" "go.opentelemetry.io/otel/label" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric/number" @@ -35,11 +35,11 @@ var asInt = number.NewInt64Number var asFloat = number.NewFloat64Number func TestDirect(t *testing.T) { - internal.ResetForTest() + global.ResetForTest() ctx := context.Background() - meter1 := global.Meter("test1", metric.WithInstrumentationVersion("semver:v1.0.0")) - meter2 := global.Meter("test2") + meter1 := otel.Meter("test1", metric.WithInstrumentationVersion("semver:v1.0.0")) + meter2 := otel.Meter("test2") labels1 := []label.KeyValue{label.String("A", "B")} labels2 := []label.KeyValue{label.String("C", "D")} labels3 := []label.KeyValue{label.String("E", "F")} @@ -67,7 +67,7 @@ func TestDirect(t *testing.T) { second.Record(ctx, 2, labels3...) mock, provider := oteltest.NewMeterProvider() - global.SetMeterProvider(provider) + otel.SetMeterProvider(provider) counter.Add(ctx, 1, labels1...) valuerecorder.Record(ctx, 3, labels1...) @@ -133,12 +133,12 @@ func TestDirect(t *testing.T) { } func TestBound(t *testing.T) { - internal.ResetForTest() + global.ResetForTest() // Note: this test uses opposite Float64/Int64 number kinds // vs. the above, to cover all the instruments. ctx := context.Background() - glob := global.Meter("test") + glob := otel.Meter("test") labels1 := []label.KeyValue{label.String("A", "B")} counter := Must(glob).NewFloat64Counter("test.counter") @@ -152,7 +152,7 @@ func TestBound(t *testing.T) { boundM.Record(ctx, 2) mock, provider := oteltest.NewMeterProvider() - global.SetMeterProvider(provider) + otel.SetMeterProvider(provider) boundC.Add(ctx, 1) boundM.Record(ctx, 3) @@ -180,9 +180,9 @@ func TestBound(t *testing.T) { func TestUnbind(t *testing.T) { // Tests Unbind with SDK never installed. - internal.ResetForTest() + global.ResetForTest() - glob := global.Meter("test") + glob := otel.Meter("test") labels1 := []label.KeyValue{label.String("A", "B")} counter := Must(glob).NewFloat64Counter("test.counter") @@ -196,15 +196,15 @@ func TestUnbind(t *testing.T) { } func TestUnbindThenRecordOne(t *testing.T) { - internal.ResetForTest() + global.ResetForTest() ctx := context.Background() mock, provider := oteltest.NewMeterProvider() - meter := global.Meter("test") + meter := otel.Meter("test") counter := Must(meter).NewInt64Counter("test.counter") boundC := counter.Bind() - global.SetMeterProvider(provider) + otel.SetMeterProvider(provider) boundC.Unbind() require.NotPanics(t, func() { @@ -230,10 +230,10 @@ func (m *meterWithConstructorError) NewSyncInstrument(_ metric.Descriptor) (metr } func TestErrorInDeferredConstructor(t *testing.T) { - internal.ResetForTest() + global.ResetForTest() ctx := context.Background() - meter := global.MeterProvider().Meter("builtin") + meter := otel.GetMeterProvider().Meter("builtin") c1 := Must(meter).NewInt64Counter("test") c2 := Must(meter).NewInt64Counter("test") @@ -242,7 +242,7 @@ func TestErrorInDeferredConstructor(t *testing.T) { sdk := &meterProviderWithConstructorError{provider} require.Panics(t, func() { - global.SetMeterProvider(sdk) + otel.SetMeterProvider(sdk) }) c1.Add(ctx, 1) @@ -250,13 +250,13 @@ func TestErrorInDeferredConstructor(t *testing.T) { } func TestImplementationIndirection(t *testing.T) { - internal.ResetForTest() + global.ResetForTest() // Test that Implementation() does the proper indirection, i.e., // returns the implementation interface not the global, after // registered. - meter1 := global.Meter("test1") + meter1 := otel.Meter("test1") // Sync: no SDK yet counter := Must(meter1).NewInt64Counter("interface.counter") @@ -281,7 +281,7 @@ func TestImplementationIndirection(t *testing.T) { // Register the SDK _, provider := oteltest.NewMeterProvider() - global.SetMeterProvider(provider) + otel.SetMeterProvider(provider) // Repeat the above tests @@ -301,16 +301,16 @@ func TestImplementationIndirection(t *testing.T) { } func TestRecordBatchMock(t *testing.T) { - internal.ResetForTest() + global.ResetForTest() - meter := global.MeterProvider().Meter("builtin") + meter := otel.GetMeterProvider().Meter("builtin") counter := Must(meter).NewInt64Counter("test.counter") meter.RecordBatch(context.Background(), nil, counter.Measurement(1)) mock, provider := oteltest.NewMeterProvider() - global.SetMeterProvider(provider) + otel.SetMeterProvider(provider) meter.RecordBatch(context.Background(), nil, counter.Measurement(1)) diff --git a/global/internal/propagator.go b/internal/global/propagator.go similarity index 74% rename from global/internal/propagator.go rename to internal/global/propagator.go index 05678bb0ffc..1c8b8589b08 100644 --- a/global/internal/propagator.go +++ b/internal/global/propagator.go @@ -12,39 +12,39 @@ // See the License for the specific language governing permissions and // limitations under the License. -package internal +package global import ( "context" "sync" - "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/propagation" ) // textMapPropagator is a default TextMapPropagator that delegates calls to a // registered delegate if one is set, otherwise it defaults to delegating the -// calls to a the default no-op otel.TextMapPropagator. +// calls to a the default no-op propagation.TextMapPropagator. type textMapPropagator struct { mtx sync.Mutex once sync.Once - delegate otel.TextMapPropagator - noop otel.TextMapPropagator + delegate propagation.TextMapPropagator + noop propagation.TextMapPropagator } // Compile-time guarantee that textMapPropagator implements the -// otel.TextMapPropagator interface. -var _ otel.TextMapPropagator = (*textMapPropagator)(nil) +// propagation.TextMapPropagator interface. +var _ propagation.TextMapPropagator = (*textMapPropagator)(nil) func newTextMapPropagator() *textMapPropagator { return &textMapPropagator{ - noop: otel.NewCompositeTextMapPropagator(), + noop: propagation.NewCompositeTextMapPropagator(), } } -// SetDelegate sets a delegate otel.TextMapPropagator that all calls are +// SetDelegate sets a delegate propagation.TextMapPropagator that all calls are // forwarded to. Delegation can only be performed once, all subsequent calls // perform no delegation. -func (p *textMapPropagator) SetDelegate(delegate otel.TextMapPropagator) { +func (p *textMapPropagator) SetDelegate(delegate propagation.TextMapPropagator) { if delegate == nil { return } @@ -57,7 +57,7 @@ func (p *textMapPropagator) SetDelegate(delegate otel.TextMapPropagator) { // effectiveDelegate returns the current delegate of p if one is set, // otherwise the default noop TextMapPropagator is returned. This method // can be called concurrently. -func (p *textMapPropagator) effectiveDelegate() otel.TextMapPropagator { +func (p *textMapPropagator) effectiveDelegate() propagation.TextMapPropagator { p.mtx.Lock() defer p.mtx.Unlock() if p.delegate != nil { @@ -67,12 +67,12 @@ func (p *textMapPropagator) effectiveDelegate() otel.TextMapPropagator { } // Inject set cross-cutting concerns from the Context into the carrier. -func (p *textMapPropagator) Inject(ctx context.Context, carrier otel.TextMapCarrier) { +func (p *textMapPropagator) Inject(ctx context.Context, carrier propagation.TextMapCarrier) { p.effectiveDelegate().Inject(ctx, carrier) } // Extract reads cross-cutting concerns from the carrier into a Context. -func (p *textMapPropagator) Extract(ctx context.Context, carrier otel.TextMapCarrier) context.Context { +func (p *textMapPropagator) Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context { return p.effectiveDelegate().Extract(ctx, carrier) } diff --git a/global/internal/propagator_test.go b/internal/global/propagator_test.go similarity index 85% rename from global/internal/propagator_test.go rename to internal/global/propagator_test.go index 58bc995ab09..1089c896ac3 100644 --- a/global/internal/propagator_test.go +++ b/internal/global/propagator_test.go @@ -12,23 +12,23 @@ // See the License for the specific language governing permissions and // limitations under the License. -package internal_test +package global_test import ( "context" "testing" - "go.opentelemetry.io/otel/global/internal" + "go.opentelemetry.io/otel/internal/global" "go.opentelemetry.io/otel/oteltest" ) func TestTextMapPropagatorDelegation(t *testing.T) { - internal.ResetForTest() + global.ResetForTest() ctx := context.Background() carrier := oteltest.NewTextMapCarrier(nil) // The default should be a noop. - initial := internal.TextMapPropagator() + initial := global.TextMapPropagator() initial.Inject(ctx, carrier) ctx = initial.Extract(ctx, carrier) if !carrier.GotN(t, 0) || !carrier.SetN(t, 0) { @@ -45,7 +45,7 @@ func TestTextMapPropagatorDelegation(t *testing.T) { // The initial propagator should use the delegate after it is set as the // global. - internal.SetTextMapPropagator(delegate) + global.SetTextMapPropagator(delegate) initial.Inject(ctx, carrier) ctx = initial.Extract(ctx, carrier) delegate.InjectedN(t, carrier, 2) @@ -53,12 +53,12 @@ func TestTextMapPropagatorDelegation(t *testing.T) { } func TestTextMapPropagatorDelegationNil(t *testing.T) { - internal.ResetForTest() + global.ResetForTest() ctx := context.Background() carrier := oteltest.NewTextMapCarrier(nil) // The default should be a noop. - initial := internal.TextMapPropagator() + initial := global.TextMapPropagator() initial.Inject(ctx, carrier) ctx = initial.Extract(ctx, carrier) if !carrier.GotN(t, 0) || !carrier.SetN(t, 0) { @@ -66,7 +66,7 @@ func TestTextMapPropagatorDelegationNil(t *testing.T) { } // Delegation to nil should not make a change. - internal.SetTextMapPropagator(nil) + global.SetTextMapPropagator(nil) initial.Inject(ctx, carrier) initial.Extract(ctx, carrier) if !carrier.GotN(t, 0) || !carrier.SetN(t, 0) { @@ -75,8 +75,8 @@ func TestTextMapPropagatorDelegationNil(t *testing.T) { } func TestTextMapPropagatorFields(t *testing.T) { - internal.ResetForTest() - initial := internal.TextMapPropagator() + global.ResetForTest() + initial := global.TextMapPropagator() delegate := oteltest.NewTextMapPropagator("test") delegateFields := delegate.Fields() @@ -84,13 +84,13 @@ func TestTextMapPropagatorFields(t *testing.T) { if got := initial.Fields(); fieldsEqual(got, delegateFields) { t.Fatalf("testing fields (%v) matched Noop fields (%v)", delegateFields, got) } - internal.SetTextMapPropagator(delegate) + global.SetTextMapPropagator(delegate) // Check previous returns from global not correctly delegate. if got := initial.Fields(); !fieldsEqual(got, delegateFields) { t.Errorf("global TextMapPropagator.Fields returned %v instead of delegating, want (%v)", got, delegateFields) } // Check new calls to global. - if got := internal.TextMapPropagator().Fields(); !fieldsEqual(got, delegateFields) { + if got := global.TextMapPropagator().Fields(); !fieldsEqual(got, delegateFields) { t.Errorf("global TextMapPropagator.Fields returned %v, want (%v)", got, delegateFields) } } diff --git a/global/internal/registry_test.go b/internal/global/registry_test.go similarity index 99% rename from global/internal/registry_test.go rename to internal/global/registry_test.go index ba67eba984e..883d3fdaab1 100644 --- a/global/internal/registry_test.go +++ b/internal/global/registry_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package internal +package global import ( "context" diff --git a/global/internal/state.go b/internal/global/state.go similarity index 95% rename from global/internal/state.go rename to internal/global/state.go index 8f6cc1590b6..f3bf0035100 100644 --- a/global/internal/state.go +++ b/internal/global/state.go @@ -12,14 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -package internal +package global import ( "sync" "sync/atomic" - "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) @@ -33,7 +33,7 @@ type ( } propagatorsHolder struct { - tm otel.TextMapPropagator + tm propagation.TextMapPropagator } ) @@ -92,12 +92,12 @@ func SetMeterProvider(mp metric.MeterProvider) { } // TextMapPropagator is the internal implementation for global.TextMapPropagator. -func TextMapPropagator() otel.TextMapPropagator { +func TextMapPropagator() propagation.TextMapPropagator { return globalPropagators.Load().(propagatorsHolder).tm } // SetTextMapPropagator is the internal implementation for global.SetTextMapPropagator. -func SetTextMapPropagator(p otel.TextMapPropagator) { +func SetTextMapPropagator(p propagation.TextMapPropagator) { // For the textMapPropagator already returned by TextMapPropagator // delegate to p. delegateTextMapPropagatorOnce.Do(func() { diff --git a/global/internal/state_test.go b/internal/global/state_test.go similarity index 80% rename from global/internal/state_test.go rename to internal/global/state_test.go index a2228c8ad08..cf5ce254370 100644 --- a/global/internal/state_test.go +++ b/internal/global/state_test.go @@ -12,25 +12,25 @@ // See the License for the specific language governing permissions and // limitations under the License. -package internal_test +package global_test import ( "testing" - "go.opentelemetry.io/otel/global/internal" + "go.opentelemetry.io/otel/internal/global" ) func TestResetsOfGlobalsPanic(t *testing.T) { - internal.ResetForTest() + global.ResetForTest() tests := map[string]func(){ "SetTextMapPropagator": func() { - internal.SetTextMapPropagator(internal.TextMapPropagator()) + global.SetTextMapPropagator(global.TextMapPropagator()) }, "SetTracerProvider": func() { - internal.SetTracerProvider(internal.TracerProvider()) + global.SetTracerProvider(global.TracerProvider()) }, "SetMeterProvider": func() { - internal.SetMeterProvider(internal.MeterProvider()) + global.SetMeterProvider(global.MeterProvider()) }, } diff --git a/global/internal/trace.go b/internal/global/trace.go similarity index 98% rename from global/internal/trace.go rename to internal/global/trace.go index c60828e8a44..7b6993153fe 100644 --- a/global/internal/trace.go +++ b/internal/global/trace.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package internal +package global /* This file contains the forwarding implementation of the TracerProvider used as @@ -84,7 +84,7 @@ func (p *tracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.T defer p.mtx.Unlock() if p.delegate != nil { - return p.delegate.Tracer(name) + return p.delegate.Tracer(name, opts...) } t := &tracer{name: name, opts: opts} diff --git a/global/internal/trace_test.go b/internal/global/trace_test.go similarity index 61% rename from global/internal/trace_test.go rename to internal/global/trace_test.go index 39baa07d2c0..6e53c4594b5 100644 --- a/global/internal/trace_test.go +++ b/internal/global/trace_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package internal_test +package global_test import ( "context" @@ -20,23 +20,24 @@ import ( "github.com/stretchr/testify/assert" - "go.opentelemetry.io/otel/global" - "go.opentelemetry.io/otel/global/internal" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/internal/global" "go.opentelemetry.io/otel/oteltest" + "go.opentelemetry.io/otel/trace" ) func TestTraceWithSDK(t *testing.T) { - internal.ResetForTest() + global.ResetForTest() ctx := context.Background() - gtp := global.TracerProvider() + gtp := otel.GetTracerProvider() tracer1 := gtp.Tracer("pre") // This is started before an SDK was registered and should be dropped. _, span1 := tracer1.Start(ctx, "span1") sr := new(oteltest.StandardSpanRecorder) tp := oteltest.NewTracerProvider(oteltest.WithSpanRecorder(sr)) - global.SetTracerProvider(tp) + otel.SetTracerProvider(tp) // This span was started before initialization, it is expected to be dropped. span1.End() @@ -61,3 +62,32 @@ func TestTraceWithSDK(t *testing.T) { assert.ElementsMatch(t, expected, filterNames(sr.Started())) assert.ElementsMatch(t, expected, filterNames(sr.Completed())) } + +type fnTracerProvider struct { + tracer func(string, ...trace.TracerOption) trace.Tracer +} + +func (fn fnTracerProvider) Tracer(instrumentationName string, opts ...trace.TracerOption) trace.Tracer { + return fn.tracer(instrumentationName, opts...) +} + +func TestTraceProviderDelegates(t *testing.T) { + global.ResetForTest() + + // Retrieve the placeholder TracerProvider. + gtp := otel.GetTracerProvider() + + // Configure it with a spy. + called := false + otel.SetTracerProvider(fnTracerProvider{ + tracer: func(name string, opts ...trace.TracerOption) trace.Tracer { + called = true + assert.Equal(t, "abc", name) + assert.Equal(t, []trace.TracerOption{trace.WithInstrumentationVersion("xyz")}, opts) + return trace.NewNoopTracerProvider().Tracer("") + }, + }) + + gtp.Tracer("abc", trace.WithInstrumentationVersion("xyz")) + assert.True(t, called, "expected configured TraceProvider to be called") +} diff --git a/internal/metric/async.go b/internal/metric/async.go index 8b1a2b3742a..11d0c032d6d 100644 --- a/internal/metric/async.go +++ b/internal/metric/async.go @@ -20,7 +20,7 @@ import ( "fmt" "sync" - "go.opentelemetry.io/otel/global" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/label" "go.opentelemetry.io/otel/metric" ) @@ -41,7 +41,7 @@ type AsyncCollector interface { type AsyncInstrumentState struct { lock sync.Mutex - // errorOnce will use the global.Handler to report an error + // errorOnce will use the otel.Handler to report an error // once in case of an invalid runner attempting to run. errorOnce sync.Once @@ -142,7 +142,7 @@ func (a *AsyncInstrumentState) Run(ctx context.Context, collector AsyncCollector } a.errorOnce.Do(func() { - global.Handle(fmt.Errorf("%w: type %T (reported once)", ErrInvalidAsyncRunner, rp)) + otel.Handle(fmt.Errorf("%w: type %T (reported once)", ErrInvalidAsyncRunner, rp)) }) } } diff --git a/internal/tools/go.mod b/internal/tools/go.mod index 2c6a978ade3..8fb7cca4465 100644 --- a/internal/tools/go.mod +++ b/internal/tools/go.mod @@ -4,7 +4,8 @@ go 1.14 require ( github.com/client9/misspell v0.3.4 - github.com/golangci/golangci-lint v1.32.2 + github.com/gogo/protobuf v1.3.1 + github.com/golangci/golangci-lint v1.33.0 github.com/itchyny/gojq v0.11.2 golang.org/x/tools v0.0.0-20201013201025-64a9e34f3752 ) diff --git a/internal/tools/go.sum b/internal/tools/go.sum index f548d3eae5c..c4e1682b1cd 100644 --- a/internal/tools/go.sum +++ b/internal/tools/go.sum @@ -103,6 +103,8 @@ github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14j github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -127,14 +129,12 @@ github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6 h1:YYWNAGTKWhKpc github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0= github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613 h1:9kfjN3AdxcbsZBf8NjltjWihK2QfBBBZuv91cMFfDHw= github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8= -github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3 h1:pe9JHs3cHHDQgOFXJJdYkK6fLz2PWyYtP4hthoCMvs8= -github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o= github.com/golangci/gocyclo v0.0.0-20180528144436-0a533e8fa43d h1:pXTK/gkVNs7Zyy7WKgLXmpQ5bHTrq5GDsp8R9Qs67g0= github.com/golangci/gocyclo v0.0.0-20180528144436-0a533e8fa43d/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU= github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a h1:iR3fYXUjHCR97qWS8ch1y9zPNsgXThGwjKPrYfqMPks= github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU= -github.com/golangci/golangci-lint v1.32.2 h1:CgIeFWTLJ3Nt1w/WU1RO351j/CjN6LIVjppbJfI9nMk= -github.com/golangci/golangci-lint v1.32.2/go.mod h1:ydr+IqtIVyAh72L16aK0bNdNg/YGa+AEgdbKj9MluzI= +github.com/golangci/golangci-lint v1.33.0 h1:/o4OtOR3Idim4FHKBJXcy+6ZjNDm82gwK/v6+gWyH9U= +github.com/golangci/golangci-lint v1.33.0/go.mod h1:zMnMLSCaDlrXExYsuq2LOweE9CHVqYk5jexk23UsjYM= github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc h1:gLLhTLMk2/SutryVJ6D4VZCU3CUqr8YloG7FPIBWFpI= github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU= github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 h1:MfyDlzVjl1hoaPzPD4Gpb/QgoRfSBR0jdhwGyAWwMSA= @@ -216,6 +216,8 @@ github.com/itchyny/gojq v0.11.2 h1:lKhMKfH7fTKMWj2Zr8az/9TliCn0TTXVc/BXfQ8Jhfc= github.com/itchyny/gojq v0.11.2/go.mod h1:XtmtF1PxeDpwLC1jyz/xAmV78ANlP0S9LVEPsKweK0A= github.com/itchyny/timefmt-go v0.1.1 h1:rLpnm9xxb39PEEVzO0n4IRp0q6/RmBc7Dy/rE4HrA0U= github.com/itchyny/timefmt-go v0.1.1/go.mod h1:0osSSCQSASBJMsIZnhAaF1C2fCBTJZXrnj37mG8/c+A= +github.com/jgautheron/goconst v0.0.0-20201117150253-ccae5bf973f3 h1:7nkB9fLPMwtn/R6qfPcHileL/x9ydlhw8XyDrLI1ZXg= +github.com/jgautheron/goconst v0.0.0-20201117150253-ccae5bf973f3/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a h1:GmsqmapfzSJkm28dhRoHz2tLRbJmqhU86IPgBtN3mmk= github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a/go.mod h1:xRskid8CManxVta/ALEhJha/pweKBaVG6fWgc0yH25s= github.com/jirfag/go-printf-func-name v0.0.0-20191110105641-45db9963cdd3 h1:jNYPNLe3d8smommaoQlK7LOA5ESyUJJ+Wf79ZtA7Vp4= @@ -229,6 +231,7 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= @@ -245,8 +248,10 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kyoh86/exportloopref v0.1.7 h1:u+iHuTbkbTS2D/JP7fCuZDo/t3rBVGo3Hf58Rc+lQVY= -github.com/kyoh86/exportloopref v0.1.7/go.mod h1:h1rDl2Kdj97+Kwh4gdz3ujE7XHmH51Q0lUiZ1z4NLj8= +github.com/kunwardeep/paralleltest v1.0.2 h1:/jJRv0TiqPoEy/Y8dQxCFJhD56uS/pnvtatgTZBHokU= +github.com/kunwardeep/paralleltest v1.0.2/go.mod h1:ZPqNm1fVHPllh5LPVujzbVz1JN2GhLxSfY+oqUsvG30= +github.com/kyoh86/exportloopref v0.1.8 h1:5Ry/at+eFdkX9Vsdw3qU4YkvGtzuVfzT4X7S77LoN/M= +github.com/kyoh86/exportloopref v0.1.8/go.mod h1:1tUcJeiioIs7VWe5gcOObrux3lb66+sBqGZrRkMwPgg= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= @@ -411,8 +416,8 @@ github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tdakkota/asciicheck v0.0.0-20200416190851-d7f85be797a2 h1:Xr9gkxfOP0KQWXKNqmwe8vEeSUiUj4Rlee9CMVX2ZUQ= github.com/tdakkota/asciicheck v0.0.0-20200416190851-d7f85be797a2/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= -github.com/tetafro/godot v0.4.9 h1:dSOiuasshpevY73eeI3+zaqFnXSBKJ3mvxbyhh54VRo= -github.com/tetafro/godot v0.4.9/go.mod h1:/7NLHhv08H1+8DNj0MElpAACw1ajsCuf3TKNQxA5S+0= +github.com/tetafro/godot v1.3.0 h1:rKXb6aAz2AnwS98jYlU3snCFFXnIInQdaGiftNwpj+k= +github.com/tetafro/godot v1.3.0/go.mod h1:/7NLHhv08H1+8DNj0MElpAACw1ajsCuf3TKNQxA5S+0= github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e h1:RumXZ56IrCj4CL+g1b9OL/oH0QnsF976bC8xQFYUD5Q= github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -543,6 +548,7 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190221204921-83362c3779f5/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -568,13 +574,13 @@ golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200321224714-0d839f3cf2ed/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200414032229-332987a829c3/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200422022333-3d57cf2e726e h1:3Dzrrxi54Io7Aoyb0PYLsI47K2TxkRQg+cqUn+m04do= golang.org/x/tools v0.0.0-20200422022333-3d57cf2e726e/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200622203043-20e05c1c8ffa/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200624225443-88f3c62a19ff/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200625211823-6506e20df31f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305 h1:yaM5S0KcY0lIoZo7Fl+oi91b/DdlU2zuWpfHrpWbCS0= diff --git a/internal/tools/tools.go b/internal/tools/tools.go index f0418c71d3a..c86ce2fdc90 100644 --- a/internal/tools/tools.go +++ b/internal/tools/tools.go @@ -18,6 +18,7 @@ package tools import ( _ "github.com/client9/misspell/cmd/misspell" + _ "github.com/gogo/protobuf/protoc-gen-gogofast" _ "github.com/golangci/golangci-lint/cmd/golangci-lint" _ "github.com/itchyny/gojq" _ "golang.org/x/tools/cmd/stringer" diff --git a/global/metric.go b/metric.go similarity index 82% rename from global/metric.go rename to metric.go index d569d73f86d..6d285b911a1 100644 --- a/global/metric.go +++ b/metric.go @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -package global // import "go.opentelemetry.io/otel/global" +package otel // import "go.opentelemetry.io/otel" import ( - "go.opentelemetry.io/otel/global/internal" + "go.opentelemetry.io/otel/internal/global" "go.opentelemetry.io/otel/metric" ) @@ -28,10 +28,10 @@ import ( // // This is short for MeterProvider().Meter(name) func Meter(instrumentationName string, opts ...metric.MeterOption) metric.Meter { - return MeterProvider().Meter(instrumentationName, opts...) + return GetMeterProvider().Meter(instrumentationName, opts...) } -// MeterProvider returns the registered global meter provider. If +// GetMeterProvider returns the registered global meter provider. If // none is registered then a default meter provider is returned that // forwards the Meter interface to the first registered Meter. // @@ -39,11 +39,11 @@ func Meter(instrumentationName string, opts ...metric.MeterOption) metric.Meter // meter := global.MeterProvider().Meter("example.com/foo") // or // meter := global.Meter("example.com/foo") -func MeterProvider() metric.MeterProvider { - return internal.MeterProvider() +func GetMeterProvider() metric.MeterProvider { + return global.MeterProvider() } // SetMeterProvider registers `mp` as the global meter provider. func SetMeterProvider(mp metric.MeterProvider) { - internal.SetMeterProvider(mp) + global.SetMeterProvider(mp) } diff --git a/metric/doc.go b/metric/doc.go new file mode 100644 index 00000000000..7889ff000f7 --- /dev/null +++ b/metric/doc.go @@ -0,0 +1,67 @@ +// 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 metric provides an implementation of the metrics part of the +OpenTelemetry API. + +This package is currently in a pre-GA phase. Backwards incompatible changes +may be introduced in subsequent minor version releases as we work to track the +evolving OpenTelemetry specification and user feedback. + +Measurements can be made about an operation being performed or the state of a +system in general. These measurements can be crucial to the reliable operation +of code and provide valuable insights about the inner workings of a system. + +Measurements are made using instruments provided by this package. The type of +instrument used will depend on the type of measurement being made and of what +part of a system is being measured. + +Instruments are categorized as Synchronous or Asynchronous and independently +as Adding or Grouping. Synchronous instruments are called by the user with a +Context. Asynchronous instruments are called by the SDK during collection. +Additive instruments are semantically intended for capturing a sum. Grouping +instruments are intended for capturing a distribution. + +Additive instruments may be monotonic, in which case they are non-decreasing +and naturally define a rate. + +The synchronous instrument names are: + + Counter: additive, monotonic + UpDownCounter: additive + ValueRecorder: grouping + +and the asynchronous instruments are: + + SumObserver: additive, monotonic + UpDownSumObserver: additive + ValueObserver: grouping + +All instruments are provided with support for either float64 or int64 input +values. + +An instrument is created using a Meter. Additionally, a Meter is used to +record batches of synchronous measurements or asynchronous observations. A +Meter is obtained using a MeterProvider. A Meter, like a Tracer, is unique to +the instrumentation it instruments and must be named and versioned when +created with a MeterProvider with the name and version of the instrumentation +library. + +Instrumentation should be designed to accept a MeterProvider from which it can +create its own unique Meter. Alternatively, the registered global +MeterProvider from the go.opentelemetry.io/otel package can be used as a +default. +*/ +package metric // import "go.opentelemetry.io/otel/metric" diff --git a/sdk/trace/trace.go b/metric/number/doc.go similarity index 60% rename from sdk/trace/trace.go rename to metric/number/doc.go index 302ca13cf72..0649ff875e7 100644 --- a/sdk/trace/trace.go +++ b/metric/number/doc.go @@ -12,20 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -package trace // import "go.opentelemetry.io/otel/sdk/trace" +/* +Package number provides a number abstraction for instruments that +either support int64 or float64 input values. -import ( - crand "crypto/rand" - "encoding/binary" - "math/rand" - - "go.opentelemetry.io/otel/sdk/trace/internal" -) - -func defIDGenerator() internal.IDGenerator { - gen := &defaultIDGenerator{} - var rngSeed int64 - _ = binary.Read(crand.Reader, binary.LittleEndian, &rngSeed) - gen.randSource = rand.New(rand.NewSource(rngSeed)) - return gen -} +This package is currently in a pre-GA phase. Backwards incompatible changes +may be introduced in subsequent minor version releases as we work to track the +evolving OpenTelemetry specification and user feedback. +*/ +package number // import "go.opentelemetry.io/otel/metric/number" diff --git a/sdk/opentelemetry.go b/metric/registry/doc.go similarity index 56% rename from sdk/opentelemetry.go rename to metric/registry/doc.go index eca958dc8a3..a53ba455455 100644 --- a/sdk/opentelemetry.go +++ b/metric/registry/doc.go @@ -12,14 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package opentelemetry contains Go support for OpenTelemetry. -// -// This package is currently in a pre-GA phase. Backwards incompatible changes -// may be introduced in subsequent minor version releases as we work to track -// the evolving OpenTelemetry specification and user feedback. -package opentelemetry // import "go.opentelemetry.io/otel/sdk" +/* +Package registry provides a non-standalone implementation of +MeterProvider that adds uniqueness checking for instrument descriptors +on top of other MeterProvider it wraps. -// Version is the current release version of OpenTelemetry in use. -func Version() string { - return "0.13.0" -} +This package is currently in a pre-GA phase. Backwards incompatible changes +may be introduced in subsequent minor version releases as we work to track the +evolving OpenTelemetry specification and user feedback. +*/ +package registry // import "go.opentelemetry.io/otel/metric/registry" diff --git a/global/metric_test.go b/metric_test.go similarity index 87% rename from global/metric_test.go rename to metric_test.go index aeb4ebe25ce..ef04c9348db 100644 --- a/global/metric_test.go +++ b/metric_test.go @@ -12,12 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -package global_test +package otel import ( "testing" - "go.opentelemetry.io/otel/global" "go.opentelemetry.io/otel/metric" ) @@ -32,10 +31,10 @@ func (*testMeterProvider) Meter(_ string, _ ...metric.MeterOption) metric.Meter func TestMultipleGlobalMeterProvider(t *testing.T) { p1 := testMeterProvider{} p2 := metric.NoopMeterProvider{} - global.SetMeterProvider(&p1) - global.SetMeterProvider(&p2) + SetMeterProvider(&p1) + SetMeterProvider(&p2) - got := global.MeterProvider() + got := GetMeterProvider() want := &p2 if got != want { t.Fatalf("MeterProvider: got %p, want %p\n", got, want) diff --git a/oteltest/text_map_propagator.go b/oteltest/text_map_propagator.go index 7fe901e26ed..6a765d0d3ea 100644 --- a/oteltest/text_map_propagator.go +++ b/oteltest/text_map_propagator.go @@ -22,7 +22,7 @@ import ( "sync" "testing" - "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/propagation" ) type ctxKeyType string @@ -167,12 +167,12 @@ func (p *TextMapPropagator) stateFromContext(ctx context.Context) state { return state{} } -func (p *TextMapPropagator) stateFromCarrier(carrier otel.TextMapCarrier) state { +func (p *TextMapPropagator) stateFromCarrier(carrier propagation.TextMapCarrier) state { return newState(carrier.Get(p.Name)) } // Inject set cross-cutting concerns for p from the Context into the carrier. -func (p *TextMapPropagator) Inject(ctx context.Context, carrier otel.TextMapCarrier) { +func (p *TextMapPropagator) Inject(ctx context.Context, carrier propagation.TextMapCarrier) { s := p.stateFromContext(ctx) s.Injections++ carrier.Set(p.Name, s.String()) @@ -188,7 +188,7 @@ func (p *TextMapPropagator) InjectedN(t *testing.T, carrier *TextMapCarrier, n i } // Extract reads cross-cutting concerns for p from the carrier into a Context. -func (p *TextMapPropagator) Extract(ctx context.Context, carrier otel.TextMapCarrier) context.Context { +func (p *TextMapPropagator) Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context { s := p.stateFromCarrier(carrier) s.Extractions++ return context.WithValue(ctx, p.ctxKey, s) diff --git a/pre_release.sh b/pre_release.sh index e09924b770e..34290a1c82e 100755 --- a/pre_release.sh +++ b/pre_release.sh @@ -54,7 +54,7 @@ if [[ ${TAG_FOUND} = ${TAG} ]] ; then exit -1 fi -# Get version for sdk/opentelemetry.go +# Get version for version.go OTEL_VERSION=$(echo "${TAG}" | grep -o '^v[0-9]\+\.[0-9]\+\.[0-9]\+') # Strip leading v OTEL_VERSION="${OTEL_VERSION#v}" @@ -68,10 +68,10 @@ if ! git diff --quiet; then \ exit 1 fi -# Update sdk/opentelemetry.go -cp ./sdk/opentelemetry.go ./sdk/opentelemetry.go.bak -sed "s/\(return \"\)[0-9]*\.[0-9]*\.[0-9]*\"/\1${OTEL_VERSION}\"/" ./sdk/opentelemetry.go.bak >./sdk/opentelemetry.go -rm -f ./sdk/opentelemetry.go.bak +# Update version.go +cp ./version.go ./version.go.bak +sed "s/\(return \"\)[0-9]*\.[0-9]*\.[0-9]*\"/\1${OTEL_VERSION}\"/" ./version.go.bak >./version.go +rm -f ./version.go.bak # Update go.mod git checkout -b pre_release_${TAG} master diff --git a/propagation.go b/propagation.go index f71e394542e..241a8cd45dd 100644 --- a/propagation.go +++ b/propagation.go @@ -14,65 +14,18 @@ package otel // import "go.opentelemetry.io/otel" -import "context" - -// TextMapCarrier is the storage medium used by a TextMapPropagator. -type TextMapCarrier interface { - // Get returns the value associated with the passed key. - Get(key string) string - // Set stores the key-value pair. - Set(key string, value string) -} - -// TextMapPropagator propagates cross-cutting concerns as key-value text -// pairs within a carrier that travels in-band across process boundaries. -type TextMapPropagator interface { - // Inject set cross-cutting concerns from the Context into the carrier. - Inject(ctx context.Context, carrier TextMapCarrier) - // Extract reads cross-cutting concerns from the carrier into a Context. - Extract(ctx context.Context, carrier TextMapCarrier) context.Context - // Fields returns the keys who's values are set with Inject. - Fields() []string -} - -type compositeTextMapPropagator []TextMapPropagator - -func (p compositeTextMapPropagator) Inject(ctx context.Context, carrier TextMapCarrier) { - for _, i := range p { - i.Inject(ctx, carrier) - } +import ( + "go.opentelemetry.io/otel/internal/global" + "go.opentelemetry.io/otel/propagation" +) + +// GetTextMapPropagator returns the global TextMapPropagator. If none has been +// set, a No-Op TextMapPropagator is returned. +func GetTextMapPropagator() propagation.TextMapPropagator { + return global.TextMapPropagator() } -func (p compositeTextMapPropagator) Extract(ctx context.Context, carrier TextMapCarrier) context.Context { - for _, i := range p { - ctx = i.Extract(ctx, carrier) - } - return ctx -} - -func (p compositeTextMapPropagator) Fields() []string { - unique := make(map[string]struct{}) - for _, i := range p { - for _, k := range i.Fields() { - unique[k] = struct{}{} - } - } - - fields := make([]string, 0, len(unique)) - for k := range unique { - fields = append(fields, k) - } - return fields -} - -// NewCompositeTextMapPropagator returns a unified TextMapPropagator from the -// group of passed TextMapPropagator. This allows different cross-cutting -// concerns to be propagates in a unified manner. -// -// The returned TextMapPropagator will inject and extract cross-cutting -// concerns in the order the TextMapPropagators were provided. Additionally, -// the Fields method will return a de-duplicated slice of the keys that are -// set with the Inject method. -func NewCompositeTextMapPropagator(p ...TextMapPropagator) TextMapPropagator { - return compositeTextMapPropagator(p) +// SetTextMapPropagator sets propagator as the global TSetTextMapPropagator. +func SetTextMapPropagator(propagator propagation.TextMapPropagator) { + global.SetTextMapPropagator(propagator) } diff --git a/propagators/baggage.go b/propagation/baggage.go similarity index 91% rename from propagators/baggage.go rename to propagation/baggage.go index d143f32f68c..2c416d7fbd7 100644 --- a/propagators/baggage.go +++ b/propagation/baggage.go @@ -12,14 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -package propagators // import "go.opentelemetry.io/otel/propagators" +package propagation // import "go.opentelemetry.io/otel/propagation" import ( "context" "net/url" "strings" - "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/internal/baggage" "go.opentelemetry.io/otel/label" ) @@ -32,10 +31,10 @@ const baggageHeader = "baggage" // specification is defined at https://w3c.github.io/baggage/. type Baggage struct{} -var _ otel.TextMapPropagator = Baggage{} +var _ TextMapPropagator = Baggage{} // Inject sets baggage key-values from ctx into the carrier. -func (b Baggage) Inject(ctx context.Context, carrier otel.TextMapCarrier) { +func (b Baggage) Inject(ctx context.Context, carrier TextMapCarrier) { baggageMap := baggage.MapFromContext(ctx) firstIter := true var headerValueBuilder strings.Builder @@ -56,7 +55,7 @@ func (b Baggage) Inject(ctx context.Context, carrier otel.TextMapCarrier) { } // Extract returns a copy of parent with the baggage from the carrier added. -func (b Baggage) Extract(parent context.Context, carrier otel.TextMapCarrier) context.Context { +func (b Baggage) Extract(parent context.Context, carrier TextMapCarrier) context.Context { bVal := carrier.Get(baggageHeader) if bVal == "" { return parent diff --git a/propagators/baggage_test.go b/propagation/baggage_test.go similarity index 95% rename from propagators/baggage_test.go rename to propagation/baggage_test.go index 267b47e30f1..a8742bf4a6a 100644 --- a/propagators/baggage_test.go +++ b/propagation/baggage_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package propagators_test +package propagation_test import ( "context" @@ -22,14 +22,13 @@ import ( "github.com/google/go-cmp/cmp" - "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/internal/baggage" "go.opentelemetry.io/otel/label" - "go.opentelemetry.io/otel/propagators" + "go.opentelemetry.io/otel/propagation" ) func TestExtractValidBaggageFromHTTPReq(t *testing.T) { - prop := otel.TextMapPropagator(propagators.Baggage{}) + prop := propagation.TextMapPropagator(propagation.Baggage{}) tests := []struct { name string header string @@ -118,7 +117,7 @@ func TestExtractValidBaggageFromHTTPReq(t *testing.T) { } func TestExtractInvalidDistributedContextFromHTTPReq(t *testing.T) { - prop := otel.TextMapPropagator(propagators.Baggage{}) + prop := propagation.TextMapPropagator(propagation.Baggage{}) tests := []struct { name string header string @@ -176,7 +175,7 @@ func TestExtractInvalidDistributedContextFromHTTPReq(t *testing.T) { } func TestInjectBaggageToHTTPReq(t *testing.T) { - propagator := propagators.Baggage{} + propagator := propagation.Baggage{} tests := []struct { name string kvs []label.KeyValue @@ -250,7 +249,7 @@ func TestInjectBaggageToHTTPReq(t *testing.T) { } func TestBaggagePropagatorGetAllKeys(t *testing.T) { - var propagator propagators.Baggage + var propagator propagation.Baggage want := []string{"baggage"} got := propagator.Fields() if diff := cmp.Diff(got, want); diff != "" { diff --git a/propagators/doc.go b/propagation/doc.go similarity index 89% rename from propagators/doc.go rename to propagation/doc.go index 48ff026d60a..89573f1baa9 100644 --- a/propagators/doc.go +++ b/propagation/doc.go @@ -13,7 +13,7 @@ // limitations under the License. /* -Package propagators contains OpenTelemetry context propagators. +Package propagation contains OpenTelemetry context propagators. This package is currently in a pre-GA phase. Backwards incompatible changes may be introduced in subsequent minor version releases as we work to track the @@ -25,4 +25,4 @@ package is the W3C Trace Context encoding (https://www.w3.org/TR/trace-context/), and W3C Baggage (https://w3c.github.io/baggage/). */ -package propagators // import "go.opentelemetry.io/otel/propagators" +package propagation // import "go.opentelemetry.io/otel/propagation" diff --git a/propagation/propagation.go b/propagation/propagation.go new file mode 100644 index 00000000000..c867f86b8f9 --- /dev/null +++ b/propagation/propagation.go @@ -0,0 +1,78 @@ +// 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 propagation // import "go.opentelemetry.io/otel/propagation" + +import "context" + +// TextMapCarrier is the storage medium used by a TextMapPropagator. +type TextMapCarrier interface { + // Get returns the value associated with the passed key. + Get(key string) string + // Set stores the key-value pair. + Set(key string, value string) +} + +// TextMapPropagator propagates cross-cutting concerns as key-value text +// pairs within a carrier that travels in-band across process boundaries. +type TextMapPropagator interface { + // Inject set cross-cutting concerns from the Context into the carrier. + Inject(ctx context.Context, carrier TextMapCarrier) + // Extract reads cross-cutting concerns from the carrier into a Context. + Extract(ctx context.Context, carrier TextMapCarrier) context.Context + // Fields returns the keys who's values are set with Inject. + Fields() []string +} + +type compositeTextMapPropagator []TextMapPropagator + +func (p compositeTextMapPropagator) Inject(ctx context.Context, carrier TextMapCarrier) { + for _, i := range p { + i.Inject(ctx, carrier) + } +} + +func (p compositeTextMapPropagator) Extract(ctx context.Context, carrier TextMapCarrier) context.Context { + for _, i := range p { + ctx = i.Extract(ctx, carrier) + } + return ctx +} + +func (p compositeTextMapPropagator) Fields() []string { + unique := make(map[string]struct{}) + for _, i := range p { + for _, k := range i.Fields() { + unique[k] = struct{}{} + } + } + + fields := make([]string, 0, len(unique)) + for k := range unique { + fields = append(fields, k) + } + return fields +} + +// NewCompositeTextMapPropagator returns a unified TextMapPropagator from the +// group of passed TextMapPropagator. This allows different cross-cutting +// concerns to be propagates in a unified manner. +// +// The returned TextMapPropagator will inject and extract cross-cutting +// concerns in the order the TextMapPropagators were provided. Additionally, +// the Fields method will return a de-duplicated slice of the keys that are +// set with the Inject method. +func NewCompositeTextMapPropagator(p ...TextMapPropagator) TextMapPropagator { + return compositeTextMapPropagator(p) +} diff --git a/propagation_test.go b/propagation/propagation_test.go similarity index 81% rename from propagation_test.go rename to propagation/propagation_test.go index 14d2058254f..477938dec3b 100644 --- a/propagation_test.go +++ b/propagation/propagation_test.go @@ -12,12 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -package otel +package propagation_test import ( "context" "strings" "testing" + + "go.opentelemetry.io/otel/propagation" ) type ctxKeyType uint @@ -38,11 +40,11 @@ type propagator struct { Name string } -func (p propagator) Inject(ctx context.Context, carrier TextMapCarrier) { +func (p propagator) Inject(ctx context.Context, carrier propagation.TextMapCarrier) { carrier.Set(p.Name, "") } -func (p propagator) Extract(ctx context.Context, carrier TextMapCarrier) context.Context { +func (p propagator) Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context { v := ctx.Value(ctxKey) if v == nil { ctx = context.WithValue(ctx, ctxKey, []string{p.Name}) @@ -62,7 +64,7 @@ func TestCompositeTextMapPropagatorFields(t *testing.T) { "a": {}, "b": {}, } - got := NewCompositeTextMapPropagator(a, b1, b2).Fields() + got := propagation.NewCompositeTextMapPropagator(a, b1, b2).Fields() if len(got) != len(want) { t.Fatalf("invalid fields from composite: %v (want %v)", got, want) } @@ -77,7 +79,7 @@ func TestCompositeTextMapPropagatorInject(t *testing.T) { a, b := propagator{"a"}, propagator{"b"} c := make(carrier, 0, 2) - NewCompositeTextMapPropagator(a, b).Inject(context.Background(), &c) + propagation.NewCompositeTextMapPropagator(a, b).Inject(context.Background(), &c) if got := strings.Join([]string(c), ","); got != "a,b" { t.Errorf("invalid inject order: %s", got) @@ -88,7 +90,7 @@ func TestCompositeTextMapPropagatorExtract(t *testing.T) { a, b := propagator{"a"}, propagator{"b"} ctx := context.Background() - ctx = NewCompositeTextMapPropagator(a, b).Extract(ctx, nil) + ctx = propagation.NewCompositeTextMapPropagator(a, b).Extract(ctx, nil) v := ctx.Value(ctxKey) if v == nil { diff --git a/propagators/propagators_test.go b/propagation/propagators_test.go similarity index 85% rename from propagators/propagators_test.go rename to propagation/propagators_test.go index 03af3ca0d38..df392b51495 100644 --- a/propagators/propagators_test.go +++ b/propagation/propagators_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package propagators_test +package propagation_test import ( "context" @@ -21,8 +21,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/propagators" + "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) @@ -58,9 +57,9 @@ type outOfThinAirPropagator struct { t *testing.T } -var _ otel.TextMapPropagator = outOfThinAirPropagator{} +var _ propagation.TextMapPropagator = outOfThinAirPropagator{} -func (p outOfThinAirPropagator) Extract(ctx context.Context, carrier otel.TextMapCarrier) context.Context { +func (p outOfThinAirPropagator) Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context { sc := trace.SpanContext{ TraceID: traceID, SpanID: spanID, @@ -70,7 +69,7 @@ func (p outOfThinAirPropagator) Extract(ctx context.Context, carrier otel.TextMa return trace.ContextWithRemoteSpanContext(ctx, sc) } -func (outOfThinAirPropagator) Inject(context.Context, otel.TextMapCarrier) {} +func (outOfThinAirPropagator) Inject(context.Context, propagation.TextMapCarrier) {} func (outOfThinAirPropagator) Fields() []string { return nil @@ -78,7 +77,7 @@ func (outOfThinAirPropagator) Fields() []string { type nilCarrier struct{} -var _ otel.TextMapCarrier = nilCarrier{} +var _ propagation.TextMapCarrier = nilCarrier{} func (nilCarrier) Get(key string) string { return "" @@ -89,8 +88,8 @@ func (nilCarrier) Set(key string, value string) {} func TestMultiplePropagators(t *testing.T) { ootaProp := outOfThinAirPropagator{t: t} ns := nilCarrier{} - testProps := []otel.TextMapPropagator{ - propagators.TraceContext{}, + testProps := []propagation.TextMapPropagator{ + propagation.TraceContext{}, } bg := context.Background() // sanity check of oota propagator, ensuring that it really @@ -109,7 +108,7 @@ func TestMultiplePropagators(t *testing.T) { require.Falsef(t, sc.IsValid(), "%#v failed sanity check", prop) } for _, prop := range testProps { - props := otel.NewCompositeTextMapPropagator(ootaProp, prop) + props := propagation.NewCompositeTextMapPropagator(ootaProp, prop) ctx := props.Extract(bg, ns) sc := trace.RemoteSpanContextFromContext(ctx) assert.Truef(t, sc.IsValid(), "%#v clobbers span context", prop) diff --git a/propagators/trace_context.go b/propagation/trace_context.go similarity index 90% rename from propagators/trace_context.go rename to propagation/trace_context.go index 0e25da785b5..ec99e0965fd 100644 --- a/propagators/trace_context.go +++ b/propagation/trace_context.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package propagators // import "go.opentelemetry.io/otel/propagators" +package propagation // import "go.opentelemetry.io/otel/propagation" import ( "context" @@ -20,7 +20,6 @@ import ( "fmt" "regexp" - "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/trace" ) @@ -47,11 +46,11 @@ const ( // their proprietary information. type TraceContext struct{} -var _ otel.TextMapPropagator = TraceContext{} +var _ TextMapPropagator = TraceContext{} var traceCtxRegExp = regexp.MustCompile("^(?P[0-9a-f]{2})-(?P[a-f0-9]{32})-(?P[a-f0-9]{16})-(?P[a-f0-9]{2})(?:-.*)?$") // Inject set tracecontext from the Context into the carrier. -func (tc TraceContext) Inject(ctx context.Context, carrier otel.TextMapCarrier) { +func (tc TraceContext) Inject(ctx context.Context, carrier TextMapCarrier) { tracestate := ctx.Value(tracestateKey) if state, ok := tracestate.(string); tracestate != nil && ok { carrier.Set(tracestateHeader, state) @@ -70,7 +69,7 @@ func (tc TraceContext) Inject(ctx context.Context, carrier otel.TextMapCarrier) } // Extract reads tracecontext from the carrier into a returned Context. -func (tc TraceContext) Extract(ctx context.Context, carrier otel.TextMapCarrier) context.Context { +func (tc TraceContext) Extract(ctx context.Context, carrier TextMapCarrier) context.Context { state := carrier.Get(tracestateHeader) if state != "" { ctx = context.WithValue(ctx, tracestateKey, state) @@ -83,7 +82,7 @@ func (tc TraceContext) Extract(ctx context.Context, carrier otel.TextMapCarrier) return trace.ContextWithRemoteSpanContext(ctx, sc) } -func (tc TraceContext) extract(carrier otel.TextMapCarrier) trace.SpanContext { +func (tc TraceContext) extract(carrier TextMapCarrier) trace.SpanContext { h := carrier.Get(traceparentHeader) if h == "" { return trace.SpanContext{} diff --git a/propagators/trace_context_benchmark_test.go b/propagation/trace_context_benchmark_test.go similarity index 95% rename from propagators/trace_context_benchmark_test.go rename to propagation/trace_context_benchmark_test.go index ba029cb481c..0f2d5fcebb2 100644 --- a/propagators/trace_context_benchmark_test.go +++ b/propagation/trace_context_benchmark_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package propagators_test +package propagation_test import ( "context" @@ -20,12 +20,12 @@ import ( "testing" "go.opentelemetry.io/otel/oteltest" - "go.opentelemetry.io/otel/propagators" + "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) func BenchmarkInject(b *testing.B) { - var t propagators.TraceContext + var t propagation.TraceContext injectSubBenchmarks(b, func(ctx context.Context, b *testing.B) { req, _ := http.NewRequest("GET", "http://example.com", nil) @@ -62,7 +62,7 @@ func injectSubBenchmarks(b *testing.B, fn func(context.Context, *testing.B)) { func BenchmarkExtract(b *testing.B) { extractSubBenchmarks(b, func(b *testing.B, req *http.Request) { - var propagator propagators.TraceContext + var propagator propagation.TraceContext ctx := context.Background() b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/propagators/trace_context_example_test.go b/propagation/trace_context_example_test.go similarity index 80% rename from propagators/trace_context_example_test.go rename to propagation/trace_context_example_test.go index e871b66f247..474b052617b 100644 --- a/propagators/trace_context_example_test.go +++ b/propagation/trace_context_example_test.go @@ -12,15 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -package propagators_test +package propagation_test import ( - "go.opentelemetry.io/otel/global" - "go.opentelemetry.io/otel/propagators" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/propagation" ) func ExampleTraceContext() { - tc := propagators.TraceContext{} + tc := propagation.TraceContext{} // Register the TraceContext propagator globally. - global.SetTextMapPropagator(tc) + otel.SetTextMapPropagator(tc) } diff --git a/propagators/trace_context_test.go b/propagation/trace_context_test.go similarity index 96% rename from propagators/trace_context_test.go rename to propagation/trace_context_test.go index b32460ed241..1fc3ba15466 100644 --- a/propagators/trace_context_test.go +++ b/propagation/trace_context_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package propagators_test +package propagation_test import ( "context" @@ -22,12 +22,12 @@ import ( "github.com/google/go-cmp/cmp" "go.opentelemetry.io/otel/oteltest" - "go.opentelemetry.io/otel/propagators" + "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) func TestExtractValidTraceContextFromHTTPReq(t *testing.T) { - prop := propagators.TraceContext{} + prop := propagation.TraceContext{} tests := []struct { name string header string @@ -122,7 +122,7 @@ func TestExtractValidTraceContextFromHTTPReq(t *testing.T) { func TestExtractInvalidTraceContextFromHTTPReq(t *testing.T) { wantSc := trace.SpanContext{} - prop := propagators.TraceContext{} + prop := propagation.TraceContext{} tests := []struct { name string header string @@ -210,7 +210,7 @@ func TestExtractInvalidTraceContextFromHTTPReq(t *testing.T) { func TestInjectTraceContextToHTTPReq(t *testing.T) { mockTracer := oteltest.DefaultTracer() - prop := propagators.TraceContext{} + prop := propagation.TraceContext{} tests := []struct { name string sc trace.SpanContext @@ -267,7 +267,7 @@ func TestInjectTraceContextToHTTPReq(t *testing.T) { } func TestTraceContextPropagator_GetAllKeys(t *testing.T) { - var propagator propagators.TraceContext + var propagator propagation.TraceContext want := []string{"traceparent", "tracestate"} got := propagator.Fields() if diff := cmp.Diff(got, want); diff != "" { @@ -276,7 +276,7 @@ func TestTraceContextPropagator_GetAllKeys(t *testing.T) { } func TestTraceStatePropagation(t *testing.T) { - prop := propagators.TraceContext{} + prop := propagation.TraceContext{} want := "opaquevalue" headerName := "tracestate" diff --git a/sdk/export/metric/metric.go b/sdk/export/metric/metric.go index 6a089601968..525fe8f3a63 100644 --- a/sdk/export/metric/metric.go +++ b/sdk/export/metric/metric.go @@ -174,6 +174,9 @@ type Aggregator interface { // // This call has no Context argument because it is expected to // perform only computation. + // + // When called with a nil `destination`, this Aggregator is reset + // and the current value is discarded. SynchronizedMove(destination Aggregator, descriptor *metric.Descriptor) error // Merge combines the checkpointed state from the argument diff --git a/sdk/export/trace/trace.go b/sdk/export/trace/trace.go index a9883bff73f..96b45b92f6b 100644 --- a/sdk/export/trace/trace.go +++ b/sdk/export/trace/trace.go @@ -26,10 +26,10 @@ import ( "go.opentelemetry.io/otel/sdk/resource" ) -// SpanExporter handles the delivery of SpanData to external receivers. This is -// the final component in the trace export pipeline. +// SpanExporter handles the delivery of SpanSnapshot structs to external +// receivers. This is the final component in the trace export pipeline. type SpanExporter interface { - // ExportSpans exports a batch of SpanData. + // ExportSpans exports a batch of SpanSnapshots. // // This function is called synchronously, so there is no concurrency // safety requirement. However, due to the synchronous calling pattern, @@ -40,7 +40,7 @@ type SpanExporter interface { // calls this function will not implement any retry logic. All errors // returned by this function are considered unrecoverable and will be // reported to a configured error Handler. - ExportSpans(ctx context.Context, spanData []*SpanData) error + ExportSpans(ctx context.Context, ss []*SpanSnapshot) error // Shutdown notifies the exporter of a pending halt to operations. The // exporter is expected to preform any cleanup or synchronization it // requires while honoring all timeouts and cancellations contained in @@ -48,8 +48,12 @@ type SpanExporter interface { Shutdown(ctx context.Context) error } -// SpanData contains all the information collected by a completed span. -type SpanData struct { +// SpanSnapshot is a snapshot of a span which contains all the information +// collected by the span. Its main purpose is exporting completed spans. +// Although SpanSnapshot fields can be accessed and potentially modified, +// SpanSnapshot should be treated as immutable. Changes to the span from which +// the SpanSnapshot was created are NOT reflected in the SpanSnapshot. +type SpanSnapshot struct { SpanContext trace.SpanContext ParentSpanID trace.SpanID SpanKind trace.SpanKind diff --git a/sdk/export/trace/tracetest/test.go b/sdk/export/trace/tracetest/test.go index bd01f97445b..e1bedad6bfb 100644 --- a/sdk/export/trace/tracetest/test.go +++ b/sdk/export/trace/tracetest/test.go @@ -30,12 +30,12 @@ func NewNoopExporter() *NoopExporter { return new(NoopExporter) } -// NoopExporter is an exporter that drops all received SpanData and performs -// no action. +// NoopExporter is an exporter that drops all received SpanSnapshots and +// performs no action. type NoopExporter struct{} -// ExportSpans handles export of SpanData by dropping it. -func (nsb *NoopExporter) ExportSpans(context.Context, []*trace.SpanData) error { return nil } +// ExportSpans handles export of SpanSnapshots by dropping them. +func (nsb *NoopExporter) ExportSpans(context.Context, []*trace.SpanSnapshot) error { return nil } // Shutdown stops the exporter by doing nothing. func (nsb *NoopExporter) Shutdown(context.Context) error { return nil } @@ -49,19 +49,19 @@ func NewInMemoryExporter() *InMemoryExporter { // InMemoryExporter is an exporter that stores all received spans in-memory. type InMemoryExporter struct { - mu sync.Mutex - sds []*trace.SpanData + mu sync.Mutex + ss []*trace.SpanSnapshot } -// ExportSpans handles export of SpanData by storing it in memory. -func (imsb *InMemoryExporter) ExportSpans(_ context.Context, sds []*trace.SpanData) error { +// ExportSpans handles export of SpanSnapshots by storing them in memory. +func (imsb *InMemoryExporter) ExportSpans(_ context.Context, ss []*trace.SpanSnapshot) error { imsb.mu.Lock() defer imsb.mu.Unlock() - imsb.sds = append(imsb.sds, sds...) + imsb.ss = append(imsb.ss, ss...) return nil } -// Shutdown stops the exporter by clearing SpanData held in memory. +// Shutdown stops the exporter by clearing SpanSnapshots held in memory. func (imsb *InMemoryExporter) Shutdown(context.Context) error { imsb.Reset() return nil @@ -71,14 +71,14 @@ func (imsb *InMemoryExporter) Shutdown(context.Context) error { func (imsb *InMemoryExporter) Reset() { imsb.mu.Lock() defer imsb.mu.Unlock() - imsb.sds = nil + imsb.ss = nil } // GetSpans returns the current in-memory stored spans. -func (imsb *InMemoryExporter) GetSpans() []*trace.SpanData { +func (imsb *InMemoryExporter) GetSpans() []*trace.SpanSnapshot { imsb.mu.Lock() defer imsb.mu.Unlock() - ret := make([]*trace.SpanData, len(imsb.sds)) - copy(ret, imsb.sds) + ret := make([]*trace.SpanSnapshot, len(imsb.ss)) + copy(ret, imsb.ss) return ret } diff --git a/sdk/export/trace/tracetest/test_test.go b/sdk/export/trace/tracetest/test_test.go index 378a71f7d57..380109c0ff8 100644 --- a/sdk/export/trace/tracetest/test_test.go +++ b/sdk/export/trace/tracetest/test_test.go @@ -29,8 +29,8 @@ func TestNoop(t *testing.T) { nsb := NewNoopExporter() require.NoError(t, nsb.ExportSpans(context.Background(), nil)) - require.NoError(t, nsb.ExportSpans(context.Background(), make([]*trace.SpanData, 10))) - require.NoError(t, nsb.ExportSpans(context.Background(), make([]*trace.SpanData, 0, 10))) + require.NoError(t, nsb.ExportSpans(context.Background(), make([]*trace.SpanSnapshot, 10))) + require.NoError(t, nsb.ExportSpans(context.Background(), make([]*trace.SpanSnapshot, 0, 10))) } func TestNewInMemoryExporter(t *testing.T) { @@ -39,9 +39,9 @@ func TestNewInMemoryExporter(t *testing.T) { require.NoError(t, imsb.ExportSpans(context.Background(), nil)) assert.Len(t, imsb.GetSpans(), 0) - input := make([]*trace.SpanData, 10) + input := make([]*trace.SpanSnapshot, 10) for i := 0; i < 10; i++ { - input[i] = new(trace.SpanData) + input[i] = new(trace.SpanSnapshot) } require.NoError(t, imsb.ExportSpans(context.Background(), input)) sds := imsb.GetSpans() diff --git a/sdk/go.mod b/sdk/go.mod index 4cdf4a3583c..ea3b45b2fd0 100644 --- a/sdk/go.mod +++ b/sdk/go.mod @@ -7,8 +7,8 @@ replace go.opentelemetry.io/otel => ../ require ( github.com/DataDog/sketches-go v0.0.1 github.com/benbjohnson/clock v1.0.3 - github.com/google/go-cmp v0.5.2 + github.com/google/go-cmp v0.5.4 github.com/google/gofuzz v1.1.0 // indirect github.com/stretchr/testify v1.6.1 - go.opentelemetry.io/otel v0.13.0 + go.opentelemetry.io/otel v0.15.0 ) diff --git a/sdk/go.sum b/sdk/go.sum index 1680073b00e..ae3c891c195 100644 --- a/sdk/go.sum +++ b/sdk/go.sum @@ -4,8 +4,8 @@ github.com/benbjohnson/clock v1.0.3 h1:vkLuvpK4fmtSCuo60+yC63p7y0BmQ8gm5ZXGuBCJy github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/sdk/internal/internal.go b/sdk/internal/internal.go index b9d318e93bb..84a02306e64 100644 --- a/sdk/internal/internal.go +++ b/sdk/internal/internal.go @@ -18,12 +18,12 @@ import ( "fmt" "time" - opentelemetry "go.opentelemetry.io/otel/sdk" + "go.opentelemetry.io/otel" ) // UserAgent is the user agent to be added to the outgoing // requests from the exporters. -var UserAgent = fmt.Sprintf("opentelemetry-go/%s", opentelemetry.Version()) +var UserAgent = fmt.Sprintf("opentelemetry-go/%s", otel.Version()) // MonotonicEndTime returns the end time at present // but offset from start, monotonically. diff --git a/sdk/metric/aggregator/aggregator.go b/sdk/metric/aggregator/aggregator.go index 0539a0fd79b..afda991e863 100644 --- a/sdk/metric/aggregator/aggregator.go +++ b/sdk/metric/aggregator/aggregator.go @@ -31,7 +31,7 @@ func NewInconsistentAggregatorError(a1, a2 export.Aggregator) error { return fmt.Errorf("%w: %T and %T", aggregation.ErrInconsistentType, a1, a2) } -// RangeTest is a commmon routine for testing for valid input values. +// RangeTest is a common routine for testing for valid input values. // This rejects NaN values. This rejects negative values when the // metric instrument does not support negative values, including // monotonic counter metrics and absolute ValueRecorder metrics. diff --git a/sdk/metric/aggregator/aggregatortest/test.go b/sdk/metric/aggregator/aggregatortest/test.go index 1b12032f07f..3a965551256 100644 --- a/sdk/metric/aggregator/aggregatortest/test.go +++ b/sdk/metric/aggregator/aggregatortest/test.go @@ -16,16 +16,20 @@ package aggregatortest // import "go.opentelemetry.io/otel/sdk/metric/aggregator import ( "context" + "errors" "math/rand" "os" "sort" "testing" "unsafe" + "github.com/stretchr/testify/require" + ottest "go.opentelemetry.io/otel/internal/testing" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric/number" export "go.opentelemetry.io/otel/sdk/export/metric" + "go.opentelemetry.io/otel/sdk/export/metric/aggregation" "go.opentelemetry.io/otel/sdk/metric/aggregator" ) @@ -36,6 +40,12 @@ type Profile struct { Random func(sign int) number.Number } +type NoopAggregator struct{} +type NoopAggregation struct{} + +var _ export.Aggregator = NoopAggregator{} +var _ aggregation.Aggregation = NoopAggregation{} + func newProfiles() []Profile { rnd := rand.New(rand.NewSource(rand.Int63())) return []Profile{ @@ -172,3 +182,111 @@ func CheckedMerge(t *testing.T, aggInto, aggFrom export.Aggregator, descriptor * t.Error("Unexpected Merge failure", err) } } + +func (NoopAggregation) Kind() aggregation.Kind { + return aggregation.Kind("Noop") +} + +func (NoopAggregator) Aggregation() aggregation.Aggregation { + return NoopAggregation{} +} + +func (NoopAggregator) Update(context.Context, number.Number, *metric.Descriptor) error { + return nil +} + +func (NoopAggregator) SynchronizedMove(export.Aggregator, *metric.Descriptor) error { + return nil +} + +func (NoopAggregator) Merge(export.Aggregator, *metric.Descriptor) error { + return nil +} + +func SynchronizedMoveResetTest(t *testing.T, mkind metric.InstrumentKind, nf func(*metric.Descriptor) export.Aggregator) { + t.Run("reset on nil", func(t *testing.T) { + // Ensures that SynchronizedMove(nil, descriptor) discards and + // resets the aggregator. + RunProfiles(t, func(t *testing.T, profile Profile) { + descriptor := NewAggregatorTest( + mkind, + profile.NumberKind, + ) + agg := nf(descriptor) + + for i := 0; i < 10; i++ { + x1 := profile.Random(+1) + CheckedUpdate(t, agg, x1, descriptor) + } + + require.NoError(t, agg.SynchronizedMove(nil, descriptor)) + + if count, ok := agg.(aggregation.Count); ok { + c, err := count.Count() + require.Equal(t, int64(0), c) + require.NoError(t, err) + } + + if sum, ok := agg.(aggregation.Sum); ok { + s, err := sum.Sum() + require.Equal(t, number.Number(0), s) + require.NoError(t, err) + } + + if lv, ok := agg.(aggregation.LastValue); ok { + v, _, err := lv.LastValue() + require.Equal(t, number.Number(0), v) + require.Error(t, err) + require.True(t, errors.Is(err, aggregation.ErrNoData)) + } + }) + }) + + t.Run("no reset on incorrect type", func(t *testing.T) { + // Ensures that SynchronizedMove(wrong_type, descriptor) does not + // reset the aggregator. + RunProfiles(t, func(t *testing.T, profile Profile) { + descriptor := NewAggregatorTest( + mkind, + profile.NumberKind, + ) + agg := nf(descriptor) + + var input number.Number + const inval = 100 + if profile.NumberKind == number.Int64Kind { + input = number.NewInt64Number(inval) + } else { + input = number.NewFloat64Number(inval) + } + + CheckedUpdate(t, agg, input, descriptor) + + err := agg.SynchronizedMove(NoopAggregator{}, descriptor) + require.Error(t, err) + require.True(t, errors.Is(err, aggregation.ErrInconsistentType)) + + // Test that the aggregator was not reset + + if count, ok := agg.(aggregation.Count); ok { + c, err := count.Count() + require.Equal(t, int64(1), c) + require.NoError(t, err) + } + + if sum, ok := agg.(aggregation.Sum); ok { + s, err := sum.Sum() + require.Equal(t, input, s) + require.NoError(t, err) + } + + if lv, ok := agg.(aggregation.LastValue); ok { + v, _, err := lv.LastValue() + require.Equal(t, input, v) + require.NoError(t, err) + } + + }) + }) + +} diff --git a/sdk/metric/aggregator/array/array.go b/sdk/metric/aggregator/array/array.go index 5346be36b0e..1ac1d82a5f1 100644 --- a/sdk/metric/aggregator/array/array.go +++ b/sdk/metric/aggregator/array/array.go @@ -97,20 +97,27 @@ func (c *Aggregator) Points() ([]number.Number, error) { // the empty set, taking a lock to prevent concurrent Update() calls. func (c *Aggregator) SynchronizedMove(oa export.Aggregator, desc *metric.Descriptor) error { o, _ := oa.(*Aggregator) - if o == nil { + + if oa != nil && o == nil { return aggregator.NewInconsistentAggregatorError(c, oa) } c.lock.Lock() - o.points, c.points = c.points, nil - o.sum, c.sum = c.sum, 0 + if o != nil { + o.points = c.points + o.sum = c.sum + } + c.points = nil + c.sum = 0 c.lock.Unlock() // TODO: This sort should be done lazily, only when quantiles // are requested. The SDK specification says you can use this // aggregator to simply list values in the order they were // received as an alternative to requesting quantile information. - o.sort(desc.NumberKind()) + if o != nil { + o.sort(desc.NumberKind()) + } return nil } diff --git a/sdk/metric/aggregator/array/array_test.go b/sdk/metric/aggregator/array/array_test.go index db32d9d603c..e9ba40b7001 100644 --- a/sdk/metric/aggregator/array/array_test.go +++ b/sdk/metric/aggregator/array/array_test.go @@ -24,6 +24,7 @@ import ( "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric/number" + export "go.opentelemetry.io/otel/sdk/export/metric" "go.opentelemetry.io/otel/sdk/export/metric/aggregation" "go.opentelemetry.io/otel/sdk/metric/aggregator/aggregatortest" ) @@ -329,3 +330,13 @@ func TestArrayFloat64(t *testing.T) { require.Equal(t, all.Points()[i], po[i], "Wrong point at position %d", i) } } + +func TestSynchronizedMoveReset(t *testing.T) { + aggregatortest.SynchronizedMoveResetTest( + t, + metric.ValueRecorderInstrumentKind, + func(desc *metric.Descriptor) export.Aggregator { + return &New(1)[0] + }, + ) +} diff --git a/sdk/metric/aggregator/ddsketch/ddsketch.go b/sdk/metric/aggregator/ddsketch/ddsketch.go index 1e844f570fe..cbd97a776cf 100644 --- a/sdk/metric/aggregator/ddsketch/ddsketch.go +++ b/sdk/metric/aggregator/ddsketch/ddsketch.go @@ -117,13 +117,17 @@ func (c *Aggregator) toNumber(f float64) number.Number { // a new sketch, taking a lock to prevent concurrent Update() calls. func (c *Aggregator) SynchronizedMove(oa export.Aggregator, _ *metric.Descriptor) error { o, _ := oa.(*Aggregator) - if o == nil { + + if oa != nil && o == nil { return aggregator.NewInconsistentAggregatorError(c, oa) } - replace := sdk.NewDDSketch(c.cfg) + replace := sdk.NewDDSketch(c.cfg) c.lock.Lock() - o.sketch, c.sketch = c.sketch, replace + if o != nil { + o.sketch = c.sketch + } + c.sketch = replace c.lock.Unlock() return nil diff --git a/sdk/metric/aggregator/ddsketch/ddsketch_test.go b/sdk/metric/aggregator/ddsketch/ddsketch_test.go index 63bcbab4675..d05ab7b1ad8 100644 --- a/sdk/metric/aggregator/ddsketch/ddsketch_test.go +++ b/sdk/metric/aggregator/ddsketch/ddsketch_test.go @@ -22,6 +22,7 @@ import ( "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/metric" + export "go.opentelemetry.io/otel/sdk/export/metric" "go.opentelemetry.io/otel/sdk/export/metric/aggregation" "go.opentelemetry.io/otel/sdk/metric/aggregator/aggregatortest" ) @@ -208,3 +209,13 @@ func TestDDSketchMerge(t *testing.T) { }) } } + +func TestSynchronizedMoveReset(t *testing.T) { + aggregatortest.SynchronizedMoveResetTest( + t, + metric.ValueRecorderInstrumentKind, + func(desc *metric.Descriptor) export.Aggregator { + return &New(1, desc, NewDefaultConfig())[0] + }, + ) +} diff --git a/sdk/metric/aggregator/histogram/histogram.go b/sdk/metric/aggregator/histogram/histogram.go index 733becd09c0..eb41fb012b6 100644 --- a/sdk/metric/aggregator/histogram/histogram.go +++ b/sdk/metric/aggregator/histogram/histogram.go @@ -118,13 +118,18 @@ func (c *Aggregator) Histogram() (aggregation.Buckets, error) { // other. func (c *Aggregator) SynchronizedMove(oa export.Aggregator, desc *metric.Descriptor) error { o, _ := oa.(*Aggregator) - if o == nil { + + if oa != nil && o == nil { return aggregator.NewInconsistentAggregatorError(c, oa) } c.lock.Lock() - o.state, c.state = c.state, emptyState(c.boundaries) + if o != nil { + o.state = c.state + } + c.state = emptyState(c.boundaries) c.lock.Unlock() + return nil } diff --git a/sdk/metric/aggregator/histogram/histogram_test.go b/sdk/metric/aggregator/histogram/histogram_test.go index c7468149ddd..e1a096f46d1 100644 --- a/sdk/metric/aggregator/histogram/histogram_test.go +++ b/sdk/metric/aggregator/histogram/histogram_test.go @@ -24,6 +24,7 @@ import ( "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric/number" + export "go.opentelemetry.io/otel/sdk/export/metric" "go.opentelemetry.io/otel/sdk/metric/aggregator/aggregatortest" "go.opentelemetry.io/otel/sdk/metric/aggregator/histogram" ) @@ -249,3 +250,13 @@ func calcBuckets(points []number.Number, profile aggregatortest.Profile) []uint6 return counts } + +func TestSynchronizedMoveReset(t *testing.T) { + aggregatortest.SynchronizedMoveResetTest( + t, + metric.ValueRecorderInstrumentKind, + func(desc *metric.Descriptor) export.Aggregator { + return &histogram.New(1, desc, boundaries)[0] + }, + ) +} diff --git a/sdk/metric/aggregator/lastvalue/lastvalue.go b/sdk/metric/aggregator/lastvalue/lastvalue.go index e220d88edfb..3cc5f7055cf 100644 --- a/sdk/metric/aggregator/lastvalue/lastvalue.go +++ b/sdk/metric/aggregator/lastvalue/lastvalue.go @@ -93,6 +93,10 @@ func (g *Aggregator) LastValue() (number.Number, time.Time, error) { // SynchronizedMove atomically saves the current value. func (g *Aggregator) SynchronizedMove(oa export.Aggregator, _ *metric.Descriptor) error { + if oa == nil { + atomic.StorePointer(&g.value, unsafe.Pointer(unsetLastValue)) + return nil + } o, _ := oa.(*Aggregator) if o == nil { return aggregator.NewInconsistentAggregatorError(g, oa) diff --git a/sdk/metric/aggregator/lastvalue/lastvalue_test.go b/sdk/metric/aggregator/lastvalue/lastvalue_test.go index 62438c36619..3aad095e7b3 100644 --- a/sdk/metric/aggregator/lastvalue/lastvalue_test.go +++ b/sdk/metric/aggregator/lastvalue/lastvalue_test.go @@ -132,3 +132,13 @@ func TestLastValueNotSet(t *testing.T) { checkZero(t, g) } + +func TestSynchronizedMoveReset(t *testing.T) { + aggregatortest.SynchronizedMoveResetTest( + t, + metric.ValueObserverInstrumentKind, + func(desc *metric.Descriptor) export.Aggregator { + return &New(1)[0] + }, + ) +} diff --git a/sdk/metric/aggregator/minmaxsumcount/mmsc.go b/sdk/metric/aggregator/minmaxsumcount/mmsc.go index 5095e594452..66a888a59d0 100644 --- a/sdk/metric/aggregator/minmaxsumcount/mmsc.go +++ b/sdk/metric/aggregator/minmaxsumcount/mmsc.go @@ -106,15 +106,15 @@ func (c *Aggregator) Max() (number.Number, error) { // the empty set. func (c *Aggregator) SynchronizedMove(oa export.Aggregator, desc *metric.Descriptor) error { o, _ := oa.(*Aggregator) - if o == nil { + + if oa != nil && o == nil { return aggregator.NewInconsistentAggregatorError(c, oa) } - - // TODO: It is incorrect to use an Aggregator of different - // kind. Should we test that o.kind == c.kind? (The same question - // occurs for several of the other aggregators in ../*.) c.lock.Lock() - o.state, c.state = c.state, emptyState(c.kind) + if o != nil { + o.state = c.state + } + c.state = emptyState(c.kind) c.lock.Unlock() return nil diff --git a/sdk/metric/aggregator/minmaxsumcount/mmsc_test.go b/sdk/metric/aggregator/minmaxsumcount/mmsc_test.go index 0df3e79ddef..0fb2be99146 100644 --- a/sdk/metric/aggregator/minmaxsumcount/mmsc_test.go +++ b/sdk/metric/aggregator/minmaxsumcount/mmsc_test.go @@ -24,6 +24,7 @@ import ( "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric/number" + export "go.opentelemetry.io/otel/sdk/export/metric" "go.opentelemetry.io/otel/sdk/export/metric/aggregation" "go.opentelemetry.io/otel/sdk/metric/aggregator/aggregatortest" ) @@ -235,3 +236,13 @@ func TestMaxSumCountNotSet(t *testing.T) { require.Equal(t, number.Number(0), max) }) } + +func TestSynchronizedMoveReset(t *testing.T) { + aggregatortest.SynchronizedMoveResetTest( + t, + metric.ValueRecorderInstrumentKind, + func(desc *metric.Descriptor) export.Aggregator { + return &New(1, desc)[0] + }, + ) +} diff --git a/sdk/metric/aggregator/sum/sum.go b/sdk/metric/aggregator/sum/sum.go index 0c559acd2ba..fc96ddb4cba 100644 --- a/sdk/metric/aggregator/sum/sum.go +++ b/sdk/metric/aggregator/sum/sum.go @@ -61,6 +61,10 @@ func (c *Aggregator) Sum() (number.Number, error) { // SynchronizedMove atomically saves the current value into oa and resets the // current sum to zero. func (c *Aggregator) SynchronizedMove(oa export.Aggregator, _ *metric.Descriptor) error { + if oa == nil { + c.value.SetRawAtomic(0) + return nil + } o, _ := oa.(*Aggregator) if o == nil { return aggregator.NewInconsistentAggregatorError(c, oa) diff --git a/sdk/metric/aggregator/sum/sum_test.go b/sdk/metric/aggregator/sum/sum_test.go index 9a9a14f2069..2b30c6a637c 100644 --- a/sdk/metric/aggregator/sum/sum_test.go +++ b/sdk/metric/aggregator/sum/sum_test.go @@ -24,6 +24,7 @@ import ( ottest "go.opentelemetry.io/otel/internal/testing" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric/number" + export "go.opentelemetry.io/otel/sdk/export/metric" "go.opentelemetry.io/otel/sdk/metric/aggregator/aggregatortest" ) @@ -141,3 +142,13 @@ func TestCounterMerge(t *testing.T) { require.Nil(t, err) }) } + +func TestSynchronizedMoveReset(t *testing.T) { + aggregatortest.SynchronizedMoveResetTest( + t, + metric.SumObserverInstrumentKind, + func(desc *metric.Descriptor) export.Aggregator { + return &New(1)[0] + }, + ) +} diff --git a/sdk/metric/benchmark_test.go b/sdk/metric/benchmark_test.go index 4da8cfaa694..bb32bb34cdb 100644 --- a/sdk/metric/benchmark_test.go +++ b/sdk/metric/benchmark_test.go @@ -20,7 +20,7 @@ import ( "math/rand" "testing" - "go.opentelemetry.io/otel/global" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/label" "go.opentelemetry.io/otel/metric" export "go.opentelemetry.io/otel/sdk/export/metric" @@ -214,8 +214,8 @@ func BenchmarkGlobalInt64CounterAddWithSDK(b *testing.B) { ctx := context.Background() fix := newFixture(b) - sdk := global.Meter("test") - global.SetMeterProvider(fix) + sdk := otel.Meter("test") + otel.SetMeterProvider(fix) labs := []label.KeyValue{label.String("A", "B")} cnt := Must(sdk).NewInt64Counter("int64.sum") diff --git a/sdk/metric/controller/push/push.go b/sdk/metric/controller/push/push.go index e5911136dc6..0b7b15267b2 100644 --- a/sdk/metric/controller/push/push.go +++ b/sdk/metric/controller/push/push.go @@ -19,7 +19,7 @@ import ( "sync" "time" - "go.opentelemetry.io/otel/global" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric/registry" export "go.opentelemetry.io/otel/sdk/export/metric" @@ -145,10 +145,10 @@ func (c *Controller) tick() { c.checkpointer.StartCollection() c.accumulator.Collect(ctx) if err := c.checkpointer.FinishCollection(); err != nil { - global.Handle(err) + otel.Handle(err) } if err := c.exporter.Export(ctx, ckpt); err != nil { - global.Handle(err) + otel.Handle(err) } } diff --git a/sdk/metric/controller/push/push_test.go b/sdk/metric/controller/push/push_test.go index d61c66dc252..8b8ec7478a2 100644 --- a/sdk/metric/controller/push/push_test.go +++ b/sdk/metric/controller/push/push_test.go @@ -24,7 +24,7 @@ import ( "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/global" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/label" "go.opentelemetry.io/otel/metric" export "go.opentelemetry.io/otel/sdk/export/metric" @@ -61,7 +61,7 @@ var testHandler *handler func init() { testHandler = new(handler) - global.SetErrorHandler(testHandler) + otel.SetErrorHandler(testHandler) } func newExporter() *processorTest.Exporter { diff --git a/sdk/metric/correct_test.go b/sdk/metric/correct_test.go index 4cee368be92..5ccba31af82 100644 --- a/sdk/metric/correct_test.go +++ b/sdk/metric/correct_test.go @@ -23,7 +23,7 @@ import ( "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/global" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/label" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric/number" @@ -66,7 +66,7 @@ var testHandler *handler func init() { testHandler = new(handler) - global.SetErrorHandler(testHandler) + otel.SetErrorHandler(testHandler) } // correctnessProcessor could be replaced with processortest.Processor @@ -300,74 +300,79 @@ func TestDefaultLabelEncoder(t *testing.T) { func TestObserverCollection(t *testing.T) { ctx := context.Background() meter, sdk, processor := newSDK(t) + mult := 1 _ = Must(meter).NewFloat64ValueObserver("float.valueobserver.lastvalue", func(_ context.Context, result metric.Float64ObserverResult) { - result.Observe(1, label.String("A", "B")) + result.Observe(float64(mult), label.String("A", "B")) // last value wins - result.Observe(-1, label.String("A", "B")) - result.Observe(-1, label.String("C", "D")) + result.Observe(float64(-mult), label.String("A", "B")) + result.Observe(float64(-mult), label.String("C", "D")) }) _ = Must(meter).NewInt64ValueObserver("int.valueobserver.lastvalue", func(_ context.Context, result metric.Int64ObserverResult) { - result.Observe(-1, label.String("A", "B")) - result.Observe(1) + result.Observe(int64(-mult), label.String("A", "B")) + result.Observe(int64(mult)) // last value wins - result.Observe(1, label.String("A", "B")) - result.Observe(1) + result.Observe(int64(mult), label.String("A", "B")) + result.Observe(int64(mult)) }) _ = Must(meter).NewFloat64SumObserver("float.sumobserver.sum", func(_ context.Context, result metric.Float64ObserverResult) { - result.Observe(1, label.String("A", "B")) - result.Observe(2, label.String("A", "B")) - result.Observe(1, label.String("C", "D")) + result.Observe(float64(mult), label.String("A", "B")) + result.Observe(float64(2*mult), label.String("A", "B")) + result.Observe(float64(mult), label.String("C", "D")) }) _ = Must(meter).NewInt64SumObserver("int.sumobserver.sum", func(_ context.Context, result metric.Int64ObserverResult) { - result.Observe(2, label.String("A", "B")) - result.Observe(1) + result.Observe(int64(2*mult), label.String("A", "B")) + result.Observe(int64(mult)) // last value wins - result.Observe(1, label.String("A", "B")) - result.Observe(1) + result.Observe(int64(mult), label.String("A", "B")) + result.Observe(int64(mult)) }) _ = Must(meter).NewFloat64UpDownSumObserver("float.updownsumobserver.sum", func(_ context.Context, result metric.Float64ObserverResult) { - result.Observe(1, label.String("A", "B")) - result.Observe(-2, label.String("A", "B")) - result.Observe(1, label.String("C", "D")) + result.Observe(float64(mult), label.String("A", "B")) + result.Observe(float64(-2*mult), label.String("A", "B")) + result.Observe(float64(mult), label.String("C", "D")) }) _ = Must(meter).NewInt64UpDownSumObserver("int.updownsumobserver.sum", func(_ context.Context, result metric.Int64ObserverResult) { - result.Observe(2, label.String("A", "B")) - result.Observe(1) + result.Observe(int64(2*mult), label.String("A", "B")) + result.Observe(int64(mult)) // last value wins - result.Observe(1, label.String("A", "B")) - result.Observe(-1) + result.Observe(int64(mult), label.String("A", "B")) + result.Observe(int64(-mult)) }) _ = Must(meter).NewInt64ValueObserver("empty.valueobserver.sum", func(_ context.Context, result metric.Int64ObserverResult) { }) - collected := sdk.Collect(ctx) + for mult = 0; mult < 3; mult++ { + processor.accumulations = nil - require.Equal(t, collected, len(processor.accumulations)) + collected := sdk.Collect(ctx) + require.Equal(t, collected, len(processor.accumulations)) - out := processortest.NewOutput(label.DefaultEncoder()) - for _, rec := range processor.accumulations { - require.NoError(t, out.AddAccumulation(rec)) + out := processortest.NewOutput(label.DefaultEncoder()) + for _, rec := range processor.accumulations { + require.NoError(t, out.AddAccumulation(rec)) + } + mult := float64(mult) + require.EqualValues(t, map[string]float64{ + "float.valueobserver.lastvalue/A=B/R=V": -mult, + "float.valueobserver.lastvalue/C=D/R=V": -mult, + "int.valueobserver.lastvalue//R=V": mult, + "int.valueobserver.lastvalue/A=B/R=V": mult, + + "float.sumobserver.sum/A=B/R=V": 2 * mult, + "float.sumobserver.sum/C=D/R=V": mult, + "int.sumobserver.sum//R=V": mult, + "int.sumobserver.sum/A=B/R=V": mult, + + "float.updownsumobserver.sum/A=B/R=V": -2 * mult, + "float.updownsumobserver.sum/C=D/R=V": mult, + "int.updownsumobserver.sum//R=V": -mult, + "int.updownsumobserver.sum/A=B/R=V": mult, + }, out.Map()) } - require.EqualValues(t, map[string]float64{ - "float.valueobserver.lastvalue/A=B/R=V": -1, - "float.valueobserver.lastvalue/C=D/R=V": -1, - "int.valueobserver.lastvalue//R=V": 1, - "int.valueobserver.lastvalue/A=B/R=V": 1, - - "float.sumobserver.sum/A=B/R=V": 2, - "float.sumobserver.sum/C=D/R=V": 1, - "int.sumobserver.sum//R=V": 1, - "int.sumobserver.sum/A=B/R=V": 1, - - "float.updownsumobserver.sum/A=B/R=V": -2, - "float.updownsumobserver.sum/C=D/R=V": 1, - "int.updownsumobserver.sum//R=V": -1, - "int.updownsumobserver.sum/A=B/R=V": 1, - }, out.Map()) } func TestSumObserverInputRange(t *testing.T) { diff --git a/sdk/metric/processor/basic/basic_test.go b/sdk/metric/processor/basic/basic_test.go index a97745c5f60..016de9677bd 100644 --- a/sdk/metric/processor/basic/basic_test.go +++ b/sdk/metric/processor/basic/basic_test.go @@ -30,7 +30,9 @@ import ( export "go.opentelemetry.io/otel/sdk/export/metric" "go.opentelemetry.io/otel/sdk/export/metric/aggregation" "go.opentelemetry.io/otel/sdk/export/metric/metrictest" + sdk "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/metric/processor/basic" + "go.opentelemetry.io/otel/sdk/metric/processor/processortest" processorTest "go.opentelemetry.io/otel/sdk/metric/processor/processortest" "go.opentelemetry.io/otel/sdk/resource" ) @@ -464,3 +466,55 @@ func TestMultiObserverSum(t *testing.T) { } } } + +func TestSumObserverEndToEnd(t *testing.T) { + ctx := context.Background() + eselector := export.CumulativeExportKindSelector() + proc := basic.New( + processorTest.AggregatorSelector(), + eselector, + ) + accum := sdk.NewAccumulator(proc, resource.Empty()) + meter := metric.WrapMeterImpl(accum, "testing") + + var calls int64 + metric.Must(meter).NewInt64SumObserver("observer.sum", + func(_ context.Context, result metric.Int64ObserverResult) { + calls++ + result.Observe(calls) + }, + ) + data := proc.CheckpointSet() + + var startTime [3]time.Time + var endTime [3]time.Time + + for i := range startTime { + data.Lock() + proc.StartCollection() + accum.Collect(ctx) + require.NoError(t, proc.FinishCollection()) + + exporter := processortest.NewExporter(eselector, label.DefaultEncoder()) + require.NoError(t, exporter.Export(ctx, data)) + + require.EqualValues(t, map[string]float64{ + "observer.sum//": float64(i + 1), + }, exporter.Values()) + + var record export.Record + require.NoError(t, data.ForEach(eselector, func(r export.Record) error { + record = r + return nil + })) + + startTime[i] = record.StartTime() + endTime[i] = record.EndTime() + data.Unlock() + } + + require.Equal(t, startTime[0], startTime[1]) + require.Equal(t, startTime[0], startTime[2]) + require.True(t, endTime[0].Before(endTime[1])) + require.True(t, endTime[1].Before(endTime[2])) +} diff --git a/sdk/metric/sdk.go b/sdk/metric/sdk.go index 1d4466afccc..dffc7b8ee25 100644 --- a/sdk/metric/sdk.go +++ b/sdk/metric/sdk.go @@ -21,7 +21,7 @@ import ( "sync" "sync/atomic" - "go.opentelemetry.io/otel/global" + "go.opentelemetry.io/otel" internal "go.opentelemetry.io/otel/internal/metric" "go.opentelemetry.io/otel/label" "go.opentelemetry.io/otel/metric" @@ -171,7 +171,7 @@ func (s *syncInstrument) Implementation() interface{} { func (a *asyncInstrument) observe(num number.Number, labels *label.Set) { if err := aggregator.RangeTest(num, &a.descriptor); err != nil { - global.Handle(err) + otel.Handle(err) return } recorder := a.getRecorder(labels) @@ -181,7 +181,7 @@ func (a *asyncInstrument) observe(num number.Number, labels *label.Set) { return } if err := recorder.Update(context.Background(), num, &a.descriptor); err != nil { - global.Handle(err) + otel.Handle(err) return } } @@ -189,13 +189,9 @@ func (a *asyncInstrument) observe(num number.Number, labels *label.Set) { func (a *asyncInstrument) getRecorder(labels *label.Set) export.Aggregator { lrec, ok := a.recorders[labels.Equivalent()] if ok { - if lrec.observedEpoch == a.meter.currentEpoch { - // last value wins for Observers, so if we see the same labels - // in the current epoch, we replace the old recorder - a.meter.processor.AggregatorFor(&a.descriptor, &lrec.observed) - } else { - lrec.observedEpoch = a.meter.currentEpoch - } + // Note: SynchronizedMove(nil) can't return an error + _ = lrec.observed.SynchronizedMove(nil, &a.descriptor) + lrec.observedEpoch = a.meter.currentEpoch a.recorders[labels.Equivalent()] = lrec return lrec.observed } @@ -457,14 +453,14 @@ func (m *Accumulator) checkpointRecord(r *record) int { } err := r.current.SynchronizedMove(r.checkpoint, &r.inst.descriptor) if err != nil { - global.Handle(err) + otel.Handle(err) return 0 } a := export.NewAccumulation(&r.inst.descriptor, r.labels, m.resource, r.checkpoint) err = m.processor.Process(a) if err != nil { - global.Handle(err) + otel.Handle(err) } return 1 } @@ -482,7 +478,7 @@ func (m *Accumulator) checkpointAsync(a *asyncInstrument) int { a := export.NewAccumulation(&a.descriptor, lrec.labels, m.resource, lrec.observed) err := m.processor.Process(a) if err != nil { - global.Handle(err) + otel.Handle(err) } checkpointed++ } @@ -530,11 +526,11 @@ func (r *record) RecordOne(ctx context.Context, num number.Number) { return } if err := aggregator.RangeTest(num, &r.inst.descriptor); err != nil { - global.Handle(err) + otel.Handle(err) return } if err := r.current.Update(ctx, num, &r.inst.descriptor); err != nil { - global.Handle(err) + otel.Handle(err) return } // Record was modified, inform the Collect() that things need @@ -562,7 +558,7 @@ func (m *Accumulator) fromSync(sync metric.SyncImpl) *syncInstrument { return inst } } - global.Handle(ErrUninitializedInstrument) + otel.Handle(ErrUninitializedInstrument) return nil } @@ -574,6 +570,6 @@ func (m *Accumulator) fromAsync(async metric.AsyncImpl) *asyncInstrument { return inst } } - global.Handle(ErrUninitializedInstrument) + otel.Handle(ErrUninitializedInstrument) return nil } diff --git a/sdk/resource/builtin.go b/sdk/resource/builtin.go index 4d1d839cb1d..a9a0fc88990 100644 --- a/sdk/resource/builtin.go +++ b/sdk/resource/builtin.go @@ -19,8 +19,8 @@ import ( "fmt" "os" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/label" - opentelemetry "go.opentelemetry.io/otel/sdk" "go.opentelemetry.io/otel/semconv" ) @@ -54,9 +54,9 @@ var ( // Detect returns a *Resource that describes the OpenTelemetry SDK used. func (TelemetrySDK) Detect(context.Context) (*Resource, error) { return NewWithAttributes( - semconv.TelemetrySDKNameKey.String("opentelemetry-go"), + semconv.TelemetrySDKNameKey.String("opentelemetry"), semconv.TelemetrySDKLanguageKey.String("go"), - semconv.TelemetrySDKVersionKey.String(opentelemetry.Version()), + semconv.TelemetrySDKVersionKey.String(otel.Version()), ), nil } diff --git a/sdk/resource/config_test.go b/sdk/resource/config_test.go index 869564f70b0..f951787296d 100644 --- a/sdk/resource/config_test.go +++ b/sdk/resource/config_test.go @@ -22,9 +22,9 @@ import ( "github.com/stretchr/testify/require" + "go.opentelemetry.io/otel" ottest "go.opentelemetry.io/otel/internal/testing" "go.opentelemetry.io/otel/label" - opentelemetry "go.opentelemetry.io/otel/sdk" "go.opentelemetry.io/otel/sdk/resource" ) @@ -42,9 +42,9 @@ func TestDefaultConfig(t *testing.T) { require.NoError(t, err) require.EqualValues(t, map[string]string{ "host.name": hostname(), - "telemetry.sdk.name": "opentelemetry-go", + "telemetry.sdk.name": "opentelemetry", "telemetry.sdk.language": "go", - "telemetry.sdk.version": opentelemetry.Version(), + "telemetry.sdk.version": otel.Version(), }, toMap(res)) } @@ -59,9 +59,9 @@ func TestDefaultConfigNoHost(t *testing.T) { res, err := resource.New(ctx, resource.WithHost(nil)) require.NoError(t, err) require.EqualValues(t, map[string]string{ - "telemetry.sdk.name": "opentelemetry-go", + "telemetry.sdk.name": "opentelemetry", "telemetry.sdk.language": "go", - "telemetry.sdk.version": opentelemetry.Version(), + "telemetry.sdk.version": otel.Version(), }, toMap(res)) } @@ -77,9 +77,9 @@ func TestDefaultConfigNoEnv(t *testing.T) { require.NoError(t, err) require.EqualValues(t, map[string]string{ "host.name": hostname(), - "telemetry.sdk.name": "opentelemetry-go", + "telemetry.sdk.name": "opentelemetry", "telemetry.sdk.language": "go", - "telemetry.sdk.version": opentelemetry.Version(), + "telemetry.sdk.version": otel.Version(), }, toMap(res)) } @@ -97,9 +97,9 @@ func TestDefaultConfigWithEnv(t *testing.T) { "key": "value", "other": "attr", "host.name": hostname(), - "telemetry.sdk.name": "opentelemetry-go", + "telemetry.sdk.name": "opentelemetry", "telemetry.sdk.language": "go", - "telemetry.sdk.version": opentelemetry.Version(), + "telemetry.sdk.version": otel.Version(), }, toMap(res)) } diff --git a/sdk/trace/attributesMap.go b/sdk/trace/attributesmap.go similarity index 86% rename from sdk/trace/attributesMap.go rename to sdk/trace/attributesmap.go index fc1aa8f4323..6b2f1346306 100644 --- a/sdk/trace/attributesMap.go +++ b/sdk/trace/attributesmap.go @@ -18,12 +18,11 @@ import ( "container/list" "go.opentelemetry.io/otel/label" - "go.opentelemetry.io/otel/sdk/export/trace" ) // attributesMap is a capped map of attributes, holding the most recent attributes. // Eviction is done via a LRU method, the oldest entry is removed to create room for a new entry. -// Updates are allowed and refreshes the usage of the key. +// Updates are allowed and they refresh the usage of the key. // // This is based from https://github.com/hashicorp/golang-lru/blob/master/simplelru/lru.go // With a subset of the its operations and specific for holding label.KeyValue @@ -62,10 +61,13 @@ func (am *attributesMap) add(kv label.KeyValue) { } } -func (am *attributesMap) toSpanData(sd *trace.SpanData) { +// toKeyValue copies the attributesMap into a slice of label.KeyValue and +// returns it. If the map is empty, a nil is returned. +// TODO: Is it more efficient to return a pointer to the slice? +func (am *attributesMap) toKeyValue() []label.KeyValue { len := am.evictList.Len() if len == 0 { - return + return nil } attributes := make([]label.KeyValue, 0, len) @@ -75,8 +77,7 @@ func (am *attributesMap) toSpanData(sd *trace.SpanData) { } } - sd.Attributes = attributes - sd.DroppedAttributeCount = am.droppedCount + return attributes } // removeOldest removes the oldest item from the cache. diff --git a/sdk/trace/attributesmap_test.go b/sdk/trace/attributesmap_test.go new file mode 100644 index 00000000000..defa378b36b --- /dev/null +++ b/sdk/trace/attributesmap_test.go @@ -0,0 +1,103 @@ +// 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 trace + +import ( + "fmt" + "testing" + + "go.opentelemetry.io/otel/label" +) + +const testKeyFmt = "test-key-%d" + +func TestAttributesMap(t *testing.T) { + wantCapacity := 128 + attrMap := newAttributesMap(wantCapacity) + + for i := 0; i < 256; i++ { + attrMap.add(label.Int(fmt.Sprintf(testKeyFmt, i), i)) + } + if attrMap.capacity != wantCapacity { + t.Errorf("attrMap.capacity: got '%d'; want '%d'", attrMap.capacity, wantCapacity) + } + + if attrMap.droppedCount != wantCapacity { + t.Errorf("attrMap.droppedCount: got '%d'; want '%d'", attrMap.droppedCount, wantCapacity) + } + + for i := 0; i < wantCapacity; i++ { + key := label.Key(fmt.Sprintf(testKeyFmt, i)) + _, ok := attrMap.attributes[key] + if ok { + t.Errorf("key %q should be dropped", testKeyFmt) + } + } + for i := wantCapacity; i < 256; i++ { + key := label.Key(fmt.Sprintf(testKeyFmt, i)) + _, ok := attrMap.attributes[key] + if !ok { + t.Errorf("key %q should not be dropped", key) + } + } +} + +func TestAttributesMapGetOldestRemoveOldest(t *testing.T) { + attrMap := newAttributesMap(128) + + for i := 0; i < 128; i++ { + attrMap.add(label.Int(fmt.Sprintf(testKeyFmt, i), i)) + } + + attrMap.removeOldest() + attrMap.removeOldest() + attrMap.removeOldest() + + for i := 0; i < 3; i++ { + key := label.Key(fmt.Sprintf(testKeyFmt, i)) + _, ok := attrMap.attributes[key] + if ok { + t.Errorf("key %q should be removed", key) + } + } +} + +func TestAttributesMapToKeyValue(t *testing.T) { + attrMap := newAttributesMap(128) + + for i := 0; i < 128; i++ { + attrMap.add(label.Int(fmt.Sprintf(testKeyFmt, i), i)) + } + + kv := attrMap.toKeyValue() + + gotAttrLen := len(kv) + wantAttrLen := 128 + if gotAttrLen != wantAttrLen { + t.Errorf("len(attrMap.attributes): got '%d'; want '%d'", gotAttrLen, wantAttrLen) + } +} + +func BenchmarkAttributesMapToKeyValue(b *testing.B) { + attrMap := newAttributesMap(128) + + for i := 0; i < 128; i++ { + attrMap.add(label.Int(fmt.Sprintf(testKeyFmt, i), i)) + } + + for n := 0; n < b.N; n++ { + attrMap.toKeyValue() + } +} diff --git a/sdk/trace/batch_span_processor.go b/sdk/trace/batch_span_processor.go index be06324cc20..ad4ee29e7c9 100644 --- a/sdk/trace/batch_span_processor.go +++ b/sdk/trace/batch_span_processor.go @@ -21,7 +21,7 @@ import ( "sync/atomic" "time" - "go.opentelemetry.io/otel/global" + "go.opentelemetry.io/otel" export "go.opentelemetry.io/otel/sdk/export/trace" ) @@ -57,16 +57,16 @@ type BatchSpanProcessorOptions struct { BlockOnQueueFull bool } -// BatchSpanProcessor is a SpanProcessor that batches asynchronously received -// SpanData and sends it to a trace.Exporter when complete. +// BatchSpanProcessor is a SpanProcessor that batches asynchronously-received +// SpanSnapshots and sends them to a trace.Exporter when complete. type BatchSpanProcessor struct { e export.SpanExporter o BatchSpanProcessorOptions - queue chan *export.SpanData + queue chan *export.SpanSnapshot dropped uint32 - batch []*export.SpanData + batch []*export.SpanSnapshot batchMutex sync.Mutex timer *time.Timer stopWait sync.WaitGroup @@ -77,7 +77,7 @@ type BatchSpanProcessor struct { var _ SpanProcessor = (*BatchSpanProcessor)(nil) // NewBatchSpanProcessor creates a new BatchSpanProcessor that will send -// SpanData batches to the exporters with the supplied options. +// SpanSnapshot batches to the exporters with the supplied options. // // The returned BatchSpanProcessor needs to be registered with the SDK using // the RegisterSpanProcessor method for it to process spans. @@ -95,9 +95,9 @@ func NewBatchSpanProcessor(exporter export.SpanExporter, options ...BatchSpanPro bsp := &BatchSpanProcessor{ e: exporter, o: o, - batch: make([]*export.SpanData, 0, o.MaxExportBatchSize), + batch: make([]*export.SpanSnapshot, 0, o.MaxExportBatchSize), timer: time.NewTimer(o.BatchTimeout), - queue: make(chan *export.SpanData, o.MaxQueueSize), + queue: make(chan *export.SpanSnapshot, o.MaxQueueSize), stopCh: make(chan struct{}), } @@ -112,15 +112,15 @@ func NewBatchSpanProcessor(exporter export.SpanExporter, options ...BatchSpanPro } // OnStart method does nothing. -func (bsp *BatchSpanProcessor) OnStart(sd *export.SpanData) {} +func (bsp *BatchSpanProcessor) OnStart(parent context.Context, s ReadWriteSpan) {} -// OnEnd method enqueues export.SpanData for later processing. -func (bsp *BatchSpanProcessor) OnEnd(sd *export.SpanData) { +// OnEnd method enqueues a ReadOnlySpan for later processing. +func (bsp *BatchSpanProcessor) OnEnd(s ReadOnlySpan) { // Do not enqueue spans if we are just going to drop them. if bsp.e == nil { return } - bsp.enqueue(sd) + bsp.enqueue(s.Snapshot()) } // Shutdown flushes the queue and waits until all spans are processed. @@ -182,7 +182,7 @@ func (bsp *BatchSpanProcessor) exportSpans() { if len(bsp.batch) > 0 { if err := bsp.e.ExportSpans(context.Background(), bsp.batch); err != nil { - global.Handle(err) + otel.Handle(err) } bsp.batch = bsp.batch[:0] } @@ -240,7 +240,7 @@ func (bsp *BatchSpanProcessor) drainQueue() { } } -func (bsp *BatchSpanProcessor) enqueue(sd *export.SpanData) { +func (bsp *BatchSpanProcessor) enqueue(sd *export.SpanSnapshot) { if !sd.SpanContext.IsSampled() { return } diff --git a/sdk/trace/batch_span_processor_test.go b/sdk/trace/batch_span_processor_test.go index f240c694682..6675484885b 100644 --- a/sdk/trace/batch_span_processor_test.go +++ b/sdk/trace/batch_span_processor_test.go @@ -29,17 +29,17 @@ import ( type testBatchExporter struct { mu sync.Mutex - spans []*export.SpanData + spans []*export.SpanSnapshot sizes []int batchCount int } -func (t *testBatchExporter) ExportSpans(ctx context.Context, sds []*export.SpanData) error { +func (t *testBatchExporter) ExportSpans(ctx context.Context, ss []*export.SpanSnapshot) error { t.mu.Lock() defer t.mu.Unlock() - t.spans = append(t.spans, sds...) - t.sizes = append(t.sizes, len(sds)) + t.spans = append(t.spans, ss...) + t.sizes = append(t.sizes, len(ss)) t.batchCount++ return nil } @@ -61,10 +61,17 @@ func (t *testBatchExporter) getBatchCount() int { var _ export.SpanExporter = (*testBatchExporter)(nil) func TestNewBatchSpanProcessorWithNilExporter(t *testing.T) { + tp := basicTracerProvider(t) bsp := sdktrace.NewBatchSpanProcessor(nil) + tp.RegisterSpanProcessor(bsp) + tr := tp.Tracer("NilExporter") + + _, span := tr.Start(context.Background(), "foo") + span.End() + // These should not panic. - bsp.OnStart(&export.SpanData{}) - bsp.OnEnd(&export.SpanData{}) + bsp.OnStart(context.Background(), span.(sdktrace.ReadWriteSpan)) + bsp.OnEnd(span.(sdktrace.ReadOnlySpan)) bsp.ForceFlush() err := bsp.Shutdown(context.Background()) if err != nil { diff --git a/sdk/trace/config.go b/sdk/trace/config.go index 3fd37de24c9..42b1851f833 100644 --- a/sdk/trace/config.go +++ b/sdk/trace/config.go @@ -16,7 +16,6 @@ package trace // import "go.opentelemetry.io/otel/sdk/trace" import ( "go.opentelemetry.io/otel/sdk/resource" - "go.opentelemetry.io/otel/sdk/trace/internal" ) // Config represents the global tracing configuration. @@ -25,7 +24,7 @@ type Config struct { DefaultSampler Sampler // IDGenerator is for internal use only. - IDGenerator internal.IDGenerator + IDGenerator IDGenerator // MaxEventsPerSpan is max number of message events per span MaxEventsPerSpan int diff --git a/sdk/trace/id_generator.go b/sdk/trace/id_generator.go index 3a4abe62833..e60a421cde9 100644 --- a/sdk/trace/id_generator.go +++ b/sdk/trace/id_generator.go @@ -15,23 +15,30 @@ package trace // import "go.opentelemetry.io/otel/sdk/trace" import ( + "context" + crand "crypto/rand" + "encoding/binary" "math/rand" "sync" "go.opentelemetry.io/otel/trace" - - "go.opentelemetry.io/otel/sdk/trace/internal" ) -type defaultIDGenerator struct { +// IDGenerator allows custom generators for TraceID and SpanID. +type IDGenerator interface { + NewIDs(ctx context.Context) (trace.TraceID, trace.SpanID) + NewSpanID(ctx context.Context, traceID trace.TraceID) trace.SpanID +} + +type randomIDGenerator struct { sync.Mutex randSource *rand.Rand } -var _ internal.IDGenerator = &defaultIDGenerator{} +var _ IDGenerator = &randomIDGenerator{} // NewSpanID returns a non-zero span ID from a randomly-chosen sequence. -func (gen *defaultIDGenerator) NewSpanID() trace.SpanID { +func (gen *randomIDGenerator) NewSpanID(ctx context.Context, traceID trace.TraceID) trace.SpanID { gen.Lock() defer gen.Unlock() sid := trace.SpanID{} @@ -39,12 +46,22 @@ func (gen *defaultIDGenerator) NewSpanID() trace.SpanID { return sid } -// NewTraceID returns a non-zero trace ID from a randomly-chosen sequence. -// mu should be held while this function is called. -func (gen *defaultIDGenerator) NewTraceID() trace.TraceID { +// NewIDs returns a non-zero trace ID and a non-zero span ID from a +// randomly-chosen sequence. +func (gen *randomIDGenerator) NewIDs(ctx context.Context) (trace.TraceID, trace.SpanID) { gen.Lock() defer gen.Unlock() tid := trace.TraceID{} gen.randSource.Read(tid[:]) - return tid + sid := trace.SpanID{} + gen.randSource.Read(sid[:]) + return tid, sid +} + +func defaultIDGenerator() IDGenerator { + gen := &randomIDGenerator{} + var rngSeed int64 + _ = binary.Read(crand.Reader, binary.LittleEndian, &rngSeed) + gen.randSource = rand.New(rand.NewSource(rngSeed)) + return gen } diff --git a/sdk/trace/provider.go b/sdk/trace/provider.go index 267a0d36fbe..901e8d4a76d 100644 --- a/sdk/trace/provider.go +++ b/sdk/trace/provider.go @@ -19,7 +19,7 @@ import ( "sync" "sync/atomic" - "go.opentelemetry.io/otel/global" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/trace" export "go.opentelemetry.io/otel/sdk/export/trace" @@ -66,7 +66,7 @@ func NewTracerProvider(opts ...TracerProviderOption) *TracerProvider { } tp.config.Store(&Config{ DefaultSampler: ParentBased(AlwaysSample()), - IDGenerator: defIDGenerator(), + IDGenerator: defaultIDGenerator(), MaxAttributesPerSpan: DefaultMaxAttributesPerSpan, MaxEventsPerSpan: DefaultMaxEventsPerSpan, MaxLinksPerSpan: DefaultMaxLinksPerSpan, @@ -144,7 +144,9 @@ func (p *TracerProvider) UnregisterSpanProcessor(s SpanProcessor) { } if stopOnce != nil { stopOnce.state.Do(func() { - global.Handle(s.Shutdown(context.Background())) + if err := s.Shutdown(context.Background()); err != nil { + otel.Handle(err) + } }) } if len(new) > 1 { @@ -192,7 +194,9 @@ func (p *TracerProvider) Shutdown(ctx context.Context) error { for _, sps := range spss { sps.state.Do(func() { - global.Handle(sps.sp.Shutdown(ctx)) + if err := sps.sp.Shutdown(ctx); err != nil { + otel.Handle(err) + } }) } return nil @@ -231,3 +235,10 @@ func WithResource(r *resource.Resource) TracerProviderOption { opts.config.Resource = r } } + +// WithIDGenerator option registers an IDGenerator with the TracerProvider. +func WithIDGenerator(g IDGenerator) TracerProviderOption { + return func(opts *TracerProviderConfig) { + opts.config.IDGenerator = g + } +} diff --git a/sdk/trace/provider_test.go b/sdk/trace/provider_test.go index edfd8735bc9..32bec2fb75c 100644 --- a/sdk/trace/provider_test.go +++ b/sdk/trace/provider_test.go @@ -16,23 +16,25 @@ package trace import ( "context" + "errors" "testing" - export "go.opentelemetry.io/otel/sdk/export/trace" + "github.com/stretchr/testify/assert" ) type basicSpanProcesor struct { - running bool + running bool + injectShutdownError error } func (t *basicSpanProcesor) Shutdown(context.Context) error { t.running = false - return nil + return t.injectShutdownError } -func (t *basicSpanProcesor) OnStart(s *export.SpanData) {} -func (t *basicSpanProcesor) OnEnd(s *export.SpanData) {} -func (t *basicSpanProcesor) ForceFlush() {} +func (t *basicSpanProcesor) OnStart(parent context.Context, s ReadWriteSpan) {} +func (t *basicSpanProcesor) OnEnd(s ReadOnlySpan) {} +func (t *basicSpanProcesor) ForceFlush() {} func TestShutdownTraceProvider(t *testing.T) { stp := NewTracerProvider() @@ -47,3 +49,36 @@ func TestShutdownTraceProvider(t *testing.T) { t.Errorf("Error shutdown basicSpanProcesor\n") } } + +func TestFailedProcessorShutdown(t *testing.T) { + handler.Reset() + stp := NewTracerProvider() + spErr := errors.New("basic span processor shutdown failure") + sp := &basicSpanProcesor{ + running: true, + injectShutdownError: spErr, + } + stp.RegisterSpanProcessor(sp) + + _ = stp.Shutdown(context.Background()) + + assert.Contains(t, handler.errs, spErr) +} + +func TestFailedProcessorShutdownInUnregister(t *testing.T) { + handler.Reset() + stp := NewTracerProvider() + spErr := errors.New("basic span processor shutdown failure") + sp := &basicSpanProcesor{ + running: true, + injectShutdownError: spErr, + } + stp.RegisterSpanProcessor(sp) + stp.UnregisterSpanProcessor(sp) + + assert.Contains(t, handler.errs, spErr) + + handler.errs = nil + _ = stp.Shutdown(context.Background()) + assert.Empty(t, handler.errs) +} diff --git a/sdk/trace/sampling_test.go b/sdk/trace/sampling_test.go index 3c998773327..6ae4afff390 100644 --- a/sdk/trace/sampling_test.go +++ b/sdk/trace/sampling_test.go @@ -15,6 +15,7 @@ package trace import ( + "context" "fmt" "math/rand" "testing" @@ -168,7 +169,7 @@ func TestTraceIdRatioSamplesInclusively(t *testing.T) { numSamplers = 1000 numTraces = 100 ) - idg := defIDGenerator() + idg := defaultIDGenerator() for i := 0; i < numSamplers; i++ { ratioLo, ratioHi := rand.Float64(), rand.Float64() @@ -178,7 +179,7 @@ func TestTraceIdRatioSamplesInclusively(t *testing.T) { samplerHi := TraceIDRatioBased(ratioHi) samplerLo := TraceIDRatioBased(ratioLo) for j := 0; j < numTraces; j++ { - traceID := idg.NewTraceID() + traceID, _ := idg.NewIDs(context.Background()) params := SamplingParameters{TraceID: traceID} if samplerLo.ShouldSample(params).Decision == RecordAndSample { diff --git a/sdk/trace/simple_span_processor.go b/sdk/trace/simple_span_processor.go index ac96fe5d01a..1ab95aa5e11 100644 --- a/sdk/trace/simple_span_processor.go +++ b/sdk/trace/simple_span_processor.go @@ -17,12 +17,12 @@ package trace // import "go.opentelemetry.io/otel/sdk/trace" import ( "context" - "go.opentelemetry.io/otel/global" + "go.opentelemetry.io/otel" export "go.opentelemetry.io/otel/sdk/export/trace" ) // SimpleSpanProcessor is a SpanProcessor that synchronously sends all -// SpanData to a trace.Exporter when the span finishes. +// SpanSnapshots to a trace.Exporter when the span finishes. type SimpleSpanProcessor struct { e export.SpanExporter } @@ -30,7 +30,7 @@ type SimpleSpanProcessor struct { var _ SpanProcessor = (*SimpleSpanProcessor)(nil) // NewSimpleSpanProcessor returns a new SimpleSpanProcessor that will -// synchronously send SpanData to the exporter. +// synchronously send SpanSnapshots to the exporter. func NewSimpleSpanProcessor(exporter export.SpanExporter) *SimpleSpanProcessor { ssp := &SimpleSpanProcessor{ e: exporter, @@ -39,14 +39,15 @@ func NewSimpleSpanProcessor(exporter export.SpanExporter) *SimpleSpanProcessor { } // OnStart method does nothing. -func (ssp *SimpleSpanProcessor) OnStart(sd *export.SpanData) { +func (ssp *SimpleSpanProcessor) OnStart(parent context.Context, s ReadWriteSpan) { } -// OnEnd method exports SpanData using associated export. -func (ssp *SimpleSpanProcessor) OnEnd(sd *export.SpanData) { - if ssp.e != nil && sd.SpanContext.IsSampled() { - if err := ssp.e.ExportSpans(context.Background(), []*export.SpanData{sd}); err != nil { - global.Handle(err) +// OnEnd method exports a ReadOnlySpan using the associated exporter. +func (ssp *SimpleSpanProcessor) OnEnd(s ReadOnlySpan) { + if ssp.e != nil && s.SpanContext().IsSampled() { + ss := s.Snapshot() + if err := ssp.e.ExportSpans(context.Background(), []*export.SpanSnapshot{ss}); err != nil { + otel.Handle(err) } } } diff --git a/sdk/trace/simple_span_processor_test.go b/sdk/trace/simple_span_processor_test.go index 8abbad213ed..181dd31790e 100644 --- a/sdk/trace/simple_span_processor_test.go +++ b/sdk/trace/simple_span_processor_test.go @@ -25,11 +25,11 @@ import ( ) type testExporter struct { - spans []*export.SpanData + spans []*export.SpanSnapshot } -func (t *testExporter) ExportSpans(ctx context.Context, spans []*export.SpanData) error { - t.spans = append(t.spans, spans...) +func (t *testExporter) ExportSpans(ctx context.Context, ss []*export.SpanSnapshot) error { + t.spans = append(t.spans, ss...) return nil } diff --git a/sdk/trace/span.go b/sdk/trace/span.go index 120bd498d6b..bf1f77b23e4 100644 --- a/sdk/trace/span.go +++ b/sdk/trace/span.go @@ -15,19 +15,20 @@ package trace // import "go.opentelemetry.io/otel/sdk/trace" import ( - "errors" + "context" "fmt" "reflect" "sync" "time" "go.opentelemetry.io/otel/codes" - "go.opentelemetry.io/otel/global" "go.opentelemetry.io/otel/label" "go.opentelemetry.io/otel/trace" export "go.opentelemetry.io/otel/sdk/export/trace" + "go.opentelemetry.io/otel/sdk/instrumentation" "go.opentelemetry.io/otel/sdk/internal" + "go.opentelemetry.io/otel/sdk/resource" ) const ( @@ -36,6 +37,40 @@ const ( errorEventName = "error" ) +// ReadOnlySpan allows reading information from the data structure underlying a +// trace.Span. It is used in places where reading information from a span is +// necessary but changing the span isn't necessary or allowed. +// TODO: Should we make the methods unexported? The purpose of this interface +// is controlling access to `span` fields, not having multiple implementations. +type ReadOnlySpan interface { + Name() string + SpanContext() trace.SpanContext + Parent() trace.SpanContext + SpanKind() trace.SpanKind + StartTime() time.Time + EndTime() time.Time + Attributes() []label.KeyValue + Links() []trace.Link + Events() []export.Event + StatusCode() codes.Code + StatusMessage() string + Tracer() trace.Tracer + IsRecording() bool + InstrumentationLibrary() instrumentation.Library + Resource() *resource.Resource + Snapshot() *export.SpanSnapshot +} + +// ReadWriteSpan exposes the same methods as trace.Span and in addition allows +// reading information from the underlying data structure. +// This interface exposes the union of the methods of trace.Span (which is a +// "write-only" span) and ReadOnlySpan. New methods for writing or reading span +// information should be added under trace.Span or ReadOnlySpan, respectively. +type ReadWriteSpan interface { + trace.Span + ReadOnlySpan +} + var emptySpanContext = trace.SpanContext{} // span is an implementation of the OpenTelemetry Span API representing the @@ -44,16 +79,47 @@ type span struct { // mu protects the contents of this span. mu sync.Mutex - // data contains information recorded about the span. - // - // It will be non-nil if we are exporting the span or recording events for it. - // Otherwise, data is nil, and the span is simply a carrier for the - // SpanContext, so that the trace ID is propagated. - data *export.SpanData + // parent holds the parent span of this span as a trace.SpanContext. + parent trace.SpanContext + + // spanKind represents the kind of this span as a trace.SpanKind. + spanKind trace.SpanKind + + // name is the name of this span. + name string + + // startTime is the time at which this span was started. + startTime time.Time + + // endTime is the time at which this span was ended. It contains the zero + // value of time.Time until the span is ended. + endTime time.Time + + // statusCode represents the status of this span as a codes.Code value. + statusCode codes.Code + + // statusMessage represents the status of this span as a string. + statusMessage string + + // hasRemoteParent is true when this span has a remote parent span. + hasRemoteParent bool + + // childSpanCount holds the number of child spans created for this span. + childSpanCount int + + // resource contains attributes representing an entity that produced this + // span. + resource *resource.Resource + + // instrumentationLibrary defines the instrumentation library used to + // provide instrumentation. + instrumentationLibrary instrumentation.Library + + // spanContext holds the SpanContext of this span. spanContext trace.SpanContext - // attributes are capped at configured limit. When the capacity is reached an oldest entry - // is removed to create room for a new entry. + // attributes are capped at configured limit. When the capacity is reached + // an oldest entry is removed to create room for a new entry. attributes *attributesMap // messageEvents are stored in FIFO queue capped by configured limit. @@ -62,9 +128,6 @@ type span struct { // links are stored in FIFO queue capped by configured limit. links *evictedQueue - // endOnce ensures End is only called once. - endOnce sync.Once - // executionTracerTaskEnd ends the execution tracer span. executionTracerTaskEnd func() @@ -85,7 +148,9 @@ func (s *span) IsRecording() bool { if s == nil { return false } - return s.data != nil + s.mu.Lock() + defer s.mu.Unlock() + return s.endTime.IsZero() } func (s *span) SetStatus(code codes.Code, msg string) { @@ -96,8 +161,8 @@ func (s *span) SetStatus(code codes.Code, msg string) { return } s.mu.Lock() - s.data.StatusCode = code - s.data.StatusMessage = msg + s.statusCode = code + s.statusMessage = msg s.mu.Unlock() } @@ -120,6 +185,10 @@ func (s *span) End(options ...trace.SpanOption) { return } + // Store the end time as soon as possible to avoid artificially increasing + // the span's duration in case some operation below takes a while. + et := internal.MonotonicEndTime(s.startTime) + if recovered := recover(); recovered != nil { // Record but don't stop the panic. defer panic(recovered) @@ -135,25 +204,28 @@ func (s *span) End(options ...trace.SpanOption) { if s.executionTracerTaskEnd != nil { s.executionTracerTaskEnd() } + if !s.IsRecording() { return } + config := trace.NewSpanConfig(options...) - s.endOnce.Do(func() { - sps, ok := s.tracer.provider.spanProcessors.Load().(spanProcessorStates) - mustExportOrProcess := ok && len(sps) > 0 - if mustExportOrProcess { - sd := s.makeSpanData() - if config.Timestamp.IsZero() { - sd.EndTime = internal.MonotonicEndTime(sd.StartTime) - } else { - sd.EndTime = config.Timestamp - } - for _, sp := range sps { - sp.sp.OnEnd(sd) - } + + s.mu.Lock() + if config.Timestamp.IsZero() { + s.endTime = et + } else { + s.endTime = config.Timestamp + } + s.mu.Unlock() + + sps, ok := s.tracer.provider.spanProcessors.Load().(spanProcessorStates) + mustExportOrProcess := ok && len(sps) > 0 + if mustExportOrProcess { + for _, sp := range sps { + sp.sp.OnEnd(s) } - }) + } } func (s *span) RecordError(err error, opts ...trace.EventOption) { @@ -201,36 +273,30 @@ func (s *span) addEvent(name string, o ...trace.EventOption) { }) } -var errUninitializedSpan = errors.New("failed to set name on uninitialized span") - func (s *span) SetName(name string) { s.mu.Lock() defer s.mu.Unlock() - if s.data == nil { - global.Handle(errUninitializedSpan) - return - } - s.data.Name = name + s.name = name // SAMPLING - noParent := !s.data.ParentSpanID.IsValid() + noParent := !s.parent.SpanID.IsValid() var ctx trace.SpanContext if noParent { ctx = trace.SpanContext{} } else { // FIXME: Where do we get the parent context from? - ctx = s.data.SpanContext + ctx = s.spanContext } data := samplingData{ noParent: noParent, - remoteParent: s.data.HasRemoteParent, + remoteParent: s.hasRemoteParent, parent: ctx, name: name, cfg: s.tracer.provider.config.Load().(*Config), span: s, - attributes: s.data.Attributes, - links: s.data.Links, - kind: s.data.SpanKind, + attributes: s.attributes.toKeyValue(), + links: s.interfaceArrayToLinksArray(), + kind: s.spanKind, } sampled := makeSamplingDecision(data) @@ -241,6 +307,87 @@ func (s *span) SetName(name string) { } } +func (s *span) Name() string { + s.mu.Lock() + defer s.mu.Unlock() + return s.name +} + +func (s *span) Parent() trace.SpanContext { + s.mu.Lock() + defer s.mu.Unlock() + return s.parent +} + +func (s *span) SpanKind() trace.SpanKind { + s.mu.Lock() + defer s.mu.Unlock() + return s.spanKind +} + +func (s *span) StartTime() time.Time { + s.mu.Lock() + defer s.mu.Unlock() + return s.startTime +} + +func (s *span) EndTime() time.Time { + s.mu.Lock() + defer s.mu.Unlock() + return s.endTime +} + +func (s *span) Attributes() []label.KeyValue { + s.mu.Lock() + defer s.mu.Unlock() + if s.attributes.evictList.Len() == 0 { + return []label.KeyValue{} + } + return s.attributes.toKeyValue() +} + +func (s *span) Links() []trace.Link { + s.mu.Lock() + defer s.mu.Unlock() + if len(s.links.queue) == 0 { + return []trace.Link{} + } + return s.interfaceArrayToLinksArray() +} + +func (s *span) Events() []export.Event { + s.mu.Lock() + defer s.mu.Unlock() + if len(s.messageEvents.queue) == 0 { + return []export.Event{} + } + return s.interfaceArrayToMessageEventArray() +} + +func (s *span) StatusCode() codes.Code { + s.mu.Lock() + defer s.mu.Unlock() + return s.statusCode +} + +func (s *span) StatusMessage() string { + s.mu.Lock() + defer s.mu.Unlock() + return s.statusMessage +} + +func (s *span) InstrumentationLibrary() instrumentation.Library { + s.mu.Lock() + defer s.mu.Unlock() + return s.instrumentationLibrary +} + +func (s *span) Resource() *resource.Resource { + s.mu.Lock() + defer s.mu.Unlock() + return s.resource +} + func (s *span) addLink(link trace.Link) { if !s.IsRecording() { return @@ -250,16 +397,30 @@ func (s *span) addLink(link trace.Link) { s.links.add(link) } -// makeSpanData produces a SpanData representing the current state of the span. -// It requires that s.data is non-nil. -func (s *span) makeSpanData() *export.SpanData { - var sd export.SpanData +// Snapshot creates a snapshot representing the current state of the span as an +// export.SpanSnapshot and returns a pointer to it. +func (s *span) Snapshot() *export.SpanSnapshot { + var sd export.SpanSnapshot s.mu.Lock() defer s.mu.Unlock() - sd = *s.data - - s.attributes.toSpanData(&sd) + sd.ChildSpanCount = s.childSpanCount + sd.EndTime = s.endTime + sd.HasRemoteParent = s.hasRemoteParent + sd.InstrumentationLibrary = s.instrumentationLibrary + sd.Name = s.name + sd.ParentSpanID = s.parent.SpanID + sd.Resource = s.resource + sd.SpanContext = s.spanContext + sd.SpanKind = s.spanKind + sd.StartTime = s.startTime + sd.StatusCode = s.statusCode + sd.StatusMessage = s.statusMessage + + if s.attributes.evictList.Len() > 0 { + sd.Attributes = s.attributes.toKeyValue() + sd.DroppedAttributeCount = s.attributes.droppedCount + } if len(s.messageEvents.queue) > 0 { sd.MessageEvents = s.interfaceArrayToMessageEventArray() sd.DroppedMessageEventCount = s.messageEvents.droppedCount @@ -302,24 +463,30 @@ func (s *span) addChild() { return } s.mu.Lock() - s.data.ChildSpanCount++ + s.childSpanCount++ s.mu.Unlock() } -func startSpanInternal(tr *tracer, name string, parent trace.SpanContext, remoteParent bool, o *trace.SpanConfig) *span { - var noParent bool +func startSpanInternal(ctx context.Context, tr *tracer, name string, parent trace.SpanContext, remoteParent bool, o *trace.SpanConfig) *span { span := &span{} span.spanContext = parent cfg := tr.provider.config.Load().(*Config) if parent == emptySpanContext { - span.spanContext.TraceID = cfg.IDGenerator.NewTraceID() - noParent = true + // Generate both TraceID and SpanID + span.spanContext.TraceID, span.spanContext.SpanID = cfg.IDGenerator.NewIDs(ctx) + } else { + // TraceID already exists, just generate a SpanID + span.spanContext.SpanID = cfg.IDGenerator.NewSpanID(ctx, parent.TraceID) } - span.spanContext.SpanID = cfg.IDGenerator.NewSpanID() + + span.attributes = newAttributesMap(cfg.MaxAttributesPerSpan) + span.messageEvents = newEvictedQueue(cfg.MaxEventsPerSpan) + span.links = newEvictedQueue(cfg.MaxLinksPerSpan) + data := samplingData{ - noParent: noParent, + noParent: parent == emptySpanContext, remoteParent: remoteParent, parent: parent, name: name, @@ -339,24 +506,17 @@ func startSpanInternal(tr *tracer, name string, parent trace.SpanContext, remote if startTime.IsZero() { startTime = time.Now() } - span.data = &export.SpanData{ - SpanContext: span.spanContext, - StartTime: startTime, - SpanKind: trace.ValidateSpanKind(o.SpanKind), - Name: name, - HasRemoteParent: remoteParent, - Resource: cfg.Resource, - InstrumentationLibrary: tr.instrumentationLibrary, - } - span.attributes = newAttributesMap(cfg.MaxAttributesPerSpan) - span.messageEvents = newEvictedQueue(cfg.MaxEventsPerSpan) - span.links = newEvictedQueue(cfg.MaxLinksPerSpan) + span.startTime = startTime + + span.spanKind = trace.ValidateSpanKind(o.SpanKind) + span.name = name + span.hasRemoteParent = remoteParent + span.resource = cfg.Resource + span.instrumentationLibrary = tr.instrumentationLibrary span.SetAttributes(sampled.Attributes...) - if !noParent { - span.data.ParentSpanID = parent.SpanID - } + span.parent = parent return span } diff --git a/sdk/trace/span_processor.go b/sdk/trace/span_processor.go index 188eb614f11..d32fed657f7 100644 --- a/sdk/trace/span_processor.go +++ b/sdk/trace/span_processor.go @@ -17,8 +17,6 @@ package trace // import "go.opentelemetry.io/otel/sdk/trace" import ( "context" "sync" - - export "go.opentelemetry.io/otel/sdk/export/trace" ) // SpanProcessor is interface to add hooks to start and end method invocations. @@ -26,11 +24,11 @@ type SpanProcessor interface { // OnStart method is invoked when span is started. It is a synchronous call // and hence should not block. - OnStart(sd *export.SpanData) + OnStart(parent context.Context, s ReadWriteSpan) // OnEnd method is invoked when span is finished. It is a synchronous call // and hence should not block. - OnEnd(sd *export.SpanData) + OnEnd(s ReadOnlySpan) // Shutdown is invoked when SDK shuts down. Use this call to cleanup any processor // data. No calls to OnStart and OnEnd method is invoked after Shutdown call is diff --git a/sdk/trace/span_processor_example_test.go b/sdk/trace/span_processor_example_test.go index f2240785249..c30b0c37d56 100644 --- a/sdk/trace/span_processor_example_test.go +++ b/sdk/trace/span_processor_example_test.go @@ -18,7 +18,6 @@ import ( "context" "time" - export "go.opentelemetry.io/otel/sdk/export/trace" "go.opentelemetry.io/otel/sdk/export/trace/tracetest" ) @@ -34,19 +33,21 @@ type DurationFilter struct { Max time.Duration } -func (f DurationFilter) OnStart(sd *export.SpanData) { f.Next.OnStart(sd) } +func (f DurationFilter) OnStart(parent context.Context, s ReadWriteSpan) { + f.Next.OnStart(parent, s) +} func (f DurationFilter) Shutdown(ctx context.Context) error { return f.Next.Shutdown(ctx) } func (f DurationFilter) ForceFlush() { f.Next.ForceFlush() } -func (f DurationFilter) OnEnd(sd *export.SpanData) { - if f.Min > 0 && sd.EndTime.Sub(sd.StartTime) < f.Min { +func (f DurationFilter) OnEnd(s ReadOnlySpan) { + if f.Min > 0 && s.EndTime().Sub(s.StartTime()) < f.Min { // Drop short lived spans. return } - if f.Max > 0 && sd.EndTime.Sub(sd.StartTime) > f.Max { + if f.Max > 0 && s.EndTime().Sub(s.StartTime()) > f.Max { // Drop long lived spans. return } - f.Next.OnEnd(sd) + f.Next.OnEnd(s) } // InstrumentationBlacklist is a SpanProcessor that drops all spans from @@ -60,15 +61,17 @@ type InstrumentationBlacklist struct { Blacklist map[string]bool } -func (f InstrumentationBlacklist) OnStart(sd *export.SpanData) { f.Next.OnStart(sd) } +func (f InstrumentationBlacklist) OnStart(parent context.Context, s ReadWriteSpan) { + f.Next.OnStart(parent, s) +} func (f InstrumentationBlacklist) Shutdown(ctx context.Context) error { return f.Next.Shutdown(ctx) } func (f InstrumentationBlacklist) ForceFlush() { f.Next.ForceFlush() } -func (f InstrumentationBlacklist) OnEnd(sd *export.SpanData) { - if f.Blacklist != nil && f.Blacklist[sd.InstrumentationLibrary.Name] { +func (f InstrumentationBlacklist) OnEnd(s ReadOnlySpan) { + if f.Blacklist != nil && f.Blacklist[s.InstrumentationLibrary().Name] { // Drop spans from this instrumentation return } - f.Next.OnEnd(sd) + f.Next.OnEnd(s) } func ExampleSpanProcessor() { diff --git a/sdk/trace/span_processor_test.go b/sdk/trace/span_processor_test.go index 081307ce90c..f2376d37df4 100644 --- a/sdk/trace/span_processor_test.go +++ b/sdk/trace/span_processor_test.go @@ -19,31 +19,42 @@ import ( "testing" "go.opentelemetry.io/otel/label" - export "go.opentelemetry.io/otel/sdk/export/trace" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + "go.opentelemetry.io/otel/trace" ) type testSpanProcessor struct { name string - spansStarted []*export.SpanData - spansEnded []*export.SpanData + spansStarted []sdktrace.ReadWriteSpan + spansEnded []sdktrace.ReadOnlySpan shutdownCount int } -func (t *testSpanProcessor) OnStart(s *export.SpanData) { - kv := label.KeyValue{ - Key: "OnStart", - Value: label.StringValue(t.name), +func (t *testSpanProcessor) OnStart(parent context.Context, s sdktrace.ReadWriteSpan) { + psc := trace.RemoteSpanContextFromContext(parent) + kv := []label.KeyValue{ + { + Key: "SpanProcessorName", + Value: label.StringValue(t.name), + }, + // Store parent trace ID and span ID as attributes to be read later in + // tests so that we "do something" with the parent argument. Real + // SpanProcessor implementations will likely use the parent argument in + // a more meaningful way. + { + Key: "ParentTraceID", + Value: label.StringValue(psc.TraceID.String()), + }, + { + Key: "ParentSpanID", + Value: label.StringValue(psc.SpanID.String()), + }, } - s.Attributes = append(s.Attributes, kv) + s.AddEvent("OnStart", trace.WithAttributes(kv...)) t.spansStarted = append(t.spansStarted, s) } -func (t *testSpanProcessor) OnEnd(s *export.SpanData) { - kv := label.KeyValue{ - Key: "OnEnd", - Value: label.StringValue(t.name), - } - s.Attributes = append(s.Attributes, kv) +func (t *testSpanProcessor) OnEnd(s sdktrace.ReadOnlySpan) { t.spansEnded = append(t.spansEnded, s) } @@ -55,7 +66,7 @@ func (t *testSpanProcessor) Shutdown(_ context.Context) error { func (t *testSpanProcessor) ForceFlush() { } -func TestRegisterSpanProcessort(t *testing.T) { +func TestRegisterSpanProcessor(t *testing.T) { name := "Register span processor before span starts" tp := basicTracerProvider(t) spNames := []string{"sp1", "sp2", "sp3"} @@ -65,8 +76,16 @@ func TestRegisterSpanProcessort(t *testing.T) { tp.RegisterSpanProcessor(sp) } + tid, _ := trace.TraceIDFromHex("01020304050607080102040810203040") + sid, _ := trace.SpanIDFromHex("0102040810203040") + parent := trace.SpanContext{ + TraceID: tid, + SpanID: sid, + } + ctx := trace.ContextWithRemoteSpanContext(context.Background(), parent) + tr := tp.Tracer("SpanProcessor") - _, span := tr.Start(context.Background(), "OnStart") + _, span := tr.Start(ctx, "OnStart") span.End() wantCount := 1 @@ -81,18 +100,42 @@ func TestRegisterSpanProcessort(t *testing.T) { } c := 0 - for _, kv := range sp.spansStarted[0].Attributes { - if kv.Key != "OnStart" { - continue + tidOK := false + sidOK := false + for _, e := range sp.spansStarted[0].Events() { + for _, kv := range e.Attributes { + switch kv.Key { + case "SpanProcessorName": + gotValue := kv.Value.AsString() + if gotValue != spNames[c] { + t.Errorf("%s: attributes: got %s, want %s\n", name, gotValue, spNames[c]) + } + c++ + case "ParentTraceID": + gotValue := kv.Value.AsString() + if gotValue != parent.TraceID.String() { + t.Errorf("%s: attributes: got %s, want %s\n", name, gotValue, parent.TraceID) + } + tidOK = true + case "ParentSpanID": + gotValue := kv.Value.AsString() + if gotValue != parent.SpanID.String() { + t.Errorf("%s: attributes: got %s, want %s\n", name, gotValue, parent.SpanID) + } + sidOK = true + default: + continue + } } - gotValue := kv.Value.AsString() - if gotValue != spNames[c] { - t.Errorf("%s: ordered attributes: got %s, want %s\n", name, gotValue, spNames[c]) - } - c++ } if c != len(spNames) { - t.Errorf("%s: expected attributes(OnStart): got %d, want %d\n", name, c, len(spNames)) + t.Errorf("%s: expected attributes(SpanProcessorName): got %d, want %d\n", name, c, len(spNames)) + } + if !tidOK { + t.Errorf("%s: expected attributes(ParentTraceID)\n", name) + } + if !sidOK { + t.Errorf("%s: expected attributes(ParentSpanID)\n", name) } } } @@ -129,21 +172,6 @@ func TestUnregisterSpanProcessor(t *testing.T) { if gotCount != wantCount { t.Errorf("%s: ended count: got %d, want %d\n", name, gotCount, wantCount) } - - c := 0 - for _, kv := range sp.spansEnded[0].Attributes { - if kv.Key != "OnEnd" { - continue - } - gotValue := kv.Value.AsString() - if gotValue != spNames[c] { - t.Errorf("%s: ordered attributes: got %s, want %s\n", name, gotValue, spNames[c]) - } - c++ - } - if c != len(spNames) { - t.Errorf("%s: expected attributes(OnEnd): got %d, want %d\n", name, c, len(spNames)) - } } } diff --git a/sdk/trace/trace_test.go b/sdk/trace/trace_test.go index af904ebb349..22ff6b20fb9 100644 --- a/sdk/trace/trace_test.go +++ b/sdk/trace/trace_test.go @@ -25,8 +25,8 @@ import ( "testing" "time" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/codes" - "go.opentelemetry.io/otel/global" "go.opentelemetry.io/otel/label" "go.opentelemetry.io/otel/oteltest" "go.opentelemetry.io/otel/trace" @@ -41,20 +41,30 @@ import ( "go.opentelemetry.io/otel/sdk/resource" ) +type storingHandler struct { + errs []error +} + +func (s *storingHandler) Handle(err error) { + s.errs = append(s.errs, err) +} + +func (s *storingHandler) Reset() { + s.errs = nil +} + var ( tid trace.TraceID sid trace.SpanID -) - -type discardHandler struct{} -func (*discardHandler) Handle(_ error) {} + handler *storingHandler = &storingHandler{} +) func init() { tid, _ = trace.TraceIDFromHex("01020304050607080102040810203040") sid, _ = trace.SpanIDFromHex("0102040810203040") - global.SetErrorHandler(new(discardHandler)) + otel.SetErrorHandler(handler) } func TestTracerFollowsExpectedAPIBehaviour(t *testing.T) { @@ -70,19 +80,19 @@ func TestTracerFollowsExpectedAPIBehaviour(t *testing.T) { type testExporter struct { mu sync.RWMutex idx map[string]int - spans []*export.SpanData + spans []*export.SpanSnapshot } func NewTestExporter() *testExporter { return &testExporter{idx: make(map[string]int)} } -func (te *testExporter) ExportSpans(_ context.Context, spans []*export.SpanData) error { +func (te *testExporter) ExportSpans(_ context.Context, ss []*export.SpanSnapshot) error { te.mu.Lock() defer te.mu.Unlock() i := len(te.spans) - for _, s := range spans { + for _, s := range ss { te.idx[s.Name] = i te.spans = append(te.spans, s) i++ @@ -90,16 +100,16 @@ func (te *testExporter) ExportSpans(_ context.Context, spans []*export.SpanData) return nil } -func (te *testExporter) Spans() []*export.SpanData { +func (te *testExporter) Spans() []*export.SpanSnapshot { te.mu.RLock() defer te.mu.RUnlock() - cp := make([]*export.SpanData, len(te.spans)) + cp := make([]*export.SpanSnapshot, len(te.spans)) copy(cp, te.spans) return cp } -func (te *testExporter) GetSpan(name string) (*export.SpanData, bool) { +func (te *testExporter) GetSpan(name string) (*export.SpanSnapshot, bool) { te.mu.RLock() defer te.mu.RUnlock() i, ok := te.idx[name] @@ -213,7 +223,7 @@ func TestRecordingIsOn(t *testing.T) { } func TestSampling(t *testing.T) { - idg := defIDGenerator() + idg := defaultIDGenerator() const total = 10000 for name, tc := range map[string]struct { sampler Sampler @@ -263,9 +273,10 @@ func TestSampling(t *testing.T) { for i := 0; i < total; i++ { ctx := context.Background() if tc.parent { + tid, sid := idg.NewIDs(ctx) psc := trace.SpanContext{ - TraceID: idg.NewTraceID(), - SpanID: idg.NewSpanID(), + TraceID: tid, + SpanID: sid, } if tc.sampledParent { psc.TraceFlags = trace.FlagsSampled @@ -350,7 +361,7 @@ func TestSetSpanAttributesOnStart(t *testing.T) { t.Fatal(err) } - want := &export.SpanData{ + want := &export.SpanSnapshot{ SpanContext: trace.SpanContext{ TraceID: tid, TraceFlags: 0x1, @@ -380,7 +391,7 @@ func TestSetSpanAttributes(t *testing.T) { t.Fatal(err) } - want := &export.SpanData{ + want := &export.SpanSnapshot{ SpanContext: trace.SpanContext{ TraceID: tid, TraceFlags: 0x1, @@ -432,7 +443,7 @@ func TestSamplerAttributesLocalChildSpan(t *testing.T) { checkTime(&got[1].StartTime) checkTime(&got[1].EndTime) - want := []*export.SpanData{ + want := []*export.SpanSnapshot{ { SpanContext: trace.SpanContext{ TraceID: tid, @@ -482,7 +493,7 @@ func TestSetSpanAttributesOverLimit(t *testing.T) { t.Fatal(err) } - want := &export.SpanData{ + want := &export.SpanSnapshot{ SpanContext: trace.SpanContext{ TraceID: tid, TraceFlags: 0x1, @@ -528,7 +539,7 @@ func TestEvents(t *testing.T) { } } - want := &export.SpanData{ + want := &export.SpanSnapshot{ SpanContext: trace.SpanContext{ TraceID: tid, TraceFlags: 0x1, @@ -579,7 +590,7 @@ func TestEventsOverLimit(t *testing.T) { } } - want := &export.SpanData{ + want := &export.SpanSnapshot{ SpanContext: trace.SpanContext{ TraceID: tid, TraceFlags: 0x1, @@ -622,7 +633,7 @@ func TestLinks(t *testing.T) { t.Fatal(err) } - want := &export.SpanData{ + want := &export.SpanSnapshot{ SpanContext: trace.SpanContext{ TraceID: tid, TraceFlags: 0x1, @@ -665,7 +676,7 @@ func TestLinksOverLimit(t *testing.T) { t.Fatal(err) } - want := &export.SpanData{ + want := &export.SpanSnapshot{ SpanContext: trace.SpanContext{ TraceID: tid, TraceFlags: 0x1, @@ -719,7 +730,7 @@ func TestSetSpanStatus(t *testing.T) { t.Fatal(err) } - want := &export.SpanData{ + want := &export.SpanSnapshot{ SpanContext: trace.SpanContext{ TraceID: tid, TraceFlags: 0x1, @@ -811,15 +822,16 @@ func startLocalSpan(tp *TracerProvider, ctx context.Context, trName, name string } // endSpan is a test utility function that ends the span in the context and -// returns the exported export.SpanData. +// returns the exported export.SpanSnapshot. // It requires that span be sampled using one of these methods // 1. Passing parent span context in context // 2. Use WithSampler(AlwaysSample()) // 3. Configuring AlwaysSample() as default sampler // // It also does some basic tests on the span. -// It also clears spanID in the export.SpanData to make the comparison easier. -func endSpan(te *testExporter, span trace.Span) (*export.SpanData, error) { +// It also clears spanID in the export.SpanSnapshot to make the comparison +// easier. +func endSpan(te *testExporter, span trace.Span) (*export.SpanSnapshot, error) { if !span.IsRecording() { return nil, fmt.Errorf("IsRecording: got false, want true") } @@ -857,12 +869,22 @@ func TestEndSpanTwice(t *testing.T) { te := NewTestExporter() tp := NewTracerProvider(WithSyncer(te)) - span := startSpan(tp, "EndSpanTwice") - span.End() - span.End() + st := time.Now() + et1 := st.Add(100 * time.Millisecond) + et2 := st.Add(200 * time.Millisecond) + + span := startSpan(tp, "EndSpanTwice", trace.WithTimestamp(st)) + span.End(trace.WithTimestamp(et1)) + span.End(trace.WithTimestamp(et2)) + if te.Len() != 1 { t.Fatalf("expected only a single span, got %#v", te.Spans()) } + + ro := span.(ReadOnlySpan) + if ro.EndTime() != et1 { + t.Fatalf("2nd call to End() should not modify end time") + } } func TestStartSpanAfterEnd(t *testing.T) { @@ -1069,7 +1091,7 @@ func TestRecordError(t *testing.T) { t.Fatal(err) } - want := &export.SpanData{ + want := &export.SpanSnapshot{ SpanContext: trace.SpanContext{ TraceID: tid, TraceFlags: 0x1, @@ -1109,7 +1131,7 @@ func TestRecordErrorNil(t *testing.T) { t.Fatal(err) } - want := &export.SpanData{ + want := &export.SpanSnapshot{ SpanContext: trace.SpanContext{ TraceID: tid, TraceFlags: 0x1, @@ -1177,7 +1199,7 @@ func TestWithResource(t *testing.T) { t.Error(err.Error()) } - want := &export.SpanData{ + want := &export.SpanSnapshot{ SpanContext: trace.SpanContext{ TraceID: tid, TraceFlags: 0x1, @@ -1212,7 +1234,7 @@ func TestWithInstrumentationVersion(t *testing.T) { t.Error(err.Error()) } - want := &export.SpanData{ + want := &export.SpanSnapshot{ SpanContext: trace.SpanContext{ TraceID: tid, TraceFlags: 0x1, @@ -1254,3 +1276,120 @@ func TestSpanCapturesPanic(t *testing.T) { errorMessageKey.String("error message"), }) } + +func TestReadOnlySpan(t *testing.T) { + kv := label.String("foo", "bar") + + tp := NewTracerProvider(WithResource(resource.NewWithAttributes(kv))) + cfg := tp.config.Load().(*Config) + tr := tp.Tracer("ReadOnlySpan", trace.WithInstrumentationVersion("3")) + + // Initialize parent context. + tID, sID := cfg.IDGenerator.NewIDs(context.Background()) + parent := trace.SpanContext{ + TraceID: tID, + SpanID: sID, + TraceFlags: 0x1, + } + ctx := trace.ContextWithRemoteSpanContext(context.Background(), parent) + + // Initialize linked context. + tID, sID = cfg.IDGenerator.NewIDs(context.Background()) + linked := trace.SpanContext{ + TraceID: tID, + SpanID: sID, + TraceFlags: 0x1, + } + + st := time.Now() + ctx, span := tr.Start(ctx, "foo", trace.WithTimestamp(st), + trace.WithLinks(trace.Link{SpanContext: linked})) + span.SetAttributes(kv) + span.AddEvent("foo", trace.WithAttributes(kv)) + span.SetStatus(codes.Ok, "foo") + + // Verify span implements ReadOnlySpan. + ro, ok := span.(ReadOnlySpan) + require.True(t, ok) + + assert.Equal(t, "foo", ro.Name()) + assert.Equal(t, trace.SpanContextFromContext(ctx), ro.SpanContext()) + assert.Equal(t, parent, ro.Parent()) + assert.Equal(t, trace.SpanKindInternal, ro.SpanKind()) + assert.Equal(t, st, ro.StartTime()) + assert.True(t, ro.EndTime().IsZero()) + assert.Equal(t, kv.Key, ro.Attributes()[0].Key) + assert.Equal(t, kv.Value, ro.Attributes()[0].Value) + assert.Equal(t, linked, ro.Links()[0].SpanContext) + assert.Equal(t, kv.Key, ro.Events()[0].Attributes[0].Key) + assert.Equal(t, kv.Value, ro.Events()[0].Attributes[0].Value) + assert.Equal(t, codes.Ok, ro.StatusCode()) + assert.Equal(t, "foo", ro.StatusMessage()) + assert.Equal(t, "ReadOnlySpan", ro.InstrumentationLibrary().Name) + assert.Equal(t, "3", ro.InstrumentationLibrary().Version) + assert.Equal(t, kv.Key, ro.Resource().Attributes()[0].Key) + assert.Equal(t, kv.Value, ro.Resource().Attributes()[0].Value) + + // Verify changes to the original span are reflected in the ReadOnlySpan. + span.SetName("bar") + assert.Equal(t, "bar", ro.Name()) + + // Verify Snapshot() returns snapshots that are independent from the + // original span and from one another. + d1 := ro.Snapshot() + span.AddEvent("baz") + d2 := ro.Snapshot() + for _, e := range d1.MessageEvents { + if e.Name == "baz" { + t.Errorf("Didn't expect to find 'baz' event") + } + } + var exists bool + for _, e := range d2.MessageEvents { + if e.Name == "baz" { + exists = true + } + } + if !exists { + t.Errorf("Expected to find 'baz' event") + } + + et := st.Add(time.Millisecond) + span.End(trace.WithTimestamp(et)) + assert.Equal(t, et, ro.EndTime()) +} + +func TestReadWriteSpan(t *testing.T) { + tp := NewTracerProvider() + cfg := tp.config.Load().(*Config) + tr := tp.Tracer("ReadWriteSpan") + + // Initialize parent context. + tID, sID := cfg.IDGenerator.NewIDs(context.Background()) + parent := trace.SpanContext{ + TraceID: tID, + SpanID: sID, + TraceFlags: 0x1, + } + ctx := trace.ContextWithRemoteSpanContext(context.Background(), parent) + + _, span := tr.Start(ctx, "foo") + defer span.End() + + // Verify span implements ReadOnlySpan. + rw, ok := span.(ReadWriteSpan) + require.True(t, ok) + + // Verify the span can be read from. + assert.False(t, rw.StartTime().IsZero()) + + // Verify the span can be written to. + rw.SetName("bar") + assert.Equal(t, "bar", rw.Name()) + + // NOTE: This function tests ReadWriteSpan which is an interface which + // embeds trace.Span and ReadOnlySpan. Since both of these interfaces have + // their own tests, there is no point in testing all the possible methods + // available via ReadWriteSpan as doing so would mean creating a lot of + // duplication. +} diff --git a/sdk/trace/tracer.go b/sdk/trace/tracer.go index 55e90b836ba..c85f866fd68 100644 --- a/sdk/trace/tracer.go +++ b/sdk/trace/tracer.go @@ -47,7 +47,7 @@ func (tr *tracer) Start(ctx context.Context, name string, options ...trace.SpanO } } - span := startSpanInternal(tr, name, parentSpanContext, remoteParent, config) + span := startSpanInternal(ctx, tr, name, parentSpanContext, remoteParent, config) for _, l := range links { span.addLink(l) } @@ -61,7 +61,7 @@ func (tr *tracer) Start(ctx context.Context, name string, options ...trace.SpanO if span.IsRecording() { sps, _ := tr.provider.spanProcessors.Load().(spanProcessorStates) for _, sp := range sps { - sp.sp.OnStart(span.data) + sp.sp.OnStart(ctx, span) } } diff --git a/semconv/http.go b/semconv/http.go index bbb51d4c3d8..50b0f696e5e 100644 --- a/semconv/http.go +++ b/semconv/http.go @@ -140,7 +140,7 @@ func HTTPClientAttributesFromHTTPRequest(request *http.Request) []label.KeyValue attrs = append(attrs, HTTPMethodKey.String(http.MethodGet)) } - attrs = append(attrs, HTTPUrlKey.String(request.URL.String())) + attrs = append(attrs, HTTPURLKey.String(request.URL.String())) return append(attrs, httpCommonAttributesFromHTTPRequest(request)...) } diff --git a/semconv/resource.go b/semconv/resource.go index 8a1ec6db9a3..59a326d27aa 100644 --- a/semconv/resource.go +++ b/semconv/resource.go @@ -219,3 +219,9 @@ var ( CloudProviderAzure = CloudProviderKey.String("azure") CloudProviderGCP = CloudProviderKey.String("gcp") ) + +// Semantic conventions for deployment attributes. +const ( + // Name of the deployment environment (aka deployment tier); e.g. (staging, production). + DeploymentEnvironmentKey = label.Key("deployment.environment") +) diff --git a/semconv/trace.go b/semconv/trace.go index 942ea7a6d2d..5f780943cda 100644 --- a/semconv/trace.go +++ b/semconv/trace.go @@ -80,7 +80,7 @@ const ( // Full HTTP request URL in the form: // scheme://host[:port]/path?query[#fragment]. - HTTPUrlKey = label.Key("http.url") + HTTPURLKey = label.Key("http.url") // The full request target as passed in a HTTP request line or // equivalent, e.g. "/path/12314/?q=ddds#123". diff --git a/global/trace.go b/trace.go similarity index 79% rename from global/trace.go rename to trace.go index 97660fbac5d..281592e94f1 100644 --- a/global/trace.go +++ b/trace.go @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -package global // import "go.opentelemetry.io/otel/global" +package otel // import "go.opentelemetry.io/otel" import ( - "go.opentelemetry.io/otel/global/internal" + "go.opentelemetry.io/otel/internal/global" "go.opentelemetry.io/otel/trace" ) @@ -24,21 +24,21 @@ import ( // // This is short for TracerProvider().Tracer(name) func Tracer(name string) trace.Tracer { - return TracerProvider().Tracer(name) + return GetTracerProvider().Tracer(name) } // TracerProvider returns the registered global trace provider. // If none is registered then an instance of NoopTracerProvider is returned. // // Use the trace provider to create a named tracer. E.g. -// tracer := global.TracerProvider().Tracer("example.com/foo") +// tracer := global.GetTracerProvider().Tracer("example.com/foo") // or // tracer := global.Tracer("example.com/foo") -func TracerProvider() trace.TracerProvider { - return internal.TracerProvider() +func GetTracerProvider() trace.TracerProvider { + return global.TracerProvider() } // SetTracerProvider registers `tp` as the global trace provider. func SetTracerProvider(tp trace.TracerProvider) { - internal.SetTracerProvider(tp) + global.SetTracerProvider(tp) } diff --git a/trace/doc.go b/trace/doc.go new file mode 100644 index 00000000000..c962f3bc622 --- /dev/null +++ b/trace/doc.go @@ -0,0 +1,70 @@ +// 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 trace provides an implementation of the tracing part of the +OpenTelemetry API. + +This package is currently in a pre-GA phase. Backwards incompatible changes +may be introduced in subsequent minor version releases as we work to track the +evolving OpenTelemetry specification and user feedback. + +To participate in distributed traces a Span needs to be created for the +operation being performed as part of a traced workflow. It its simplest form: + + var tracer trace.Tracer + + func init() { + tracer = otel.Tracer("instrumentation/package/name") + } + + func operation(ctx context.Context) { + var span trace.Span + ctx, span = tracer.Start(ctx, "operation") + defer span.End() + // ... + } + +A Tracer is unique to the instrumentation and is used to create Spans. +Instrumentation should be designed to accept a TracerProvider from which it +can create its own unique Tracer. Alternatively, the registered global +TracerProvider from the go.opentelemetry.io/otel package can be used as +a default. + + const ( + name = "instrumentation/package/name" + version = "0.1.0" + ) + + type Instrumentation struct { + tracer trace.Tracer + } + + func NewInstrumentation(tp trace.TracerProvider) *Instrumentation { + if tp == nil { + tp = otel.TracerProvider() + } + return &Instrumentation{ + tracer: tp.Tracer(name, trace.WithInstrumentationVersion(version)), + } + } + + func operation(ctx context.Context, inst *Instrumentation) { + var span trace.Span + ctx, span = inst.tracer.Start(ctx, "operation") + defer span.End() + // ... + } +*/ +package trace // import "go.opentelemetry.io/otel/trace" diff --git a/global/trace_test.go b/trace_test.go similarity index 88% rename from global/trace_test.go rename to trace_test.go index 0c6bd385896..f7cb2142149 100644 --- a/global/trace_test.go +++ b/trace_test.go @@ -12,12 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -package global_test +package otel import ( "testing" - "go.opentelemetry.io/otel/global" "go.opentelemetry.io/otel/internal/trace/noop" "go.opentelemetry.io/otel/trace" ) @@ -33,10 +32,10 @@ func (*testTracerProvider) Tracer(_ string, _ ...trace.TracerOption) trace.Trace func TestMultipleGlobalTracerProvider(t *testing.T) { p1 := testTracerProvider{} p2 := trace.NewNoopTracerProvider() - global.SetTracerProvider(&p1) - global.SetTracerProvider(p2) + SetTracerProvider(&p1) + SetTracerProvider(p2) - got := global.TracerProvider() + got := GetTracerProvider() want := p2 if got != want { t.Fatalf("TracerProvider: got %p, want %p\n", got, want) diff --git a/sdk/trace/internal/internal.go b/version.go similarity index 70% rename from sdk/trace/internal/internal.go rename to version.go index 08898efae35..fca98b74951 100644 --- a/sdk/trace/internal/internal.go +++ b/version.go @@ -12,13 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package internal provides trace internals. -package internal +package otel // import "go.opentelemetry.io/otel" -import "go.opentelemetry.io/otel/trace" - -// IDGenerator allows custom generators for TraceId and SpanId. -type IDGenerator interface { - NewTraceID() trace.TraceID - NewSpanID() trace.SpanID +// Version is the current release version of OpenTelemetry in use. +func Version() string { + return "0.15.0" }