From cece9b65fc25bbc58ec62ce07e56ecdc3d5ca4ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2024 10:50:41 +0000 Subject: [PATCH 01/42] build(deps): bump thiserror from 1.0.63 to 1.0.64 (#3219) Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.63 to 1.0.64. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/1.0.63...1.0.64) --- updated-dependencies: - dependency-name: thiserror dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7164fe91ce..78de6ca0be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3292,18 +3292,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", From 38ca37e60e4d2913368a153a0cdce56daab053a8 Mon Sep 17 00:00:00 2001 From: Scott Fleener Date: Mon, 23 Sep 2024 13:53:39 +0000 Subject: [PATCH 02/42] Vendor OpenTelemetry protocol In preparation for supporting the OpenTelemetry protocol for the proxy's traces, this vendors the relevant protobufs as well as some convenience helpers here. This works around the fact that the existing `opentelemetry` crates do not support the version of tonic that we currently use (0.10), and this vendoring can be removed once we update. [#10111](https://github.com/linkerd/linkerd2/issues/10111) Signed-off-by: Scott Fleener --- Cargo.lock | 123 +++++ Cargo.toml | 1 + opentelemetry-proto/Cargo.toml | 25 + opentelemetry-proto/README.md | 21 + .../collector/trace/v1/trace_service.proto | 79 ++++ .../proto/common/v1/common.proto | 81 ++++ .../proto/resource/v1/resource.proto | 37 ++ .../opentelemetry/proto/trace/v1/trace.proto | 355 ++++++++++++++ .../opentelemetry.proto.collector.trace.v1.rs | 165 +++++++ .../src/gen/opentelemetry.proto.common.v1.rs | 87 ++++ .../gen/opentelemetry.proto.resource.v1.rs | 15 + .../src/gen/opentelemetry.proto.trace.v1.rs | 438 ++++++++++++++++++ opentelemetry-proto/src/lib.rs | 11 + opentelemetry-proto/src/proto.rs | 25 + opentelemetry-proto/src/transform/common.rs | 148 ++++++ opentelemetry-proto/src/transform/mod.rs | 2 + opentelemetry-proto/src/transform/trace.rs | 345 ++++++++++++++ opentelemetry-proto/tests/bootstrap.rs | 52 +++ 18 files changed, 2010 insertions(+) create mode 100644 opentelemetry-proto/Cargo.toml create mode 100644 opentelemetry-proto/README.md create mode 100644 opentelemetry-proto/opentelemetry/proto/collector/trace/v1/trace_service.proto create mode 100644 opentelemetry-proto/opentelemetry/proto/common/v1/common.proto create mode 100644 opentelemetry-proto/opentelemetry/proto/resource/v1/resource.proto create mode 100644 opentelemetry-proto/opentelemetry/proto/trace/v1/trace.proto create mode 100644 opentelemetry-proto/src/gen/opentelemetry.proto.collector.trace.v1.rs create mode 100644 opentelemetry-proto/src/gen/opentelemetry.proto.common.v1.rs create mode 100644 opentelemetry-proto/src/gen/opentelemetry.proto.resource.v1.rs create mode 100644 opentelemetry-proto/src/gen/opentelemetry.proto.trace.v1.rs create mode 100644 opentelemetry-proto/src/lib.rs create mode 100644 opentelemetry-proto/src/proto.rs create mode 100644 opentelemetry-proto/src/transform/common.rs create mode 100644 opentelemetry-proto/src/transform/mod.rs create mode 100644 opentelemetry-proto/src/transform/trace.rs create mode 100644 opentelemetry-proto/tests/bootstrap.rs diff --git a/Cargo.lock b/Cargo.lock index 78de6ca0be..9f811ebb45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -288,6 +288,12 @@ dependencies = [ "fslock", ] +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + [[package]] name = "byteorder" version = "1.5.0" @@ -1032,6 +1038,15 @@ dependencies = [ "libc", ] +[[package]] +name = "js-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "kubert-prometheus-tokio" version = "0.1.0" @@ -2590,6 +2605,59 @@ dependencies = [ "tonic-build", ] +[[package]] +name = "opentelemetry" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b69a91d4893e713e06f724597ad630f1fa76057a5e1026c0ca67054a9032a76" +dependencies = [ + "futures-core", + "futures-sink", + "js-sys", + "once_cell", + "pin-project-lite", + "thiserror", +] + +[[package]] +name = "opentelemetry-proto" +version = "0.1.0" +dependencies = [ + "opentelemetry", + "opentelemetry_sdk", + "prost", + "tonic", + "tonic-build", +] + +[[package]] +name = "opentelemetry_sdk" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae312d58eaa90a82d2e627fd86e075cf5230b3f11794e2ed74199ebbe572d4fd" +dependencies = [ + "async-trait", + "futures-channel", + "futures-executor", + "futures-util", + "lazy_static", + "once_cell", + "opentelemetry", + "ordered-float", + "percent-encoding", + "rand", + "thiserror", +] + +[[package]] +name = "ordered-float" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a91171844676f8c7990ce64959210cd2eaef32c2612c50f9fae9f8aaa6065a6" +dependencies = [ + "num-traits", +] + [[package]] name = "overload" version = "0.1.1" @@ -3728,6 +3796,61 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" + [[package]] name = "widestring" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index d20bccfbb6..bfb8093e4d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -78,6 +78,7 @@ members = [ "linkerd/transport-metrics", "linkerd2-proxy", "opencensus-proto", + "opentelemetry-proto", "spiffe-proto", "tools", ] diff --git a/opentelemetry-proto/Cargo.toml b/opentelemetry-proto/Cargo.toml new file mode 100644 index 0000000000..79e20ef9c3 --- /dev/null +++ b/opentelemetry-proto/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "opentelemetry-proto" +version = "0.1.0" +authors = ["The OpenTelemetry Authors"] +license = "Apache-2.0" +edition = "2021" +publish = false +description = """ +gRPC bindings for OpenTelemetry. + +Vendored from https://github.com/open-telemetry/opentelemetry-rust/. +""" + +[dependencies] +tonic = { version = "0.10", features = ["codegen", "prost", "transport"] } +prost = "0.12" +opentelemetry = { version = "0.23", default-features = false, features = ["trace"] } +opentelemetry_sdk = { version = "0.23", default-features = false, features = ["trace"] } + +[dev-dependencies] +opentelemetry = { version = "0.23", default-features = false, features = ["trace", "testing"] } +tonic-build = { version = "0.10", default-features = false, features = ["prost"] } + +[lib] +doctest = false diff --git a/opentelemetry-proto/README.md b/opentelemetry-proto/README.md new file mode 100644 index 0000000000..c802805818 --- /dev/null +++ b/opentelemetry-proto/README.md @@ -0,0 +1,21 @@ +# opentelemetry-proto + +This library mirrors parts of the +[`opentelemetry-proto`](https://github.com/census-instrumentation/opencensus-proto/) +repo, with the non-tracing and build-related components removed. + +## License + +Copyright 2024, 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. diff --git a/opentelemetry-proto/opentelemetry/proto/collector/trace/v1/trace_service.proto b/opentelemetry-proto/opentelemetry/proto/collector/trace/v1/trace_service.proto new file mode 100644 index 0000000000..d6fe67f9e5 --- /dev/null +++ b/opentelemetry-proto/opentelemetry/proto/collector/trace/v1/trace_service.proto @@ -0,0 +1,79 @@ +// Copyright 2019, 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. + +syntax = "proto3"; + +package opentelemetry.proto.collector.trace.v1; + +import "opentelemetry/proto/trace/v1/trace.proto"; + +option csharp_namespace = "OpenTelemetry.Proto.Collector.Trace.V1"; +option java_multiple_files = true; +option java_package = "io.opentelemetry.proto.collector.trace.v1"; +option java_outer_classname = "TraceServiceProto"; +option go_package = "go.opentelemetry.io/proto/otlp/collector/trace/v1"; + +// Service that can be used to push spans between one Application instrumented with +// OpenTelemetry and a collector, or between a collector and a central collector (in this +// case spans are sent/received to/from multiple Applications). +service TraceService { + // For performance reasons, it is recommended to keep this RPC + // alive for the entire life of the application. + rpc Export(ExportTraceServiceRequest) returns (ExportTraceServiceResponse) {} +} + +message ExportTraceServiceRequest { + // An array of ResourceSpans. + // For data coming from a single resource this array will typically contain one + // element. Intermediary nodes (such as OpenTelemetry Collector) that receive + // data from multiple origins typically batch the data before forwarding further and + // in that case this array will contain multiple elements. + repeated opentelemetry.proto.trace.v1.ResourceSpans resource_spans = 1; +} + +message ExportTraceServiceResponse { + // The details of a partially successful export request. + // + // If the request is only partially accepted + // (i.e. when the server accepts only parts of the data and rejects the rest) + // the server MUST initialize the `partial_success` field and MUST + // set the `rejected_` with the number of items it rejected. + // + // Servers MAY also make use of the `partial_success` field to convey + // warnings/suggestions to senders even when the request was fully accepted. + // In such cases, the `rejected_` MUST have a value of `0` and + // the `error_message` MUST be non-empty. + // + // A `partial_success` message with an empty value (rejected_ = 0 and + // `error_message` = "") is equivalent to it not being set/present. Senders + // SHOULD interpret it the same way as in the full success case. + ExportTracePartialSuccess partial_success = 1; +} + +message ExportTracePartialSuccess { + // The number of rejected spans. + // + // A `rejected_` field holding a `0` value indicates that the + // request was fully accepted. + int64 rejected_spans = 1; + + // A developer-facing human-readable message in English. It should be used + // either to explain why the server rejected parts of the data during a partial + // success or to convey warnings/suggestions during a full success. The message + // should offer guidance on how users can address such issues. + // + // error_message is an optional field. An error_message with an empty value + // is equivalent to it not being set. + string error_message = 2; +} diff --git a/opentelemetry-proto/opentelemetry/proto/common/v1/common.proto b/opentelemetry-proto/opentelemetry/proto/common/v1/common.proto new file mode 100644 index 0000000000..ff8a21a1fa --- /dev/null +++ b/opentelemetry-proto/opentelemetry/proto/common/v1/common.proto @@ -0,0 +1,81 @@ +// Copyright 2019, 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. + +syntax = "proto3"; + +package opentelemetry.proto.common.v1; + +option csharp_namespace = "OpenTelemetry.Proto.Common.V1"; +option java_multiple_files = true; +option java_package = "io.opentelemetry.proto.common.v1"; +option java_outer_classname = "CommonProto"; +option go_package = "go.opentelemetry.io/proto/otlp/common/v1"; + +// AnyValue is used to represent any type of attribute value. AnyValue may contain a +// primitive value such as a string or integer or it may contain an arbitrary nested +// object containing arrays, key-value lists and primitives. +message AnyValue { + // The value is one of the listed fields. It is valid for all values to be unspecified + // in which case this AnyValue is considered to be "empty". + oneof value { + string string_value = 1; + bool bool_value = 2; + int64 int_value = 3; + double double_value = 4; + ArrayValue array_value = 5; + KeyValueList kvlist_value = 6; + bytes bytes_value = 7; + } +} + +// ArrayValue is a list of AnyValue messages. We need ArrayValue as a message +// since oneof in AnyValue does not allow repeated fields. +message ArrayValue { + // Array of values. The array may be empty (contain 0 elements). + repeated AnyValue values = 1; +} + +// KeyValueList is a list of KeyValue messages. We need KeyValueList as a message +// since `oneof` in AnyValue does not allow repeated fields. Everywhere else where we need +// a list of KeyValue messages (e.g. in Span) we use `repeated KeyValue` directly to +// avoid unnecessary extra wrapping (which slows down the protocol). The 2 approaches +// are semantically equivalent. +message KeyValueList { + // A collection of key/value pairs of key-value pairs. The list may be empty (may + // contain 0 elements). + // The keys MUST be unique (it is not allowed to have more than one + // value with the same key). + repeated KeyValue values = 1; +} + +// KeyValue is a key-value pair that is used to store Span attributes, Link +// attributes, etc. +message KeyValue { + string key = 1; + AnyValue value = 2; +} + +// InstrumentationScope is a message representing the instrumentation scope information +// such as the fully qualified name and version. +message InstrumentationScope { + // An empty instrumentation scope name means the name is unknown. + string name = 1; + string version = 2; + + // Additional attributes that describe the scope. [Optional]. + // Attribute keys MUST be unique (it is not allowed to have more than one + // attribute with the same key). + repeated KeyValue attributes = 3; + uint32 dropped_attributes_count = 4; +} diff --git a/opentelemetry-proto/opentelemetry/proto/resource/v1/resource.proto b/opentelemetry-proto/opentelemetry/proto/resource/v1/resource.proto new file mode 100644 index 0000000000..6637560bc3 --- /dev/null +++ b/opentelemetry-proto/opentelemetry/proto/resource/v1/resource.proto @@ -0,0 +1,37 @@ +// Copyright 2019, 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. + +syntax = "proto3"; + +package opentelemetry.proto.resource.v1; + +import "opentelemetry/proto/common/v1/common.proto"; + +option csharp_namespace = "OpenTelemetry.Proto.Resource.V1"; +option java_multiple_files = true; +option java_package = "io.opentelemetry.proto.resource.v1"; +option java_outer_classname = "ResourceProto"; +option go_package = "go.opentelemetry.io/proto/otlp/resource/v1"; + +// Resource information. +message Resource { + // Set of attributes that describe the resource. + // Attribute keys MUST be unique (it is not allowed to have more than one + // attribute with the same key). + repeated opentelemetry.proto.common.v1.KeyValue attributes = 1; + + // dropped_attributes_count is the number of dropped attributes. If the value is 0, then + // no attributes were dropped. + uint32 dropped_attributes_count = 2; +} diff --git a/opentelemetry-proto/opentelemetry/proto/trace/v1/trace.proto b/opentelemetry-proto/opentelemetry/proto/trace/v1/trace.proto new file mode 100644 index 0000000000..5cb2f3ce1c --- /dev/null +++ b/opentelemetry-proto/opentelemetry/proto/trace/v1/trace.proto @@ -0,0 +1,355 @@ +// Copyright 2019, 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. + +syntax = "proto3"; + +package opentelemetry.proto.trace.v1; + +import "opentelemetry/proto/common/v1/common.proto"; +import "opentelemetry/proto/resource/v1/resource.proto"; + +option csharp_namespace = "OpenTelemetry.Proto.Trace.V1"; +option java_multiple_files = true; +option java_package = "io.opentelemetry.proto.trace.v1"; +option java_outer_classname = "TraceProto"; +option go_package = "go.opentelemetry.io/proto/otlp/trace/v1"; + +// TracesData represents the traces data that can be stored in a persistent storage, +// OR can be embedded by other protocols that transfer OTLP traces data but do +// not implement the OTLP protocol. +// +// The main difference between this message and collector protocol is that +// in this message there will not be any "control" or "metadata" specific to +// OTLP protocol. +// +// When new fields are added into this message, the OTLP request MUST be updated +// as well. +message TracesData { + // An array of ResourceSpans. + // For data coming from a single resource this array will typically contain + // one element. Intermediary nodes that receive data from multiple origins + // typically batch the data before forwarding further and in that case this + // array will contain multiple elements. + repeated ResourceSpans resource_spans = 1; +} + +// A collection of ScopeSpans from a Resource. +message ResourceSpans { + reserved 1000; + + // The resource for the spans in this message. + // If this field is not set then no resource info is known. + opentelemetry.proto.resource.v1.Resource resource = 1; + + // A list of ScopeSpans that originate from a resource. + repeated ScopeSpans scope_spans = 2; + + // The Schema URL, if known. This is the identifier of the Schema that the resource data + // is recorded in. To learn more about Schema URL see + // https://opentelemetry.io/docs/specs/otel/schemas/#schema-url + // This schema_url applies to the data in the "resource" field. It does not apply + // to the data in the "scope_spans" field which have their own schema_url field. + string schema_url = 3; +} + +// A collection of Spans produced by an InstrumentationScope. +message ScopeSpans { + // The instrumentation scope information for the spans in this message. + // Semantically when InstrumentationScope isn't set, it is equivalent with + // an empty instrumentation scope name (unknown). + opentelemetry.proto.common.v1.InstrumentationScope scope = 1; + + // A list of Spans that originate from an instrumentation scope. + repeated Span spans = 2; + + // The Schema URL, if known. This is the identifier of the Schema that the span data + // is recorded in. To learn more about Schema URL see + // https://opentelemetry.io/docs/specs/otel/schemas/#schema-url + // This schema_url applies to all spans and span events in the "spans" field. + string schema_url = 3; +} + +// A Span represents a single operation performed by a single component of the system. +// +// The next available field id is 17. +message Span { + // A unique identifier for a trace. All spans from the same trace share + // the same `trace_id`. The ID is a 16-byte array. An ID with all zeroes OR + // of length other than 16 bytes is considered invalid (empty string in OTLP/JSON + // is zero-length and thus is also invalid). + // + // This field is required. + bytes trace_id = 1; + + // A unique identifier for a span within a trace, assigned when the span + // is created. The ID is an 8-byte array. An ID with all zeroes OR of length + // other than 8 bytes is considered invalid (empty string in OTLP/JSON + // is zero-length and thus is also invalid). + // + // This field is required. + bytes span_id = 2; + + // trace_state conveys information about request position in multiple distributed tracing graphs. + // It is a trace_state in w3c-trace-context format: https://www.w3.org/TR/trace-context/#tracestate-header + // See also https://github.com/w3c/distributed-tracing for more details about this field. + string trace_state = 3; + + // The `span_id` of this span's parent span. If this is a root span, then this + // field must be empty. The ID is an 8-byte array. + bytes parent_span_id = 4; + + // Flags, a bit field. + // + // Bits 0-7 (8 least significant bits) are the trace flags as defined in W3C Trace + // Context specification. To read the 8-bit W3C trace flag, use + // `flags & SPAN_FLAGS_TRACE_FLAGS_MASK`. + // + // See https://www.w3.org/TR/trace-context-2/#trace-flags for the flag definitions. + // + // Bits 8 and 9 represent the 3 states of whether a span's parent + // is remote. The states are (unknown, is not remote, is remote). + // To read whether the value is known, use `(flags & SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK) != 0`. + // To read whether the span is remote, use `(flags & SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK) != 0`. + // + // When creating span messages, if the message is logically forwarded from another source + // with an equivalent flags fields (i.e., usually another OTLP span message), the field SHOULD + // be copied as-is. If creating from a source that does not have an equivalent flags field + // (such as a runtime representation of an OpenTelemetry span), the high 22 bits MUST + // be set to zero. + // Readers MUST NOT assume that bits 10-31 (22 most significant bits) will be zero. + // + // [Optional]. + fixed32 flags = 16; + + // A description of the span's operation. + // + // For example, the name can be a qualified method name or a file name + // and a line number where the operation is called. A best practice is to use + // the same display name at the same call point in an application. + // This makes it easier to correlate spans in different traces. + // + // This field is semantically required to be set to non-empty string. + // Empty value is equivalent to an unknown span name. + // + // This field is required. + string name = 5; + + // SpanKind is the type of span. Can be used to specify additional relationships between spans + // in addition to a parent/child relationship. + enum SpanKind { + // Unspecified. Do NOT use as default. + // Implementations MAY assume SpanKind to be INTERNAL when receiving UNSPECIFIED. + SPAN_KIND_UNSPECIFIED = 0; + + // Indicates that the span represents an internal operation within an application, + // as opposed to an operation happening at the boundaries. Default value. + SPAN_KIND_INTERNAL = 1; + + // Indicates that the span covers server-side handling of an RPC or other + // remote network request. + SPAN_KIND_SERVER = 2; + + // Indicates that the span describes a request to some remote service. + SPAN_KIND_CLIENT = 3; + + // Indicates that the span describes a producer sending a message to a broker. + // Unlike CLIENT and SERVER, there is often no direct critical path latency relationship + // between producer and consumer spans. A PRODUCER span ends when the message was accepted + // by the broker while the logical processing of the message might span a much longer time. + SPAN_KIND_PRODUCER = 4; + + // Indicates that the span describes consumer receiving a message from a broker. + // Like the PRODUCER kind, there is often no direct critical path latency relationship + // between producer and consumer spans. + SPAN_KIND_CONSUMER = 5; + } + + // Distinguishes between spans generated in a particular context. For example, + // two spans with the same name may be distinguished using `CLIENT` (caller) + // and `SERVER` (callee) to identify queueing latency associated with the span. + SpanKind kind = 6; + + // start_time_unix_nano is the start time of the span. On the client side, this is the time + // kept by the local machine where the span execution starts. On the server side, this + // is the time when the server's application handler starts running. + // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970. + // + // This field is semantically required and it is expected that end_time >= start_time. + fixed64 start_time_unix_nano = 7; + + // end_time_unix_nano is the end time of the span. On the client side, this is the time + // kept by the local machine where the span execution ends. On the server side, this + // is the time when the server application handler stops running. + // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970. + // + // This field is semantically required and it is expected that end_time >= start_time. + fixed64 end_time_unix_nano = 8; + + // attributes is a collection of key/value pairs. Note, global attributes + // like server name can be set using the resource API. Examples of attributes: + // + // "/http/user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36" + // "/http/server_latency": 300 + // "example.com/myattribute": true + // "example.com/score": 10.239 + // + // The OpenTelemetry API specification further restricts the allowed value types: + // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/common/README.md#attribute + // Attribute keys MUST be unique (it is not allowed to have more than one + // attribute with the same key). + repeated opentelemetry.proto.common.v1.KeyValue attributes = 9; + + // dropped_attributes_count is the number of attributes that were discarded. Attributes + // can be discarded because their keys are too long or because there are too many + // attributes. If this value is 0, then no attributes were dropped. + uint32 dropped_attributes_count = 10; + + // Event is a time-stamped annotation of the span, consisting of user-supplied + // text description and key-value pairs. + message Event { + // time_unix_nano is the time the event occurred. + fixed64 time_unix_nano = 1; + + // name of the event. + // This field is semantically required to be set to non-empty string. + string name = 2; + + // attributes is a collection of attribute key/value pairs on the event. + // Attribute keys MUST be unique (it is not allowed to have more than one + // attribute with the same key). + repeated opentelemetry.proto.common.v1.KeyValue attributes = 3; + + // dropped_attributes_count is the number of dropped attributes. If the value is 0, + // then no attributes were dropped. + uint32 dropped_attributes_count = 4; + } + + // events is a collection of Event items. + repeated Event events = 11; + + // dropped_events_count is the number of dropped events. If the value is 0, then no + // events were dropped. + uint32 dropped_events_count = 12; + + // A pointer from the current span to another span in the same trace or in a + // different trace. For example, this can be used in batching operations, + // where a single batch handler processes multiple requests from different + // traces or when the handler receives a request from a different project. + message Link { + // A unique identifier of a trace that this linked span is part of. The ID is a + // 16-byte array. + bytes trace_id = 1; + + // A unique identifier for the linked span. The ID is an 8-byte array. + bytes span_id = 2; + + // The trace_state associated with the link. + string trace_state = 3; + + // attributes is a collection of attribute key/value pairs on the link. + // Attribute keys MUST be unique (it is not allowed to have more than one + // attribute with the same key). + repeated opentelemetry.proto.common.v1.KeyValue attributes = 4; + + // dropped_attributes_count is the number of dropped attributes. If the value is 0, + // then no attributes were dropped. + uint32 dropped_attributes_count = 5; + + // Flags, a bit field. + // + // Bits 0-7 (8 least significant bits) are the trace flags as defined in W3C Trace + // Context specification. To read the 8-bit W3C trace flag, use + // `flags & SPAN_FLAGS_TRACE_FLAGS_MASK`. + // + // See https://www.w3.org/TR/trace-context-2/#trace-flags for the flag definitions. + // + // Bits 8 and 9 represent the 3 states of whether the link is remote. + // The states are (unknown, is not remote, is remote). + // To read whether the value is known, use `(flags & SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK) != 0`. + // To read whether the link is remote, use `(flags & SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK) != 0`. + // + // Readers MUST NOT assume that bits 10-31 (22 most significant bits) will be zero. + // When creating new spans, bits 10-31 (most-significant 22-bits) MUST be zero. + // + // [Optional]. + fixed32 flags = 6; + } + + // links is a collection of Links, which are references from this span to a span + // in the same or different trace. + repeated Link links = 13; + + // 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. + uint32 dropped_links_count = 14; + + // 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 = 15; +} + +// The Status type defines a logical error model that is suitable for different +// programming environments, including REST APIs and RPC APIs. +message Status { + reserved 1; + + // A developer-facing human readable error message. + string message = 2; + + // For the semantics of status codes see + // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#set-status + enum StatusCode { + // The default status. + STATUS_CODE_UNSET = 0; + // The Span has been validated by an Application developer or Operator to + // have completed successfully. + STATUS_CODE_OK = 1; + // The Span contains an error. + STATUS_CODE_ERROR = 2; + }; + + // The status code. + StatusCode code = 3; +} + +// SpanFlags represents constants used to interpret the +// Span.flags field, which is protobuf 'fixed32' type and is to +// be used as bit-fields. Each non-zero value defined in this enum is +// a bit-mask. To extract the bit-field, for example, use an +// expression like: +// +// (span.flags & SPAN_FLAGS_TRACE_FLAGS_MASK) +// +// See https://www.w3.org/TR/trace-context-2/#trace-flags for the flag definitions. +// +// Note that Span flags were introduced in version 1.1 of the +// OpenTelemetry protocol. Older Span producers do not set this +// field, consequently consumers should not rely on the absence of a +// particular flag bit to indicate the presence of a particular feature. +enum SpanFlags { + // The zero value for the enum. Should not be used for comparisons. + // Instead use bitwise "and" with the appropriate mask as shown above. + SPAN_FLAGS_DO_NOT_USE = 0; + + // Bits 0-7 are used for trace flags. + SPAN_FLAGS_TRACE_FLAGS_MASK = 0x000000FF; + + // Bits 8 and 9 are used to indicate that the parent span or link span is remote. + // Bit 8 (`HAS_IS_REMOTE`) indicates whether the value is known. + // Bit 9 (`IS_REMOTE`) indicates whether the span or link is remote. + SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK = 0x00000100; + SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK = 0x00000200; + + // Bits 10-31 are reserved for future use. +} diff --git a/opentelemetry-proto/src/gen/opentelemetry.proto.collector.trace.v1.rs b/opentelemetry-proto/src/gen/opentelemetry.proto.collector.trace.v1.rs new file mode 100644 index 0000000000..49756a86c2 --- /dev/null +++ b/opentelemetry-proto/src/gen/opentelemetry.proto.collector.trace.v1.rs @@ -0,0 +1,165 @@ +// This file is @generated by prost-build. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ExportTraceServiceRequest { + /// An array of ResourceSpans. + /// For data coming from a single resource this array will typically contain one + /// element. Intermediary nodes (such as OpenTelemetry Collector) that receive + /// data from multiple origins typically batch the data before forwarding further and + /// in that case this array will contain multiple elements. + #[prost(message, repeated, tag = "1")] + pub resource_spans: ::prost::alloc::vec::Vec< + super::super::super::trace::v1::ResourceSpans, + >, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ExportTraceServiceResponse { + /// The details of a partially successful export request. + /// + /// If the request is only partially accepted + /// (i.e. when the server accepts only parts of the data and rejects the rest) + /// the server MUST initialize the `partial_success` field and MUST + /// set the `rejected_` with the number of items it rejected. + /// + /// Servers MAY also make use of the `partial_success` field to convey + /// warnings/suggestions to senders even when the request was fully accepted. + /// In such cases, the `rejected_` MUST have a value of `0` and + /// the `error_message` MUST be non-empty. + /// + /// A `partial_success` message with an empty value (rejected_ = 0 and + /// `error_message` = "") is equivalent to it not being set/present. Senders + /// SHOULD interpret it the same way as in the full success case. + #[prost(message, optional, tag = "1")] + pub partial_success: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ExportTracePartialSuccess { + /// The number of rejected spans. + /// + /// A `rejected_` field holding a `0` value indicates that the + /// request was fully accepted. + #[prost(int64, tag = "1")] + pub rejected_spans: i64, + /// A developer-facing human-readable message in English. It should be used + /// either to explain why the server rejected parts of the data during a partial + /// success or to convey warnings/suggestions during a full success. The message + /// should offer guidance on how users can address such issues. + /// + /// error_message is an optional field. An error_message with an empty value + /// is equivalent to it not being set. + #[prost(string, tag = "2")] + pub error_message: ::prost::alloc::string::String, +} +/// Generated client implementations. +pub mod trace_service_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// Service that can be used to push spans between one Application instrumented with + /// OpenTelemetry and a collector, or between a collector and a central collector (in this + /// case spans are sent/received to/from multiple Applications). + #[derive(Debug, Clone)] + pub struct TraceServiceClient { + inner: tonic::client::Grpc, + } + impl TraceServiceClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> TraceServiceClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + TraceServiceClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// For performance reasons, it is recommended to keep this RPC + /// alive for the entire life of the application. + pub async fn export( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/opentelemetry.proto.collector.trace.v1.TraceService/Export", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "opentelemetry.proto.collector.trace.v1.TraceService", + "Export", + ), + ); + self.inner.unary(req, path, codec).await + } + } +} diff --git a/opentelemetry-proto/src/gen/opentelemetry.proto.common.v1.rs b/opentelemetry-proto/src/gen/opentelemetry.proto.common.v1.rs new file mode 100644 index 0000000000..4fbfaf954e --- /dev/null +++ b/opentelemetry-proto/src/gen/opentelemetry.proto.common.v1.rs @@ -0,0 +1,87 @@ +// This file is @generated by prost-build. +/// AnyValue is used to represent any type of attribute value. AnyValue may contain a +/// primitive value such as a string or integer or it may contain an arbitrary nested +/// object containing arrays, key-value lists and primitives. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AnyValue { + /// The value is one of the listed fields. It is valid for all values to be unspecified + /// in which case this AnyValue is considered to be "empty". + #[prost(oneof = "any_value::Value", tags = "1, 2, 3, 4, 5, 6, 7")] + pub value: ::core::option::Option, +} +/// Nested message and enum types in `AnyValue`. +pub mod any_value { + /// The value is one of the listed fields. It is valid for all values to be unspecified + /// in which case this AnyValue is considered to be "empty". + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Value { + #[prost(string, tag = "1")] + StringValue(::prost::alloc::string::String), + #[prost(bool, tag = "2")] + BoolValue(bool), + #[prost(int64, tag = "3")] + IntValue(i64), + #[prost(double, tag = "4")] + DoubleValue(f64), + #[prost(message, tag = "5")] + ArrayValue(super::ArrayValue), + #[prost(message, tag = "6")] + KvlistValue(super::KeyValueList), + #[prost(bytes, tag = "7")] + BytesValue(::prost::alloc::vec::Vec), + } +} +/// ArrayValue is a list of AnyValue messages. We need ArrayValue as a message +/// since oneof in AnyValue does not allow repeated fields. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ArrayValue { + /// Array of values. The array may be empty (contain 0 elements). + #[prost(message, repeated, tag = "1")] + pub values: ::prost::alloc::vec::Vec, +} +/// KeyValueList is a list of KeyValue messages. We need KeyValueList as a message +/// since `oneof` in AnyValue does not allow repeated fields. Everywhere else where we need +/// a list of KeyValue messages (e.g. in Span) we use `repeated KeyValue` directly to +/// avoid unnecessary extra wrapping (which slows down the protocol). The 2 approaches +/// are semantically equivalent. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct KeyValueList { + /// A collection of key/value pairs of key-value pairs. The list may be empty (may + /// contain 0 elements). + /// The keys MUST be unique (it is not allowed to have more than one + /// value with the same key). + #[prost(message, repeated, tag = "1")] + pub values: ::prost::alloc::vec::Vec, +} +/// KeyValue is a key-value pair that is used to store Span attributes, Link +/// attributes, etc. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct KeyValue { + #[prost(string, tag = "1")] + pub key: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub value: ::core::option::Option, +} +/// InstrumentationScope is a message representing the instrumentation scope information +/// such as the fully qualified name and version. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct InstrumentationScope { + /// An empty instrumentation scope name means the name is unknown. + #[prost(string, tag = "1")] + pub name: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub version: ::prost::alloc::string::String, + /// Additional attributes that describe the scope. \[Optional\]. + /// Attribute keys MUST be unique (it is not allowed to have more than one + /// attribute with the same key). + #[prost(message, repeated, tag = "3")] + pub attributes: ::prost::alloc::vec::Vec, + #[prost(uint32, tag = "4")] + pub dropped_attributes_count: u32, +} diff --git a/opentelemetry-proto/src/gen/opentelemetry.proto.resource.v1.rs b/opentelemetry-proto/src/gen/opentelemetry.proto.resource.v1.rs new file mode 100644 index 0000000000..ce317b6663 --- /dev/null +++ b/opentelemetry-proto/src/gen/opentelemetry.proto.resource.v1.rs @@ -0,0 +1,15 @@ +// This file is @generated by prost-build. +/// Resource information. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Resource { + /// Set of attributes that describe the resource. + /// Attribute keys MUST be unique (it is not allowed to have more than one + /// attribute with the same key). + #[prost(message, repeated, tag = "1")] + pub attributes: ::prost::alloc::vec::Vec, + /// dropped_attributes_count is the number of dropped attributes. If the value is 0, then + /// no attributes were dropped. + #[prost(uint32, tag = "2")] + pub dropped_attributes_count: u32, +} diff --git a/opentelemetry-proto/src/gen/opentelemetry.proto.trace.v1.rs b/opentelemetry-proto/src/gen/opentelemetry.proto.trace.v1.rs new file mode 100644 index 0000000000..c80917c2ca --- /dev/null +++ b/opentelemetry-proto/src/gen/opentelemetry.proto.trace.v1.rs @@ -0,0 +1,438 @@ +// This file is @generated by prost-build. +/// TracesData represents the traces data that can be stored in a persistent storage, +/// OR can be embedded by other protocols that transfer OTLP traces data but do +/// not implement the OTLP protocol. +/// +/// The main difference between this message and collector protocol is that +/// in this message there will not be any "control" or "metadata" specific to +/// OTLP protocol. +/// +/// When new fields are added into this message, the OTLP request MUST be updated +/// as well. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TracesData { + /// An array of ResourceSpans. + /// For data coming from a single resource this array will typically contain + /// one element. Intermediary nodes that receive data from multiple origins + /// typically batch the data before forwarding further and in that case this + /// array will contain multiple elements. + #[prost(message, repeated, tag = "1")] + pub resource_spans: ::prost::alloc::vec::Vec, +} +/// A collection of ScopeSpans from a Resource. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResourceSpans { + /// The resource for the spans in this message. + /// If this field is not set then no resource info is known. + #[prost(message, optional, tag = "1")] + pub resource: ::core::option::Option, + /// A list of ScopeSpans that originate from a resource. + #[prost(message, repeated, tag = "2")] + pub scope_spans: ::prost::alloc::vec::Vec, + /// The Schema URL, if known. This is the identifier of the Schema that the resource data + /// is recorded in. To learn more about Schema URL see + /// + /// This schema_url applies to the data in the "resource" field. It does not apply + /// to the data in the "scope_spans" field which have their own schema_url field. + #[prost(string, tag = "3")] + pub schema_url: ::prost::alloc::string::String, +} +/// A collection of Spans produced by an InstrumentationScope. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ScopeSpans { + /// The instrumentation scope information for the spans in this message. + /// Semantically when InstrumentationScope isn't set, it is equivalent with + /// an empty instrumentation scope name (unknown). + #[prost(message, optional, tag = "1")] + pub scope: ::core::option::Option, + /// A list of Spans that originate from an instrumentation scope. + #[prost(message, repeated, tag = "2")] + pub spans: ::prost::alloc::vec::Vec, + /// The Schema URL, if known. This is the identifier of the Schema that the span data + /// is recorded in. To learn more about Schema URL see + /// + /// This schema_url applies to all spans and span events in the "spans" field. + #[prost(string, tag = "3")] + pub schema_url: ::prost::alloc::string::String, +} +/// A Span represents a single operation performed by a single component of the system. +/// +/// The next available field id is 17. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Span { + /// A unique identifier for a trace. All spans from the same trace share + /// the same `trace_id`. The ID is a 16-byte array. An ID with all zeroes OR + /// of length other than 16 bytes is considered invalid (empty string in OTLP/JSON + /// is zero-length and thus is also invalid). + /// + /// This field is required. + #[prost(bytes = "vec", tag = "1")] + pub trace_id: ::prost::alloc::vec::Vec, + /// A unique identifier for a span within a trace, assigned when the span + /// is created. The ID is an 8-byte array. An ID with all zeroes OR of length + /// other than 8 bytes is considered invalid (empty string in OTLP/JSON + /// is zero-length and thus is also invalid). + /// + /// This field is required. + #[prost(bytes = "vec", tag = "2")] + pub span_id: ::prost::alloc::vec::Vec, + /// trace_state conveys information about request position in multiple distributed tracing graphs. + /// It is a trace_state in w3c-trace-context format: + /// See also for more details about this field. + #[prost(string, tag = "3")] + pub trace_state: ::prost::alloc::string::String, + /// The `span_id` of this span's parent span. If this is a root span, then this + /// field must be empty. The ID is an 8-byte array. + #[prost(bytes = "vec", tag = "4")] + pub parent_span_id: ::prost::alloc::vec::Vec, + /// Flags, a bit field. + /// + /// Bits 0-7 (8 least significant bits) are the trace flags as defined in W3C Trace + /// Context specification. To read the 8-bit W3C trace flag, use + /// `flags & SPAN_FLAGS_TRACE_FLAGS_MASK`. + /// + /// See for the flag definitions. + /// + /// Bits 8 and 9 represent the 3 states of whether a span's parent + /// is remote. The states are (unknown, is not remote, is remote). + /// To read whether the value is known, use `(flags & SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK) != 0`. + /// To read whether the span is remote, use `(flags & SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK) != 0`. + /// + /// When creating span messages, if the message is logically forwarded from another source + /// with an equivalent flags fields (i.e., usually another OTLP span message), the field SHOULD + /// be copied as-is. If creating from a source that does not have an equivalent flags field + /// (such as a runtime representation of an OpenTelemetry span), the high 22 bits MUST + /// be set to zero. + /// Readers MUST NOT assume that bits 10-31 (22 most significant bits) will be zero. + /// + /// \[Optional\]. + #[prost(fixed32, tag = "16")] + pub flags: u32, + /// A description of the span's operation. + /// + /// For example, the name can be a qualified method name or a file name + /// and a line number where the operation is called. A best practice is to use + /// the same display name at the same call point in an application. + /// This makes it easier to correlate spans in different traces. + /// + /// This field is semantically required to be set to non-empty string. + /// Empty value is equivalent to an unknown span name. + /// + /// This field is required. + #[prost(string, tag = "5")] + pub name: ::prost::alloc::string::String, + /// Distinguishes between spans generated in a particular context. For example, + /// two spans with the same name may be distinguished using `CLIENT` (caller) + /// and `SERVER` (callee) to identify queueing latency associated with the span. + #[prost(enumeration = "span::SpanKind", tag = "6")] + pub kind: i32, + /// start_time_unix_nano is the start time of the span. On the client side, this is the time + /// kept by the local machine where the span execution starts. On the server side, this + /// is the time when the server's application handler starts running. + /// Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970. + /// + /// This field is semantically required and it is expected that end_time >= start_time. + #[prost(fixed64, tag = "7")] + pub start_time_unix_nano: u64, + /// end_time_unix_nano is the end time of the span. On the client side, this is the time + /// kept by the local machine where the span execution ends. On the server side, this + /// is the time when the server application handler stops running. + /// Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970. + /// + /// This field is semantically required and it is expected that end_time >= start_time. + #[prost(fixed64, tag = "8")] + pub end_time_unix_nano: u64, + /// attributes is a collection of key/value pairs. Note, global attributes + /// like server name can be set using the resource API. Examples of attributes: + /// + /// "/http/user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36" + /// "/http/server_latency": 300 + /// "example.com/myattribute": true + /// "example.com/score": 10.239 + /// + /// The OpenTelemetry API specification further restricts the allowed value types: + /// + /// Attribute keys MUST be unique (it is not allowed to have more than one + /// attribute with the same key). + #[prost(message, repeated, tag = "9")] + pub attributes: ::prost::alloc::vec::Vec, + /// dropped_attributes_count is the number of attributes that were discarded. Attributes + /// can be discarded because their keys are too long or because there are too many + /// attributes. If this value is 0, then no attributes were dropped. + #[prost(uint32, tag = "10")] + pub dropped_attributes_count: u32, + /// events is a collection of Event items. + #[prost(message, repeated, tag = "11")] + pub events: ::prost::alloc::vec::Vec, + /// dropped_events_count is the number of dropped events. If the value is 0, then no + /// events were dropped. + #[prost(uint32, tag = "12")] + pub dropped_events_count: u32, + /// links is a collection of Links, which are references from this span to a span + /// in the same or different trace. + #[prost(message, repeated, tag = "13")] + pub links: ::prost::alloc::vec::Vec, + /// 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. + #[prost(uint32, tag = "14")] + pub dropped_links_count: u32, + /// 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). + #[prost(message, optional, tag = "15")] + pub status: ::core::option::Option, +} +/// Nested message and enum types in `Span`. +pub mod span { + /// Event is a time-stamped annotation of the span, consisting of user-supplied + /// text description and key-value pairs. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct Event { + /// time_unix_nano is the time the event occurred. + #[prost(fixed64, tag = "1")] + pub time_unix_nano: u64, + /// name of the event. + /// This field is semantically required to be set to non-empty string. + #[prost(string, tag = "2")] + pub name: ::prost::alloc::string::String, + /// attributes is a collection of attribute key/value pairs on the event. + /// Attribute keys MUST be unique (it is not allowed to have more than one + /// attribute with the same key). + #[prost(message, repeated, tag = "3")] + pub attributes: ::prost::alloc::vec::Vec< + super::super::super::common::v1::KeyValue, + >, + /// dropped_attributes_count is the number of dropped attributes. If the value is 0, + /// then no attributes were dropped. + #[prost(uint32, tag = "4")] + pub dropped_attributes_count: u32, + } + /// A pointer from the current span to another span in the same trace or in a + /// different trace. For example, this can be used in batching operations, + /// where a single batch handler processes multiple requests from different + /// traces or when the handler receives a request from a different project. + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct Link { + /// A unique identifier of a trace that this linked span is part of. The ID is a + /// 16-byte array. + #[prost(bytes = "vec", tag = "1")] + pub trace_id: ::prost::alloc::vec::Vec, + /// A unique identifier for the linked span. The ID is an 8-byte array. + #[prost(bytes = "vec", tag = "2")] + pub span_id: ::prost::alloc::vec::Vec, + /// The trace_state associated with the link. + #[prost(string, tag = "3")] + pub trace_state: ::prost::alloc::string::String, + /// attributes is a collection of attribute key/value pairs on the link. + /// Attribute keys MUST be unique (it is not allowed to have more than one + /// attribute with the same key). + #[prost(message, repeated, tag = "4")] + pub attributes: ::prost::alloc::vec::Vec< + super::super::super::common::v1::KeyValue, + >, + /// dropped_attributes_count is the number of dropped attributes. If the value is 0, + /// then no attributes were dropped. + #[prost(uint32, tag = "5")] + pub dropped_attributes_count: u32, + /// Flags, a bit field. + /// + /// Bits 0-7 (8 least significant bits) are the trace flags as defined in W3C Trace + /// Context specification. To read the 8-bit W3C trace flag, use + /// `flags & SPAN_FLAGS_TRACE_FLAGS_MASK`. + /// + /// See for the flag definitions. + /// + /// Bits 8 and 9 represent the 3 states of whether the link is remote. + /// The states are (unknown, is not remote, is remote). + /// To read whether the value is known, use `(flags & SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK) != 0`. + /// To read whether the link is remote, use `(flags & SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK) != 0`. + /// + /// Readers MUST NOT assume that bits 10-31 (22 most significant bits) will be zero. + /// When creating new spans, bits 10-31 (most-significant 22-bits) MUST be zero. + /// + /// \[Optional\]. + #[prost(fixed32, tag = "6")] + pub flags: u32, + } + /// SpanKind is the type of span. Can be used to specify additional relationships between spans + /// in addition to a parent/child relationship. + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum SpanKind { + /// Unspecified. Do NOT use as default. + /// Implementations MAY assume SpanKind to be INTERNAL when receiving UNSPECIFIED. + Unspecified = 0, + /// Indicates that the span represents an internal operation within an application, + /// as opposed to an operation happening at the boundaries. Default value. + Internal = 1, + /// Indicates that the span covers server-side handling of an RPC or other + /// remote network request. + Server = 2, + /// Indicates that the span describes a request to some remote service. + Client = 3, + /// Indicates that the span describes a producer sending a message to a broker. + /// Unlike CLIENT and SERVER, there is often no direct critical path latency relationship + /// between producer and consumer spans. A PRODUCER span ends when the message was accepted + /// by the broker while the logical processing of the message might span a much longer time. + Producer = 4, + /// Indicates that the span describes consumer receiving a message from a broker. + /// Like the PRODUCER kind, there is often no direct critical path latency relationship + /// between producer and consumer spans. + Consumer = 5, + } + impl SpanKind { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + SpanKind::Unspecified => "SPAN_KIND_UNSPECIFIED", + SpanKind::Internal => "SPAN_KIND_INTERNAL", + SpanKind::Server => "SPAN_KIND_SERVER", + SpanKind::Client => "SPAN_KIND_CLIENT", + SpanKind::Producer => "SPAN_KIND_PRODUCER", + SpanKind::Consumer => "SPAN_KIND_CONSUMER", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "SPAN_KIND_UNSPECIFIED" => Some(Self::Unspecified), + "SPAN_KIND_INTERNAL" => Some(Self::Internal), + "SPAN_KIND_SERVER" => Some(Self::Server), + "SPAN_KIND_CLIENT" => Some(Self::Client), + "SPAN_KIND_PRODUCER" => Some(Self::Producer), + "SPAN_KIND_CONSUMER" => Some(Self::Consumer), + _ => None, + } + } + } +} +/// The Status type defines a logical error model that is suitable for different +/// programming environments, including REST APIs and RPC APIs. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Status { + /// A developer-facing human readable error message. + #[prost(string, tag = "2")] + pub message: ::prost::alloc::string::String, + /// The status code. + #[prost(enumeration = "status::StatusCode", tag = "3")] + pub code: i32, +} +/// Nested message and enum types in `Status`. +pub mod status { + /// For the semantics of status codes see + /// + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum StatusCode { + /// The default status. + Unset = 0, + /// The Span has been validated by an Application developer or Operator to + /// have completed successfully. + Ok = 1, + /// The Span contains an error. + Error = 2, + } + impl StatusCode { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + StatusCode::Unset => "STATUS_CODE_UNSET", + StatusCode::Ok => "STATUS_CODE_OK", + StatusCode::Error => "STATUS_CODE_ERROR", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "STATUS_CODE_UNSET" => Some(Self::Unset), + "STATUS_CODE_OK" => Some(Self::Ok), + "STATUS_CODE_ERROR" => Some(Self::Error), + _ => None, + } + } + } +} +/// SpanFlags represents constants used to interpret the +/// Span.flags field, which is protobuf 'fixed32' type and is to +/// be used as bit-fields. Each non-zero value defined in this enum is +/// a bit-mask. To extract the bit-field, for example, use an +/// expression like: +/// +/// (span.flags & SPAN_FLAGS_TRACE_FLAGS_MASK) +/// +/// See for the flag definitions. +/// +/// Note that Span flags were introduced in version 1.1 of the +/// OpenTelemetry protocol. Older Span producers do not set this +/// field, consequently consumers should not rely on the absence of a +/// particular flag bit to indicate the presence of a particular feature. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum SpanFlags { + /// The zero value for the enum. Should not be used for comparisons. + /// Instead use bitwise "and" with the appropriate mask as shown above. + DoNotUse = 0, + /// Bits 0-7 are used for trace flags. + TraceFlagsMask = 255, + /// Bits 8 and 9 are used to indicate that the parent span or link span is remote. + /// Bit 8 (`HAS_IS_REMOTE`) indicates whether the value is known. + /// Bit 9 (`IS_REMOTE`) indicates whether the span or link is remote. + ContextHasIsRemoteMask = 256, + ContextIsRemoteMask = 512, +} +impl SpanFlags { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + SpanFlags::DoNotUse => "SPAN_FLAGS_DO_NOT_USE", + SpanFlags::TraceFlagsMask => "SPAN_FLAGS_TRACE_FLAGS_MASK", + SpanFlags::ContextHasIsRemoteMask => "SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK", + SpanFlags::ContextIsRemoteMask => "SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "SPAN_FLAGS_DO_NOT_USE" => Some(Self::DoNotUse), + "SPAN_FLAGS_TRACE_FLAGS_MASK" => Some(Self::TraceFlagsMask), + "SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK" => Some(Self::ContextHasIsRemoteMask), + "SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK" => Some(Self::ContextIsRemoteMask), + _ => None, + } + } +} diff --git a/opentelemetry-proto/src/lib.rs b/opentelemetry-proto/src/lib.rs new file mode 100644 index 0000000000..d9ed84a41f --- /dev/null +++ b/opentelemetry-proto/src/lib.rs @@ -0,0 +1,11 @@ +//! gRPC bindings for OpenTelemetry. +//! +//! Vendored from . + +// proto mod contains file generated by protobuf or other build tools. +// we shouldn't manually change it. Thus skip format and lint check. +#[rustfmt::skip] +#[allow(warnings)] +pub mod proto; + +pub mod transform; diff --git a/opentelemetry-proto/src/proto.rs b/opentelemetry-proto/src/proto.rs new file mode 100644 index 0000000000..46bf90c367 --- /dev/null +++ b/opentelemetry-proto/src/proto.rs @@ -0,0 +1,25 @@ +pub mod collector { + pub mod trace { + pub mod v1 { + include!("gen/opentelemetry.proto.collector.trace.v1.rs"); + } + } +} + +pub mod common { + pub mod v1 { + include!("gen/opentelemetry.proto.common.v1.rs"); + } +} + +pub mod trace { + pub mod v1 { + include!("gen/opentelemetry.proto.trace.v1.rs"); + } +} + +pub mod resource { + pub mod v1 { + include!("gen/opentelemetry.proto.resource.v1.rs"); + } +} \ No newline at end of file diff --git a/opentelemetry-proto/src/transform/common.rs b/opentelemetry-proto/src/transform/common.rs new file mode 100644 index 0000000000..d5e3230d37 --- /dev/null +++ b/opentelemetry-proto/src/transform/common.rs @@ -0,0 +1,148 @@ +use std::time::{Duration, SystemTime, UNIX_EPOCH}; + +pub(crate) fn to_nanos(time: SystemTime) -> u64 { + time.duration_since(UNIX_EPOCH) + .unwrap_or_else(|_| Duration::from_secs(0)) + .as_nanos() as u64 +} + +use crate::proto::common::v1::{any_value, AnyValue, ArrayValue, InstrumentationScope, KeyValue}; +use opentelemetry::{Array, Value}; +use std::borrow::Cow; + +#[derive(Debug, Default)] +pub struct ResourceAttributesWithSchema { + pub attributes: Attributes, + pub schema_url: Option, +} + +impl From<&opentelemetry_sdk::Resource> for ResourceAttributesWithSchema { + fn from(resource: &opentelemetry_sdk::Resource) -> Self { + ResourceAttributesWithSchema { + attributes: resource_attributes(resource), + schema_url: resource.schema_url().map(ToString::to_string), + } + } +} + +impl + From<( + opentelemetry_sdk::InstrumentationLibrary, + Option>, + )> for InstrumentationScope +{ + fn from( + data: ( + opentelemetry_sdk::InstrumentationLibrary, + Option>, + ), + ) -> Self { + let (library, target) = data; + if let Some(t) = target { + InstrumentationScope { + name: t.to_string(), + version: String::new(), + attributes: vec![], + ..Default::default() + } + } else { + InstrumentationScope { + name: library.name.into_owned(), + version: library.version.map(Cow::into_owned).unwrap_or_default(), + attributes: Attributes::from(library.attributes).0, + ..Default::default() + } + } + } +} + +impl + From<( + &opentelemetry_sdk::InstrumentationLibrary, + Option>, + )> for InstrumentationScope +{ + fn from( + data: ( + &opentelemetry_sdk::InstrumentationLibrary, + Option>, + ), + ) -> Self { + let (library, target) = data; + if let Some(t) = target { + InstrumentationScope { + name: t.to_string(), + version: String::new(), + attributes: vec![], + ..Default::default() + } + } else { + InstrumentationScope { + name: library.name.to_string(), + version: library + .version + .as_ref() + .map(ToString::to_string) + .unwrap_or_default(), + attributes: Attributes::from(library.attributes.clone()).0, + ..Default::default() + } + } + } +} + +/// Wrapper type for Vec<`KeyValue`> +#[derive(Default, Debug)] +pub struct Attributes(pub ::std::vec::Vec); + +impl From> for Attributes { + fn from(kvs: Vec) -> Self { + Attributes( + kvs.into_iter() + .map(|api_kv| KeyValue { + key: api_kv.key.as_str().to_string(), + value: Some(api_kv.value.into()), + }) + .collect(), + ) + } +} + +impl From for AnyValue { + fn from(value: Value) -> Self { + AnyValue { + value: match value { + Value::Bool(val) => Some(any_value::Value::BoolValue(val)), + Value::I64(val) => Some(any_value::Value::IntValue(val)), + Value::F64(val) => Some(any_value::Value::DoubleValue(val)), + Value::String(val) => Some(any_value::Value::StringValue(val.to_string())), + Value::Array(array) => Some(any_value::Value::ArrayValue(match array { + Array::Bool(vals) => array_into_proto(vals), + Array::I64(vals) => array_into_proto(vals), + Array::F64(vals) => array_into_proto(vals), + Array::String(vals) => array_into_proto(vals), + })), + }, + } + } +} + +fn array_into_proto(vals: Vec) -> ArrayValue +where + Value: From, +{ + let values = vals + .into_iter() + .map(|val| AnyValue::from(Value::from(val))) + .collect(); + + ArrayValue { values } +} + +pub(crate) fn resource_attributes(resource: &opentelemetry_sdk::Resource) -> Attributes { + resource + .iter() + .map(|(k, v)| opentelemetry::KeyValue::new(k.clone(), v.clone())) + .collect::>() + .into() +} diff --git a/opentelemetry-proto/src/transform/mod.rs b/opentelemetry-proto/src/transform/mod.rs new file mode 100644 index 0000000000..c764fb5e07 --- /dev/null +++ b/opentelemetry-proto/src/transform/mod.rs @@ -0,0 +1,2 @@ +pub mod common; +pub mod trace; diff --git a/opentelemetry-proto/src/transform/trace.rs b/opentelemetry-proto/src/transform/trace.rs new file mode 100644 index 0000000000..5fba33b960 --- /dev/null +++ b/opentelemetry-proto/src/transform/trace.rs @@ -0,0 +1,345 @@ +use crate::proto::resource::v1::Resource; +use crate::proto::trace::v1::{span, status, ResourceSpans, ScopeSpans, Span, Status}; +use crate::transform::common::{to_nanos, Attributes, ResourceAttributesWithSchema}; +use opentelemetry::trace; +use opentelemetry::trace::{Link, SpanId, SpanKind}; +use opentelemetry_sdk::export::trace::SpanData; +use std::collections::HashMap; + +impl From for span::SpanKind { + fn from(span_kind: SpanKind) -> Self { + match span_kind { + SpanKind::Client => span::SpanKind::Client, + SpanKind::Consumer => span::SpanKind::Consumer, + SpanKind::Internal => span::SpanKind::Internal, + SpanKind::Producer => span::SpanKind::Producer, + SpanKind::Server => span::SpanKind::Server, + } + } +} + +impl From<&trace::Status> for status::StatusCode { + fn from(status: &trace::Status) -> Self { + match status { + trace::Status::Ok => status::StatusCode::Ok, + trace::Status::Unset => status::StatusCode::Unset, + trace::Status::Error { .. } => status::StatusCode::Error, + } + } +} + +impl From for span::Link { + fn from(link: Link) -> Self { + span::Link { + trace_id: link.span_context.trace_id().to_bytes().to_vec(), + span_id: link.span_context.span_id().to_bytes().to_vec(), + trace_state: link.span_context.trace_state().header(), + attributes: Attributes::from(link.attributes).0, + dropped_attributes_count: link.dropped_attributes_count, + flags: link.span_context.trace_flags().to_u8() as u32, + } + } +} +impl From for Span { + fn from(source_span: opentelemetry_sdk::export::trace::SpanData) -> Self { + let span_kind: span::SpanKind = source_span.span_kind.into(); + Span { + trace_id: source_span.span_context.trace_id().to_bytes().to_vec(), + span_id: source_span.span_context.span_id().to_bytes().to_vec(), + trace_state: source_span.span_context.trace_state().header(), + parent_span_id: { + if source_span.parent_span_id != SpanId::INVALID { + source_span.parent_span_id.to_bytes().to_vec() + } else { + vec![] + } + }, + flags: source_span.span_context.trace_flags().to_u8() as u32, + name: source_span.name.into_owned(), + kind: span_kind as i32, + start_time_unix_nano: to_nanos(source_span.start_time), + end_time_unix_nano: to_nanos(source_span.end_time), + dropped_attributes_count: source_span.dropped_attributes_count, + attributes: Attributes::from(source_span.attributes).0, + dropped_events_count: source_span.events.dropped_count, + events: source_span + .events + .into_iter() + .map(|event| span::Event { + time_unix_nano: to_nanos(event.timestamp), + name: event.name.into(), + attributes: Attributes::from(event.attributes).0, + dropped_attributes_count: event.dropped_attributes_count, + }) + .collect(), + dropped_links_count: source_span.links.dropped_count, + links: source_span.links.into_iter().map(Into::into).collect(), + status: Some(Status { + code: status::StatusCode::from(&source_span.status).into(), + message: match source_span.status { + trace::Status::Error { description } => description.to_string(), + _ => Default::default(), + }, + }), + } + } +} + +impl ResourceSpans { + pub fn new(source_span: SpanData, resource: &ResourceAttributesWithSchema) -> Self { + let span_kind: span::SpanKind = source_span.span_kind.into(); + ResourceSpans { + resource: Some(Resource { + attributes: resource.attributes.0.clone(), + dropped_attributes_count: 0, + }), + schema_url: resource.schema_url.clone().unwrap_or_default(), + scope_spans: vec![ScopeSpans { + schema_url: source_span + .instrumentation_lib + .schema_url + .as_ref() + .map(ToString::to_string) + .unwrap_or_default(), + scope: Some((source_span.instrumentation_lib, None).into()), + spans: vec![Span { + trace_id: source_span.span_context.trace_id().to_bytes().to_vec(), + span_id: source_span.span_context.span_id().to_bytes().to_vec(), + trace_state: source_span.span_context.trace_state().header(), + parent_span_id: { + if source_span.parent_span_id != SpanId::INVALID { + source_span.parent_span_id.to_bytes().to_vec() + } else { + vec![] + } + }, + flags: source_span.span_context.trace_flags().to_u8() as u32, + name: source_span.name.into_owned(), + kind: span_kind as i32, + start_time_unix_nano: to_nanos(source_span.start_time), + end_time_unix_nano: to_nanos(source_span.end_time), + dropped_attributes_count: source_span.dropped_attributes_count, + attributes: Attributes::from(source_span.attributes).0, + dropped_events_count: source_span.events.dropped_count, + events: source_span + .events + .into_iter() + .map(|event| span::Event { + time_unix_nano: to_nanos(event.timestamp), + name: event.name.into(), + attributes: Attributes::from(event.attributes).0, + dropped_attributes_count: event.dropped_attributes_count, + }) + .collect(), + dropped_links_count: source_span.links.dropped_count, + links: source_span.links.into_iter().map(Into::into).collect(), + status: Some(Status { + code: status::StatusCode::from(&source_span.status).into(), + message: match source_span.status { + trace::Status::Error { description } => description.to_string(), + _ => Default::default(), + }, + }), + }], + }], + } + } +} + +pub fn group_spans_by_resource_and_scope( + spans: Vec, + resource: &ResourceAttributesWithSchema, +) -> Vec { + // Group spans by their instrumentation library + let scope_map = spans.iter().fold( + HashMap::new(), + |mut scope_map: HashMap<&opentelemetry_sdk::InstrumentationLibrary, Vec<&SpanData>>, + span| { + let instrumentation = &span.instrumentation_lib; + scope_map.entry(instrumentation).or_default().push(span); + scope_map + }, + ); + + // Convert the grouped spans into ScopeSpans + let scope_spans = scope_map + .into_iter() + .map(|(instrumentation, span_records)| ScopeSpans { + scope: Some((instrumentation, None).into()), + schema_url: resource.schema_url.clone().unwrap_or_default(), + spans: span_records + .into_iter() + .map(|span_data| span_data.clone().into()) + .collect(), + }) + .collect(); + + // Wrap ScopeSpans into a single ResourceSpans + vec![ResourceSpans { + resource: Some(Resource { + attributes: resource.attributes.0.clone(), + dropped_attributes_count: 0, + }), + scope_spans, + schema_url: resource.schema_url.clone().unwrap_or_default(), + }] +} + +#[cfg(test)] +mod tests { + use crate::proto::common::v1::any_value::Value; + use crate::transform::common::ResourceAttributesWithSchema; + use opentelemetry::trace::{ + SpanContext, SpanId, SpanKind, Status, TraceFlags, TraceId, TraceState, + }; + use opentelemetry::KeyValue; + use opentelemetry_sdk::export::trace::SpanData; + use opentelemetry_sdk::resource::Resource; + use opentelemetry_sdk::trace::{SpanEvents, SpanLinks}; + use opentelemetry_sdk::InstrumentationLibrary; + use std::borrow::Cow; + use std::time::{Duration, SystemTime}; + + fn create_test_span_data(instrumentation_name: &'static str) -> SpanData { + let span_context = SpanContext::new( + TraceId::from_u128(123), + SpanId::from_u64(456), + TraceFlags::default(), + false, + TraceState::default(), + ); + + SpanData { + span_context, + parent_span_id: SpanId::from_u64(0), + span_kind: SpanKind::Internal, + name: Cow::Borrowed("test_span"), + start_time: SystemTime::now(), + end_time: SystemTime::now() + Duration::from_secs(1), + attributes: vec![KeyValue::new("key", "value")], + dropped_attributes_count: 0, + events: SpanEvents::default(), + links: SpanLinks::default(), + status: Status::Unset, + resource: Default::default(), + instrumentation_lib: InstrumentationLibrary::builder(instrumentation_name).build(), + } + } + + #[test] + fn test_group_spans_by_resource_and_scope_single_scope() { + let resource = Resource::new(vec![KeyValue::new("resource_key", "resource_value")]); + let span_data = create_test_span_data("lib1"); + + let spans = vec![span_data.clone()]; + let resource: ResourceAttributesWithSchema = (&resource).into(); // Convert Resource to ResourceAttributesWithSchema + + let grouped_spans = + crate::transform::trace::group_spans_by_resource_and_scope(spans, &resource); + + assert_eq!(grouped_spans.len(), 1); + + let resource_spans = &grouped_spans[0]; + assert_eq!( + resource_spans.resource.as_ref().unwrap().attributes.len(), + 1 + ); + assert_eq!( + resource_spans.resource.as_ref().unwrap().attributes[0].key, + "resource_key" + ); + assert_eq!( + resource_spans.resource.as_ref().unwrap().attributes[0] + .value + .clone() + .unwrap() + .value + .unwrap(), + Value::StringValue("resource_value".to_string()) + ); + + let scope_spans = &resource_spans.scope_spans; + assert_eq!(scope_spans.len(), 1); + + let scope_span = &scope_spans[0]; + assert_eq!(scope_span.scope.as_ref().unwrap().name, "lib1"); + assert_eq!(scope_span.spans.len(), 1); + + assert_eq!( + scope_span.spans[0].trace_id, + span_data.span_context.trace_id().to_bytes().to_vec() + ); + } + + #[test] + fn test_group_spans_by_resource_and_scope_multiple_scopes() { + let resource = Resource::new(vec![KeyValue::new("resource_key", "resource_value")]); + let span_data1 = create_test_span_data("lib1"); + let span_data2 = create_test_span_data("lib1"); + let span_data3 = create_test_span_data("lib2"); + + let spans = vec![span_data1.clone(), span_data2.clone(), span_data3.clone()]; + let resource: ResourceAttributesWithSchema = (&resource).into(); // Convert Resource to ResourceAttributesWithSchema + + let grouped_spans = + crate::transform::trace::group_spans_by_resource_and_scope(spans, &resource); + + assert_eq!(grouped_spans.len(), 1); + + let resource_spans = &grouped_spans[0]; + assert_eq!( + resource_spans.resource.as_ref().unwrap().attributes.len(), + 1 + ); + assert_eq!( + resource_spans.resource.as_ref().unwrap().attributes[0].key, + "resource_key" + ); + assert_eq!( + resource_spans.resource.as_ref().unwrap().attributes[0] + .value + .clone() + .unwrap() + .value + .unwrap(), + Value::StringValue("resource_value".to_string()) + ); + + let scope_spans = &resource_spans.scope_spans; + assert_eq!(scope_spans.len(), 2); + + // Check the scope spans for both lib1 and lib2 + let mut lib1_scope_span = None; + let mut lib2_scope_span = None; + + for scope_span in scope_spans { + match scope_span.scope.as_ref().unwrap().name.as_str() { + "lib1" => lib1_scope_span = Some(scope_span), + "lib2" => lib2_scope_span = Some(scope_span), + _ => {} + } + } + + let lib1_scope_span = lib1_scope_span.expect("lib1 scope span not found"); + let lib2_scope_span = lib2_scope_span.expect("lib2 scope span not found"); + + assert_eq!(lib1_scope_span.scope.as_ref().unwrap().name, "lib1"); + assert_eq!(lib2_scope_span.scope.as_ref().unwrap().name, "lib2"); + + assert_eq!(lib1_scope_span.spans.len(), 2); + assert_eq!(lib2_scope_span.spans.len(), 1); + + assert_eq!( + lib1_scope_span.spans[0].trace_id, + span_data1.span_context.trace_id().to_bytes().to_vec() + ); + assert_eq!( + lib1_scope_span.spans[1].trace_id, + span_data2.span_context.trace_id().to_bytes().to_vec() + ); + assert_eq!( + lib2_scope_span.spans[0].trace_id, + span_data3.span_context.trace_id().to_bytes().to_vec() + ); + } +} diff --git a/opentelemetry-proto/tests/bootstrap.rs b/opentelemetry-proto/tests/bootstrap.rs new file mode 100644 index 0000000000..2e06255edc --- /dev/null +++ b/opentelemetry-proto/tests/bootstrap.rs @@ -0,0 +1,52 @@ +//! A test that regenerates the Rust protobuf bindings. +//! +//! It can be run via: +//! +//! ```no_run +//! cargo test -p opentelmetry-proto --test=bootstrap +//! ``` + +/// Generates protobuf bindings into src/gen and fails if the generated files do +/// not match those that are already checked into git +#[test] +fn bootstrap() { + let out_dir = std::path::PathBuf::from(std::env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("gen"); + generate(&out_dir); + if changed(&out_dir) { + panic!("protobuf interfaces do not match generated sources"); + } +} + +/// Generates protobuf bindings into the given directory +fn generate(out_dir: &std::path::Path) { + let iface_files = &[ + "opentelemetry/proto/collector/trace/v1/trace_service.proto", + "opentelemetry/proto/common/v1/common.proto", + "opentelemetry/proto/resource/v1/resource.proto", + "opentelemetry/proto/trace/v1/trace.proto", + ]; + if let Err(error) = tonic_build::configure() + .build_client(true) + .build_server(false) + .emit_rerun_if_changed(false) + .out_dir(out_dir) + .compile(iface_files, &["."]) + { + panic!("failed to compile protobuf: {error}") + } +} + +/// Returns true if the given path contains files that have changed since the +/// last Git commit +fn changed(path: &std::path::Path) -> bool { + let status = std::process::Command::new("git") + .arg("diff") + .arg("--exit-code") + .arg("--") + .arg(path) + .status() + .expect("failed to run git"); + !status.success() +} From a1d3c79af3d59d59d720d794604d1e128977e21c Mon Sep 17 00:00:00 2001 From: Scott Fleener Date: Mon, 23 Sep 2024 19:49:21 +0000 Subject: [PATCH 03/42] Add OpenTelemetry exporter implementation This duplicates most of the logic from the existing OpenCensus exporter to keep the functionality as similar as possible. [#10111](linkerd/linkerd2#10111) Signed-off-by: Scott Fleener --- Cargo.lock | 18 +++ Cargo.toml | 1 + linkerd/opentelemetry/Cargo.toml | 24 +++ linkerd/opentelemetry/src/lib.rs | 212 +++++++++++++++++++++++++++ linkerd/opentelemetry/src/metrics.rs | 58 ++++++++ 5 files changed, 313 insertions(+) create mode 100644 linkerd/opentelemetry/Cargo.toml create mode 100644 linkerd/opentelemetry/src/lib.rs create mode 100644 linkerd/opentelemetry/src/metrics.rs diff --git a/Cargo.lock b/Cargo.lock index 9f811ebb45..bce8c03238 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1750,6 +1750,24 @@ dependencies = [ "tracing", ] +[[package]] +name = "linkerd-opentelemetry" +version = "0.1.0" +dependencies = [ + "futures", + "http", + "http-body", + "linkerd-error", + "linkerd-metrics", + "opentelemetry", + "opentelemetry-proto", + "opentelemetry_sdk", + "tokio", + "tokio-stream", + "tonic", + "tracing", +] + [[package]] name = "linkerd-pool" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index bfb8093e4d..29f9651998 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,7 @@ members = [ "linkerd/meshtls/verifier", "linkerd/metrics", "linkerd/opencensus", + "linkerd/opentelemetry", "linkerd/pool", "linkerd/pool/mock", "linkerd/pool/p2c", diff --git a/linkerd/opentelemetry/Cargo.toml b/linkerd/opentelemetry/Cargo.toml new file mode 100644 index 0000000000..78c0ae7f72 --- /dev/null +++ b/linkerd/opentelemetry/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "linkerd-opentelemetry" +version = "0.1.0" +authors = ["Linkerd Developers "] +license = "Apache-2.0" +edition = "2021" +publish = false + +[dependencies] +futures = { version = "0.3", default-features = false } +http = "0.2" +http-body = "0.4" +linkerd-error = { path = "../error" } +linkerd-metrics = { path = "../metrics" } +opentelemetry = { version = "0.23", default-features = false, features = ["trace"] } +opentelemetry_sdk = { version = "0.23", default-features = false, features = ["trace"] } +opentelemetry-proto = { path = "../../opentelemetry-proto" } +tonic = { version = "0.10", default-features = false, features = [ + "prost", + "codegen", +] } +tokio = { version = "1", features = ["macros", "sync", "time"] } +tokio-stream = { version = "0.1", features = ["sync"] } +tracing = "0.1" diff --git a/linkerd/opentelemetry/src/lib.rs b/linkerd/opentelemetry/src/lib.rs new file mode 100644 index 0000000000..2f983cade7 --- /dev/null +++ b/linkerd/opentelemetry/src/lib.rs @@ -0,0 +1,212 @@ +#![deny(rust_2018_idioms, clippy::disallowed_methods, clippy::disallowed_types)] +#![forbid(unsafe_code)] + +pub mod metrics; + +use futures::stream::{Stream, StreamExt}; +use http_body::Body as HttpBody; +use linkerd_error::Error; +use metrics::Registry; +pub use opentelemetry_proto as proto; +use opentelemetry_proto::proto::collector::trace::v1::trace_service_client::TraceServiceClient; +use opentelemetry_proto::proto::collector::trace::v1::ExportTraceServiceRequest; +use opentelemetry_proto::proto::trace::v1::ResourceSpans; +use opentelemetry_proto::transform::common::ResourceAttributesWithSchema; +use opentelemetry_proto::transform::trace::group_spans_by_resource_and_scope; +pub use opentelemetry_sdk::export::trace::SpanData; +use tokio::{sync::mpsc, time}; +use tonic::{self as grpc, body::BoxBody, client::GrpcService}; +use tracing::{debug, trace}; + +pub async fn export_spans( + client: T, + spans: S, + resource: ResourceAttributesWithSchema, + metrics: Registry, +) where + T: GrpcService + Clone, + T::Error: Into, + T::ResponseBody: Default + HttpBody + Send + 'static, + ::Error: Into + Send, + S: Stream + Unpin, +{ + debug!("Span exporter running"); + SpanExporter::new(client, spans, resource, metrics) + .run() + .await +} + +/// SpanExporter sends a Stream of spans to the given TraceService gRPC service. +struct SpanExporter { + client: T, + spans: S, + resource: ResourceAttributesWithSchema, + metrics: Registry, +} + +#[derive(Debug)] +struct SpanRxClosed; + +// === impl SpanExporter === + +impl SpanExporter +where + T: GrpcService + Clone, + T::Error: Into, + T::ResponseBody: Default + HttpBody + Send + 'static, + ::Error: Into + Send, + S: Stream + Unpin, +{ + const MAX_BATCH_SIZE: usize = 1000; + const MAX_BATCH_IDLE: time::Duration = time::Duration::from_secs(10); + + fn new(client: T, spans: S, resource: ResourceAttributesWithSchema, metrics: Registry) -> Self { + Self { + client, + spans, + resource, + metrics, + } + } + + async fn run(self) { + let Self { + client, + mut spans, + resource, + mut metrics, + } = self; + + // Holds the batch of pending spans. Cleared as the spans are flushed. + // Contains no more than MAX_BATCH_SIZE spans. + let mut accum = Vec::new(); + + let mut svc = TraceServiceClient::new(client); + loop { + trace!("Establishing new TraceService::export request"); + metrics.start_stream(); + let (tx, mut rx) = mpsc::channel(1); + + let recv_future = async { + while let Some(req) = rx.recv().await { + match svc.export(grpc::Request::new(req)).await { + Ok(rsp) => { + let Some(partial_success) = rsp.into_inner().partial_success else { + continue; + }; + + if !partial_success.error_message.is_empty() { + debug!( + %partial_success.error_message, + rejected_spans = partial_success.rejected_spans, + "Response partially successful", + ); + } + } + Err(error) => { + debug!(%error, "Response future failed; restarting"); + } + } + } + }; + + // Drive both the response future and the export stream + // simultaneously. + tokio::select! { + _ = recv_future => {} + res = Self::export(&tx, &mut spans, &resource, &mut accum) => match res { + // The export stream closed; reconnect. + Ok(()) => {}, + // No more spans. + Err(SpanRxClosed) => return, + }, + } + } + } + + /// Accumulate spans and send them on the export stream. + /// + /// Returns an error when the proxy has closed the span stream. + async fn export( + tx: &mpsc::Sender, + spans: &mut S, + resource: &ResourceAttributesWithSchema, + accum: &mut Vec, + ) -> Result<(), SpanRxClosed> { + loop { + // Collect spans into a batch. + let collect = Self::collect_batch(spans, resource, accum).await; + + // If we collected spans, flush them. + if !accum.is_empty() { + // Once a batch has been accumulated, ensure that the + // request stream is ready to accept the batch. + match tx.reserve().await { + Ok(tx) => { + let msg = ExportTraceServiceRequest { + resource_spans: std::mem::take(accum), + }; + trace!(spans = msg.resource_spans.len(), "Sending batch"); + tx.send(msg); + } + Err(error) => { + // If the channel isn't open, start a new stream + // and retry sending the batch. + debug!(%error, "Request stream lost; restarting"); + return Ok(()); + } + } + } + + // If the span source was closed, end the task. + if let Err(closed) = collect { + debug!("Span channel lost"); + return Err(closed); + } + } + } + + /// Collects spans from the proxy into `accum`. + /// + /// Returns an error when the span stream has completed. An error may be + /// returned after accumulating spans. + async fn collect_batch( + span_stream: &mut S, + resource: &ResourceAttributesWithSchema, + accum: &mut Vec, + ) -> Result<(), SpanRxClosed> { + let mut input_accum: Vec = vec![]; + + let res = loop { + if input_accum.len() == Self::MAX_BATCH_SIZE { + trace!(capacity = Self::MAX_BATCH_SIZE, "Batch capacity reached"); + break Ok(()); + } + + tokio::select! { + biased; + + res = span_stream.next() => match res { + Some(span) => { + trace!(?span, "Adding to batch"); + input_accum.push(span); + } + None => break Err(SpanRxClosed), + }, + + // Don't hold spans indefinitely. Return if we hit an idle + // timeout and spans have been collected. + _ = time::sleep(Self::MAX_BATCH_IDLE) => { + if !input_accum.is_empty() { + trace!(spans = input_accum.len(), "Flushing spans due to inactivitiy"); + break Ok(()); + } + } + } + }; + + *accum = group_spans_by_resource_and_scope(input_accum, resource); + + res + } +} diff --git a/linkerd/opentelemetry/src/metrics.rs b/linkerd/opentelemetry/src/metrics.rs new file mode 100644 index 0000000000..5c785de9d4 --- /dev/null +++ b/linkerd/opentelemetry/src/metrics.rs @@ -0,0 +1,58 @@ +use linkerd_metrics::{metrics, Counter, FmtMetrics}; +use std::fmt; +use std::sync::Arc; + +metrics! { + opentelemetry_span_export_streams: Counter { "Total count of opened span export streams" }, + opentelemetry_span_export_requests: Counter { "Total count of span export request messages" }, + opentelemetry_span_exports: Counter { "Total count of spans exported" } +} + +#[derive(Debug)] +struct Metrics { + streams: Counter, + requests: Counter, + spans: Counter, +} + +#[derive(Clone, Debug)] +pub struct Registry(Arc); + +#[derive(Clone, Debug)] +pub struct Report(Arc); + +pub fn new() -> (Registry, Report) { + let metrics = Metrics { + streams: Counter::default(), + requests: Counter::default(), + spans: Counter::default(), + }; + let shared = Arc::new(metrics); + (Registry(shared.clone()), Report(shared)) +} + +impl Registry { + pub fn start_stream(&mut self) { + self.0.streams.incr() + } + + pub fn send(&mut self, spans: u64) { + self.0.requests.incr(); + self.0.spans.add(spans); + } +} + +impl FmtMetrics for Report { + fn fmt_metrics(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + opentelemetry_span_export_streams.fmt_help(f)?; + opentelemetry_span_export_streams.fmt_metric(f, &self.0.streams)?; + + opentelemetry_span_export_requests.fmt_help(f)?; + opentelemetry_span_export_requests.fmt_metric(f, &self.0.requests)?; + + opentelemetry_span_exports.fmt_help(f)?; + opentelemetry_span_exports.fmt_metric(f, &self.0.spans)?; + + Ok(()) + } +} From 67ed1212097987a4e61f832980ca73be6d976ad0 Mon Sep 17 00:00:00 2001 From: katelyn martin Date: Mon, 23 Sep 2024 17:51:13 -0400 Subject: [PATCH 04/42] fix(retry): Avoid panicking if responses come early (#3216) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `linkerd-http-retry` and `linkerd-retry` provide generic `tower` middleware to allow services to retry requests that fail. part of this middleware hinges on a `ReplayBody` that will lazily buffer request bodies' data for use in subsequent attempts. if a request fails, the retry middleware will attempt to send another request, assuming the original body was able to completely fit into this buffer. `ReplayBody` makes a subtle assummption, most succinctly stated in this excerpt of an internal method's documentation: ```rust // linkerd/http/retry/src/replay.rs impl ReplayBody { /// This panics if another clone has currently acquired the state, based on /// the assumption that a retry body will not be polled until the previous /// request has been dropped. fn acquire_state<'a>( state: &'a mut Option>, shared: &Mutex>>, ) -> &'a mut BodyState { // ... } } ``` this assumption is slightly at odds with the request/response lifecycle permitted within the HTTP/2 specification. see RFC 9113 § 8.1, "_HTTP Message Framing_" (emphasis added): > .. > An HTTP request/response exchange fully consumes a single stream. A > request starts with the HEADERS frame that puts the stream into the > "open" state. **The request ends with a frame with the END_STREAM flag > set**, which causes the stream to become "half-closed (local)" for the > client and "half-closed (remote)" for the server. A response stream > starts with zero or more interim responses in HEADERS frames, followed > by a HEADERS frame containing a final status code. > > An HTTP response is complete after the server sends -- or the client > receives -- a frame with the END_STREAM flag set (including any > CONTINUATION frames needed to complete a field block). **A server can > send a complete response prior to the client sending an entire request > if the response does not depend on any portion of the request that has > not been sent and received.** because of this, a retry may panic when checking if the previous request body was capped, if a server delivers a response before the request is complete. this has been observed when retrying [wire-grpc](https://github.com/square/wire) requests, manifesting in a panic with this message: ```text thread 'main' panicked at 'if our `state` was `None`, the shared state must be `Some`', /__w/linkerd2-proxy/linkerd2-proxy/linkerd/http-retry/src/replay.rs:152:22 ``` this commit refactors `ReplayBody::is_capped()` so that it will no longer panic if there is an outstanding body still being polled. rather, it will return `Some(true)` or `Some(false)` if the previous body was capped, or `None` if it has not finished streaming. the related logic in the `linkerd-http-retry` library is updated to refrain from attempting a retry if a response is received before the request stream was completed. Signed-off-by: katelyn martin --- linkerd/app/outbound/src/http/retry.rs | 13 +++++++++++-- linkerd/http/retry/src/lib.rs | 7 +++++-- linkerd/http/retry/src/replay.rs | 16 ++++++---------- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/linkerd/app/outbound/src/http/retry.rs b/linkerd/app/outbound/src/http/retry.rs index ef9a90fe87..427587d5f0 100644 --- a/linkerd/app/outbound/src/http/retry.rs +++ b/linkerd/app/outbound/src/http/retry.rs @@ -93,8 +93,17 @@ where .is_failure(); // did the body exceed the maximum length limit? let exceeded_max_len = req.body().is_capped(); - let retryable = is_failure && !exceeded_max_len; - tracing::trace!(is_failure, exceeded_max_len, retryable); + let retryable = if let Some(false) = exceeded_max_len { + // If the body hasn't exceeded our length limit, we should + // retry the request if it's a failure of some sort. + is_failure + } else { + // We received a response before the request body was fully + // finished streaming. To be safe, we will consider this + // as an unretryable request. + false + }; + tracing::trace!(is_failure, ?exceeded_max_len, retryable); retryable } }; diff --git a/linkerd/http/retry/src/lib.rs b/linkerd/http/retry/src/lib.rs index ac07c6c868..5c47cc2c64 100644 --- a/linkerd/http/retry/src/lib.rs +++ b/linkerd/http/retry/src/lib.rs @@ -268,7 +268,10 @@ async fn send_req_with_retries( tracing::trace!("Success on first attempt"); return result.map(|rsp| rsp.map(BoxBody::new)); } - if backup.body().is_capped() { + if matches!(backup.body().is_capped(), None | Some(true)) { + // The body was either too large, or we received an early response + // before the request body was completed read. We cannot safely + // attempt to send this request again. return result.map(|rsp| rsp.map(BoxBody::new)); } @@ -300,7 +303,7 @@ async fn send_req_with_retries( tracing::debug!("Retry success"); return result.map(|rsp| rsp.map(BoxBody::new)); } - if backup.body().is_capped() { + if matches!(backup.body().is_capped(), None | Some(true)) { return result.map(|rsp| rsp.map(BoxBody::new)); } } diff --git a/linkerd/http/retry/src/replay.rs b/linkerd/http/retry/src/replay.rs index ff53843146..e57f80991d 100644 --- a/linkerd/http/retry/src/replay.rs +++ b/linkerd/http/retry/src/replay.rs @@ -136,23 +136,19 @@ impl ReplayBody { state.get_or_insert_with(|| shared.lock().take().expect("missing body state")) } - /// Returns `true` if the body previously exceeded the configured maximum + /// Returns `Some(true)` if the body previously exceeded the configured maximum /// length limit. /// /// If this is true, the body is now empty, and the request should *not* be /// retried with this body. - pub fn is_capped(&self) -> bool { + /// + /// If this is `None`, another clone has currently acquired the state, and is + /// still being polled. + pub fn is_capped(&self) -> Option { self.state .as_ref() .map(BodyState::is_capped) - .unwrap_or_else(|| { - self.shared - .body - .lock() - .as_ref() - .expect("if our `state` was `None`, the shared state must be `Some`") - .is_capped() - }) + .or_else(|| self.shared.body.lock().as_ref().map(BodyState::is_capped)) } } From 87cb8fd02e1197ef085e71a363053ea43e2433b5 Mon Sep 17 00:00:00 2001 From: Scott Fleener Date: Tue, 24 Sep 2024 15:16:04 +0000 Subject: [PATCH 05/42] Group opentelemetry dependency updates OpenTelemetry packages should always be updated in lockstep with each other. This tells dependabot to group dependency updates into a single PR: https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#groups Signed-off-by: Scott Fleener --- .github/dependabot.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 48a3bc7591..c492558f7d 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -24,6 +24,10 @@ updates: - dependency-name: "wasm-bindgen" - dependency-name: "web-sys" - dependency-name: "windows*" + groups: + opentelemetry: + patterns: + - "opentelemetry*" - package-ecosystem: cargo directory: /linkerd/addr/fuzz From 44c610aae7a050a4e82c00a6fc8ff6039d456a27 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 13:06:24 -0700 Subject: [PATCH 06/42] build(deps): bump libc from 0.2.158 to 0.2.159 (#3226) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.158 to 0.2.159. - [Release notes](https://github.com/rust-lang/libc/releases) - [Changelog](https://github.com/rust-lang/libc/blob/0.2.159/CHANGELOG.md) - [Commits](https://github.com/rust-lang/libc/compare/0.2.158...0.2.159) --- updated-dependencies: - dependency-name: libc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bce8c03238..437cf92e61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1073,9 +1073,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.158" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libfuzzer-sys" From d05b616949e547ce9551425df1d2dc49328e4d8e Mon Sep 17 00:00:00 2001 From: katelyn martin Date: Tue, 24 Sep 2024 16:35:56 -0400 Subject: [PATCH 07/42] docs(http/prom): Document request count middleware (#3228) this is a light documentation pass outlining how the request counting middleware fits together. Signed-off-by: katelyn martin --- linkerd/http/prom/src/count_reqs.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/linkerd/http/prom/src/count_reqs.rs b/linkerd/http/prom/src/count_reqs.rs index e2092fbdbc..ce0ea296d7 100644 --- a/linkerd/http/prom/src/count_reqs.rs +++ b/linkerd/http/prom/src/count_reqs.rs @@ -1,3 +1,5 @@ +//! A Tower middleware for counting requests processed by a service. + use linkerd_stack as svc; use prometheus_client::{ encoding::EncodeLabelSet, @@ -6,18 +8,29 @@ use prometheus_client::{ }; use std::task::{Context, Poll}; +/// A [`Family`] of counters with `L`-encoded labels. +/// +/// See [`EncodeLabelSet`] for more information about encoding labels. #[derive(Clone, Debug)] pub struct RequestCountFamilies(Family); +// A single [`Counter`] that tracks the number of requests. #[derive(Clone, Debug)] pub struct RequestCount(Counter); +/// A [`NewService`][svc::NewService] that creates [`RequestCount`] services. #[derive(Clone, Debug)] pub struct NewCountRequests { + /// The inner [`NewService`][svc::NewService]. inner: N, + /// The [`ExtractParam`][svc::ExtractParam] strategy for obtaining our parameters. extract: X, } +/// Counts requests for an inner `S`-typed [`Service`][svc::Service]. +/// +/// This will increment its counter when [`call()`][svc::Service::call]ed, before calling the inner +/// service. #[derive(Clone, Debug)] pub struct CountRequests { inner: S, @@ -31,6 +44,10 @@ impl NewCountRequests { Self { extract, inner } } + /// Returns a [`Layer`] that counts requests. + /// + /// This uses an `X`-typed [`ExtractParam`] implementation to extract [`RequestCount`] from a + /// `T`-typed target. pub fn layer_via(extract: X) -> impl svc::layer::Layer + Clone { svc::layer::mk(move |inner| Self::new(extract.clone(), inner)) } @@ -72,6 +89,7 @@ where } fn call(&mut self, req: http::Request) -> Self::Future { + // We received a request! Increment the counter and then call the inner service `S`. self.requests.inc(); self.inner.call(req) } @@ -94,6 +112,7 @@ where L: EncodeLabelSet + std::fmt::Debug + std::hash::Hash, L: Eq + Clone + Send + Sync + 'static, { + /// Registers this family of counters with the given [`Registry`]. pub fn register(registry: &mut Registry) -> Self { let requests = Family::default(); registry.register( @@ -104,6 +123,7 @@ where Self(requests) } + /// Returns a [`RequestCount`] for the given label set. pub fn metrics(&self, labels: &L) -> RequestCount { RequestCount(self.0.get_or_create(labels).clone()) } @@ -112,6 +132,7 @@ where // === impl RequestCount === impl RequestCount { + /// Returns the current value of the counter. pub fn get(&self) -> u64 { self.0.get() } From ca612202d589afa4298889f90ddcd4c26716a389 Mon Sep 17 00:00:00 2001 From: katelyn martin Date: Tue, 24 Sep 2024 16:36:18 -0400 Subject: [PATCH 08/42] chore(app): Disallow warnings in policy router's backend metrics (#3227) a stray `#![allow(warnings)]` directive seems to have slipped in from an initial prototyping phase. this commit removes this directive from `/linkerd/app/outbound/src/http/logical/policy/route/backend/metrics.rs`, and addresses the newly unearthed warnings, related to unused imports. Signed-off-by: katelyn martin --- .../src/http/logical/policy/route/backend/metrics.rs | 8 +------- .../http/logical/policy/route/backend/metrics/tests.rs | 4 +--- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/linkerd/app/outbound/src/http/logical/policy/route/backend/metrics.rs b/linkerd/app/outbound/src/http/logical/policy/route/backend/metrics.rs index 0d79f95b5a..3e2684bed1 100644 --- a/linkerd/app/outbound/src/http/logical/policy/route/backend/metrics.rs +++ b/linkerd/app/outbound/src/http/logical/policy/route/backend/metrics.rs @@ -1,11 +1,5 @@ -#![allow(warnings)] - use crate::{BackendRef, ParentRef, RouteRef}; -use futures::Stream; -use linkerd_app_core::{ - metrics::prom::{self, encoding::*, EncodeLabelSetMut}, - svc, -}; +use linkerd_app_core::{metrics::prom, svc}; use linkerd_http_prom::{ record_response::{self, NewResponseDuration, StreamLabel}, NewCountRequests, RequestCount, RequestCountFamilies, diff --git a/linkerd/app/outbound/src/http/logical/policy/route/backend/metrics/tests.rs b/linkerd/app/outbound/src/http/logical/policy/route/backend/metrics/tests.rs index bcca14482d..1ba6427e6f 100644 --- a/linkerd/app/outbound/src/http/logical/policy/route/backend/metrics/tests.rs +++ b/linkerd/app/outbound/src/http/logical/policy/route/backend/metrics/tests.rs @@ -5,10 +5,8 @@ use super::{ LabelGrpcRouteBackendRsp, LabelHttpRouteBackendRsp, RouteBackendMetrics, }; use crate::http::{concrete, logical::Concrete}; -use linkerd2_proxy_api::outbound::backend; use linkerd_app_core::{ - metrics::prom::Counter, - svc::{self, http::BoxBody, Layer, NewService, Service, ServiceExt}, + svc::{self, http::BoxBody, Layer, NewService}, transport::{Remote, ServerAddr}, }; use linkerd_proxy_client_policy as policy; From 65b7fec2f284806b90b920b2f3fa51309375d1f6 Mon Sep 17 00:00:00 2001 From: katelyn martin Date: Wed, 25 Sep 2024 08:33:35 -0400 Subject: [PATCH 09/42] chore(app): Add `impl` banner comments (#3231) the equivalent blocks in the parent `route.rs` file have the same `// === impl T ===` blocks that are added here. these are introduced, because they help visually group impl blocks when code in these files is folded. Signed-off-by: katelyn martin --- .../app/outbound/src/http/logical/policy/route/backend.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/linkerd/app/outbound/src/http/logical/policy/route/backend.rs b/linkerd/app/outbound/src/http/logical/policy/route/backend.rs index 6ee2c507a3..9005830546 100644 --- a/linkerd/app/outbound/src/http/logical/policy/route/backend.rs +++ b/linkerd/app/outbound/src/http/logical/policy/route/backend.rs @@ -44,7 +44,7 @@ impl Clone for Backend { } } -// === impl Matched === +// === impl MatchedBackend === impl From<(Backend, super::MatchedRoute)> for MatchedBackend @@ -133,6 +133,8 @@ impl svc::Param for MatchedBackend { } } +// === impl Http === + impl filters::Apply for Http { #[inline] fn apply_request(&self, req: &mut ::http::Request) -> Result<()> { @@ -160,6 +162,8 @@ impl metrics::MkStreamLabel for Http { } } +// === impl Grpc === + impl filters::Apply for Grpc { #[inline] fn apply_request(&self, req: &mut ::http::Request) -> Result<()> { From 4624122dd6264e0e920cb5ea04e0a05671f54dde Mon Sep 17 00:00:00 2001 From: katelyn martin Date: Wed, 25 Sep 2024 08:37:32 -0400 Subject: [PATCH 10/42] docs(http/prom): Add metadata to Cargo.toml manifest (#3230) this commit introduces a description and adds the authors. Signed-off-by: katelyn martin --- linkerd/http/prom/Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linkerd/http/prom/Cargo.toml b/linkerd/http/prom/Cargo.toml index 36c253ed29..53c5a5496e 100644 --- a/linkerd/http/prom/Cargo.toml +++ b/linkerd/http/prom/Cargo.toml @@ -1,9 +1,13 @@ [package] name = "linkerd-http-prom" version = "0.1.0" +authors = ["Linkerd Developers "] edition = "2021" publish = false license = "Apache-2.0" +description = """ +Tower middleware for Prometheus metrics. +""" [features] test-util = [] From 911d4432f2cd525f26e4f3e3e7dd0caf34093a8d Mon Sep 17 00:00:00 2001 From: katelyn martin Date: Wed, 25 Sep 2024 08:38:28 -0400 Subject: [PATCH 11/42] docs(integration): Document test environment interfaces (#3229) this is a documentation pass, fleshing out information about how the `TestEnv` interfaces work. Signed-off-by: katelyn martin --- linkerd/app/integration/src/test_env.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linkerd/app/integration/src/test_env.rs b/linkerd/app/integration/src/test_env.rs index da7886cd96..c364998fb9 100644 --- a/linkerd/app/integration/src/test_env.rs +++ b/linkerd/app/integration/src/test_env.rs @@ -1,6 +1,7 @@ use linkerd_app::env::{EnvError, Strings}; use std::collections::HashMap; +/// An implementation of [`Strings`] that wraps for use in tests. #[derive(Clone, Default)] pub struct TestEnv { values: HashMap<&'static str, String>, @@ -9,18 +10,22 @@ pub struct TestEnv { // === impl TestEnv === impl TestEnv { + /// Puts a new key-value pair in the test environment. pub fn put(&mut self, key: &'static str, value: String) { self.values.insert(key, value); } + /// Returns true if this environment contains the given key. pub fn contains_key(&self, key: &'static str) -> bool { self.values.contains_key(key) } + /// Removes a new key-value pair from the test environment. pub fn remove(&mut self, key: &'static str) { self.values.remove(key); } + /// Extends this test environment using the other given [`TestEnv`]. pub fn extend(&mut self, other: TestEnv) { self.values.extend(other.values); } From a5e43f4011de2d6e72c6cd03974a0c4497903506 Mon Sep 17 00:00:00 2001 From: katelyn martin Date: Wed, 25 Sep 2024 08:39:12 -0400 Subject: [PATCH 12/42] docs(http/prom): Fix broken doc links (#3232) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this fixes some links, because i observed github actions warning about these in a different pr. pardon me! 😅 Signed-off-by: katelyn martin --- linkerd/http/prom/src/count_reqs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linkerd/http/prom/src/count_reqs.rs b/linkerd/http/prom/src/count_reqs.rs index ce0ea296d7..49e7dbde6b 100644 --- a/linkerd/http/prom/src/count_reqs.rs +++ b/linkerd/http/prom/src/count_reqs.rs @@ -44,10 +44,10 @@ impl NewCountRequests { Self { extract, inner } } - /// Returns a [`Layer`] that counts requests. + /// Returns a [`Layer`][svc::layer::Layer] that counts requests. /// - /// This uses an `X`-typed [`ExtractParam`] implementation to extract [`RequestCount`] from a - /// `T`-typed target. + /// This uses an `X`-typed [`ExtractParam`][svc::ExtractParam] implementation to extract + /// [`RequestCount`] from a `T`-typed target. pub fn layer_via(extract: X) -> impl svc::layer::Layer + Clone { svc::layer::mk(move |inner| Self::new(extract.clone(), inner)) } From 25589d440e603af82f40e4f136cb9f664d1e5948 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 08:08:52 -0700 Subject: [PATCH 13/42] build(deps): bump the opentelemetry group with 2 updates (#3225) * build(deps): bump the opentelemetry group with 2 updates Bumps the opentelemetry group with 2 updates: [opentelemetry](https://github.com/open-telemetry/opentelemetry-rust) and [opentelemetry_sdk](https://github.com/open-telemetry/opentelemetry-rust). Updates `opentelemetry` from 0.23.0 to 0.25.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-rust/releases) - [Commits](https://github.com/open-telemetry/opentelemetry-rust/compare/opentelemetry-0.23.0...opentelemetry-0.25.0) Updates `opentelemetry_sdk` from 0.23.0 to 0.25.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-rust/releases) - [Commits](https://github.com/open-telemetry/opentelemetry-rust/compare/opentelemetry-0.23.0...opentelemetry_sdk-0.25.0) --- updated-dependencies: - dependency-name: opentelemetry dependency-type: direct:production update-type: version-update:semver-minor dependency-group: opentelemetry - dependency-name: opentelemetry_sdk dependency-type: direct:production update-type: version-update:semver-minor dependency-group: opentelemetry ... Signed-off-by: dependabot[bot] * Fix API breakage with OpenTelemetry SpanData Signed-off-by: Scott Fleener --------- Signed-off-by: dependabot[bot] Signed-off-by: Scott Fleener Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Scott Fleener --- Cargo.lock | 19 ++++--------------- linkerd/opentelemetry/Cargo.toml | 4 ++-- opentelemetry-proto/Cargo.toml | 6 +++--- opentelemetry-proto/src/transform/trace.rs | 1 - 4 files changed, 9 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 437cf92e61..26f0f510f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2625,9 +2625,9 @@ dependencies = [ [[package]] name = "opentelemetry" -version = "0.23.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b69a91d4893e713e06f724597ad630f1fa76057a5e1026c0ca67054a9032a76" +checksum = "803801d3d3b71cd026851a53f974ea03df3d179cb758b260136a6c9e22e196af" dependencies = [ "futures-core", "futures-sink", @@ -2650,32 +2650,21 @@ dependencies = [ [[package]] name = "opentelemetry_sdk" -version = "0.23.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae312d58eaa90a82d2e627fd86e075cf5230b3f11794e2ed74199ebbe572d4fd" +checksum = "e0da0d6b47a3dbc6e9c9e36a0520e25cf943e046843818faaa3f87365a548c82" dependencies = [ "async-trait", "futures-channel", "futures-executor", "futures-util", - "lazy_static", "once_cell", "opentelemetry", - "ordered-float", "percent-encoding", "rand", "thiserror", ] -[[package]] -name = "ordered-float" -version = "4.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a91171844676f8c7990ce64959210cd2eaef32c2612c50f9fae9f8aaa6065a6" -dependencies = [ - "num-traits", -] - [[package]] name = "overload" version = "0.1.1" diff --git a/linkerd/opentelemetry/Cargo.toml b/linkerd/opentelemetry/Cargo.toml index 78c0ae7f72..8ae7509f05 100644 --- a/linkerd/opentelemetry/Cargo.toml +++ b/linkerd/opentelemetry/Cargo.toml @@ -12,8 +12,8 @@ http = "0.2" http-body = "0.4" linkerd-error = { path = "../error" } linkerd-metrics = { path = "../metrics" } -opentelemetry = { version = "0.23", default-features = false, features = ["trace"] } -opentelemetry_sdk = { version = "0.23", default-features = false, features = ["trace"] } +opentelemetry = { version = "0.25", default-features = false, features = ["trace"] } +opentelemetry_sdk = { version = "0.25", default-features = false, features = ["trace"] } opentelemetry-proto = { path = "../../opentelemetry-proto" } tonic = { version = "0.10", default-features = false, features = [ "prost", diff --git a/opentelemetry-proto/Cargo.toml b/opentelemetry-proto/Cargo.toml index 79e20ef9c3..9fd590d6ea 100644 --- a/opentelemetry-proto/Cargo.toml +++ b/opentelemetry-proto/Cargo.toml @@ -14,11 +14,11 @@ Vendored from https://github.com/open-telemetry/opentelemetry-rust/. [dependencies] tonic = { version = "0.10", features = ["codegen", "prost", "transport"] } prost = "0.12" -opentelemetry = { version = "0.23", default-features = false, features = ["trace"] } -opentelemetry_sdk = { version = "0.23", default-features = false, features = ["trace"] } +opentelemetry = { version = "0.25", default-features = false, features = ["trace"] } +opentelemetry_sdk = { version = "0.25", default-features = false, features = ["trace"] } [dev-dependencies] -opentelemetry = { version = "0.23", default-features = false, features = ["trace", "testing"] } +opentelemetry = { version = "0.25", default-features = false, features = ["trace", "testing"] } tonic-build = { version = "0.10", default-features = false, features = ["prost"] } [lib] diff --git a/opentelemetry-proto/src/transform/trace.rs b/opentelemetry-proto/src/transform/trace.rs index 5fba33b960..249c8a8f63 100644 --- a/opentelemetry-proto/src/transform/trace.rs +++ b/opentelemetry-proto/src/transform/trace.rs @@ -221,7 +221,6 @@ mod tests { events: SpanEvents::default(), links: SpanLinks::default(), status: Status::Unset, - resource: Default::default(), instrumentation_lib: InstrumentationLibrary::builder(instrumentation_name).build(), } } From fa4c8dcbc1290684488557a1e6719728dd0356f1 Mon Sep 17 00:00:00 2001 From: Zahari Dichev Date: Wed, 25 Sep 2024 18:36:56 +0300 Subject: [PATCH 14/42] tls: add `DetectSni` middleware (#3199) This change adds a new `DetectSni` middleware to be used in the outbound stack in order to extract the SNI extension from the `ClientHello` of a TLS session and apply routing decisions based on it. In contrast to `DetectTls` this new middleware is concerned with just extracting the SNI as opposed to terminating the TLS session. Signed-off-by: Zahari Dichev --- linkerd/tls/src/detect_sni.rs | 107 ++++++++++++++++++++++++++++++++++ linkerd/tls/src/lib.rs | 1 + linkerd/tls/src/server.rs | 2 +- 3 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 linkerd/tls/src/detect_sni.rs diff --git a/linkerd/tls/src/detect_sni.rs b/linkerd/tls/src/detect_sni.rs new file mode 100644 index 0000000000..45747d63ed --- /dev/null +++ b/linkerd/tls/src/detect_sni.rs @@ -0,0 +1,107 @@ +use crate::{ + server::{detect_sni, DetectIo, Timeout}, + ServerName, +}; +use linkerd_error::Error; +use linkerd_io as io; +use linkerd_stack::{layer, ExtractParam, InsertParam, NewService, Service, ServiceExt}; +use std::{ + future::Future, + pin::Pin, + task::{Context, Poll}, +}; +use thiserror::Error; +use tokio::time; +use tracing::debug; + +#[derive(Clone, Debug, Error)] +#[error("SNI detection timed out")] +pub struct SniDetectionTimeoutError; + +#[derive(Clone, Debug, Error)] +#[error("Could not find SNI")] +pub struct NoSniFoundError; + +#[derive(Clone, Debug)] +pub struct NewDetectSni { + params: P, + inner: N, +} + +#[derive(Clone, Debug)] +pub struct DetectSni { + target: T, + inner: N, + timeout: Timeout, + params: P, +} + +impl NewDetectSni { + pub fn new(params: P, inner: N) -> Self { + Self { inner, params } + } + + pub fn layer(params: P) -> impl layer::Layer + Clone + where + P: Clone, + { + layer::mk(move |inner| Self::new(params.clone(), inner)) + } +} + +impl NewService for NewDetectSni +where + P: ExtractParam + Clone, + N: Clone, +{ + type Service = DetectSni; + + fn new_service(&self, target: T) -> Self::Service { + let timeout = self.params.extract_param(&target); + DetectSni { + target, + timeout, + inner: self.inner.clone(), + params: self.params.clone(), + } + } +} + +impl Service for DetectSni +where + T: Clone + Send + Sync + 'static, + P: InsertParam + Clone + Send + Sync + 'static, + P::Target: Send + 'static, + I: io::AsyncRead + io::Peek + io::AsyncWrite + Send + Sync + Unpin + 'static, + N: NewService + Clone + Send + 'static, + S: Service> + Send, + S::Error: Into, + S::Future: Send, +{ + type Response = S::Response; + type Error = Error; + type Future = Pin> + Send + 'static>>; + + #[inline] + fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn call(&mut self, io: I) -> Self::Future { + let target = self.target.clone(); + let new_accept = self.inner.clone(); + let params = self.params.clone(); + + // Detect the SNI from a ClientHello (or timeout). + let Timeout(timeout) = self.timeout; + let detect = time::timeout(timeout, detect_sni(io)); + Box::pin(async move { + let (sni, io) = detect.await.map_err(|_| SniDetectionTimeoutError)??; + let sni = sni.ok_or(NoSniFoundError)?; + + debug!("detected SNI: {:?}", sni); + let svc = new_accept.new_service(params.insert_param(sni, target)); + svc.oneshot(io).await.map_err(Into::into) + }) + } +} diff --git a/linkerd/tls/src/lib.rs b/linkerd/tls/src/lib.rs index 0e54d86442..0a281e2b36 100755 --- a/linkerd/tls/src/lib.rs +++ b/linkerd/tls/src/lib.rs @@ -2,6 +2,7 @@ #![forbid(unsafe_code)] pub mod client; +pub mod detect_sni; pub mod server; pub use self::{ diff --git a/linkerd/tls/src/server.rs b/linkerd/tls/src/server.rs index 04862401f9..1c85c92ee6 100644 --- a/linkerd/tls/src/server.rs +++ b/linkerd/tls/src/server.rs @@ -192,7 +192,7 @@ where } /// Peek or buffer the provided stream to determine an SNI value. -async fn detect_sni(mut io: I) -> io::Result<(Option, DetectIo)> +pub(crate) async fn detect_sni(mut io: I) -> io::Result<(Option, DetectIo)> where I: io::Peek + io::AsyncRead + io::AsyncWrite + Send + Sync + Unpin, { From 6e84339d7c4b13536cb846637b82902d22e790de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 14:04:41 -0700 Subject: [PATCH 15/42] build(deps): bump actions/checkout from 4.1.7 to 4.2.0 (#3235) Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.7 to 4.2.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/692973e3d937129bcbf40652eb9f2f61becf3332...d632683dd7b4114ad314bca15554477dd762a938) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/beta.yml | 2 +- .github/workflows/coverage.yml | 4 ++-- .github/workflows/fuzzers.yml | 4 ++-- .github/workflows/markdown.yml | 2 +- .github/workflows/nightly.yml | 2 +- .github/workflows/pr.yml | 12 ++++++------ .github/workflows/release-weekly.yml | 2 +- .github/workflows/release.yml | 6 +++--- .github/workflows/shellcheck.yml | 2 +- .github/workflows/toolchain.yml | 4 ++-- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/beta.yml b/.github/workflows/beta.yml index 731f77f126..9a70cda15e 100644 --- a/.github/workflows/beta.yml +++ b/.github/workflows/beta.yml @@ -28,7 +28,7 @@ jobs: continue-on-error: true steps: - run: rustup toolchain install --profile=minimal beta - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 - run: git config --global --add safe.directory "$PWD" # actions/runner#2033 - run: just toolchain=beta fetch - run: just toolchain=beta build diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 3dfeed1cde..7009432383 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -23,7 +23,7 @@ jobs: timeout-minutes: 5 runs-on: ubuntu-latest steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 - id: changed uses: tj-actions/changed-files@48d8f15b2aaa3d255ca5af3eba4870f807ce6b3c with: @@ -48,7 +48,7 @@ jobs: env: CXX: "/usr/bin/clang++-14" steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 - run: cargo tarpaulin --locked --workspace --exclude=linkerd2-proxy --exclude=linkerd-transport-header --exclude=opencensus-proto --exclude=spire-proto --no-run - run: cargo tarpaulin --locked --workspace --exclude=linkerd2-proxy --exclude=linkerd-transport-header --exclude=opencensus-proto --exclude=spire-proto --skip-clean --ignore-tests --no-fail-fast --out=Xml diff --git a/.github/workflows/fuzzers.yml b/.github/workflows/fuzzers.yml index 07d4842deb..fff9f58c63 100644 --- a/.github/workflows/fuzzers.yml +++ b/.github/workflows/fuzzers.yml @@ -30,7 +30,7 @@ jobs: container: docker://rust:1.76.0 steps: - run: apt update && apt install -y jo - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 - run: git config --global --add safe.directory "$PWD" # actions/runner#2033 - uses: tj-actions/changed-files@48d8f15b2aaa3d255ca5af3eba4870f807ce6b3c id: changed-files @@ -55,7 +55,7 @@ jobs: steps: - run: rustup toolchain add nightly - run: cargo install cargo-fuzz - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 - run: git config --global --add safe.directory "$PWD" # actions/runner#2033 - working-directory: ${{matrix.dir}} run: cargo +nightly fetch diff --git a/.github/workflows/markdown.yml b/.github/workflows/markdown.yml index 207aa0678b..a105624798 100644 --- a/.github/workflows/markdown.yml +++ b/.github/workflows/markdown.yml @@ -14,7 +14,7 @@ jobs: timeout-minutes: 5 runs-on: ubuntu-latest steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 - uses: DavidAnson/markdownlint-cli2-action@db43aef879112c3119a410d69f66701e0d530809 with: globs: "**/*.md" diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 707b6fdf91..1834a6c5fc 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -28,7 +28,7 @@ jobs: continue-on-error: true steps: - run: rustup toolchain install --profile=minimal nightly - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 - run: git config --global --add safe.directory "$PWD" # actions/runner#2033 - run: just toolchain=nightly fetch - run: just toolchain=nightly profile=release build diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 6ecd4e609c..aae761d2f8 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -16,7 +16,7 @@ jobs: timeout-minutes: 5 runs-on: ubuntu-latest steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 - id: build uses: tj-actions/changed-files@48d8f15b2aaa3d255ca5af3eba4870f807ce6b3c with: @@ -77,7 +77,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: linkerd/dev/actions/setup-tools@v43 - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 - run: just action-lint - run: just action-dev-check @@ -91,7 +91,7 @@ jobs: timeout-minutes: 20 steps: - run: git config --global --add safe.directory "$PWD" # actions/runner#2033 - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 - run: just fetch - name: Run cargo deny check bans licenses sources @@ -117,7 +117,7 @@ jobs: crate: ${{ fromJson(needs.meta.outputs.cargo_crates) }} steps: - run: git config --global --add safe.directory "$PWD" # actions/runner#2033 - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 - run: just fetch - run: just check-crate ${{ matrix.crate }} @@ -137,7 +137,7 @@ jobs: tag=$(linkerd version --client --short) echo "linkerd $tag" echo "LINKERD_TAG=$tag" >> "$GITHUB_ENV" - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 - run: just docker - run: just-k3d create - run: just k3d-load-linkerd @@ -169,7 +169,7 @@ jobs: if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') run: exit 1 - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 if: needs.meta.outputs.is_dependabot == 'true' && needs.meta.outputs.any_changed == 'true' - name: "Merge dependabot changes" if: needs.meta.outputs.is_dependabot == 'true' && needs.meta.outputs.any_changed == 'true' diff --git a/.github/workflows/release-weekly.yml b/.github/workflows/release-weekly.yml index 26672611a5..2966a1e308 100644 --- a/.github/workflows/release-weekly.yml +++ b/.github/workflows/release-weekly.yml @@ -44,7 +44,7 @@ jobs: runs-on: ubuntu-22.04 timeout-minutes: 5 steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 - name: Check if the most recent commit is after the last release id: recency env: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4329ac229b..7d292c2a41 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -80,7 +80,7 @@ jobs: echo archs='["amd64", "arm64", "arm"]' ) >> "$GITHUB_OUTPUT" - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 if: github.event_name == 'pull_request' - id: changed if: github.event_name == 'pull_request' @@ -140,7 +140,7 @@ jobs: steps: - name: Configure git run: git config --global --add safe.directory "$PWD" # actions/runner#2033 - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 with: ref: ${{ needs.meta.outputs.ref }} - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 @@ -174,7 +174,7 @@ jobs: git config --global user.name "$GITHUB_USERNAME" git config --global user.email "$GITHUB_USERNAME"@users.noreply.github.com # Tag the release. - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 with: token: ${{ secrets.LINKERD2_PROXY_GITHUB_TOKEN || github.token }} ref: ${{ needs.meta.outputs.ref }} diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index bdf5fdfaaf..92277f11b5 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -16,5 +16,5 @@ jobs: runs-on: ubuntu-latest steps: - uses: linkerd/dev/actions/setup-tools@v43 - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 - run: just sh-lint diff --git a/.github/workflows/toolchain.yml b/.github/workflows/toolchain.yml index c4baf6c9d1..687e0135ea 100644 --- a/.github/workflows/toolchain.yml +++ b/.github/workflows/toolchain.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest container: ghcr.io/linkerd/dev:v43-rust steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 - run: git config --global --add safe.directory "$PWD" # actions/runner#2033 - run: | VERSION_REGEX='channel = "([0-9]+\.[0-9]+\.[0-9]+)"' @@ -38,7 +38,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: linkerd/dev/actions/setup-tools@v43 - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 - shell: bash run: | VERSION_REGEX='channel = "([0-9]+\.[0-9]+\.[0-9]+)"' From 642c2af145a4bd0d3cd0085dfac4b2aa73517736 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 14:04:54 -0700 Subject: [PATCH 16/42] build(deps): bump async-trait from 0.1.82 to 0.1.83 (#3233) Bumps [async-trait](https://github.com/dtolnay/async-trait) from 0.1.82 to 0.1.83. - [Release notes](https://github.com/dtolnay/async-trait/releases) - [Commits](https://github.com/dtolnay/async-trait/compare/0.1.82...0.1.83) --- updated-dependencies: - dependency-name: async-trait dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 26f0f510f2..aca9ab8f2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -129,9 +129,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.82" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", From 3130e3c08aa1d510310220caa091529c0db8c009 Mon Sep 17 00:00:00 2001 From: Scott Fleener Date: Fri, 27 Sep 2024 16:38:09 +0000 Subject: [PATCH 17/42] Integrate OpenTelemetry into the proxy OpenCensus is a deprecated protocol and is slated to be removed from upstream collectors soon. This wires up the proxy to optionally use OpenTelmetry as the format for exported traces. Currently, this defaults to the existing OpenCensus exporter, and we can switch the default later. [#10111](linkerd/linkerd2#10111) Signed-off-by: Scott Fleener --- Cargo.lock | 4 + linkerd/app/Cargo.toml | 1 + linkerd/app/core/Cargo.toml | 1 + linkerd/app/core/src/http_tracing.rs | 165 ++++++------------ linkerd/app/core/src/lib.rs | 3 +- linkerd/app/core/src/metrics.rs | 6 +- linkerd/app/inbound/src/lib.rs | 9 +- linkerd/app/outbound/src/http/server.rs | 2 +- linkerd/app/outbound/src/lib.rs | 4 +- linkerd/app/src/env.rs | 30 ++-- .../app/src/env/{opencensus.rs => trace.rs} | 0 linkerd/app/src/lib.rs | 51 +++--- linkerd/app/src/oc_collector.rs | 103 ----------- linkerd/app/src/trace_collector.rs | 103 +++++++++++ .../app/src/trace_collector/oc_collector.rs | 58 ++++++ .../app/src/trace_collector/otel_collector.rs | 112 ++++++++++++ linkerd/opencensus/Cargo.toml | 1 + linkerd/opencensus/src/lib.rs | 75 +++++++- linkerd/opentelemetry/Cargo.toml | 1 + linkerd/opentelemetry/src/lib.rs | 56 +++++- linkerd/trace-context/src/export.rs | 18 ++ linkerd/trace-context/src/lib.rs | 22 +++ linkerd2-proxy/src/main.rs | 11 +- tools/src/bin/gen-protos.rs | 41 ++++- 24 files changed, 601 insertions(+), 276 deletions(-) rename linkerd/app/src/env/{opencensus.rs => trace.rs} (100%) delete mode 100644 linkerd/app/src/oc_collector.rs create mode 100644 linkerd/app/src/trace_collector.rs create mode 100644 linkerd/app/src/trace_collector/oc_collector.rs create mode 100644 linkerd/app/src/trace_collector/otel_collector.rs create mode 100644 linkerd/trace-context/src/export.rs diff --git a/Cargo.lock b/Cargo.lock index aca9ab8f2f..e7d34d2666 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1126,6 +1126,7 @@ dependencies = [ "linkerd-app-outbound", "linkerd-error", "linkerd-opencensus", + "linkerd-opentelemetry", "linkerd-tonic-stream", "rangemap", "regex", @@ -1184,6 +1185,7 @@ dependencies = [ "linkerd-meshtls", "linkerd-metrics", "linkerd-opencensus", + "linkerd-opentelemetry", "linkerd-proxy-api-resolve", "linkerd-proxy-balance", "linkerd-proxy-client-policy", @@ -1743,6 +1745,7 @@ dependencies = [ "http-body", "linkerd-error", "linkerd-metrics", + "linkerd-trace-context", "opencensus-proto", "tokio", "tokio-stream", @@ -1759,6 +1762,7 @@ dependencies = [ "http-body", "linkerd-error", "linkerd-metrics", + "linkerd-trace-context", "opentelemetry", "opentelemetry-proto", "opentelemetry_sdk", diff --git a/linkerd/app/Cargo.toml b/linkerd/app/Cargo.toml index af443530a3..1420c6edfe 100644 --- a/linkerd/app/Cargo.toml +++ b/linkerd/app/Cargo.toml @@ -25,6 +25,7 @@ linkerd-app-inbound = { path = "./inbound" } linkerd-app-outbound = { path = "./outbound" } linkerd-error = { path = "../error" } linkerd-opencensus = { path = "../opencensus" } +linkerd-opentelemetry = { path = "../opentelemetry" } linkerd-tonic-stream = { path = "../tonic-stream" } rangemap = "1" regex = "1" diff --git a/linkerd/app/core/Cargo.toml b/linkerd/app/core/Cargo.toml index 43e19a2816..fff82289f7 100644 --- a/linkerd/app/core/Cargo.toml +++ b/linkerd/app/core/Cargo.toml @@ -47,6 +47,7 @@ linkerd-io = { path = "../../io" } linkerd-meshtls = { path = "../../meshtls", default-features = false } linkerd-metrics = { path = "../../metrics", features = ["process", "stack"] } linkerd-opencensus = { path = "../../opencensus" } +linkerd-opentelemetry = { path = "../../opentelemetry" } linkerd-proxy-api-resolve = { path = "../../proxy/api-resolve" } linkerd-proxy-balance = { path = "../../proxy/balance" } linkerd-proxy-core = { path = "../../proxy/core" } diff --git a/linkerd/app/core/src/http_tracing.rs b/linkerd/app/core/src/http_tracing.rs index 6b24c599e3..b0ddb05ce5 100644 --- a/linkerd/app/core/src/http_tracing.rs +++ b/linkerd/app/core/src/http_tracing.rs @@ -1,139 +1,76 @@ use linkerd_error::Error; -use linkerd_opencensus::proto::trace::v1 as oc; use linkerd_stack::layer; -use linkerd_trace_context::{self as trace_context, TraceContext}; -use std::{collections::HashMap, sync::Arc}; -use thiserror::Error; +use linkerd_trace_context::{ + self as trace_context, + export::{ExportSpan, SpanKind, SpanLabels}, + Span, TraceContext, +}; +use std::{str::FromStr, sync::Arc}; use tokio::sync::mpsc; -pub type OpenCensusSink = Option>; -pub type Labels = Arc>; - -/// SpanConverter converts trace_context::Span objects into OpenCensus agent -/// protobuf span objects. SpanConverter receives trace_context::Span objects by -/// implmenting the SpanSink trait. For each span that it receives, it converts -/// it to an OpenCensus span and then sends it on the provided mpsc::Sender. -#[derive(Clone)] -pub struct SpanConverter { - kind: Kind, - sink: mpsc::Sender, - labels: Labels, +#[derive(Debug, Copy, Clone, Default)] +pub enum CollectorProtocol { + #[default] + OpenCensus, + OpenTelemetry, } -#[derive(Debug, Error)] -#[error("ID '{:?} should have {} bytes, but it has {}", self.id, self.expected_size, self.actual_size)] -pub struct IdLengthError { - id: Vec, - expected_size: usize, - actual_size: usize, +impl FromStr for CollectorProtocol { + type Err = (); + + fn from_str(s: &str) -> Result { + if s.eq_ignore_ascii_case("opencensus") { + Ok(Self::OpenCensus) + } else if s.eq_ignore_ascii_case("opentelemetry") { + Ok(Self::OpenTelemetry) + } else { + Err(()) + } + } } +pub type SpanSink = mpsc::Sender; + pub fn server( - sink: OpenCensusSink, - labels: impl Into, + sink: Option, + labels: impl Into, ) -> impl layer::Layer, S>> + Clone { - SpanConverter::layer(Kind::Server, sink, labels) + TraceContext::layer(sink.map(move |sink| SpanConverter { + kind: SpanKind::Server, + sink, + labels: labels.into(), + })) } pub fn client( - sink: OpenCensusSink, - labels: impl Into, + sink: Option, + labels: impl Into, ) -> impl layer::Layer, S>> + Clone { - SpanConverter::layer(Kind::Client, sink, labels) -} - -#[derive(Copy, Clone, Debug, PartialEq)] -enum Kind { - Server = 1, - Client = 2, + TraceContext::layer(sink.map(move |sink| SpanConverter { + kind: SpanKind::Client, + sink, + labels: labels.into(), + })) } -impl SpanConverter { - fn layer( - kind: Kind, - sink: OpenCensusSink, - labels: impl Into, - ) -> impl layer::Layer, S>> + Clone { - TraceContext::layer(sink.map(move |sink| Self { - kind, - sink, - labels: labels.into(), - })) - } - - fn mk_span(&self, mut span: trace_context::Span) -> Result { - let mut attributes = HashMap::::new(); - for (k, v) in self.labels.iter() { - attributes.insert( - k.clone(), - oc::AttributeValue { - value: Some(oc::attribute_value::Value::StringValue(truncatable( - v.clone(), - ))), - }, - ); - } - for (k, v) in span.labels.drain() { - attributes.insert( - k.to_string(), - oc::AttributeValue { - value: Some(oc::attribute_value::Value::StringValue(truncatable(v))), - }, - ); - } - Ok(oc::Span { - trace_id: into_bytes(span.trace_id, 16)?, - span_id: into_bytes(span.span_id, 8)?, - tracestate: None, - parent_span_id: into_bytes(span.parent_id, 8)?, - name: Some(truncatable(span.span_name)), - kind: self.kind as i32, - start_time: Some(span.start.into()), - end_time: Some(span.end.into()), - attributes: Some(oc::span::Attributes { - attribute_map: attributes, - dropped_attributes_count: 0, - }), - stack_trace: None, - time_events: None, - links: None, - status: None, // TODO: this is gRPC status; we must read response trailers to populate this - resource: None, - same_process_as_parent_span: Some(self.kind == Kind::Client), - child_span_count: None, - }) - } +#[derive(Clone)] +pub struct SpanConverter { + kind: SpanKind, + sink: SpanSink, + labels: SpanLabels, } impl trace_context::SpanSink for SpanConverter { - #[inline] fn is_enabled(&self) -> bool { true } - fn try_send(&mut self, span: trace_context::Span) -> Result<(), Error> { - let span = self.mk_span(span)?; - self.sink.try_send(span).map_err(Into::into) - } -} - -fn into_bytes(id: trace_context::Id, size: usize) -> Result, IdLengthError> { - let bytes: Vec = id.into(); - if bytes.len() == size { - Ok(bytes) - } else { - let actual_size = bytes.len(); - Err(IdLengthError { - id: bytes, - expected_size: size, - actual_size, - }) - } -} - -fn truncatable(value: String) -> oc::TruncatableString { - oc::TruncatableString { - value, - truncated_byte_count: 0, + fn try_send(&mut self, span: Span) -> Result<(), Error> { + self.sink.try_send(ExportSpan { + span, + kind: self.kind, + labels: Arc::clone(&self.labels), + })?; + Ok(()) } } diff --git a/linkerd/app/core/src/lib.rs b/linkerd/app/core/src/lib.rs index fc98a3b621..8d3a433791 100644 --- a/linkerd/app/core/src/lib.rs +++ b/linkerd/app/core/src/lib.rs @@ -40,6 +40,7 @@ pub use linkerd_http_metrics as http_metrics; pub use linkerd_idle_cache as idle_cache; pub use linkerd_io as io; pub use linkerd_opencensus as opencensus; +pub use linkerd_opentelemetry as opentelemetry; pub use linkerd_service_profiles as profiles; pub use linkerd_stack_metrics as stack_metrics; pub use linkerd_stack_tracing as stack_tracing; @@ -65,7 +66,7 @@ pub struct ProxyRuntime { pub identity: identity::creds::Receiver, pub metrics: metrics::Proxy, pub tap: proxy::tap::Registry, - pub span_sink: http_tracing::OpenCensusSink, + pub span_sink: Option, pub drain: drain::Watch, } diff --git a/linkerd/app/core/src/metrics.rs b/linkerd/app/core/src/metrics.rs index 3fd374031b..084403e365 100644 --- a/linkerd/app/core/src/metrics.rs +++ b/linkerd/app/core/src/metrics.rs @@ -9,7 +9,7 @@ pub use crate::transport::labels::{TargetAddr, TlsAccept}; use crate::{ classify::Class, - control, http_metrics, opencensus, profiles, stack_metrics, + control, http_metrics, opencensus, opentelemetry, profiles, stack_metrics, svc::Param, tls, transport::{self, labels::TlsConnect}, @@ -39,6 +39,7 @@ pub struct Metrics { pub proxy: Proxy, pub control: ControlHttp, pub opencensus: opencensus::metrics::Registry, + pub opentelemetry: opentelemetry::metrics::Registry, } #[derive(Clone, Debug)] @@ -191,11 +192,13 @@ impl Metrics { }; let (opencensus, opencensus_report) = opencensus::metrics::new(); + let (opentelemetry, opentelemetry_report) = opentelemetry::metrics::new(); let metrics = Metrics { proxy, control, opencensus, + opentelemetry, }; let report = endpoint_report @@ -205,6 +208,7 @@ impl Metrics { .and_report(control_report) .and_report(transport_report) .and_report(opencensus_report) + .and_report(opentelemetry_report) .and_report(stack); (metrics, report) diff --git a/linkerd/app/inbound/src/lib.rs b/linkerd/app/inbound/src/lib.rs index 88ec18afb8..94f13701f6 100644 --- a/linkerd/app/inbound/src/lib.rs +++ b/linkerd/app/inbound/src/lib.rs @@ -18,11 +18,13 @@ mod server; #[cfg(any(test, feature = "test-util", fuzzing))] pub mod test_util; +#[cfg(fuzzing)] +pub use self::http::fuzz as http_fuzz; pub use self::{metrics::InboundMetrics, policy::DefaultPolicy}; use linkerd_app_core::{ config::{ConnectConfig, ProxyConfig, QueueConfig}, drain, - http_tracing::OpenCensusSink, + http_tracing::SpanSink, identity, io, proxy::{tap, tcp}, svc, @@ -33,9 +35,6 @@ use std::{fmt::Debug, time::Duration}; use thiserror::Error; use tracing::debug_span; -#[cfg(fuzzing)] -pub use self::http::fuzz as http_fuzz; - #[derive(Clone, Debug)] pub struct Config { pub allow_discovery: NameMatch, @@ -67,7 +66,7 @@ struct Runtime { metrics: InboundMetrics, identity: identity::creds::Receiver, tap: tap::Registry, - span_sink: OpenCensusSink, + span_sink: Option, drain: drain::Watch, } diff --git a/linkerd/app/outbound/src/http/server.rs b/linkerd/app/outbound/src/http/server.rs index dc8f77cb1c..0fb34ded58 100644 --- a/linkerd/app/outbound/src/http/server.rs +++ b/linkerd/app/outbound/src/http/server.rs @@ -47,7 +47,7 @@ impl Outbound> { .check_new_service::>() .push(ServerRescue::layer(config.emit_headers)) .check_new_service::>() - // Initiates OpenCensus tracing. + // Initiates OpenTelemetry tracing. .push_on_service(http_tracing::server(rt.span_sink.clone(), trace_labels())) .push_on_service(http::BoxResponse::layer()) // Convert origin form HTTP/1 URIs to absolute form for Hyper's diff --git a/linkerd/app/outbound/src/lib.rs b/linkerd/app/outbound/src/lib.rs index 75ee6c70d5..2cc8fccecc 100644 --- a/linkerd/app/outbound/src/lib.rs +++ b/linkerd/app/outbound/src/lib.rs @@ -6,11 +6,11 @@ #![allow(opaque_hidden_inferred_bound)] #![forbid(unsafe_code)] +use linkerd_app_core::http_tracing::SpanSink; use linkerd_app_core::{ config::{ProxyConfig, QueueConfig}, drain, exp_backoff::ExponentialBackoff, - http_tracing::OpenCensusSink, identity, io, metrics::prom, profiles, @@ -95,7 +95,7 @@ struct Runtime { metrics: OutboundMetrics, identity: identity::NewClient, tap: tap::Registry, - span_sink: OpenCensusSink, + span_sink: Option, drain: drain::Watch, } diff --git a/linkerd/app/src/env.rs b/linkerd/app/src/env.rs index 49e00a88ba..c4ca612596 100644 --- a/linkerd/app/src/env.rs +++ b/linkerd/app/src/env.rs @@ -1,8 +1,9 @@ -use crate::{dns, gateway, identity, inbound, oc_collector, outbound, policy, spire}; +use crate::{dns, gateway, identity, inbound, outbound, policy, spire, trace_collector}; use linkerd_app_core::{ addr, config::*, control::{Config as ControlConfig, ControlAddr}, + http_tracing::CollectorProtocol, proxy::http::{h1, h2}, tls, transport::{DualListenAddr, Keepalive, ListenAddr, UserTimeout}, @@ -19,7 +20,7 @@ use tracing::{debug, error, info, warn}; mod control; mod http2; -mod opencensus; +mod trace; mod types; use self::types::*; @@ -145,7 +146,8 @@ pub const ENV_OUTBOUND_MAX_IN_FLIGHT: &str = "LINKERD2_PROXY_OUTBOUND_MAX_IN_FLI const ENV_OUTBOUND_DISABLE_INFORMATIONAL_HEADERS: &str = "LINKERD2_PROXY_OUTBOUND_DISABLE_INFORMATIONAL_HEADERS"; -pub const ENV_TRACE_ATTRIBUTES_PATH: &str = "LINKERD2_PROXY_TRACE_ATTRIBUTES_PATH"; +const ENV_TRACE_ATTRIBUTES_PATH: &str = "LINKERD2_PROXY_TRACE_ATTRIBUTES_PATH"; +const ENV_TRACE_PROTOCOL: &str = "LINKERD2_PROXY_TRACE_PROTOCOL"; /// Constrains which destination names may be used for profile/route discovery. /// @@ -428,7 +430,8 @@ pub fn parse_config(strings: &S) -> Result let hostname = strings.get(ENV_HOSTNAME); - let oc_attributes_file_path = strings.get(ENV_TRACE_ATTRIBUTES_PATH); + let trace_attributes_file_path = strings.get(ENV_TRACE_ATTRIBUTES_PATH); + let trace_protocol = strings.get(ENV_TRACE_PROTOCOL); let trace_collector_addr = parse_control_addr(strings, ENV_TRACE_COLLECTOR_SVC_BASE); @@ -813,8 +816,8 @@ pub fn parse_config(strings: &S) -> Result .into(), }; - let oc_collector = match trace_collector_addr? { - None => oc_collector::Config::Disabled, + let trace_collector = match trace_collector_addr? { + None => trace_collector::Config::Disabled, Some(addr) => { let connect = if addr.addr.is_loopback() { inbound.proxy.connect.clone() @@ -826,14 +829,20 @@ pub fn parse_config(strings: &S) -> Result } else { outbound.http_request_queue.failfast_timeout }; - let attributes = oc_attributes_file_path + let attributes = trace_attributes_file_path .map(|path| match path.and_then(|p| p.parse::().ok()) { - Some(path) => opencensus::read_trace_attributes(&path), + Some(path) => trace::read_trace_attributes(&path), None => HashMap::new(), }) .unwrap_or_default(); - oc_collector::Config::Enabled(Box::new(oc_collector::EnabledConfig { + let trace_protocol = trace_protocol + .map(|proto| proto.and_then(|p| p.parse::().ok())) + .ok() + .flatten() + .unwrap_or_default(); + + trace_collector::Config::Enabled(Box::new(trace_collector::EnabledConfig { attributes, hostname: hostname?, control: ControlConfig { @@ -844,6 +853,7 @@ pub fn parse_config(strings: &S) -> Result failfast_timeout, }, }, + kind: trace_protocol, })) } }; @@ -923,7 +933,7 @@ pub fn parse_config(strings: &S) -> Result dns, dst, tap, - oc_collector, + trace_collector, policy, identity, outbound, diff --git a/linkerd/app/src/env/opencensus.rs b/linkerd/app/src/env/trace.rs similarity index 100% rename from linkerd/app/src/env/opencensus.rs rename to linkerd/app/src/env/trace.rs diff --git a/linkerd/app/src/lib.rs b/linkerd/app/src/lib.rs index aa73893851..4fceec08dd 100644 --- a/linkerd/app/src/lib.rs +++ b/linkerd/app/src/lib.rs @@ -7,10 +7,10 @@ pub mod dst; pub mod env; pub mod identity; -pub mod oc_collector; pub mod policy; pub mod spire; pub mod tap; +pub mod trace_collector; pub use self::metrics::Metrics; use futures::{future, Future, FutureExt}; @@ -60,7 +60,7 @@ pub struct Config { pub policy: policy::Config, pub admin: admin::Config, pub tap: tap::Config, - pub oc_collector: oc_collector::Config, + pub trace_collector: trace_collector::Config, /// Grace period for graceful shutdowns. /// @@ -75,7 +75,7 @@ pub struct App { dst: ControlAddr, identity: identity::Identity, inbound_addr: Local, - oc_collector: oc_collector::OcCollector, + trace_collector: trace_collector::TraceCollector, outbound_addr: Local, outbound_addr_additional: Option>, start_proxy: Pin + Send + 'static>>, @@ -123,7 +123,7 @@ impl Config { policy, identity, inbound, - oc_collector, + trace_collector, outbound, gateway, tap, @@ -188,16 +188,27 @@ impl Config { }) }?; - debug!(config = ?oc_collector, "Building client"); - let oc_collector = { - let control_metrics = - ControlMetrics::register(registry.sub_registry_with_prefix("opencensus")); + debug!(config = ?trace_collector, "Building client"); + let trace_collector = { + let control_metrics = if let Some(prefix) = trace_collector.metrics_prefix() { + ControlMetrics::register(registry.sub_registry_with_prefix(prefix)) + } else { + ControlMetrics::register(&mut prom::Registry::default()) + }; let identity = identity.receiver().new_client(); let dns = dns.resolver; let client_metrics = metrics.control.clone(); - let metrics = metrics.opencensus; - info_span!("opencensus").in_scope(|| { - oc_collector.build(identity, dns, metrics, control_metrics, client_metrics) + let otel_metrics = metrics.opentelemetry; + let oc_metrics = metrics.opencensus; + info_span!("tracing").in_scope(|| { + trace_collector.build( + identity, + dns, + oc_metrics, + otel_metrics, + control_metrics, + client_metrics, + ) }) }?; @@ -205,7 +216,7 @@ impl Config { identity: identity.receiver(), metrics: metrics.proxy, tap: tap.registry(), - span_sink: oc_collector.span_sink(), + span_sink: trace_collector.span_sink(), drain: drain_rx.clone(), }; let inbound = Inbound::new(inbound, runtime.clone()); @@ -309,7 +320,7 @@ impl Config { drain: drain_tx, identity, inbound_addr, - oc_collector, + trace_collector, outbound_addr, outbound_addr_additional, start_proxy, @@ -369,10 +380,10 @@ impl App { self.identity.receiver().local_id().clone() } - pub fn opencensus_addr(&self) -> Option<&ControlAddr> { - match self.oc_collector { - oc_collector::OcCollector::Disabled { .. } => None, - oc_collector::OcCollector::Enabled(ref oc) => Some(&oc.addr), + pub fn tracing_addr(&self) -> Option<&ControlAddr> { + match self.trace_collector { + trace_collector::TraceCollector::Disabled { .. } => None, + crate::trace_collector::TraceCollector::Enabled(ref oc) => Some(&oc.addr), } } @@ -381,7 +392,7 @@ impl App { admin, drain, identity, - oc_collector, + trace_collector: collector, start_proxy, tap, .. @@ -446,8 +457,8 @@ impl App { tokio::spawn(serve.instrument(info_span!("tap").or_current())); } - if let oc_collector::OcCollector::Enabled(oc) = oc_collector { - tokio::spawn(oc.task.instrument(info_span!("opencensus").or_current())); + if let trace_collector::TraceCollector::Enabled(collector) = collector { + tokio::spawn(collector.task.instrument(info_span!("tracing"))); } // we don't care if the admin shutdown channel is diff --git a/linkerd/app/src/oc_collector.rs b/linkerd/app/src/oc_collector.rs deleted file mode 100644 index e8f25e23c5..0000000000 --- a/linkerd/app/src/oc_collector.rs +++ /dev/null @@ -1,103 +0,0 @@ -use linkerd_app_core::{ - control, dns, identity, metrics::ControlHttp as HttpMetrics, svc::NewService, Error, -}; -use linkerd_opencensus::{self as opencensus, metrics, proto}; -use std::{collections::HashMap, future::Future, pin::Pin, time::SystemTime}; -use tokio::sync::mpsc; -use tokio_stream::wrappers::ReceiverStream; -use tracing::Instrument; - -#[derive(Clone, Debug)] -pub enum Config { - Disabled, - Enabled(Box), -} - -#[derive(Clone, Debug)] -pub struct EnabledConfig { - pub control: control::Config, - pub attributes: HashMap, - pub hostname: Option, -} - -pub type Task = Pin + Send + 'static>>; - -pub type SpanSink = mpsc::Sender; - -pub enum OcCollector { - Disabled, - Enabled(Box), -} - -pub struct EnabledCollector { - pub addr: control::ControlAddr, - pub span_sink: SpanSink, - pub task: Task, -} - -impl Config { - const SPAN_BUFFER_CAPACITY: usize = 100; - const SERVICE_NAME: &'static str = "linkerd-proxy"; - - pub fn build( - self, - identity: identity::NewClient, - dns: dns::Resolver, - legacy_metrics: metrics::Registry, - control_metrics: control::Metrics, - client_metrics: HttpMetrics, - ) -> Result { - match self { - Config::Disabled => Ok(OcCollector::Disabled), - Config::Enabled(inner) => { - let addr = inner.control.addr.clone(); - let svc = inner - .control - .build(dns, client_metrics, control_metrics, identity) - .new_service(()); - - let (span_sink, spans_rx) = mpsc::channel(Self::SPAN_BUFFER_CAPACITY); - let spans_rx = ReceiverStream::new(spans_rx); - - let task = { - use self::proto::agent::common::v1 as oc; - - let node = oc::Node { - identifier: Some(oc::ProcessIdentifier { - host_name: inner.hostname.unwrap_or_default(), - pid: std::process::id(), - start_timestamp: Some(SystemTime::now().into()), - }), - service_info: Some(oc::ServiceInfo { - name: Self::SERVICE_NAME.to_string(), - }), - attributes: inner.attributes, - ..oc::Node::default() - }; - - let addr = addr.clone(); - Box::pin( - opencensus::export_spans(svc, node, spans_rx, legacy_metrics).instrument( - tracing::debug_span!("opencensus", peer.addr = %addr).or_current(), - ), - ) - }; - - Ok(OcCollector::Enabled(Box::new(EnabledCollector { - addr, - task, - span_sink, - }))) - } - } - } -} - -impl OcCollector { - pub fn span_sink(&self) -> Option { - match self { - OcCollector::Disabled => None, - OcCollector::Enabled(inner) => Some(inner.span_sink.clone()), - } - } -} diff --git a/linkerd/app/src/trace_collector.rs b/linkerd/app/src/trace_collector.rs new file mode 100644 index 0000000000..2e93732179 --- /dev/null +++ b/linkerd/app/src/trace_collector.rs @@ -0,0 +1,103 @@ +use linkerd_app_core::http_tracing::{CollectorProtocol, SpanSink}; +use linkerd_app_core::metrics::ControlHttp as HttpMetrics; +use linkerd_app_core::svc::NewService; +use linkerd_app_core::{control, dns, identity, opencensus, opentelemetry}; +use linkerd_error::Error; +use std::collections::HashMap; +use std::future::Future; +use std::pin::Pin; + +pub mod oc_collector; +pub mod otel_collector; + +const SPAN_BUFFER_CAPACITY: usize = 100; +const SERVICE_NAME: &str = "linkerd-proxy"; + +#[derive(Clone, Debug)] +pub enum Config { + Disabled, + Enabled(Box), +} + +#[derive(Clone, Debug)] +pub struct EnabledConfig { + pub control: control::Config, + pub attributes: HashMap, + pub hostname: Option, + pub kind: CollectorProtocol, +} + +pub type Task = Pin + Send + 'static>>; + +pub enum TraceCollector { + Disabled, + Enabled(Box), +} + +pub struct EnabledCollector { + pub addr: control::ControlAddr, + pub kind: CollectorProtocol, + pub span_sink: SpanSink, + pub task: Task, +} + +impl TraceCollector { + pub fn span_sink(&self) -> Option { + match self { + TraceCollector::Disabled => None, + TraceCollector::Enabled(inner) => Some(inner.span_sink.clone()), + } + } +} + +impl Config { + pub fn metrics_prefix(&self) -> Option<&'static str> { + match self { + Config::Disabled => None, + Config::Enabled(config) => match config.kind { + CollectorProtocol::OpenCensus => Some("opencensus"), + CollectorProtocol::OpenTelemetry => Some("opentelemetry"), + }, + } + } + + pub fn build( + self, + identity: identity::NewClient, + dns: dns::Resolver, + legacy_oc_metrics: opencensus::metrics::Registry, + legacy_otel_metrics: opentelemetry::metrics::Registry, + control_metrics: control::Metrics, + client_metrics: HttpMetrics, + ) -> Result { + match self { + Config::Disabled => Ok(TraceCollector::Disabled), + Config::Enabled(inner) => { + let addr = inner.control.addr.clone(); + let svc = inner + .control + .build(dns, client_metrics, control_metrics, identity) + .new_service(()); + + let collector = match inner.kind { + CollectorProtocol::OpenCensus => oc_collector::create_collector( + addr.clone(), + inner.hostname, + inner.attributes, + svc, + legacy_oc_metrics, + ), + CollectorProtocol::OpenTelemetry => otel_collector::create_collector( + addr.clone(), + inner.hostname, + inner.attributes, + svc, + legacy_otel_metrics, + ), + }; + + Ok(TraceCollector::Enabled(Box::new(collector))) + } + } + } +} diff --git a/linkerd/app/src/trace_collector/oc_collector.rs b/linkerd/app/src/trace_collector/oc_collector.rs new file mode 100644 index 0000000000..ee80db652e --- /dev/null +++ b/linkerd/app/src/trace_collector/oc_collector.rs @@ -0,0 +1,58 @@ +use crate::trace_collector::EnabledCollector; +use linkerd_app_core::{ + control::ControlAddr, http_tracing::CollectorProtocol, proxy::http::HttpBody, Error, +}; +use linkerd_opencensus::{self as opencensus, metrics, proto}; +use std::{collections::HashMap, time::SystemTime}; +use tokio::sync::mpsc; +use tokio_stream::wrappers::ReceiverStream; +use tonic::{body::BoxBody, client::GrpcService}; +use tracing::Instrument; + +pub(super) fn create_collector( + addr: ControlAddr, + hostname: Option, + attributes: HashMap, + svc: S, + legacy_metrics: metrics::Registry, +) -> EnabledCollector +where + S: GrpcService + Clone + Send + 'static, + S::Error: Into, + S::Future: Send, + S::ResponseBody: Default + HttpBody + Send + 'static, + ::Error: Into + Send, +{ + let (span_sink, spans_rx) = mpsc::channel(crate::trace_collector::SPAN_BUFFER_CAPACITY); + let spans_rx = ReceiverStream::new(spans_rx); + + let task = { + use self::proto::agent::common::v1 as oc; + + let node = oc::Node { + identifier: Some(oc::ProcessIdentifier { + host_name: hostname.unwrap_or_default(), + pid: std::process::id(), + start_timestamp: Some(SystemTime::now().into()), + }), + service_info: Some(oc::ServiceInfo { + name: crate::trace_collector::SERVICE_NAME.to_string(), + }), + attributes, + ..oc::Node::default() + }; + + let addr = addr.clone(); + Box::pin( + opencensus::export_spans(svc, node, spans_rx, legacy_metrics) + .instrument(tracing::debug_span!("opencensus", peer.addr = %addr).or_current()), + ) + }; + + EnabledCollector { + addr, + task, + span_sink, + kind: CollectorProtocol::OpenCensus, + } +} diff --git a/linkerd/app/src/trace_collector/otel_collector.rs b/linkerd/app/src/trace_collector/otel_collector.rs new file mode 100644 index 0000000000..f933389b8e --- /dev/null +++ b/linkerd/app/src/trace_collector/otel_collector.rs @@ -0,0 +1,112 @@ +use super::EnabledCollector; +use linkerd_app_core::{ + control::ControlAddr, http_tracing::CollectorProtocol, proxy::http::HttpBody, Error, +}; +use linkerd_opentelemetry::{ + self as opentelemetry, metrics, + proto::proto::common::v1::{any_value, AnyValue, KeyValue}, + proto::transform::common::ResourceAttributesWithSchema, +}; +use std::{collections::HashMap, time::SystemTime, time::UNIX_EPOCH}; +use tokio::sync::mpsc; +use tokio_stream::wrappers::ReceiverStream; +use tonic::{body::BoxBody, client::GrpcService}; +use tracing::Instrument; + +pub(super) fn create_collector( + addr: ControlAddr, + hostname: Option, + attributes: HashMap, + svc: S, + legacy_metrics: metrics::Registry, +) -> EnabledCollector +where + S: GrpcService + Clone + Send + 'static, + S::Error: Into, + S::Future: Send, + S::ResponseBody: Default + HttpBody + Send + 'static, + ::Error: Into + Send, +{ + let (span_sink, spans_rx) = mpsc::channel(crate::trace_collector::SPAN_BUFFER_CAPACITY); + let spans_rx = ReceiverStream::new(spans_rx); + + let mut resources = ResourceAttributesWithSchema::default(); + + resources + .attributes + .0 + .push(crate::trace_collector::SERVICE_NAME.with_key("service.name")); + resources + .attributes + .0 + .push((std::process::id() as i64).with_key("process.pid")); + + resources.attributes.0.push( + SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|d| d.as_secs() as i64) + .unwrap_or_else(|e| -(e.duration().as_secs() as i64)) + .with_key("process.start_timestamp"), + ); + resources + .attributes + .0 + .push(hostname.unwrap_or_default().with_key("host.name")); + + resources.attributes.0.extend( + attributes + .into_iter() + .map(|(key, value)| value.with_key(&key)), + ); + + let addr = addr.clone(); + let task = Box::pin( + opentelemetry::export_spans(svc, spans_rx, resources, legacy_metrics) + .instrument(tracing::debug_span!("opentelemetry", peer.addr = %addr).or_current()), + ); + + EnabledCollector { + addr, + task, + span_sink, + kind: CollectorProtocol::OpenTelemetry, + } +} + +trait IntoAnyValue +where + Self: Sized, +{ + fn into_any_value(self) -> AnyValue; + + fn with_key(self, key: &str) -> KeyValue { + KeyValue { + key: key.to_string(), + value: Some(self.into_any_value()), + } + } +} + +impl IntoAnyValue for String { + fn into_any_value(self) -> AnyValue { + AnyValue { + value: Some(any_value::Value::StringValue(self)), + } + } +} + +impl IntoAnyValue for &str { + fn into_any_value(self) -> AnyValue { + AnyValue { + value: Some(any_value::Value::StringValue(self.to_string())), + } + } +} + +impl IntoAnyValue for i64 { + fn into_any_value(self) -> AnyValue { + AnyValue { + value: Some(any_value::Value::IntValue(self)), + } + } +} diff --git a/linkerd/opencensus/Cargo.toml b/linkerd/opencensus/Cargo.toml index 65d1b45eed..87699ec356 100644 --- a/linkerd/opencensus/Cargo.toml +++ b/linkerd/opencensus/Cargo.toml @@ -12,6 +12,7 @@ http = "0.2" http-body = "0.4" linkerd-error = { path = "../error" } linkerd-metrics = { path = "../metrics" } +linkerd-trace-context = { path = "../trace-context" } opencensus-proto = { path = "../../opencensus-proto" } tonic = { version = "0.10", default-features = false, features = [ "prost", diff --git a/linkerd/opencensus/src/lib.rs b/linkerd/opencensus/src/lib.rs index dd7d0a156c..65fbf2c4b0 100644 --- a/linkerd/opencensus/src/lib.rs +++ b/linkerd/opencensus/src/lib.rs @@ -6,17 +6,19 @@ pub mod metrics; use futures::stream::{Stream, StreamExt}; use http_body::Body as HttpBody; use linkerd_error::Error; +use linkerd_trace_context::export::{ExportSpan, SpanKind}; use metrics::Registry; pub use opencensus_proto as proto; use opencensus_proto::agent::common::v1::Node; use opencensus_proto::agent::trace::v1::{ trace_service_client::TraceServiceClient, ExportTraceServiceRequest, }; -use opencensus_proto::trace::v1::Span; +use opencensus_proto::trace::v1::{Span, TruncatableString}; +use std::collections::HashMap; use tokio::{sync::mpsc, time}; use tokio_stream::wrappers::ReceiverStream; use tonic::{self as grpc, body::BoxBody, client::GrpcService}; -use tracing::{debug, trace}; +use tracing::{debug, info, trace}; pub async fn export_spans(client: T, node: Node, spans: S, metrics: Registry) where @@ -24,7 +26,7 @@ where T::Error: Into, T::ResponseBody: Default + HttpBody + Send + 'static, ::Error: Into + Send, - S: Stream + Unpin, + S: Stream + Unpin, { debug!("Span exporter running"); SpanExporter::new(client, node, spans, metrics).run().await @@ -49,7 +51,7 @@ where T::Error: Into, T::ResponseBody: Default + HttpBody + Send + 'static, ::Error: Into + Send, - S: Stream + Unpin, + S: Stream + Unpin, { const MAX_BATCH_SIZE: usize = 1000; const MAX_BATCH_IDLE: time::Duration = time::Duration::from_secs(10); @@ -175,6 +177,13 @@ where res = spans.next() => match res { Some(span) => { trace!(?span, "Adding to batch"); + let span = match convert_span(span) { + Ok(span) => span, + Err(error) => { + info!(%error, "Span dropped"); + continue; + } + }; accum.push(span); } None => return Err(SpanRxClosed), @@ -192,3 +201,61 @@ where } } } + +fn convert_span(span: ExportSpan) -> Result { + use proto::trace::v1 as oc; + + let ExportSpan { + mut span, + kind, + labels, + } = span; + + let mut attributes = HashMap::::new(); + for (k, v) in labels.iter() { + attributes.insert( + k.clone(), + oc::AttributeValue { + value: Some(oc::attribute_value::Value::StringValue(truncatable( + v.clone(), + ))), + }, + ); + } + for (k, v) in span.labels.drain() { + attributes.insert( + k.to_string(), + oc::AttributeValue { + value: Some(oc::attribute_value::Value::StringValue(truncatable(v))), + }, + ); + } + Ok(Span { + trace_id: span.trace_id.into_bytes::<16>()?.to_vec(), + span_id: span.span_id.into_bytes::<8>()?.to_vec(), + tracestate: None, + parent_span_id: span.parent_id.into_bytes::<8>()?.to_vec(), + name: Some(truncatable(span.span_name)), + kind: kind as i32, + start_time: Some(span.start.into()), + end_time: Some(span.end.into()), + attributes: Some(oc::span::Attributes { + attribute_map: attributes, + dropped_attributes_count: 0, + }), + stack_trace: None, + time_events: None, + links: None, + status: None, // TODO: this is gRPC status; we must read response trailers to populate this + resource: None, + same_process_as_parent_span: Some(kind == SpanKind::Client), + child_span_count: None, + }) +} + +fn truncatable(value: String) -> TruncatableString { + TruncatableString { + value, + truncated_byte_count: 0, + } +} diff --git a/linkerd/opentelemetry/Cargo.toml b/linkerd/opentelemetry/Cargo.toml index 8ae7509f05..4322449bca 100644 --- a/linkerd/opentelemetry/Cargo.toml +++ b/linkerd/opentelemetry/Cargo.toml @@ -12,6 +12,7 @@ http = "0.2" http-body = "0.4" linkerd-error = { path = "../error" } linkerd-metrics = { path = "../metrics" } +linkerd-trace-context = { path = "../trace-context" } opentelemetry = { version = "0.25", default-features = false, features = ["trace"] } opentelemetry_sdk = { version = "0.25", default-features = false, features = ["trace"] } opentelemetry-proto = { path = "../../opentelemetry-proto" } diff --git a/linkerd/opentelemetry/src/lib.rs b/linkerd/opentelemetry/src/lib.rs index 2f983cade7..10bcc6ad42 100644 --- a/linkerd/opentelemetry/src/lib.rs +++ b/linkerd/opentelemetry/src/lib.rs @@ -6,17 +6,26 @@ pub mod metrics; use futures::stream::{Stream, StreamExt}; use http_body::Body as HttpBody; use linkerd_error::Error; +use linkerd_trace_context as trace_context; use metrics::Registry; +pub use opentelemetry as otel; +use opentelemetry::trace::{ + SpanContext, SpanId, SpanKind, Status, TraceFlags, TraceId, TraceState, +}; +use opentelemetry::KeyValue; pub use opentelemetry_proto as proto; use opentelemetry_proto::proto::collector::trace::v1::trace_service_client::TraceServiceClient; use opentelemetry_proto::proto::collector::trace::v1::ExportTraceServiceRequest; use opentelemetry_proto::proto::trace::v1::ResourceSpans; use opentelemetry_proto::transform::common::ResourceAttributesWithSchema; use opentelemetry_proto::transform::trace::group_spans_by_resource_and_scope; +pub use opentelemetry_sdk as sdk; pub use opentelemetry_sdk::export::trace::SpanData; +use opentelemetry_sdk::trace::SpanLinks; use tokio::{sync::mpsc, time}; use tonic::{self as grpc, body::BoxBody, client::GrpcService}; -use tracing::{debug, trace}; +use trace_context::export::ExportSpan; +use tracing::{debug, info, trace}; pub async fn export_spans( client: T, @@ -28,7 +37,7 @@ pub async fn export_spans( T::Error: Into, T::ResponseBody: Default + HttpBody + Send + 'static, ::Error: Into + Send, - S: Stream + Unpin, + S: Stream + Unpin, { debug!("Span exporter running"); SpanExporter::new(client, spans, resource, metrics) @@ -55,7 +64,7 @@ where T::Error: Into, T::ResponseBody: Default + HttpBody + Send + 'static, ::Error: Into + Send, - S: Stream + Unpin, + S: Stream + Unpin, { const MAX_BATCH_SIZE: usize = 1000; const MAX_BATCH_IDLE: time::Duration = time::Duration::from_secs(10); @@ -189,6 +198,14 @@ where res = span_stream.next() => match res { Some(span) => { trace!(?span, "Adding to batch"); + let span = match convert_span(span) { + Ok(span) => span, + Err(error) => { + info!(%error, "Span dropped"); + continue; + } + }; + input_accum.push(span); } None => break Err(SpanRxClosed), @@ -210,3 +227,36 @@ where res } } + +fn convert_span(span: ExportSpan) -> Result { + let ExportSpan { span, kind, labels } = span; + + let mut attributes = Vec::::new(); + for (k, v) in labels.iter() { + attributes.push(KeyValue::new(k.clone(), v.clone())); + } + let is_remote = kind != trace_context::export::SpanKind::Client; + Ok(SpanData { + parent_span_id: SpanId::from_bytes(span.parent_id.into_bytes()?), + span_kind: match kind { + trace_context::export::SpanKind::Server => SpanKind::Server, + trace_context::export::SpanKind::Client => SpanKind::Client, + }, + name: span.span_name.into(), + start_time: span.start, + end_time: span.end, + attributes, + dropped_attributes_count: 0, + links: SpanLinks::default(), + status: Status::Unset, // TODO: this is gRPC status; we must read response trailers to populate this + span_context: SpanContext::new( + TraceId::from_bytes(span.trace_id.into_bytes()?), + SpanId::from_bytes(span.span_id.into_bytes()?), + TraceFlags::default(), + is_remote, + TraceState::NONE, + ), + events: Default::default(), + instrumentation_lib: Default::default(), + }) +} diff --git a/linkerd/trace-context/src/export.rs b/linkerd/trace-context/src/export.rs new file mode 100644 index 0000000000..262c98ee7f --- /dev/null +++ b/linkerd/trace-context/src/export.rs @@ -0,0 +1,18 @@ +use crate::Span; +use std::collections::HashMap; +use std::sync::Arc; + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum SpanKind { + Server = 1, + Client = 2, +} + +pub type SpanLabels = Arc>; + +#[derive(Debug)] +pub struct ExportSpan { + pub span: Span, + pub kind: SpanKind, + pub labels: SpanLabels, +} diff --git a/linkerd/trace-context/src/lib.rs b/linkerd/trace-context/src/lib.rs index ed8c36017c..f88b04bca4 100644 --- a/linkerd/trace-context/src/lib.rs +++ b/linkerd/trace-context/src/lib.rs @@ -1,6 +1,7 @@ #![deny(rust_2018_idioms, clippy::disallowed_methods, clippy::disallowed_types)] #![forbid(unsafe_code)] +pub mod export; mod propagation; mod service; @@ -18,6 +19,27 @@ const SPAN_ID_LEN: usize = 8; #[derive(Debug, Default)] pub struct Id(Vec); +#[derive(Debug, Error)] +#[error("ID '{:?} should have {} bytes, but it has {}", self.id, self.expected_size, self.actual_size)] +pub struct IdLengthError { + id: Vec, + expected_size: usize, + actual_size: usize, +} + +impl Id { + pub fn into_bytes(self) -> Result<[u8; N], IdLengthError> { + self.as_ref().try_into().map_err(|_| { + let bytes: Vec = self.into(); + IdLengthError { + expected_size: N, + actual_size: bytes.len(), + id: bytes, + } + }) + } +} + #[derive(Debug, Default)] pub struct Flags(u8); diff --git a/linkerd2-proxy/src/main.rs b/linkerd2-proxy/src/main.rs index 61c54102df..f198d135e2 100644 --- a/linkerd2-proxy/src/main.rs +++ b/linkerd2-proxy/src/main.rs @@ -108,14 +108,11 @@ fn main() { ), } - if let Some(oc) = app.opencensus_addr() { - match oc.identity.value() { - None => info!("OpenCensus tracing collector at {}", oc.addr), + if let Some(tracing) = app.tracing_addr() { + match tracing.identity.value() { + None => info!("Tracing collector at {}", tracing.addr), Some(tls) => { - info!( - "OpenCensus tracing collector at {} ({})", - oc.addr, tls.server_id - ) + info!("Tracing collector at {} ({})", tracing.addr, tls.server_id) } } } diff --git a/tools/src/bin/gen-protos.rs b/tools/src/bin/gen-protos.rs index 4e85f3bffe..7100d21633 100644 --- a/tools/src/bin/gen-protos.rs +++ b/tools/src/bin/gen-protos.rs @@ -1,8 +1,12 @@ +use std::path::{Path, PathBuf}; + fn main() { - let opencensus_dir = { - let manifest_dir = std::path::PathBuf::from(std::env!("CARGO_MANIFEST_DIR")); - manifest_dir.parent().unwrap().join("opencensus-proto") - }; + generate_opentelemetry_protos(); + generate_opencensus_protos(); +} + +fn generate_opencensus_protos() { + let opencensus_dir = get_proto_dir("opencensus-proto"); let out_dir = opencensus_dir.join("src").join("gen"); @@ -17,12 +21,39 @@ fn main() { ] }; + generate_protos(&out_dir, iface_files, &opencensus_dir); +} + +fn generate_opentelemetry_protos() { + let opentelemetry_dir = get_proto_dir("opentelemetry-proto"); + + let out_dir = opentelemetry_dir.join("src").join("gen"); + + let iface_files = { + let proto_dir = opentelemetry_dir.join("opentelemetry").join("proto"); + &[ + proto_dir.join("collector/trace/v1/trace_service.proto"), + proto_dir.join("common/v1/common.proto"), + proto_dir.join("resource/v1/resource.proto"), + proto_dir.join("trace/v1/trace.proto"), + ] + }; + + generate_protos(&out_dir, iface_files, &opentelemetry_dir); +} + +fn get_proto_dir(name: &str) -> PathBuf { + let manifest_dir = std::path::PathBuf::from(std::env!("CARGO_MANIFEST_DIR")); + manifest_dir.parent().unwrap().join(name) +} + +fn generate_protos(out_dir: &Path, iface_files: &[PathBuf], includes: &Path) { if let Err(error) = tonic_build::configure() .build_client(true) .build_server(false) .emit_rerun_if_changed(false) .out_dir(out_dir) - .compile(iface_files, &[opencensus_dir]) + .compile(iface_files, &[includes]) { eprintln!("\nfailed to compile protos: {}", error); } From e072e6315b736597ff471b0493798c7a7b0cf835 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 07:51:13 -0700 Subject: [PATCH 18/42] build(deps): bump flate2 from 1.0.33 to 1.0.34 (#3236) Bumps [flate2](https://github.com/rust-lang/flate2-rs) from 1.0.33 to 1.0.34. - [Release notes](https://github.com/rust-lang/flate2-rs/releases) - [Changelog](https://github.com/rust-lang/flate2-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-lang/flate2-rs/compare/1.0.33...1.0.34) --- updated-dependencies: - dependency-name: flate2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e7d34d2666..6937dcd229 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -545,9 +545,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.33" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", "miniz_oxide 0.8.0", From 04b79f6801cba091c2db0f34185fdb7536c930fe Mon Sep 17 00:00:00 2001 From: Scott Fleener Date: Thu, 26 Sep 2024 14:02:02 +0000 Subject: [PATCH 19/42] Allow configuring proxy trace exporter service name Currently, we hard-code the trace service name to "linkerd-proxy". This allows this name to be configured through an env that can be set by the injector, annotations, etc. linkerd/linkerd2#11157 Signed-off-by: Scott Fleener --- linkerd/app/src/env.rs | 5 +++++ linkerd/app/src/trace_collector.rs | 6 ++++++ linkerd/app/src/trace_collector/oc_collector.rs | 5 ++--- linkerd/app/src/trace_collector/otel_collector.rs | 3 ++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/linkerd/app/src/env.rs b/linkerd/app/src/env.rs index c4ca612596..b90970dae8 100644 --- a/linkerd/app/src/env.rs +++ b/linkerd/app/src/env.rs @@ -148,6 +148,7 @@ const ENV_OUTBOUND_DISABLE_INFORMATIONAL_HEADERS: &str = const ENV_TRACE_ATTRIBUTES_PATH: &str = "LINKERD2_PROXY_TRACE_ATTRIBUTES_PATH"; const ENV_TRACE_PROTOCOL: &str = "LINKERD2_PROXY_TRACE_PROTOCOL"; +const ENV_TRACE_SERVICE_NAME: &str = "LINKERD2_PROXY_TRACE_SERVICE_NAME"; /// Constrains which destination names may be used for profile/route discovery. /// @@ -432,6 +433,7 @@ pub fn parse_config(strings: &S) -> Result let trace_attributes_file_path = strings.get(ENV_TRACE_ATTRIBUTES_PATH); let trace_protocol = strings.get(ENV_TRACE_PROTOCOL); + let trace_service_name = strings.get(ENV_TRACE_SERVICE_NAME); let trace_collector_addr = parse_control_addr(strings, ENV_TRACE_COLLECTOR_SVC_BASE); @@ -842,9 +844,12 @@ pub fn parse_config(strings: &S) -> Result .flatten() .unwrap_or_default(); + let trace_service_name = trace_service_name.ok().flatten(); + trace_collector::Config::Enabled(Box::new(trace_collector::EnabledConfig { attributes, hostname: hostname?, + service_name: trace_service_name, control: ControlConfig { addr, connect, diff --git a/linkerd/app/src/trace_collector.rs b/linkerd/app/src/trace_collector.rs index 2e93732179..ea362e9921 100644 --- a/linkerd/app/src/trace_collector.rs +++ b/linkerd/app/src/trace_collector.rs @@ -24,6 +24,7 @@ pub struct EnabledConfig { pub control: control::Config, pub attributes: HashMap, pub hostname: Option, + pub service_name: Option, pub kind: CollectorProtocol, } @@ -78,11 +79,15 @@ impl Config { .control .build(dns, client_metrics, control_metrics, identity) .new_service(()); + let svc_name = inner + .service_name + .unwrap_or_else(|| SERVICE_NAME.to_string()); let collector = match inner.kind { CollectorProtocol::OpenCensus => oc_collector::create_collector( addr.clone(), inner.hostname, + svc_name, inner.attributes, svc, legacy_oc_metrics, @@ -90,6 +95,7 @@ impl Config { CollectorProtocol::OpenTelemetry => otel_collector::create_collector( addr.clone(), inner.hostname, + svc_name, inner.attributes, svc, legacy_otel_metrics, diff --git a/linkerd/app/src/trace_collector/oc_collector.rs b/linkerd/app/src/trace_collector/oc_collector.rs index ee80db652e..e344599cf7 100644 --- a/linkerd/app/src/trace_collector/oc_collector.rs +++ b/linkerd/app/src/trace_collector/oc_collector.rs @@ -12,6 +12,7 @@ use tracing::Instrument; pub(super) fn create_collector( addr: ControlAddr, hostname: Option, + service_name: String, attributes: HashMap, svc: S, legacy_metrics: metrics::Registry, @@ -35,9 +36,7 @@ where pid: std::process::id(), start_timestamp: Some(SystemTime::now().into()), }), - service_info: Some(oc::ServiceInfo { - name: crate::trace_collector::SERVICE_NAME.to_string(), - }), + service_info: Some(oc::ServiceInfo { name: service_name }), attributes, ..oc::Node::default() }; diff --git a/linkerd/app/src/trace_collector/otel_collector.rs b/linkerd/app/src/trace_collector/otel_collector.rs index f933389b8e..a5115f1dbd 100644 --- a/linkerd/app/src/trace_collector/otel_collector.rs +++ b/linkerd/app/src/trace_collector/otel_collector.rs @@ -16,6 +16,7 @@ use tracing::Instrument; pub(super) fn create_collector( addr: ControlAddr, hostname: Option, + service_name: String, attributes: HashMap, svc: S, legacy_metrics: metrics::Registry, @@ -35,7 +36,7 @@ where resources .attributes .0 - .push(crate::trace_collector::SERVICE_NAME.with_key("service.name")); + .push(service_name.with_key("service.name")); resources .attributes .0 From c900ba5af8f1fea13250977dc6086cab7e8a321e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:34:31 -0700 Subject: [PATCH 20/42] build(deps): bump cc from 1.1.21 to 1.1.24 (#3244) Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.1.21 to 1.1.24. - [Release notes](https://github.com/rust-lang/cc-rs/releases) - [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.1.21...cc-v1.1.24) --- updated-dependencies: - dependency-name: cc dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6937dcd229..b7d33175f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -308,9 +308,9 @@ checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "cc" -version = "1.1.21" +version = "1.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" +checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938" dependencies = [ "jobserver", "libc", From a41c37bbfae6d82d5fe94d2005293e6aa0354d27 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:35:10 -0700 Subject: [PATCH 21/42] build(deps): bump autocfg from 1.3.0 to 1.4.0 (#3237) Bumps [autocfg](https://github.com/cuviper/autocfg) from 1.3.0 to 1.4.0. - [Commits](https://github.com/cuviper/autocfg/compare/1.3.0...1.4.0) --- updated-dependencies: - dependency-name: autocfg dependency-type: indirect update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b7d33175f5..f38a75af88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -140,9 +140,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "axum" From 771dfd58dacad551061346fcef91d7cdd5aa0f02 Mon Sep 17 00:00:00 2001 From: katelyn martin Date: Wed, 2 Oct 2024 17:46:15 -0400 Subject: [PATCH 22/42] justfile: Add devcontainer cli recipes (#3241) this commit introduces two recipes to manage a dev container for this repository using the [cli]. `just devcontainer-up` will create and run a devcontainer. `just devcontainer-exec` will execute a command in the container. [cli]: https://github.com/devcontainers/cli Signed-off-by: katelyn martin --- justfile | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/justfile b/justfile index 2f9b9906d4..a5983a8f2c 100644 --- a/justfile +++ b/justfile @@ -314,3 +314,13 @@ _linkerd-ready: {{ _kubectl }} wait pod --for=condition=ready \ --namespace=linkerd --selector='linkerd.io/control-plane-component' \ --timeout=1m + +# +# Dev Container +# + +devcontainer-up: + devcontainer.js up --workspace-folder=. + +devcontainer-exec container-id *args: + devcontainer.js exec --container-id={{ container-id }} {{ args }} From 7a4eb542d84d73d6763385d0f52e70cd5f86b7b9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Oct 2024 10:38:37 -0400 Subject: [PATCH 23/42] build(deps): bump the opentelemetry group with 2 updates (#3246) Bumps the opentelemetry group with 2 updates: [opentelemetry](https://github.com/open-telemetry/opentelemetry-rust) and [opentelemetry_sdk](https://github.com/open-telemetry/opentelemetry-rust). Updates `opentelemetry` from 0.25.0 to 0.26.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-rust/releases) - [Commits](https://github.com/open-telemetry/opentelemetry-rust/compare/opentelemetry-0.25.0...opentelemetry-0.26.0) Updates `opentelemetry_sdk` from 0.25.0 to 0.26.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-rust/releases) - [Commits](https://github.com/open-telemetry/opentelemetry-rust/compare/opentelemetry_sdk-0.25.0...opentelemetry_sdk-0.26.0) --- updated-dependencies: - dependency-name: opentelemetry dependency-type: direct:production update-type: version-update:semver-minor dependency-group: opentelemetry - dependency-name: opentelemetry_sdk dependency-type: direct:production update-type: version-update:semver-minor dependency-group: opentelemetry ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- linkerd/opentelemetry/Cargo.toml | 4 ++-- opentelemetry-proto/Cargo.toml | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f38a75af88..0f45149cdb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2629,9 +2629,9 @@ dependencies = [ [[package]] name = "opentelemetry" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "803801d3d3b71cd026851a53f974ea03df3d179cb758b260136a6c9e22e196af" +checksum = "570074cc999d1a58184080966e5bd3bf3a9a4af650c3b05047c2621e7405cd17" dependencies = [ "futures-core", "futures-sink", @@ -2654,9 +2654,9 @@ dependencies = [ [[package]] name = "opentelemetry_sdk" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0da0d6b47a3dbc6e9c9e36a0520e25cf943e046843818faaa3f87365a548c82" +checksum = "d2c627d9f4c9cdc1f21a29ee4bfbd6028fcb8bcf2a857b43f3abdf72c9c862f3" dependencies = [ "async-trait", "futures-channel", diff --git a/linkerd/opentelemetry/Cargo.toml b/linkerd/opentelemetry/Cargo.toml index 4322449bca..c8becc0ec6 100644 --- a/linkerd/opentelemetry/Cargo.toml +++ b/linkerd/opentelemetry/Cargo.toml @@ -13,8 +13,8 @@ http-body = "0.4" linkerd-error = { path = "../error" } linkerd-metrics = { path = "../metrics" } linkerd-trace-context = { path = "../trace-context" } -opentelemetry = { version = "0.25", default-features = false, features = ["trace"] } -opentelemetry_sdk = { version = "0.25", default-features = false, features = ["trace"] } +opentelemetry = { version = "0.26", default-features = false, features = ["trace"] } +opentelemetry_sdk = { version = "0.26", default-features = false, features = ["trace"] } opentelemetry-proto = { path = "../../opentelemetry-proto" } tonic = { version = "0.10", default-features = false, features = [ "prost", diff --git a/opentelemetry-proto/Cargo.toml b/opentelemetry-proto/Cargo.toml index 9fd590d6ea..024935a9e7 100644 --- a/opentelemetry-proto/Cargo.toml +++ b/opentelemetry-proto/Cargo.toml @@ -14,11 +14,11 @@ Vendored from https://github.com/open-telemetry/opentelemetry-rust/. [dependencies] tonic = { version = "0.10", features = ["codegen", "prost", "transport"] } prost = "0.12" -opentelemetry = { version = "0.25", default-features = false, features = ["trace"] } -opentelemetry_sdk = { version = "0.25", default-features = false, features = ["trace"] } +opentelemetry = { version = "0.26", default-features = false, features = ["trace"] } +opentelemetry_sdk = { version = "0.26", default-features = false, features = ["trace"] } [dev-dependencies] -opentelemetry = { version = "0.25", default-features = false, features = ["trace", "testing"] } +opentelemetry = { version = "0.26", default-features = false, features = ["trace", "testing"] } tonic-build = { version = "0.10", default-features = false, features = ["prost"] } [lib] From 3abb0ee2b753f7bd15f3130bfb33ad65e2c0ba07 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Oct 2024 10:39:28 -0400 Subject: [PATCH 24/42] build(deps): bump httparse from 1.9.4 to 1.9.5 (#3251) Bumps [httparse](https://github.com/seanmonstar/httparse) from 1.9.4 to 1.9.5. - [Release notes](https://github.com/seanmonstar/httparse/releases) - [Commits](https://github.com/seanmonstar/httparse/compare/v1.9.4...v1.9.5) --- updated-dependencies: - dependency-name: httparse dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f45149cdb..d48d6da2ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -871,9 +871,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" From 637efa6a57e688a2ba88375509396b971b2758a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Oct 2024 12:12:37 -0400 Subject: [PATCH 25/42] build(deps): bump indexmap from 2.5.0 to 2.6.0 (#3250) Bumps [indexmap](https://github.com/indexmap-rs/indexmap) from 2.5.0 to 2.6.0. - [Changelog](https://github.com/indexmap-rs/indexmap/blob/master/RELEASES.md) - [Commits](https://github.com/indexmap-rs/indexmap/compare/2.5.0...2.6.0) --- updated-dependencies: - dependency-name: indexmap dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d48d6da2ac..13440f8556 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -754,7 +754,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.5.0", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -769,9 +769,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" [[package]] name = "heck" @@ -968,12 +968,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.15.0", ] [[package]] @@ -1409,7 +1409,7 @@ name = "linkerd-distribute" version = "0.1.0" dependencies = [ "ahash", - "indexmap 2.5.0", + "indexmap 2.6.0", "linkerd-stack", "parking_lot", "rand", @@ -1800,7 +1800,7 @@ dependencies = [ "ahash", "futures", "futures-util", - "indexmap 2.5.0", + "indexmap 2.6.0", "linkerd-error", "linkerd-metrics", "linkerd-pool", @@ -2727,7 +2727,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.5.0", + "indexmap 2.6.0", ] [[package]] From 33082d6af219099385c579e42ec2412c8ee0e9ad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Oct 2024 12:13:05 -0400 Subject: [PATCH 26/42] build(deps): bump codecov/codecov-action from 4.5.0 to 4.6.0 (#3249) Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 4.5.0 to 4.6.0. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/e28ff129e5465c2c0dcc6f003fc735cb6ae0c673...b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 7009432383..e5eeb646df 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -55,4 +55,4 @@ jobs: # Some tests are especially flakey in coverage tests. That's fine. We # only really care to measure how much of our codebase is covered. continue-on-error: true - - uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 + - uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 From 0c9aef926821a06cd764288be10f046441abeabf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Oct 2024 12:13:18 -0400 Subject: [PATCH 27/42] build(deps): bump async-stream from 0.3.5 to 0.3.6 (#3248) Bumps [async-stream](https://github.com/tokio-rs/async-stream) from 0.3.5 to 0.3.6. - [Release notes](https://github.com/tokio-rs/async-stream/releases) - [Commits](https://github.com/tokio-rs/async-stream/compare/v0.3.5...v0.3.6) --- updated-dependencies: - dependency-name: async-stream dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 13440f8556..aaba5d1298 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -107,9 +107,9 @@ dependencies = [ [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -118,9 +118,9 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", From 269cbbc76b173a80f2afe9ad5e68b7c728380a68 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Oct 2024 12:13:37 -0400 Subject: [PATCH 28/42] build(deps): bump symbolic-demangle from 12.11.1 to 12.12.0 (#3247) Bumps [symbolic-demangle](https://github.com/getsentry/symbolic) from 12.11.1 to 12.12.0. - [Release notes](https://github.com/getsentry/symbolic/releases) - [Changelog](https://github.com/getsentry/symbolic/blob/master/CHANGELOG.md) - [Commits](https://github.com/getsentry/symbolic/compare/12.11.1...12.12.0) --- updated-dependencies: - dependency-name: symbolic-demangle dependency-type: indirect update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aaba5d1298..11b4dfe3a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3297,9 +3297,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "symbolic-common" -version = "12.11.1" +version = "12.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fdf97c441f18a4f92425b896a4ec7a27e03631a0b1047ec4e34e9916a9a167e" +checksum = "366f1b4c6baf6cfefc234bbd4899535fca0b06c74443039a73f6dfb2fad88d77" dependencies = [ "debugid", "memmap2", @@ -3309,9 +3309,9 @@ dependencies = [ [[package]] name = "symbolic-demangle" -version = "12.11.1" +version = "12.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc8ece6b129e97e53d1fbb3f61d33a6a9e5369b11d01228c068094d6d134eaea" +checksum = "aba05ba5b9962ea5617baf556293720a8b2d0a282aa14ee4bf10e22efc7da8c8" dependencies = [ "cpp_demangle", "rustc-demangle", From 318cf75ed654140b501710271d807792710c7465 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2024 10:45:46 -0400 Subject: [PATCH 29/42] build(deps): bump ipnet from 2.10.0 to 2.10.1 (#3257) Bumps [ipnet](https://github.com/krisprice/ipnet) from 2.10.0 to 2.10.1. - [Release notes](https://github.com/krisprice/ipnet/releases) - [Changelog](https://github.com/krisprice/ipnet/blob/master/RELEASES.md) - [Commits](https://github.com/krisprice/ipnet/commits) --- updated-dependencies: - dependency-name: ipnet dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 11b4dfe3a4..7192b8abeb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -990,9 +990,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.10.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "itertools" From fd92be54cc878d50f7dee169db378803c14ff7c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2024 10:48:01 -0400 Subject: [PATCH 30/42] build(deps): bump syn from 2.0.77 to 2.0.79 (#3256) Bumps [syn](https://github.com/dtolnay/syn) from 2.0.77 to 2.0.79. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.77...2.0.79) --- updated-dependencies: - dependency-name: syn dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7192b8abeb..fef9affe4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3320,9 +3320,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", From e0502b52f8d58ae710724592d883b957adb65b17 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2024 10:48:29 -0400 Subject: [PATCH 31/42] build(deps): bump once_cell from 1.20.0 to 1.20.1 (#3255) Bumps [once_cell](https://github.com/matklad/once_cell) from 1.20.0 to 1.20.1. - [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md) - [Commits](https://github.com/matklad/once_cell/compare/v1.20.0...v1.20.1) --- updated-dependencies: - dependency-name: once_cell dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fef9affe4d..33cccc770d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2612,9 +2612,12 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ea5043e58958ee56f3e15a90aee535795cd7dfd319846288d93c5b57d85cbe" +checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1" +dependencies = [ + "portable-atomic", +] [[package]] name = "opencensus-proto" @@ -2762,6 +2765,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "portable-atomic" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" + [[package]] name = "powerfmt" version = "0.2.0" From bd91d6a5d6bde7fb4f7503bfe61afefa9f0031f9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 10:11:33 -0400 Subject: [PATCH 32/42] build(deps): bump object from 0.36.4 to 0.36.5 (#3259) Bumps [object](https://github.com/gimli-rs/object) from 0.36.4 to 0.36.5. - [Changelog](https://github.com/gimli-rs/object/blob/master/CHANGELOG.md) - [Commits](https://github.com/gimli-rs/object/compare/0.36.4...0.36.5) --- updated-dependencies: - dependency-name: object dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 33cccc770d..909879417c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2594,9 +2594,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.4" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] From 18b2892ddacda91872581dfd1de0db7267523cd2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 10:13:06 -0400 Subject: [PATCH 33/42] build(deps): bump regex from 1.10.6 to 1.11.0 (#3260) Bumps [regex](https://github.com/rust-lang/regex) from 1.10.6 to 1.11.0. - [Release notes](https://github.com/rust-lang/regex/releases) - [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/regex/compare/1.10.6...1.11.0) --- updated-dependencies: - dependency-name: regex dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 909879417c..0df4d8204c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3011,14 +3011,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.5", - "regex-syntax 0.8.2", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] [[package]] @@ -3032,13 +3032,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.5" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax 0.8.5", ] [[package]] @@ -3049,9 +3049,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "resolv-conf" From 53b528a38ff2eabe79ef4f6986e56e00eefb4c1c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 10:14:05 -0400 Subject: [PATCH 34/42] build(deps): bump cc from 1.1.24 to 1.1.28 (#3261) Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.1.24 to 1.1.28. - [Release notes](https://github.com/rust-lang/cc-rs/releases) - [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.1.24...cc-v1.1.28) --- updated-dependencies: - dependency-name: cc dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0df4d8204c..361837c5d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -308,9 +308,9 @@ checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "cc" -version = "1.1.24" +version = "1.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938" +checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1" dependencies = [ "jobserver", "libc", From 8a7d9956e56c919108fa7ab30c239f3808f1d4bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Oct 2024 11:39:48 -0400 Subject: [PATCH 35/42] build(deps): bump futures from 0.3.30 to 0.3.31 (#3267) Bumps [futures](https://github.com/rust-lang/futures-rs) from 0.3.30 to 0.3.31. - [Release notes](https://github.com/rust-lang/futures-rs/releases) - [Changelog](https://github.com/rust-lang/futures-rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/futures-rs/compare/0.3.30...0.3.31) --- updated-dependencies: - dependency-name: futures dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 361837c5d7..59ce505adc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -613,9 +613,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -628,9 +628,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -638,15 +638,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -655,15 +655,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", @@ -672,21 +672,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", From 79281f388d2fb4f22f4efea21f747c86c63a4762 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 01:03:18 -0400 Subject: [PATCH 36/42] build(deps): bump proc-macro2 from 1.0.86 to 1.0.87 (#3265) Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.86 to 1.0.87. - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.86...1.0.87) --- updated-dependencies: - dependency-name: proc-macro2 dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 59ce505adc..46ba36f199 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2822,9 +2822,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" dependencies = [ "unicode-ident", ] From b1e055f9ae8b16fb0e58add1fcb25a0c63aec6c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 01:04:38 -0400 Subject: [PATCH 37/42] build(deps): bump once_cell from 1.20.1 to 1.20.2 (#3266) Bumps [once_cell](https://github.com/matklad/once_cell) from 1.20.1 to 1.20.2. - [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md) - [Commits](https://github.com/matklad/once_cell/compare/v1.20.1...v1.20.2) --- updated-dependencies: - dependency-name: once_cell dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 46ba36f199..2c08375b24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2612,12 +2612,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.1" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1" -dependencies = [ - "portable-atomic", -] +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "opencensus-proto" @@ -2765,12 +2762,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "portable-atomic" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" - [[package]] name = "powerfmt" version = "0.2.0" From 89ba5b5d8b39f54de8a8c6e1e8cf552e9c9a5527 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 13:07:33 -0400 Subject: [PATCH 38/42] build(deps): bump pin-project from 1.1.5 to 1.1.6 (#3270) Bumps [pin-project](https://github.com/taiki-e/pin-project) from 1.1.5 to 1.1.6. - [Release notes](https://github.com/taiki-e/pin-project/releases) - [Changelog](https://github.com/taiki-e/pin-project/blob/main/CHANGELOG.md) - [Commits](https://github.com/taiki-e/pin-project/compare/v1.1.5...v1.1.6) --- updated-dependencies: - dependency-name: pin-project dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2c08375b24..c97651502d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2732,18 +2732,18 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" dependencies = [ "proc-macro2", "quote", From 7a37294b8a44959590d3191955b81247cabdeba9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2024 07:21:13 -0700 Subject: [PATCH 39/42] build(deps): bump actions/checkout from 4.2.0 to 4.2.1 (#3264) Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.0 to 4.2.1. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/d632683dd7b4114ad314bca15554477dd762a938...eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/beta.yml | 2 +- .github/workflows/coverage.yml | 4 ++-- .github/workflows/fuzzers.yml | 4 ++-- .github/workflows/markdown.yml | 2 +- .github/workflows/nightly.yml | 2 +- .github/workflows/pr.yml | 12 ++++++------ .github/workflows/release-weekly.yml | 2 +- .github/workflows/release.yml | 6 +++--- .github/workflows/shellcheck.yml | 2 +- .github/workflows/toolchain.yml | 4 ++-- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/beta.yml b/.github/workflows/beta.yml index 9a70cda15e..f0042c2b38 100644 --- a/.github/workflows/beta.yml +++ b/.github/workflows/beta.yml @@ -28,7 +28,7 @@ jobs: continue-on-error: true steps: - run: rustup toolchain install --profile=minimal beta - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 - run: git config --global --add safe.directory "$PWD" # actions/runner#2033 - run: just toolchain=beta fetch - run: just toolchain=beta build diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index e5eeb646df..75d84107f1 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -23,7 +23,7 @@ jobs: timeout-minutes: 5 runs-on: ubuntu-latest steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 - id: changed uses: tj-actions/changed-files@48d8f15b2aaa3d255ca5af3eba4870f807ce6b3c with: @@ -48,7 +48,7 @@ jobs: env: CXX: "/usr/bin/clang++-14" steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 - run: cargo tarpaulin --locked --workspace --exclude=linkerd2-proxy --exclude=linkerd-transport-header --exclude=opencensus-proto --exclude=spire-proto --no-run - run: cargo tarpaulin --locked --workspace --exclude=linkerd2-proxy --exclude=linkerd-transport-header --exclude=opencensus-proto --exclude=spire-proto --skip-clean --ignore-tests --no-fail-fast --out=Xml diff --git a/.github/workflows/fuzzers.yml b/.github/workflows/fuzzers.yml index fff9f58c63..4674a87f32 100644 --- a/.github/workflows/fuzzers.yml +++ b/.github/workflows/fuzzers.yml @@ -30,7 +30,7 @@ jobs: container: docker://rust:1.76.0 steps: - run: apt update && apt install -y jo - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 - run: git config --global --add safe.directory "$PWD" # actions/runner#2033 - uses: tj-actions/changed-files@48d8f15b2aaa3d255ca5af3eba4870f807ce6b3c id: changed-files @@ -55,7 +55,7 @@ jobs: steps: - run: rustup toolchain add nightly - run: cargo install cargo-fuzz - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 - run: git config --global --add safe.directory "$PWD" # actions/runner#2033 - working-directory: ${{matrix.dir}} run: cargo +nightly fetch diff --git a/.github/workflows/markdown.yml b/.github/workflows/markdown.yml index a105624798..2be8e0d515 100644 --- a/.github/workflows/markdown.yml +++ b/.github/workflows/markdown.yml @@ -14,7 +14,7 @@ jobs: timeout-minutes: 5 runs-on: ubuntu-latest steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 - uses: DavidAnson/markdownlint-cli2-action@db43aef879112c3119a410d69f66701e0d530809 with: globs: "**/*.md" diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 1834a6c5fc..536e37d51b 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -28,7 +28,7 @@ jobs: continue-on-error: true steps: - run: rustup toolchain install --profile=minimal nightly - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 - run: git config --global --add safe.directory "$PWD" # actions/runner#2033 - run: just toolchain=nightly fetch - run: just toolchain=nightly profile=release build diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index aae761d2f8..f23902ba20 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -16,7 +16,7 @@ jobs: timeout-minutes: 5 runs-on: ubuntu-latest steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 - id: build uses: tj-actions/changed-files@48d8f15b2aaa3d255ca5af3eba4870f807ce6b3c with: @@ -77,7 +77,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: linkerd/dev/actions/setup-tools@v43 - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 - run: just action-lint - run: just action-dev-check @@ -91,7 +91,7 @@ jobs: timeout-minutes: 20 steps: - run: git config --global --add safe.directory "$PWD" # actions/runner#2033 - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 - run: just fetch - name: Run cargo deny check bans licenses sources @@ -117,7 +117,7 @@ jobs: crate: ${{ fromJson(needs.meta.outputs.cargo_crates) }} steps: - run: git config --global --add safe.directory "$PWD" # actions/runner#2033 - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 - run: just fetch - run: just check-crate ${{ matrix.crate }} @@ -137,7 +137,7 @@ jobs: tag=$(linkerd version --client --short) echo "linkerd $tag" echo "LINKERD_TAG=$tag" >> "$GITHUB_ENV" - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 - run: just docker - run: just-k3d create - run: just k3d-load-linkerd @@ -169,7 +169,7 @@ jobs: if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') run: exit 1 - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 if: needs.meta.outputs.is_dependabot == 'true' && needs.meta.outputs.any_changed == 'true' - name: "Merge dependabot changes" if: needs.meta.outputs.is_dependabot == 'true' && needs.meta.outputs.any_changed == 'true' diff --git a/.github/workflows/release-weekly.yml b/.github/workflows/release-weekly.yml index 2966a1e308..d7605821bd 100644 --- a/.github/workflows/release-weekly.yml +++ b/.github/workflows/release-weekly.yml @@ -44,7 +44,7 @@ jobs: runs-on: ubuntu-22.04 timeout-minutes: 5 steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 - name: Check if the most recent commit is after the last release id: recency env: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7d292c2a41..fd7cefcf27 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -80,7 +80,7 @@ jobs: echo archs='["amd64", "arm64", "arm"]' ) >> "$GITHUB_OUTPUT" - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 if: github.event_name == 'pull_request' - id: changed if: github.event_name == 'pull_request' @@ -140,7 +140,7 @@ jobs: steps: - name: Configure git run: git config --global --add safe.directory "$PWD" # actions/runner#2033 - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 with: ref: ${{ needs.meta.outputs.ref }} - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 @@ -174,7 +174,7 @@ jobs: git config --global user.name "$GITHUB_USERNAME" git config --global user.email "$GITHUB_USERNAME"@users.noreply.github.com # Tag the release. - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 with: token: ${{ secrets.LINKERD2_PROXY_GITHUB_TOKEN || github.token }} ref: ${{ needs.meta.outputs.ref }} diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index 92277f11b5..7dc2e6943c 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -16,5 +16,5 @@ jobs: runs-on: ubuntu-latest steps: - uses: linkerd/dev/actions/setup-tools@v43 - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 - run: just sh-lint diff --git a/.github/workflows/toolchain.yml b/.github/workflows/toolchain.yml index 687e0135ea..9a398536ee 100644 --- a/.github/workflows/toolchain.yml +++ b/.github/workflows/toolchain.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest container: ghcr.io/linkerd/dev:v43-rust steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 - run: git config --global --add safe.directory "$PWD" # actions/runner#2033 - run: | VERSION_REGEX='channel = "([0-9]+\.[0-9]+\.[0-9]+)"' @@ -38,7 +38,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: linkerd/dev/actions/setup-tools@v43 - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 - shell: bash run: | VERSION_REGEX='channel = "([0-9]+\.[0-9]+\.[0-9]+)"' From 56c76ad9cdf9d86a61fd61557e4e170128bde4ed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2024 07:21:30 -0700 Subject: [PATCH 40/42] build(deps): bump procfs from 0.16.0 to 0.17.0 (#3269) Bumps [procfs](https://github.com/eminence/procfs) from 0.16.0 to 0.17.0. - [Release notes](https://github.com/eminence/procfs/releases) - [Commits](https://github.com/eminence/procfs/compare/v0.16.0...v0.17.0) --- updated-dependencies: - dependency-name: procfs dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 9 ++++----- linkerd/system/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c97651502d..04125e0018 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2822,22 +2822,21 @@ dependencies = [ [[package]] name = "procfs" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4" +checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f" dependencies = [ "bitflags 2.4.2", "hex", - "lazy_static", "procfs-core", "rustix", ] [[package]] name = "procfs-core" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" +checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec" dependencies = [ "bitflags 2.4.2", "hex", diff --git a/linkerd/system/Cargo.toml b/linkerd/system/Cargo.toml index e36892a32e..0d04303c67 100644 --- a/linkerd/system/Cargo.toml +++ b/linkerd/system/Cargo.toml @@ -14,4 +14,4 @@ tracing = "0.1" [target.'cfg(target_os = "linux")'.dependencies] libc = "0.2" -procfs = { version = "0.16.0", default-features = false } +procfs = { version = "0.17.0", default-features = false } From bbaaa4bc1a6c4e5ad191ff97d1dace1eb737ddbc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2024 07:22:36 -0700 Subject: [PATCH 41/42] build(deps): bump actions/upload-artifact from 4.4.0 to 4.4.3 (#3271) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.4.0 to 4.4.3. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/50769540e7f4bd5e21e526ee35c689e35e0d6874...b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fd7cefcf27..424aabc2b8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -150,7 +150,7 @@ jobs: - run: just arch=${{ matrix.arch }} libc=${{ matrix.libc }} rustup - run: just arch=${{ matrix.arch }} libc=${{ matrix.libc }} profile=${{ needs.meta.outputs.profile }} build - run: just arch=${{ matrix.arch }} libc=${{ matrix.libc }} profile=${{ needs.meta.outputs.profile }} package - - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 + - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 with: name: ${{ matrix.arch }}-artifacts path: target/package/* From 44854bd4c37cd94eafdb1358b1d088a8ab3eec85 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2024 14:28:43 +0000 Subject: [PATCH 42/42] build(deps): bump unicode-bidi from 0.3.15 to 0.3.17 (#3254) Bumps [unicode-bidi](https://github.com/servo/unicode-bidi) from 0.3.15 to 0.3.17. - [Release notes](https://github.com/servo/unicode-bidi/releases) - [Commits](https://github.com/servo/unicode-bidi/compare/v0.3.15...v0.3.17) --- updated-dependencies: - dependency-name: unicode-bidi dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 04125e0018..f35dcbe4dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3737,9 +3737,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident"