From: Otto Moerbeek Date: Tue, 20 May 2025 08:30:30 +0000 (+0200) Subject: Added comments on the semantics of the various fields, added forgotten flags field... X-Git-Tag: rec-5.3.0-alpha1^2~18 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9dea3d46d71c101ff81234ecae8a82cd506b35dc;p=thirdparty%2Fpdns.git Added comments on the semantics of the various fields, added forgotten flags field to Span Signed-off-by: Otto Moerbeek --- diff --git a/pdns/recursordist/protozero-trace.cc b/pdns/recursordist/protozero-trace.cc index d391e9c82a..5ab684da12 100644 --- a/pdns/recursordist/protozero-trace.cc +++ b/pdns/recursordist/protozero-trace.cc @@ -325,6 +325,7 @@ void Span::encode(protozero::pbf_writer& writer) const protozero::pbf_writer sub{writer, 15}; status.encode(sub); } + pdns::trace::encodeFixed(writer, 16, flags); } Span Span::decode(protozero::pbf_reader& reader) @@ -385,6 +386,9 @@ Span Span::decode(protozero::pbf_reader& reader) ret.status = Status::decode(sub); break; } + case 16: + ret.flags = reader.get_fixed32(); + break; default: break; } diff --git a/pdns/recursordist/protozero-trace.hh b/pdns/recursordist/protozero-trace.hh index 2bb168ebdd..e2b6244cbe 100644 --- a/pdns/recursordist/protozero-trace.hh +++ b/pdns/recursordist/protozero-trace.hh @@ -55,7 +55,9 @@ inline void encode(protozero::pbf_writer& writer, uint8_t field, uint32_t value, inline void encodeFixed(protozero::pbf_writer& writer, uint8_t field, uint32_t value) { - writer.add_fixed32(field, value); + if (value != 0) { + writer.add_fixed32(field, value); + } } inline void encode(protozero::pbf_writer& writer, uint8_t field, int64_t value, bool always = false) @@ -74,7 +76,9 @@ inline void encode(protozero::pbf_writer& writer, uint8_t field, uint64_t value, inline void encodeFixed(protozero::pbf_writer& writer, uint8_t field, uint64_t value) { - writer.add_fixed64(field, value); + if (value != 0) { + writer.add_fixed64(field, value); + } } inline void encode(protozero::pbf_writer& writer, uint8_t field, double value, bool always = false) @@ -242,16 +246,23 @@ inline SpanID decodeSpanID(protozero::pbf_reader& reader) return bytes; } +// The Status type defines a logical error model that is suitable for different +// programming environments, including REST APIs and RPC APIs. struct Status { + // A developer-facing human readable error message. std::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 class StatusCode : uint8_t { + // 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, }; @@ -264,44 +275,164 @@ struct Status 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. TraceID 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. SpanID 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. std::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. SpanID parent_span_id; // = 4 + // 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. std::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 class SpanKind : uint8_t { + // Unspecified. Do NOT use as default. + // Implementations MAY assume SpanKind to be INTERNAL when receiving UNSPECIFIED. SPAN_KINUNSPECIFIED = 0, + // Indicates that the span represents an internal operation within an application, + // as opposed to an operation happening at the boundaries. Default value. SPAN_KININTERNAL = 1, + // Indicates that the span covers server-side handling of an RPC or other + // remote network request. SPAN_KINSERVER = 2, + // Indicates that the span describes a request to some remote service. SPAN_KINCLIENT = 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_KINPRODUCER = 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_KINCONSUMER = 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{Span::SpanKind::SPAN_KINUNSPECIFIED}; // = 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. uint64_t start_time_unix_nano{0}; // = 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. uint64_t end_time_unix_nano{0}; // = 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). std::vector 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_t dropped_attributes_count{0}; // = 10 + + // Event is a time-stamped annotation of the span, consisting of user-supplied + // text description and key-value pairs.x struct Event { + // time_unix_nano is the time the event occurred. uint64_t time_unix_nano; // = 1 + // name of the event. + // This field is semantically required to be set to non-empty string. std::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). std::vector attributes; // = 3 + // dropped_attributes_count is the number of dropped attributes. If the value is 0, + // then no attributes were dropped. uint32_t dropped_attributes_count{0}; // = 4 void encode(protozero::pbf_writer& writer) const; static Event decode(protozero::pbf_reader& reader); }; + // events is a collection of Event items. std::vector events; // = 11 + // dropped_events_count is the number of dropped events. If the value is 0, then no + // events were dropped. uint32_t 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. struct Link { + // A unique identifier of a trace that this linked span is part of. The ID is a + // 16-byte array. TraceID trace_id; // = 1 + // A unique identifier for the linked span. The ID is an 8-byte array. SpanID span_id; // = 2 + // The trace_state associated with the link. std::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). std::vector attributes; // = 4 + // dropped_attributes_count is the number of dropped attributes. If the value is 0, + // then no attributes were dropped. uint32_t dropped_attributes_count{0}; // = 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]. uint32_t flags{0}; // = 6 void encode(protozero::pbf_writer& writer) const; @@ -311,40 +442,119 @@ struct Span uint32_t dropped_links_count{0}; // = 14 Status status; // = 15 + // 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]. + uint32_t flags{0}; // = 16; + void encode(protozero::pbf_writer& writer) const; static Span decode(protozero::pbf_reader& reader); }; +// 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 class SpanFlags : uint16_t { + // 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 + SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK = 0x00000200, + // Bits 10-31 are reserved for future use. }; - + +// A collection of Spans produced by an InstrumentationScope. 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). InstrumentationScope scope; // = 1 + // A list of Spans that originate from an instrumentation scope. std::vector spans; // = 2 + // The Schema URL, if known. This is the identifier of the Schema that the span data + // is recorded in. Notably, the last part of the URL path is the version number of the + // schema: http[s]://server[:port]/path/. 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. std::string schema_url; // = 3 void encode(protozero::pbf_writer& writer) const; static ScopeSpans decode(protozero::pbf_reader& reader); }; +// A collection of ScopeSpans from a Resource. struct ResourceSpans { + // The resource for the spans in this message. + // If this field is not set then no resource info is known. Resource resource; // = 1 + // A list of ScopeSpans that originate from a resource. std::vector scope_spans; // = 2 + // The Schema URL, if known. This is the identifier of the Schema that the resource data + // is recorded in. Notably, the last part of the URL path is the version number of the + // schema: http[s]://server[:port]/path/. 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. std::string schema_url; // = 3 void encode(protozero::pbf_writer& writer) const; static ResourceSpans decode(protozero::pbf_reader& reader); }; +// 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. 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. std::vector resource_spans; // = 1 void encode(protozero::pbf_writer& writer) const; diff --git a/pdns/recursordist/test-protozero-trace.cc b/pdns/recursordist/test-protozero-trace.cc index 2346111b00..d50715c81a 100644 --- a/pdns/recursordist/test-protozero-trace.cc +++ b/pdns/recursordist/test-protozero-trace.cc @@ -187,6 +187,7 @@ BOOST_AUTO_TEST_CASE(traces2) }, .dropped_links_count = 3, .status = {"hi", pdns::trace::Status::StatusCode::STATUS_CODE_OK}, + .flags = 33, }; pdns::trace::Span span2{span1}; pdns::trace::Span span3{span1};