diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/README.md b/crates/weaver_forge/codegen_examples/expected_codegen/README.md new file mode 100644 index 00000000..e5f4ef77 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/expected_codegen/README.md @@ -0,0 +1,20 @@ +# Semantic Conventions for Rust + +# Usage + +```rust +fn main() { + // Display the KeyValue of the attribute CLIENT_ADDRESS initialized with the value "145.34.23.56" + println!("{:?}", semconv::client::CLIENT_ADDRESS.value("145.34.23.56".into())); + // Display the key of the attribute CLIENT_ADDRESS + println!("{:?}", semconv::client::CLIENT_ADDRESS.key()); + + // Display the KeyValue of the attribute CLIENT_PORT initialized with the value 8080 + println!("{:?}", semconv::client::CLIENT_PORT.value(8080)); + // Display the key of the attribute CLIENT_PORT + println!("{:?}", semconv::client::CLIENT_PORT.key()); + + // Display the string representation of the enum variant HttpRequestMethod::Connect + println!("{}", semconv::http::HttpRequestMethod::Connect); +} +``` \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/client.rs b/crates/weaver_forge/codegen_examples/expected_codegen/client.rs index d0aa5790..edec5e7c 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/client.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/client.rs @@ -6,15 +6,13 @@ //! These attributes may be used to describe the client in a connection-based network interaction where there is one side that initiates the connection (the client is the side that initiates the connection). This covers all TCP network interactions since TCP is connection-based and one side initiates the connection (an exception is made for peer-to-peer communication over TCP where the "user-facing" surface of the protocol / API doesn't expose a clear notion of client and server). This also covers UDP network interactions where one side initiates the interaction, e.g. QUIC (HTTP/3) and DNS. //! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 -use opentelemetry::StringValue; -use crate::AttributeKey; - /// Client address - domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. /// /// Notes: /// When observed from the server side, and when communicating through an intermediary, `client.address` SHOULD represent the client address behind any intermediaries, for example proxies, if it's available. -pub const CLIENT_ADDRESS: AttributeKey = AttributeKey::new("client.address"); +pub const CLIENT_ADDRESS: crate::AttributeKey = crate::AttributeKey::new("client.address"); + @@ -22,5 +20,6 @@ pub const CLIENT_ADDRESS: AttributeKey = AttributeKey::new("client. /// /// Notes: /// When observed from the server side, and when communicating through an intermediary, `client.port` SHOULD represent the client port behind any intermediaries, for example proxies, if it's available. -pub const CLIENT_PORT: AttributeKey = AttributeKey::new("client.port"); +pub const CLIENT_PORT: crate::AttributeKey = crate::AttributeKey::new("client.port"); + diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/exception.rs b/crates/weaver_forge/codegen_examples/expected_codegen/exception.rs index d283e009..f907c364 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/exception.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/exception.rs @@ -6,22 +6,22 @@ //! This document defines the shared attributes used to report a single exception associated with a span or log. //! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 -use opentelemetry::StringValue; -use crate::AttributeKey; - /// The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it. -pub const EXCEPTION_TYPE: AttributeKey = AttributeKey::new("exception.type"); +pub const EXCEPTION_TYPE: crate::AttributeKey = crate::AttributeKey::new("exception.type"); + /// The exception message. -pub const EXCEPTION_MESSAGE: AttributeKey = AttributeKey::new("exception.message"); +pub const EXCEPTION_MESSAGE: crate::AttributeKey = crate::AttributeKey::new("exception.message"); + /// A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG. -pub const EXCEPTION_STACKTRACE: AttributeKey = AttributeKey::new("exception.stacktrace"); +pub const EXCEPTION_STACKTRACE: crate::AttributeKey = crate::AttributeKey::new("exception.stacktrace"); + @@ -44,5 +44,6 @@ pub const EXCEPTION_STACKTRACE: AttributeKey = AttributeKey::new("e /// even if the `exception.escaped` attribute was not set or set to false, /// since the event might have been recorded at a time where it was not /// clear whether the exception will escape. -pub const EXCEPTION_ESCAPED: AttributeKey = AttributeKey::new("exception.escaped"); +pub const EXCEPTION_ESCAPED: crate::AttributeKey = crate::AttributeKey::new("exception.escaped"); + diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/http.rs b/crates/weaver_forge/codegen_examples/expected_codegen/http.rs index c7c3f48a..ca045c86 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/http.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/http.rs @@ -6,13 +6,11 @@ //! This document defines semantic convention attributes in the HTTP namespace. //! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 -use opentelemetry::StringValue; -use crate::AttributeKey; - /// The size of the request payload body in bytes. This is the number of bytes transferred excluding headers and is often, but not always, present as the [Content-Length](https://www.rfc-editor.org/rfc/rfc9110.html#field.content-length) header. For requests using transport encoding, this should be the compressed size. #[cfg(feature = "semconv_experimental")] -pub const HTTP_REQUEST_BODY_SIZE: AttributeKey = AttributeKey::new("http.request.body.size"); +pub const HTTP_REQUEST_BODY_SIZE: crate::AttributeKey = crate::AttributeKey::new("http.request.body.size"); + /// HTTP request headers, `` being the normalized HTTP Header name (lowercase), the value being the header values. @@ -21,7 +19,8 @@ pub const HTTP_REQUEST_BODY_SIZE: AttributeKey = AttributeKey::new("http.re /// Instrumentations SHOULD require an explicit configuration of which headers are to be captured. Including all request headers can be a security risk - explicit configuration helps avoid leaking sensitive information. /// The `User-Agent` header is already captured in the `user_agent.original` attribute. Users MAY explicitly configure instrumentations to capture them even though it is not recommended. /// The attribute value MUST consist of either multiple header values as an array of strings or a single-item array containing a possibly comma-concatenated string, depending on the way the HTTP library provides access to headers. -pub const HTTP_REQUEST_HEADER: AttributeKey> = AttributeKey::new("http.request.header"); +pub const HTTP_REQUEST_HEADER: crate::AttributeKey> = crate::AttributeKey::new("http.request.header"); + /// HTTP request method. @@ -41,7 +40,8 @@ pub const HTTP_REQUEST_HEADER: AttributeKey> = AttributeKey::new("ht /// HTTP method names are case-sensitive and `http.request.method` attribute value MUST match a known HTTP method name exactly. /// Instrumentations for specific web frameworks that consider HTTP methods to be case insensitive, SHOULD populate a canonical equivalent. /// Tracing instrumentations that do so, MUST also set `http.request.method_original` to the original value. -pub const HTTP_REQUEST_METHOD: AttributeKey = AttributeKey::new("http.request.method"); +pub const HTTP_REQUEST_METHOD: crate::AttributeKey = crate::AttributeKey::new("http.request.method"); + /// HTTP request method. @@ -70,9 +70,40 @@ pub enum HttpRequestMethod { } +impl HttpRequestMethod { + /// Returns the string representation of the [`HttpRequestMethod`]. + pub fn as_str(&self) -> &'static str { + match self { + HttpRequestMethod::Connect => "CONNECT", + HttpRequestMethod::Delete => "DELETE", + HttpRequestMethod::Get => "GET", + HttpRequestMethod::Head => "HEAD", + HttpRequestMethod::Options => "OPTIONS", + HttpRequestMethod::Patch => "PATCH", + HttpRequestMethod::Post => "POST", + HttpRequestMethod::Put => "PUT", + HttpRequestMethod::Trace => "TRACE", + HttpRequestMethod::Other => "_OTHER", + // Without this default case, the match expression would not + // contain any variants if all variants are annotated with the + // 'semconv_experimental' feature and the feature is not enabled. + #[allow(unreachable_patterns)] + _ => unreachable!(), + } + } +} + +impl core::fmt::Display for HttpRequestMethod { + /// Formats the value using the given formatter. + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } +} + /// Original HTTP method sent by the client in the request line. -pub const HTTP_REQUEST_METHOD_ORIGINAL: AttributeKey = AttributeKey::new("http.request.method_original"); +pub const HTTP_REQUEST_METHOD_ORIGINAL: crate::AttributeKey = crate::AttributeKey::new("http.request.method_original"); + @@ -80,17 +111,20 @@ pub const HTTP_REQUEST_METHOD_ORIGINAL: AttributeKey = AttributeKey /// /// Notes: /// The resend count SHOULD be updated each time an HTTP request gets resent by the client, regardless of what was the cause of the resending (e.g. redirection, authorization failure, 503 Server Unavailable, network issues, or any other). -pub const HTTP_REQUEST_RESEND_COUNT: AttributeKey = AttributeKey::new("http.request.resend_count"); +pub const HTTP_REQUEST_RESEND_COUNT: crate::AttributeKey = crate::AttributeKey::new("http.request.resend_count"); + /// The total size of the request in bytes. This should be the total number of bytes sent over the wire, including the request line (HTTP/1.1), framing (HTTP/2 and HTTP/3), headers, and request body if any. #[cfg(feature = "semconv_experimental")] -pub const HTTP_REQUEST_SIZE: AttributeKey = AttributeKey::new("http.request.size"); +pub const HTTP_REQUEST_SIZE: crate::AttributeKey = crate::AttributeKey::new("http.request.size"); + /// The size of the response payload body in bytes. This is the number of bytes transferred excluding headers and is often, but not always, present as the [Content-Length](https://www.rfc-editor.org/rfc/rfc9110.html#field.content-length) header. For requests using transport encoding, this should be the compressed size. #[cfg(feature = "semconv_experimental")] -pub const HTTP_RESPONSE_BODY_SIZE: AttributeKey = AttributeKey::new("http.response.body.size"); +pub const HTTP_RESPONSE_BODY_SIZE: crate::AttributeKey = crate::AttributeKey::new("http.response.body.size"); + /// HTTP response headers, `` being the normalized HTTP Header name (lowercase), the value being the header values. @@ -99,16 +133,19 @@ pub const HTTP_RESPONSE_BODY_SIZE: AttributeKey = AttributeKey::new("http.r /// Instrumentations SHOULD require an explicit configuration of which headers are to be captured. Including all response headers can be a security risk - explicit configuration helps avoid leaking sensitive information. /// Users MAY explicitly configure instrumentations to capture them even though it is not recommended. /// The attribute value MUST consist of either multiple header values as an array of strings or a single-item array containing a possibly comma-concatenated string, depending on the way the HTTP library provides access to headers. -pub const HTTP_RESPONSE_HEADER: AttributeKey> = AttributeKey::new("http.response.header"); +pub const HTTP_RESPONSE_HEADER: crate::AttributeKey> = crate::AttributeKey::new("http.response.header"); + /// The total size of the response in bytes. This should be the total number of bytes sent over the wire, including the status line (HTTP/1.1), framing (HTTP/2 and HTTP/3), headers, and response body and trailers if any. #[cfg(feature = "semconv_experimental")] -pub const HTTP_RESPONSE_SIZE: AttributeKey = AttributeKey::new("http.response.size"); +pub const HTTP_RESPONSE_SIZE: crate::AttributeKey = crate::AttributeKey::new("http.response.size"); + /// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). -pub const HTTP_RESPONSE_STATUS_CODE: AttributeKey = AttributeKey::new("http.response.status_code"); +pub const HTTP_RESPONSE_STATUS_CODE: crate::AttributeKey = crate::AttributeKey::new("http.response.status_code"); + /// The matched route, that is, the path template in the format used by the respective server framework. @@ -116,13 +153,15 @@ pub const HTTP_RESPONSE_STATUS_CODE: AttributeKey = AttributeKey::new("http /// Notes: /// MUST NOT be populated when this is not supported by the HTTP server framework as the route attribute should have low-cardinality and the URI path can NOT substitute it. /// SHOULD include the [application root](/docs/http/http-spans.md#http-server-definitions) if there is one. -pub const HTTP_ROUTE: AttributeKey = AttributeKey::new("http.route"); +pub const HTTP_ROUTE: crate::AttributeKey = crate::AttributeKey::new("http.route"); + /// State of the HTTP connection in the HTTP connection pool. #[cfg(feature = "semconv_experimental")] -pub const HTTP_CONNECTION_STATE: AttributeKey = AttributeKey::new("http.connection.state"); +pub const HTTP_CONNECTION_STATE: crate::AttributeKey = crate::AttributeKey::new("http.connection.state"); + /// State of the HTTP connection in the HTTP connection pool. @@ -137,3 +176,27 @@ pub enum HttpConnectionState { } +impl HttpConnectionState { + /// Returns the string representation of the [`HttpConnectionState`]. + pub fn as_str(&self) -> &'static str { + match self { + #[cfg(feature = "semconv_experimental")] + HttpConnectionState::Active => "active", + #[cfg(feature = "semconv_experimental")] + HttpConnectionState::Idle => "idle", + // Without this default case, the match expression would not + // contain any variants if all variants are annotated with the + // 'semconv_experimental' feature and the feature is not enabled. + #[allow(unreachable_patterns)] + _ => unreachable!(), + } + } +} + +impl core::fmt::Display for HttpConnectionState { + /// Formats the value using the given formatter. + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } +} + diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/lib.rs b/crates/weaver_forge/codegen_examples/expected_codegen/lib.rs index b997ff69..35c0717c 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/lib.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/lib.rs @@ -16,7 +16,7 @@ pub mod exception; /// This document defines semantic convention attributes in the HTTP namespace. pub mod http; /// These attributes may be used for any network related operation. -pub mod net; +pub mod network; /// A typed attribute key. pub struct AttributeKey { diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/net.rs b/crates/weaver_forge/codegen_examples/expected_codegen/net.rs deleted file mode 100644 index 477f41f2..00000000 --- a/crates/weaver_forge/codegen_examples/expected_codegen/net.rs +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! These attributes may be used for any network related operation. -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 - -use opentelemetry::StringValue; -use crate::AttributeKey; - - -/// Deprecated, no replacement at this time. -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Removed.")] -pub const NET_SOCK_PEER_NAME: AttributeKey = AttributeKey::new("net.sock.peer.name"); - - - -/// Deprecated, use `network.peer.address`. -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `network.peer.address`.")] -pub const NET_SOCK_PEER_ADDR: AttributeKey = AttributeKey::new("net.sock.peer.addr"); - - - -/// Deprecated, use `network.peer.port`. -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `network.peer.port`.")] -pub const NET_SOCK_PEER_PORT: AttributeKey = AttributeKey::new("net.sock.peer.port"); - - -/// Deprecated, use `server.address` on client spans and `client.address` on server spans. -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `server.address` on client spans and `client.address` on server spans.")] -pub const NET_PEER_NAME: AttributeKey = AttributeKey::new("net.peer.name"); - - - -/// Deprecated, use `server.port` on client spans and `client.port` on server spans. -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `server.port` on client spans and `client.port` on server spans.")] -pub const NET_PEER_PORT: AttributeKey = AttributeKey::new("net.peer.port"); - - -/// Deprecated, use `server.address`. -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `server.address`.")] -pub const NET_HOST_NAME: AttributeKey = AttributeKey::new("net.host.name"); - - - -/// Deprecated, use `server.port`. -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `server.port`.")] -pub const NET_HOST_PORT: AttributeKey = AttributeKey::new("net.host.port"); - - -/// Deprecated, use `network.local.address`. -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `network.local.address`.")] -pub const NET_SOCK_HOST_ADDR: AttributeKey = AttributeKey::new("net.sock.host.addr"); - - - -/// Deprecated, use `network.local.port`. -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `network.local.port`.")] -pub const NET_SOCK_HOST_PORT: AttributeKey = AttributeKey::new("net.sock.host.port"); - - -/// Deprecated, use `network.transport`. -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `network.transport`.")] -pub const NET_TRANSPORT: AttributeKey = AttributeKey::new("net.transport"); - - -/// Deprecated, use `network.transport`. -#[non_exhaustive] -pub enum NetTransport { - - #[cfg(feature = "semconv_experimental")] - IpTcp, - - #[cfg(feature = "semconv_experimental")] - IpUdp, - /// Named or anonymous pipe. - #[cfg(feature = "semconv_experimental")] - Pipe, - /// In-process communication. /// Signals that there is only in-process communication not using a "real" network protocol in cases where network attributes would normally be expected. Usually all other network attributes can be left out in that case. - #[cfg(feature = "semconv_experimental")] - Inproc, - /// Something else (non IP-based). - #[cfg(feature = "semconv_experimental")] - Other, - -} - - -/// Deprecated, use `network.protocol.name`. -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `network.protocol.name`.")] -pub const NET_PROTOCOL_NAME: AttributeKey = AttributeKey::new("net.protocol.name"); - - - -/// Deprecated, use `network.protocol.version`. -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `network.protocol.version`.")] -pub const NET_PROTOCOL_VERSION: AttributeKey = AttributeKey::new("net.protocol.version"); - - - -/// Deprecated, use `network.transport` and `network.type`. -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Split to `network.transport` and `network.type`.")] -pub const NET_SOCK_FAMILY: AttributeKey = AttributeKey::new("net.sock.family"); - - -/// Deprecated, use `network.transport` and `network.type`. -#[non_exhaustive] -pub enum NetSockFamily { - /// IPv4 address - #[cfg(feature = "semconv_experimental")] - Inet, - /// IPv6 address - #[cfg(feature = "semconv_experimental")] - Inet6, - /// Unix domain socket path - #[cfg(feature = "semconv_experimental")] - Unix, - -} - diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/network.rs b/crates/weaver_forge/codegen_examples/expected_codegen/network.rs new file mode 100644 index 00000000..ba6f96da --- /dev/null +++ b/crates/weaver_forge/codegen_examples/expected_codegen/network.rs @@ -0,0 +1,200 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! These attributes may be used for any network related operation. +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 + + +/// Deprecated, no replacement at this time. +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Removed.")] +pub const NET_SOCK_PEER_NAME: crate::AttributeKey = crate::AttributeKey::new("net.sock.peer.name"); + + + + +/// Deprecated, use `network.peer.address`. +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `network.peer.address`.")] +pub const NET_SOCK_PEER_ADDR: crate::AttributeKey = crate::AttributeKey::new("net.sock.peer.addr"); + + + + +/// Deprecated, use `network.peer.port`. +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `network.peer.port`.")] +pub const NET_SOCK_PEER_PORT: crate::AttributeKey = crate::AttributeKey::new("net.sock.peer.port"); + + + +/// Deprecated, use `server.address` on client spans and `client.address` on server spans. +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `server.address` on client spans and `client.address` on server spans.")] +pub const NET_PEER_NAME: crate::AttributeKey = crate::AttributeKey::new("net.peer.name"); + + + + +/// Deprecated, use `server.port` on client spans and `client.port` on server spans. +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `server.port` on client spans and `client.port` on server spans.")] +pub const NET_PEER_PORT: crate::AttributeKey = crate::AttributeKey::new("net.peer.port"); + + + +/// Deprecated, use `server.address`. +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `server.address`.")] +pub const NET_HOST_NAME: crate::AttributeKey = crate::AttributeKey::new("net.host.name"); + + + + +/// Deprecated, use `server.port`. +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `server.port`.")] +pub const NET_HOST_PORT: crate::AttributeKey = crate::AttributeKey::new("net.host.port"); + + + +/// Deprecated, use `network.local.address`. +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `network.local.address`.")] +pub const NET_SOCK_HOST_ADDR: crate::AttributeKey = crate::AttributeKey::new("net.sock.host.addr"); + + + + +/// Deprecated, use `network.local.port`. +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `network.local.port`.")] +pub const NET_SOCK_HOST_PORT: crate::AttributeKey = crate::AttributeKey::new("net.sock.host.port"); + + + +/// Deprecated, use `network.transport`. +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `network.transport`.")] +pub const NET_TRANSPORT: crate::AttributeKey = crate::AttributeKey::new("net.transport"); + + + +/// Deprecated, use `network.transport`. +#[non_exhaustive] +pub enum NetTransport { + + #[cfg(feature = "semconv_experimental")] + IpTcp, + + #[cfg(feature = "semconv_experimental")] + IpUdp, + /// Named or anonymous pipe. + #[cfg(feature = "semconv_experimental")] + Pipe, + /// In-process communication. /// Signals that there is only in-process communication not using a "real" network protocol in cases where network attributes would normally be expected. Usually all other network attributes can be left out in that case. + #[cfg(feature = "semconv_experimental")] + Inproc, + /// Something else (non IP-based). + #[cfg(feature = "semconv_experimental")] + Other, + +} + +impl NetTransport { + /// Returns the string representation of the [`NetTransport`]. + pub fn as_str(&self) -> &'static str { + match self { + #[cfg(feature = "semconv_experimental")] + NetTransport::IpTcp => "ip_tcp", + #[cfg(feature = "semconv_experimental")] + NetTransport::IpUdp => "ip_udp", + #[cfg(feature = "semconv_experimental")] + NetTransport::Pipe => "pipe", + #[cfg(feature = "semconv_experimental")] + NetTransport::Inproc => "inproc", + #[cfg(feature = "semconv_experimental")] + NetTransport::Other => "other", + // Without this default case, the match expression would not + // contain any variants if all variants are annotated with the + // 'semconv_experimental' feature and the feature is not enabled. + #[allow(unreachable_patterns)] + _ => unreachable!(), + } + } +} + +impl core::fmt::Display for NetTransport { + /// Formats the value using the given formatter. + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } +} + + +/// Deprecated, use `network.protocol.name`. +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `network.protocol.name`.")] +pub const NET_PROTOCOL_NAME: crate::AttributeKey = crate::AttributeKey::new("net.protocol.name"); + + + + +/// Deprecated, use `network.protocol.version`. +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `network.protocol.version`.")] +pub const NET_PROTOCOL_VERSION: crate::AttributeKey = crate::AttributeKey::new("net.protocol.version"); + + + + +/// Deprecated, use `network.transport` and `network.type`. +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Split to `network.transport` and `network.type`.")] +pub const NET_SOCK_FAMILY: crate::AttributeKey = crate::AttributeKey::new("net.sock.family"); + + + +/// Deprecated, use `network.transport` and `network.type`. +#[non_exhaustive] +pub enum NetSockFamily { + /// IPv4 address + #[cfg(feature = "semconv_experimental")] + Inet, + /// IPv6 address + #[cfg(feature = "semconv_experimental")] + Inet6, + /// Unix domain socket path + #[cfg(feature = "semconv_experimental")] + Unix, + +} + +impl NetSockFamily { + /// Returns the string representation of the [`NetSockFamily`]. + pub fn as_str(&self) -> &'static str { + match self { + #[cfg(feature = "semconv_experimental")] + NetSockFamily::Inet => "inet", + #[cfg(feature = "semconv_experimental")] + NetSockFamily::Inet6 => "inet6", + #[cfg(feature = "semconv_experimental")] + NetSockFamily::Unix => "unix", + // Without this default case, the match expression would not + // contain any variants if all variants are annotated with the + // 'semconv_experimental' feature and the feature is not enabled. + #[allow(unreachable_patterns)] + _ => unreachable!(), + } + } +} + +impl core::fmt::Display for NetSockFamily { + /// Formats the value using the given formatter. + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } +} + diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/lib.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/lib.rs.j2 index 7f092619..d16af4cd 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/lib.rs.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/lib.rs.j2 @@ -12,7 +12,7 @@ use opentelemetry::{Key, KeyValue, StringValue}; {% for group in ctx %} {{ group.brief | comment_with_prefix("/// ") }} -pub mod {{ group.prefix | snake_case }}; +pub mod {{ group.id | attribute_registry_namespace | snake_case }}; {%- endfor %} /// A typed attribute key. diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/semantic_attributes.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/semantic_attributes.rs.j2 index a9000b34..1f8f55d0 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/semantic_attributes.rs.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/semantic_attributes.rs.j2 @@ -1,4 +1,4 @@ -{%- set file_name = ctx.prefix | snake_case -%} +{%- set file_name = ctx.id | attribute_registry_namespace | snake_case -%} {{- template.set_file_name(file_name ~ ".rs") -}} /* @@ -14,9 +14,6 @@ {%- endif %} //! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 -use opentelemetry::StringValue; -use crate::AttributeKey; - {% for attribute in ctx.attributes %} {%- if attribute.brief %} @@ -33,9 +30,9 @@ use crate::AttributeKey; {%- if attribute is deprecated %} #[deprecated(note="{{ attribute.deprecated }}")] {%- endif %} -{% if attribute.type.allow_custom_values is defined %}pub const {{ attribute.name | screaming_snake_case }}: AttributeKey<{{ attribute.name | pascal_case }}> = AttributeKey::new("{{ attribute.name }}"); -{% elif attribute.type == "string" %}pub const {{ attribute.name | screaming_snake_case }}: AttributeKey<{{ attribute.type | type_mapping }}Value> = AttributeKey::new("{{ attribute.name }}"); -{% else %}pub const {{ attribute.name | screaming_snake_case }}: AttributeKey<{{ attribute.type | type_mapping }}> = AttributeKey::new("{{ attribute.name }}");{% endif %} +{% if attribute.type.allow_custom_values is defined %}pub const {{ attribute.name | screaming_snake_case }}: crate::AttributeKey<{{ attribute.name | pascal_case }}> = crate::AttributeKey::new("{{ attribute.name }}"); +{% elif attribute.type == "string" %}pub const {{ attribute.name | screaming_snake_case }}: crate::AttributeKey = crate::AttributeKey::new("{{ attribute.name }}"); +{% else %}pub const {{ attribute.name | screaming_snake_case }}: crate::AttributeKey<{{ attribute.type | type_mapping }}> = crate::AttributeKey::new("{{ attribute.name }}");{% endif %} {% if attribute.type.allow_custom_values is defined %} {%- if attribute.brief %} @@ -61,9 +58,10 @@ impl {{ attribute.name | pascal_case }} { #[cfg(feature = "semconv_experimental")] {% endif %} {{ attribute.name | pascal_case }}::{{ variant.id | pascal_case }} => "{{ variant.value }}", {%- endfor %} - /// Without this default case, the match expression would not - /// contain any variants if all variants are annotated with the - /// 'semconv_experimental' feature and the feature is not enabled. + // Without this default case, the match expression would not + // contain any variants if all variants are annotated with the + // 'semconv_experimental' feature and the feature is not enabled. + #[allow(unreachable_patterns)] _ => unreachable!(), } } diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml b/crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml index c451b703..77be059d 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml @@ -28,8 +28,8 @@ templates: type, brief, prefix}) - | unique_by(.prefix) - | sort_by(.prefix) + | unique_by(.id | split(".") | .[1]) + | sort_by(.id | split(".") | .[1]) application_mode: single - pattern: semantic_attributes.rs.j2 # The following JQ filter extracts the id, type, brief, prefix, and attributes of groups matching the following @@ -49,9 +49,15 @@ templates: brief, prefix, attributes}) - | sort_by(.prefix // empty) + | sort_by(.id | split(".") | .[1]) application_mode: each +# .groups +# | map(select(.type == "attribute_group")) +# | map(select(.id | startswith("registry"))) +# | group_by(.id | split(".") | .[1]) +# | map({id: .[0].id | split(".") | .[1], groups: .}) + # Other examples of filters # The following JQ filter extracts the id, type, brief, and prefix of groups matching the following criteria: diff --git a/crates/weaver_forge/src/extensions/mod.rs b/crates/weaver_forge/src/extensions/mod.rs index cce185bd..40e53026 100644 --- a/crates/weaver_forge/src/extensions/mod.rs +++ b/crates/weaver_forge/src/extensions/mod.rs @@ -4,4 +4,4 @@ pub mod acronym; pub mod case_converter; pub mod code; -pub mod test; +pub mod otel; diff --git a/crates/weaver_forge/src/extensions/test.rs b/crates/weaver_forge/src/extensions/otel.rs similarity index 53% rename from crates/weaver_forge/src/extensions/test.rs rename to crates/weaver_forge/src/extensions/otel.rs index c37ca680..b8db0f42 100644 --- a/crates/weaver_forge/src/extensions/test.rs +++ b/crates/weaver_forge/src/extensions/otel.rs @@ -1,8 +1,57 @@ // SPDX-License-Identifier: Apache-2.0 -//! Set of tests +//! Set of filters, tests, and functions that are specific to the OpenTelemetry project. -use minijinja::Value; +use crate::config::CaseConvention; +use minijinja::{ErrorKind, Value}; + +/// Converts registry.{namespace}.{other}.{components} to {namespace}. +/// +/// A [`minijinja::Error`] is returned if the input does not start with "registry" or does not have +/// at least two parts. Otherwise, it returns the namespace (second part of the input). +pub(crate) fn attribute_registry_namespace(input: &str) -> Result { + let parts: Vec<&str> = input.split('.').collect(); + if parts.len() < 2 || parts[0] != "registry" { + return Err(minijinja::Error::new( + ErrorKind::InvalidOperation, + format!("This attribute registry id `{}` is invalid", input), + )); + } + Ok(parts[1].to_owned()) +} + +/// Converts registry.{namespace}.{other}.{components} to {Namespace} (title case the namespace). +/// +/// A [`minijinja::Error`] is returned if the input does not start with "registry" or does not have +/// at least two parts. Otherwise, it returns the namespace (second part of the input, title case). +pub(crate) fn attribute_registry_title(input: &str) -> Result { + let parts: Vec<&str> = input.split('.').collect(); + if parts.len() < 2 || parts[0] != "registry" { + return Err(minijinja::Error::new( + ErrorKind::InvalidOperation, + format!("This attribute registry id `{}` is invalid", input), + )); + } + Ok(CaseConvention::TitleCase.convert(parts[1])) +} + +/// attribute_registry_file: Converts registry.{namespace}.{other}.{components} to attributes-registry/{namespace}.md (kebab-case namespace). +/// +/// A [`minijinja::Error`] is returned if the input does not start with "registry" or does not have +/// at least two parts. Otherwise, it returns the file path (kebab-case namespace). +pub(crate) fn attribute_registry_file(input: &str) -> Result { + let parts: Vec<&str> = input.split('.').collect(); + if parts.len() < 2 || parts[0] != "registry" { + return Err(minijinja::Error::new( + ErrorKind::InvalidOperation, + format!("This attribute registry id `{}` is invalid", input), + )); + } + Ok(format!( + "attributes-registry/{}.md", + CaseConvention::KebabCase.convert(parts[1]) + )) +} /// Checks if the input value is an object with a field named "stability" that has the value "stable". /// Otherwise, it returns false. @@ -48,9 +97,12 @@ pub(crate) fn is_deprecated(input: Value) -> bool { #[cfg(test)] mod tests { + use crate::extensions::otel::{ + attribute_registry_file, attribute_registry_namespace, attribute_registry_title, + is_deprecated, is_experimental, is_stable, + }; use minijinja::value::StructObject; - - use super::*; + use minijinja::Value; struct DynAttr { id: String, @@ -86,6 +138,66 @@ mod tests { } } + #[test] + fn test_attribute_registry_namespace() { + // A string that does not start with "registry" + let input = "test"; + assert!(attribute_registry_namespace(input).is_err()); + + // A string that starts with "registry" but does not have at least two parts + let input = "registry"; + assert!(attribute_registry_namespace(input).is_err()); + + // A string that starts with "registry" and has at least two parts + let input = "registry.namespace.other.components"; + assert_eq!(attribute_registry_namespace(input).unwrap(), "namespace"); + + // An empty string + let input = ""; + assert!(attribute_registry_namespace(input).is_err()); + } + + #[test] + fn test_attribute_registry_title() { + // A string that does not start with "registry" + let input = "test"; + assert!(attribute_registry_title(input).is_err()); + + // A string that starts with "registry" but does not have at least two parts + let input = "registry"; + assert!(attribute_registry_title(input).is_err()); + + // A string that starts with "registry" and has at least two parts + let input = "registry.namespace.other.components"; + assert_eq!(attribute_registry_title(input).unwrap(), "Namespace"); + + // An empty string + let input = ""; + assert!(attribute_registry_title(input).is_err()); + } + + #[test] + fn test_attribute_registry_file() { + // A string that does not start with "registry" + let input = "test"; + assert!(attribute_registry_file(input).is_err()); + + // A string that starts with "registry" but does not have at least two parts + let input = "registry"; + assert!(attribute_registry_file(input).is_err()); + + // A string that starts with "registry" and has at least two parts + let input = "registry.namespace.other.components"; + assert_eq!( + attribute_registry_file(input).unwrap(), + "attributes-registry/namespace.md" + ); + + // An empty string + let input = ""; + assert!(attribute_registry_file(input).is_err()); + } + #[test] fn test_is_stable() { // An attribute with stability "stable" diff --git a/crates/weaver_forge/src/lib.rs b/crates/weaver_forge/src/lib.rs index b7fbffd0..b6189803 100644 --- a/crates/weaver_forge/src/lib.rs +++ b/crates/weaver_forge/src/lib.rs @@ -391,13 +391,24 @@ impl TemplateEngine { env.add_filter("acronym", acronym(self.target_config.acronyms.clone())); - // ToDo required, not_required, stable, experimental, deprecated - - // Register custom tests - env.add_test("stable", extensions::test::is_stable); - env.add_test("experimental", extensions::test::is_experimental); - env.add_test("deprecated", extensions::test::is_deprecated); - // ToDo required, not_required + // Register custom OpenTelemetry filters and tests + env.add_filter( + "attribute_registry_namespace", + extensions::otel::attribute_registry_namespace, + ); + env.add_filter( + "attribute_registry_title", + extensions::otel::attribute_registry_title, + ); + env.add_filter( + "attribute_registry_file", + extensions::otel::attribute_registry_file, + ); + // ToDo Implement more filters: required, not_required, stable, experimental, deprecated + env.add_test("stable", extensions::otel::is_stable); + env.add_test("experimental", extensions::otel::is_experimental); + env.add_test("deprecated", extensions::otel::is_deprecated); + // ToDo Implement more tests: required, not_required // env.add_filter("unique_attributes", extensions::unique_attributes); // env.add_filter("instrument", extensions::instrument);