From 328a89f6f652f26b236646c778c9e50b0b03ff1c Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Fri, 26 Apr 2024 12:00:55 -0700 Subject: [PATCH 01/39] feat(codegen): create an example of codegen for SemConv Rust --- crates/weaver_forge/src/extensions/code.rs | 41 ++++++ crates/weaver_forge/src/extensions/mod.rs | 2 + crates/weaver_forge/src/extensions/tests.rs | 124 ++++++++++++++++++ crates/weaver_forge/src/lib.rs | 6 + .../registry/rust/semantic_attributes.rs.j2 | 18 +++ templates/registry/rust/weaver.yaml | 4 + templates/{ => schema}/go/config.yaml | 0 .../{ => schema}/go/optional_attrs.macro.tera | 0 .../go/otel/attribute/attrs.go.tera | 0 templates/{ => schema}/go/otel/client.go.tera | 0 .../{ => schema}/go/otel/eventer/event.tera | 0 .../{ => schema}/go/otel/meter/metric.tera | 0 .../go/otel/meter/metric_group.tera | 0 .../{ => schema}/go/otel/tracer/span.tera | 0 .../{ => schema}/go/required_attrs.macro.tera | 0 templates/{ => schema}/rust/config.yaml | 0 .../{ => schema}/rust/eventer/mod.rs.tera | 0 templates/{ => schema}/rust/meter/mod.rs.tera | 0 templates/{ => schema}/rust/mod.rs.tera | 0 templates/{ => schema}/rust/span.tera.bak | 0 .../{ => schema}/rust/tracer/mod.rs.tera | 0 21 files changed, 195 insertions(+) create mode 100644 crates/weaver_forge/src/extensions/code.rs create mode 100644 crates/weaver_forge/src/extensions/tests.rs create mode 100644 templates/registry/rust/semantic_attributes.rs.j2 create mode 100644 templates/registry/rust/weaver.yaml rename templates/{ => schema}/go/config.yaml (100%) rename templates/{ => schema}/go/optional_attrs.macro.tera (100%) rename templates/{ => schema}/go/otel/attribute/attrs.go.tera (100%) rename templates/{ => schema}/go/otel/client.go.tera (100%) rename templates/{ => schema}/go/otel/eventer/event.tera (100%) rename templates/{ => schema}/go/otel/meter/metric.tera (100%) rename templates/{ => schema}/go/otel/meter/metric_group.tera (100%) rename templates/{ => schema}/go/otel/tracer/span.tera (100%) rename templates/{ => schema}/go/required_attrs.macro.tera (100%) rename templates/{ => schema}/rust/config.yaml (100%) rename templates/{ => schema}/rust/eventer/mod.rs.tera (100%) rename templates/{ => schema}/rust/meter/mod.rs.tera (100%) rename templates/{ => schema}/rust/mod.rs.tera (100%) rename templates/{ => schema}/rust/span.tera.bak (100%) rename templates/{ => schema}/rust/tracer/mod.rs.tera (100%) diff --git a/crates/weaver_forge/src/extensions/code.rs b/crates/weaver_forge/src/extensions/code.rs new file mode 100644 index 00000000..cc0d6ef9 --- /dev/null +++ b/crates/weaver_forge/src/extensions/code.rs @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: Apache-2.0 + +//! Set of filters used to facilitate the generation of code. + +/// Converts the input string into a comment with a prefix. +pub fn comment_with_prefix(input: &str, prefix: &str) -> String { + let mut comment = String::new(); + for line in input.lines() { + if !comment.is_empty() { + comment.push_str("\n"); + } + comment.push_str(&format!("{}{}", prefix, line)); + } + comment +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_comment() { + assert_eq!(comment_with_prefix("test", "// "), "// test"); + + let brief = r#"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."#; + + let expected_brief = r#"/// 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."#; + + assert_eq!(comment_with_prefix(brief, "/// "), expected_brief); + } +} diff --git a/crates/weaver_forge/src/extensions/mod.rs b/crates/weaver_forge/src/extensions/mod.rs index dd8bb066..3647ebff 100644 --- a/crates/weaver_forge/src/extensions/mod.rs +++ b/crates/weaver_forge/src/extensions/mod.rs @@ -3,3 +3,5 @@ //! Custom filters used by the template engine. pub mod acronym; pub mod case_converter; +pub mod code; +pub mod tests; diff --git a/crates/weaver_forge/src/extensions/tests.rs b/crates/weaver_forge/src/extensions/tests.rs new file mode 100644 index 00000000..a6d892c5 --- /dev/null +++ b/crates/weaver_forge/src/extensions/tests.rs @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: Apache-2.0 + +//! Set of tests + +use minijinja::Value; + +/// Checks if the input value is an object with a field named "stability" that has the value "stable". +/// Otherwise, it returns false. +pub fn is_stable(input: Value) -> bool { + if let Some(object) = input.as_struct() { + let stability = object.get_field("stability"); + if let Some(stability) = stability { + if let Some(stability) = stability.as_str() { + return stability == "stable"; + } + } + } + false +} + +/// Checks if the input value is an object with a field named "stability" that has the value "deprecated". +/// Otherwise, it returns false. +pub fn is_deprecated(input: Value) -> bool { + if let Some(object) = input.as_struct() { + let stability = object.get_field("stability"); + if let Some(stability) = stability { + if let Some(stability) = stability.as_str() { + return stability == "deprecated"; + } + } + } + false +} + +#[cfg(test)] +mod tests { + use minijinja::value::StructObject; + + use super::*; + + struct DynAttr { + id: String, + r#type: String, + stability: String, + } + + impl StructObject for DynAttr { + fn get_field(&self, field: &str) -> Option { + match field { + "id" => Some(Value::from(self.id.as_str())), + "type" => Some(Value::from(self.r#type.as_str())), + "stability" => Some(Value::from(self.stability.as_str())), + _ => None, + } + } + } + + struct DynSomethingElse { + id: String, + r#type: String, + } + + impl StructObject for DynSomethingElse { + fn get_field(&self, field: &str) -> Option { + match field { + "id" => Some(Value::from(self.id.as_str())), + "type" => Some(Value::from(self.r#type.as_str())), + _ => None, + } + } + } + + #[test] + fn test_is_stable() { + // An attribute with stability "stable" + let attr = Value::from_struct_object(DynAttr { + id: "test".to_owned(), + r#type: "test".to_owned(), + stability: "stable".to_owned(), + }); + assert!(is_stable(attr)); + + // An attribute with stability "deprecated" + let attr = Value::from_struct_object(DynAttr { + id: "test".to_owned(), + r#type: "test".to_owned(), + stability: "deprecated".to_owned(), + }); + assert!(!is_stable(attr)); + + // An object without a stability field + let object = Value::from_struct_object(DynSomethingElse { + id: "test".to_owned(), + r#type: "test".to_owned(), + }); + assert!(!is_stable(object)); + } + + #[test] + fn test_is_deprecated() { + // An attribute with stability "deprecated" + let attr = Value::from_struct_object(DynAttr { + id: "test".to_owned(), + r#type: "test".to_owned(), + stability: "deprecated".to_owned(), + }); + assert!(is_deprecated(attr)); + + // An attribute with stability "stable" + let attr = Value::from_struct_object(DynAttr { + id: "test".to_owned(), + r#type: "test".to_owned(), + stability: "stable".to_owned(), + }); + assert!(!is_deprecated(attr)); + + // An object without a stability field + let object = Value::from_struct_object(DynSomethingElse { + id: "test".to_owned(), + r#type: "test".to_owned(), + }); + assert!(!is_deprecated(object)); + } +} \ No newline at end of file diff --git a/crates/weaver_forge/src/lib.rs b/crates/weaver_forge/src/lib.rs index f8e3bc3f..2e7701a2 100644 --- a/crates/weaver_forge/src/lib.rs +++ b/crates/weaver_forge/src/lib.rs @@ -27,6 +27,7 @@ use crate::debug::error_summary; use crate::error::Error::InvalidConfigFile; use crate::extensions::acronym::acronym; use crate::extensions::case_converter::case_converter; +use crate::extensions::code; use crate::registry::{TemplateGroup, TemplateRegistry}; mod config; @@ -375,6 +376,11 @@ impl TemplateEngine { env.add_filter("acronym", acronym(self.target_config.acronyms.clone())); + env.add_filter("comment_with_prefix", code::comment_with_prefix); + + env.add_test("stable", extensions::tests::is_stable); + env.add_test("deprecated", extensions::tests::is_deprecated); + // env.add_filter("unique_attributes", extensions::unique_attributes); // env.add_filter("instrument", extensions::instrument); // env.add_filter("required", extensions::required); diff --git a/templates/registry/rust/semantic_attributes.rs.j2 b/templates/registry/rust/semantic_attributes.rs.j2 new file mode 100644 index 00000000..86f263d3 --- /dev/null +++ b/templates/registry/rust/semantic_attributes.rs.j2 @@ -0,0 +1,18 @@ +{%- set file_name = ctx.prefix | snake_case -%} +{{- template.set_file_name(file_name ~ ".rs") -}} + +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +{%- for attribute in ctx.attributes %} + +{{ attribute.brief | comment_with_prefix("/// ") }} +{%- if attribute.note %} +/// +/// Notes: +{{ attribute.note | comment_with_prefix("/// ") }} +{%- endif %} +pub const {{ attribute.name | screaming_snake_case }}: &str = "{{ attribute.name }}"; +{%- endfor %} \ No newline at end of file diff --git a/templates/registry/rust/weaver.yaml b/templates/registry/rust/weaver.yaml new file mode 100644 index 00000000..98bee57e --- /dev/null +++ b/templates/registry/rust/weaver.yaml @@ -0,0 +1,4 @@ +templates: + - pattern: semantic_attributes.rs.j2 + filter: '.groups | map(select(.id | startswith("registry."))) | map(select(.type == "attribute_group" and .prefix != null and .prefix != "") | { id, type, brief, prefix, attributes: (.attributes | map(select(.stability == "stable")))}) | sort_by(.prefix // empty) | map(select(.attributes | length > 0))' + application_mode: each diff --git a/templates/go/config.yaml b/templates/schema/go/config.yaml similarity index 100% rename from templates/go/config.yaml rename to templates/schema/go/config.yaml diff --git a/templates/go/optional_attrs.macro.tera b/templates/schema/go/optional_attrs.macro.tera similarity index 100% rename from templates/go/optional_attrs.macro.tera rename to templates/schema/go/optional_attrs.macro.tera diff --git a/templates/go/otel/attribute/attrs.go.tera b/templates/schema/go/otel/attribute/attrs.go.tera similarity index 100% rename from templates/go/otel/attribute/attrs.go.tera rename to templates/schema/go/otel/attribute/attrs.go.tera diff --git a/templates/go/otel/client.go.tera b/templates/schema/go/otel/client.go.tera similarity index 100% rename from templates/go/otel/client.go.tera rename to templates/schema/go/otel/client.go.tera diff --git a/templates/go/otel/eventer/event.tera b/templates/schema/go/otel/eventer/event.tera similarity index 100% rename from templates/go/otel/eventer/event.tera rename to templates/schema/go/otel/eventer/event.tera diff --git a/templates/go/otel/meter/metric.tera b/templates/schema/go/otel/meter/metric.tera similarity index 100% rename from templates/go/otel/meter/metric.tera rename to templates/schema/go/otel/meter/metric.tera diff --git a/templates/go/otel/meter/metric_group.tera b/templates/schema/go/otel/meter/metric_group.tera similarity index 100% rename from templates/go/otel/meter/metric_group.tera rename to templates/schema/go/otel/meter/metric_group.tera diff --git a/templates/go/otel/tracer/span.tera b/templates/schema/go/otel/tracer/span.tera similarity index 100% rename from templates/go/otel/tracer/span.tera rename to templates/schema/go/otel/tracer/span.tera diff --git a/templates/go/required_attrs.macro.tera b/templates/schema/go/required_attrs.macro.tera similarity index 100% rename from templates/go/required_attrs.macro.tera rename to templates/schema/go/required_attrs.macro.tera diff --git a/templates/rust/config.yaml b/templates/schema/rust/config.yaml similarity index 100% rename from templates/rust/config.yaml rename to templates/schema/rust/config.yaml diff --git a/templates/rust/eventer/mod.rs.tera b/templates/schema/rust/eventer/mod.rs.tera similarity index 100% rename from templates/rust/eventer/mod.rs.tera rename to templates/schema/rust/eventer/mod.rs.tera diff --git a/templates/rust/meter/mod.rs.tera b/templates/schema/rust/meter/mod.rs.tera similarity index 100% rename from templates/rust/meter/mod.rs.tera rename to templates/schema/rust/meter/mod.rs.tera diff --git a/templates/rust/mod.rs.tera b/templates/schema/rust/mod.rs.tera similarity index 100% rename from templates/rust/mod.rs.tera rename to templates/schema/rust/mod.rs.tera diff --git a/templates/rust/span.tera.bak b/templates/schema/rust/span.tera.bak similarity index 100% rename from templates/rust/span.tera.bak rename to templates/schema/rust/span.tera.bak diff --git a/templates/rust/tracer/mod.rs.tera b/templates/schema/rust/tracer/mod.rs.tera similarity index 100% rename from templates/rust/tracer/mod.rs.tera rename to templates/schema/rust/tracer/mod.rs.tera From d430eb6f1c139520ef911e68b3573593a457d0eb Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Fri, 26 Apr 2024 14:39:17 -0700 Subject: [PATCH 02/39] feat(codegen): create lib.rs and one rs file per group prefix --- templates/registry/rust/lib.rs.j2 | 13 +++++++++++++ templates/registry/rust/semantic_attributes.rs.j2 | 7 +++++++ templates/registry/rust/weaver.yaml | 3 +++ 3 files changed, 23 insertions(+) create mode 100644 templates/registry/rust/lib.rs.j2 diff --git a/templates/registry/rust/lib.rs.j2 b/templates/registry/rust/lib.rs.j2 new file mode 100644 index 00000000..2a403395 --- /dev/null +++ b/templates/registry/rust/lib.rs.j2 @@ -0,0 +1,13 @@ +{{- template.set_file_name("lib.rs") -}} + +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! # OpenTelemetry Semantic Convention Attributes + +{% for group in ctx %} +{{ group.brief | comment_with_prefix("/// ") }} +pub mod {{ group.prefix | snake_case }}; +{%- endfor %} \ No newline at end of file diff --git a/templates/registry/rust/semantic_attributes.rs.j2 b/templates/registry/rust/semantic_attributes.rs.j2 index 86f263d3..a1f476d8 100644 --- a/templates/registry/rust/semantic_attributes.rs.j2 +++ b/templates/registry/rust/semantic_attributes.rs.j2 @@ -6,6 +6,13 @@ * SPDX-License-Identifier: Apache-2.0 */ +{{ ctx.brief | comment_with_prefix("//! ") }} +{%- if ctx.note %} +//! +//! Notes: +{{ ctx.note | comment_with_prefix("/// ") }} +{%- endif %} + {%- for attribute in ctx.attributes %} {{ attribute.brief | comment_with_prefix("/// ") }} diff --git a/templates/registry/rust/weaver.yaml b/templates/registry/rust/weaver.yaml index 98bee57e..3574d83b 100644 --- a/templates/registry/rust/weaver.yaml +++ b/templates/registry/rust/weaver.yaml @@ -1,4 +1,7 @@ templates: + - pattern: lib.rs.j2 + filter: '.groups | map(select(.id | startswith("registry."))) | map(select(.type == "attribute_group" and .prefix != null and .prefix != "") | { id, type, brief, prefix, attributes: (.attributes | map(select(.stability == "stable")))}) | sort_by(.prefix // empty) | map(select(.attributes | length > 0))' + application_mode: single - pattern: semantic_attributes.rs.j2 filter: '.groups | map(select(.id | startswith("registry."))) | map(select(.type == "attribute_group" and .prefix != null and .prefix != "") | { id, type, brief, prefix, attributes: (.attributes | map(select(.stability == "stable")))}) | sort_by(.prefix // empty) | map(select(.attributes | length > 0))' application_mode: each From 35959a759bcd72884c574cc94cf02c2662bc1500 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Fri, 26 Apr 2024 14:53:41 -0700 Subject: [PATCH 03/39] feat(codegen): remove old tera templates --- templates/schema/go/config.yaml | 15 - templates/schema/go/optional_attrs.macro.tera | 52 -- .../schema/go/otel/attribute/attrs.go.tera | 15 - templates/schema/go/otel/client.go.tera | 181 ------- templates/schema/go/otel/eventer/event.tera | 57 --- templates/schema/go/otel/meter/metric.tera | 462 ------------------ .../schema/go/otel/meter/metric_group.tera | 20 - templates/schema/go/otel/tracer/span.tera | 160 ------ templates/schema/go/required_attrs.macro.tera | 54 -- templates/schema/rust/config.yaml | 15 - templates/schema/rust/eventer/mod.rs.tera | 19 - templates/schema/rust/meter/mod.rs.tera | 94 ---- templates/schema/rust/mod.rs.tera | 7 - templates/schema/rust/span.tera.bak | 142 ------ templates/schema/rust/tracer/mod.rs.tera | 142 ------ 15 files changed, 1435 deletions(-) delete mode 100644 templates/schema/go/config.yaml delete mode 100644 templates/schema/go/optional_attrs.macro.tera delete mode 100644 templates/schema/go/otel/attribute/attrs.go.tera delete mode 100644 templates/schema/go/otel/client.go.tera delete mode 100644 templates/schema/go/otel/eventer/event.tera delete mode 100644 templates/schema/go/otel/meter/metric.tera delete mode 100644 templates/schema/go/otel/meter/metric_group.tera delete mode 100644 templates/schema/go/otel/tracer/span.tera delete mode 100644 templates/schema/go/required_attrs.macro.tera delete mode 100644 templates/schema/rust/config.yaml delete mode 100644 templates/schema/rust/eventer/mod.rs.tera delete mode 100644 templates/schema/rust/meter/mod.rs.tera delete mode 100644 templates/schema/rust/mod.rs.tera delete mode 100644 templates/schema/rust/span.tera.bak delete mode 100644 templates/schema/rust/tracer/mod.rs.tera diff --git a/templates/schema/go/config.yaml b/templates/schema/go/config.yaml deleted file mode 100644 index 452e1bf4..00000000 --- a/templates/schema/go/config.yaml +++ /dev/null @@ -1,15 +0,0 @@ -file_name: snake_case -function_name: PascalCase -arg_name: camelCase -struct_name: PascalCase -field_name: PascalCase - -type_mapping: - int: int64 - double: double - boolean: bool - string: string - "int[]": "[]int64" - "double[]": "[]double" - "boolean[]": "[]bool" - "string[]": "[]string" \ No newline at end of file diff --git a/templates/schema/go/optional_attrs.macro.tera b/templates/schema/go/optional_attrs.macro.tera deleted file mode 100644 index 89fcf653..00000000 --- a/templates/schema/go/optional_attrs.macro.tera +++ /dev/null @@ -1,52 +0,0 @@ -{% macro attr_type(prefix) -%}Optional{{prefix}}Attribute{% endmacro attr_type %} - -{% macro declare_attrs(prefix="", marker, attrs) -%} -{% set not_require_attrs = attrs | not_required | without_value %} -{%- if not_require_attrs | length > 0 -%} -// =============================================== -// ====== Definition of optional attributes ====== -// =============================================== - -// Optional{{marker}}Attribute is an interface implemented by all optional attributes of the {{marker}}. -type Optional{{marker}}Attribute interface { - Attribute() otel_attr.KeyValue - {{ marker | function_name }}Marker() -} - -{% for attr in not_require_attrs | without_enum %} -// {{prefix}}{{attr.id | struct_name}}OptAttr represents an optional attribute. -// {{ [attr.brief, attr.note, "", "# Examples", attr.examples] | comment(prefix="// ") }} -func {{prefix}}{{attr.id | struct_name}}OptAttr(v {{ attr.type | type_mapping(enum=attr.id | struct_name) }}) {{prefix}}{{attr.id | struct_name}}OptAttrWrapper { return {{prefix}}{{attr.id | struct_name}}OptAttrWrapper{v} } -// {{prefix}}{{attr.id | struct_name}}OptAttrWrapper is a wrapper for the attribute `{{attr.id}}`. -// Use the function {{attr.id | struct_name}}OptAttr(value) to create an instance. -type {{prefix}}{{attr.id | struct_name}}OptAttrWrapper struct { {{ attr.type | type_mapping(enum=attr.id | struct_name) }} } -func (w {{prefix}}{{attr.id | struct_name}}OptAttrWrapper) Attribute() otel_attr.KeyValue { - return attribute.{{ attr.id | field_name }}Key.{{ attr.type | type_mapping(enum="String" | struct_name) | function_name }}(w.{{ attr.type | type_mapping(enum="string" | struct_name) }}) -} -func (w {{prefix}}{{attr.id | struct_name}}OptAttrWrapper) {{marker}}Marker() {} - -{% endfor %} - -{% for attr in not_require_attrs | with_enum %} -// {{prefix}}{{attr.id | struct_name}}OptAttr represents an optional attribute. -// {{ [attr.brief, attr.note, "", "# Examples", attr.examples] | comment(prefix="// ") }} -func {{prefix}}{{attr.id | struct_name}}OptAttr(v {{ attr.type | type_mapping(enum=attr.id | struct_name) }}) {{prefix}}{{attr.id | struct_name}}OptAttrWrapper { return {{prefix}}{{attr.id | struct_name}}OptAttrWrapper{v} } -// {{prefix}}{{attr.id | struct_name}}OptAttrWrapper is a wrapper for the attribute `{{attr.id}}`. -// Use the function {{attr.id | struct_name}}OptAttr(value) to create an instance. -type {{prefix}}{{attr.id | struct_name}}OptAttrWrapper struct { {{ attr.type | type_mapping(enum=attr.id | struct_name) }} } -func (w {{prefix}}{{attr.id | struct_name}}OptAttrWrapper) Attribute() otel_attr.KeyValue { - return attribute.{{ attr.id | field_name }}Key.String(string(w.{{ attr.type | type_mapping(enum=attr.id | struct_name) }})) -} -func (w {{prefix}}{{attr.id | struct_name}}OptAttrWrapper) {{marker}}Marker() {} - -type {{attr.id | struct_name}} string -const ( -{% for variant in attr.type.members %} - // {{variant.id | struct_name}} is a possible value of {{attr.id | struct_name}}. - // {{ [variant.brief, variant.note] | comment(prefix=" // ") }} - {{variant.id | struct_name}} {{attr.id | struct_name}} = "{{variant.id}}" -{%- endfor %} -) -{% endfor %} -{%- endif -%} -{% endmacro declare_attrs %} \ No newline at end of file diff --git a/templates/schema/go/otel/attribute/attrs.go.tera b/templates/schema/go/otel/attribute/attrs.go.tera deleted file mode 100644 index ec1fd2f3..00000000 --- a/templates/schema/go/otel/attribute/attrs.go.tera +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package attribute - -import ( - "go.opentelemetry.io/otel/attribute" -) - -{% set attrs = schema | unique_attributes(recursive=true) -%} -// Declaration of all attribute keys. -var ( -{%- for attr in attrs %} - {{ attr.id | field_name }}Key = attribute.Key("{{attr.id}}") -{%- endfor %} -) \ No newline at end of file diff --git a/templates/schema/go/otel/client.go.tera b/templates/schema/go/otel/client.go.tera deleted file mode 100644 index 7ec1ba53..00000000 --- a/templates/schema/go/otel/client.go.tera +++ /dev/null @@ -1,181 +0,0 @@ -{% import "required_attrs.macro.tera" as required %} -{% import "optional_attrs.macro.tera" as optional %} -package otel - -import ( - "context" - "fmt" - "log" - "os" - "time" - - "go.opentelemetry.io/otel" - otel_attr "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric" - "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" - "go.opentelemetry.io/otel/metric" - sdkmetric "go.opentelemetry.io/otel/sdk/metric" - "go.opentelemetry.io/otel/sdk/resource" - sdktrace "go.opentelemetry.io/otel/sdk/trace" - "go.opentelemetry.io/otel/trace" - - "go_test/pkg/otel/attribute" -) - -const ( - InstrumentationName = "{{ schema.instrumentation_library.name }}" - InstrumentationVersion = "{{ schema.instrumentation_library.version }}" -) - -var ( - Meter = otel.GetMeterProvider().Meter( - InstrumentationName, - metric.WithInstrumentationVersion(InstrumentationVersion), - metric.WithSchemaURL("{{ schema_url }}"), - ) - Tracer = otel.GetTracerProvider().Tracer( - InstrumentationName, - trace.WithInstrumentationVersion(InstrumentationVersion), - trace.WithSchemaURL("{{ schema_url }}"), - ) -) - -// ClientHandler is a handler for the OTel Weaver client. -type ClientHandler struct { - ctx context.Context - metricShutdown func(context.Context) error - traceShutdown func(context.Context) error -} - -{%- set required_attrs = schema.resource.attributes | required | without_value -%} -{%- set not_required_attrs = schema.resource.attributes | not_required | without_value %} - -{{ required::declare_attrs(attrs=required_attrs) }} -{{ optional::declare_attrs(marker="Resource", attrs=not_required_attrs) }} - -// ================== -// ===== Client ===== -// ================== - -// Client returns a OTel client (generated by OTel Weaver). -// It uses a context initialized with `context.Background()`. -func Client( - {{- required::declare_args(attrs=required_attrs) }} - {% if not_required_attrs | length > 0 -%}optionalAttributes ...OptionalResourceAttribute,{% endif %} -) *ClientHandler { - return ClientWithContext( - context.Background(), - {%- for attr in required_attrs %} - {{attr.id | arg_name}}, - {%- endfor %} - {% if not_required_attrs | length > 0 -%}optionalAttributes...,{% endif %} - ) -} - -// ClientWithContext returns a OTel client with a given context (generated by OTel Weaver). -func ClientWithContext( - ctx context.Context, - {{- required::declare_args(attrs=required_attrs) }} - {% if not_required_attrs | length > 0 -%}optionalAttributes ...OptionalResourceAttribute,{% endif %} -) *ClientHandler { - metricShutdown, traceShutdown, err := installExportPipeline( - {%- for attr in required_attrs %} - {{attr.id | arg_name}}, - {%- endfor %} - {% if not_required_attrs | length > 0 -%}optionalAttributes...,{% endif %} - ) - if err != nil { - log.Fatal(err) - } - - return &ClientHandler{ - ctx: ctx, - metricShutdown: metricShutdown, - traceShutdown: traceShutdown, - } -} - -func (o *ClientHandler) Shutdown() { - metricErr := o.metricShutdown(o.ctx) - traceErr := o.traceShutdown(o.ctx) - - mustExit := false - if metricErr != nil { - log.Println(metricErr) - mustExit = true - } - if traceErr != nil { - log.Println(traceErr) - mustExit = true - } - if mustExit { - os.Exit(1) - } -} - -func resourceBuilder( - {%- for attr in required_attrs %} - {{attr.id | arg_name}} {{attr.id | struct_name}}ReqAttrWrapper, - {%- endfor %} - {% if not_required_attrs | length > 0 -%}optionalAttributes ...OptionalResourceAttribute,{% endif %} -) *resource.Resource { - attrs := []otel_attr.KeyValue { - {%- for attr in schema.resource.attributes | with_value %} - attribute.{{ attr.id | field_name }}Key.{{ attr.type | type_mapping(enum=attr.id | struct_name) | function_name }}({{ attr.value | value }}), - {%- endfor %} - {%- for attr in required_attrs %} - {{attr.id | arg_name}}.Attribute(), - {%- endfor %} - } - {% if not_required_attrs | length > 0 -%} - for _, attr := range optionalAttributes { - attrs = append(attrs, attr.Attribute()) - } - {% endif %} - return resource.NewWithAttributes("{{ schema_url }}", attrs...) -} - -func installExportPipeline( - {%- for attr in required_attrs %} - {{attr.id | arg_name}} {{attr.id | struct_name}}ReqAttrWrapper, - {%- endfor %} - {% if not_required_attrs | length > 0 -%}optionalAttributes ...OptionalResourceAttribute,{% endif %} -) (metricShutdown func(context.Context) error, traceShutdown func(context.Context) error, err error) { - metricExporter, err := stdoutmetric.New(stdoutmetric.WithPrettyPrint()) - if err != nil { - err = fmt.Errorf("creating metric stdout exporter: %w", err) - return - } - - traceExporter, err := stdouttrace.New(stdouttrace.WithPrettyPrint()) - if err != nil { - err = fmt.Errorf("creating trace stdout exporter: %w", err) - return - } - - metricProvider := sdkmetric.NewMeterProvider( - sdkmetric.WithReader(sdkmetric.NewPeriodicReader(metricExporter, sdkmetric.WithInterval(3*time.Second))), - sdkmetric.WithResource(resourceBuilder( - {%- for attr in required_attrs %} - {{attr.id | arg_name}}, - {%- endfor %} - {% if not_required_attrs | length > 0 -%}optionalAttributes...,{% endif %} - )), - ) - otel.SetMeterProvider(metricProvider) - - tracerProvider := sdktrace.NewTracerProvider( - sdktrace.WithBatcher(traceExporter), - sdktrace.WithResource(resourceBuilder( - {%- for attr in required_attrs %} - {{attr.id | arg_name}}, - {%- endfor %} - {% if not_required_attrs | length > 0 -%}optionalAttributes...,{% endif %} - )), - ) - otel.SetTracerProvider(tracerProvider) - - metricShutdown = metricProvider.Shutdown - traceShutdown = tracerProvider.Shutdown - return -} \ No newline at end of file diff --git a/templates/schema/go/otel/eventer/event.tera b/templates/schema/go/otel/eventer/event.tera deleted file mode 100644 index 5e489334..00000000 --- a/templates/schema/go/otel/eventer/event.tera +++ /dev/null @@ -1,57 +0,0 @@ -{% import "required_attrs.macro.tera" as required %} -{% import "optional_attrs.macro.tera" as optional %} -{# Define the file name for the generated code #} -{%- set file_name = event_name | file_name -%} -{{- config(file_name="otel/eventer/event_" ~ file_name ~ "/event.go") -}} -// SPDX-License-Identifier: Apache-2.0 - -package {{ event_name | file_name }} - -import ( - "context" - - otel_attr "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/trace" - - client "go_test/pkg/otel" - "go_test/pkg/otel/attribute" -) - -// Event records a new `{{ event_name }}` event with -// the given required attributes. -func Event( - {{- required::declare_args(attrs=attributes) }} - optionalAttributes ...{{ optional::attr_type(prefix="Span") }}, -) { - EventWithContext( - context.TODO(), - {%- for attr in attributes | required | without_value %} - {{attr.id | arg_name}}, - {%- endfor %} - optionalAttributes..., - ) -} - -// EventWithContext records a new `{{ event_name }}` event with -// the given context and required attributes. -func EventWithContext( - ctx context.Context, - {{- required::declare_args(attrs=attributes) }} - optionalAttributes ...{{ optional::attr_type(prefix="Span") }}, -) { - - ctx, span := client.Tracer.Start(ctx, "{{ event_name }}", - {%- for attr in attributes | with_value %} - trace.WithAttributes(attribute.{{ attr.id | function_name }}Key.{{attr.type | type_mapping(enum=attr.id) | function_name}}({{attr.value | value}})), - {%- endfor %} - {%- for attr in attributes | required | without_value %} - trace.WithAttributes({{ attr.id | arg_name }}.Attribute()), - {%- endfor %} - ) - for _, opt := range optionalAttributes { - span.SetAttributes(opt.Attribute()) - } -} - -{{ required::declare_attrs(attrs=attributes) }} -{{ optional::declare_attrs(marker="Span", attrs=attributes) }} diff --git a/templates/schema/go/otel/meter/metric.tera b/templates/schema/go/otel/meter/metric.tera deleted file mode 100644 index 4e2a5cc7..00000000 --- a/templates/schema/go/otel/meter/metric.tera +++ /dev/null @@ -1,462 +0,0 @@ -{% import "required_attrs.macro.tera" as required %} -{% import "optional_attrs.macro.tera" as optional %} -{# Define the file name for the generated code #} -{%- set file_name = name | file_name -%} -{{- config(file_name="otel/meter/metric_" ~ file_name ~ "/metric.go") -}} -// SPDX-License-Identifier: Apache-2.0 - -package {{ name | file_name }} - -import ( - "context" - - otel_attr "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/metric" - - client "go_test/pkg/otel" - "go_test/pkg/otel/attribute" -) - -type Int64Observer func() (int64, {% for attr in attributes | required | without_value %}{{attr.id | struct_name}}ReqAttrWrapper, {% endfor %}[]OptionalMetricAttribute, error) -type Float64Observer func() (float64, {% for attr in attributes | required | without_value %}{{attr.id | struct_name}}ReqAttrWrapper, {% endfor %}[]OptionalMetricAttribute, error) - -{% if instrument == "counter" %} -// ===== Synchronous Counter Declaration ===== -type Int64Counter_ struct { - ctx context.Context - counter metric.Int64Counter -} - -type Float64Counter_ struct { - ctx context.Context - counter metric.Float64Counter -} - -func Int64Counter() (*Int64Counter_, error) { - return Int64CounterWithContext(context.TODO()) -} - -func Int64CounterWithContext(ctx context.Context) (*Int64Counter_, error) { - counter, err := client.Meter.Int64Counter( - "{{name}}", - metric.WithDescription("{{brief}}"), - metric.WithUnit("{{unit}}"), - ) - if err != nil { - return nil, err - } - return &Int64Counter_{ - ctx: ctx, - counter: counter, - }, nil -} - -func (g *Int64Counter_) Add(incr uint64, {% for attr in attributes | required | without_value %}{{attr.id | arg_name}} {{attr.id | struct_name}}ReqAttrWrapper, {% endfor %}optAttrs ...OptionalMetricAttribute) { - options := []metric.AddOption { - {% for attr in attributes | required | without_value %}metric.WithAttributes({{attr.id | arg_name}}.Attribute()),{% endfor %} - } - for _, opt := range optAttrs { - options = append(options, metric.WithAttributes(opt.Attribute())) - } - g.counter.Add(g.ctx, int64(incr), options...) -} - -func (g *Int64Counter_) AddWithContext(ctx context.Context, incr uint64, {% for attr in attributes | required | without_value %}{{attr.id | arg_name}} {{attr.id | struct_name}}ReqAttrWrapper, {% endfor %}optAttrs ...OptionalMetricAttribute) { - options := []metric.AddOption { - {% for attr in attributes | required | without_value %}metric.WithAttributes({{attr.id | arg_name}}.Attribute()),{% endfor %} - } - for _, opt := range optAttrs { - options = append(options, metric.WithAttributes(opt.Attribute())) - } - g.counter.Add(ctx, int64(incr), options...) -} - -func Float64Counter() (*Float64Counter_, error) { - return Float64CounterWithContext(context.TODO()) -} - -func Float64CounterWithContext(ctx context.Context) (*Float64Counter_, error) { - counter, err := client.Meter.Float64Counter( - "{{name}}", - metric.WithDescription("{{brief}}"), - metric.WithUnit("{{unit}}"), - ) - if err != nil { - return nil, err - } - return &Float64Counter_{ - ctx: ctx, - counter: counter, - }, nil -} - -func (g *Float64Counter_) Add(incr float64, {% for attr in attributes | required | without_value %}{{attr.id | arg_name}} {{attr.id | struct_name}}ReqAttrWrapper, {% endfor %}optAttrs ...OptionalMetricAttribute) { - options := []metric.AddOption { - {% for attr in attributes | required | without_value %}metric.WithAttributes({{attr.id | arg_name}}.Attribute()),{% endfor %} - } - for _, opt := range optAttrs { - options = append(options, metric.WithAttributes(opt.Attribute())) - } - g.counter.Add(g.ctx, incr, options...) -} - -func (g *Float64Counter_) AddWithContext(ctx context.Context, incr float64, {% for attr in attributes | required | without_value %}{{attr.id | arg_name}} {{attr.id | struct_name}}ReqAttrWrapper, {% endfor %}optAttrs ...OptionalMetricAttribute) { - options := []metric.AddOption { - {% for attr in attributes | required | without_value %}metric.WithAttributes({{attr.id | arg_name}}.Attribute()),{% endfor %} - } - for _, opt := range optAttrs { - options = append(options, metric.WithAttributes(opt.Attribute())) - } - g.counter.Add(ctx, incr, options...) -} - -// ============================================ -// ===== Asynchronous Counter Declaration ===== -// ============================================ - -func Int64ObservableCounter(observer Int64Observer) error { - _, err := client.Meter.Int64ObservableCounter( - "{{name}}", - metric.WithDescription("{{brief}}"), - metric.WithUnit("{{unit}}"), - metric.WithInt64Callback(func(ctx context.Context, otelObserver metric.Int64Observer) error { - v, {% for attr in attributes | required | without_value %}{{attr.id | arg_name}}, {% endfor %}optAttrs, err := observer() - if err != nil { - return err - } - options := []metric.ObserveOption { - {% for attr in attributes | required | without_value %}metric.WithAttributes({{attr.id | arg_name}}.Attribute()),{% endfor %} - } - for _, opt := range optAttrs { - options = append(options, metric.WithAttributes(opt.Attribute())) - } - otelObserver.Observe(v, options...) - return nil - })) - if err != nil { - return err - } - return nil -} - -func Float64ObservableCounter(observer Float64Observer) error { - _, err := client.Meter.Float64ObservableCounter( - "{{name}}", - metric.WithDescription("{{brief}}"), - metric.WithUnit("{{unit}}"), - metric.WithFloat64Callback(func(ctx context.Context, otelObserver metric.Float64Observer) error { - v, {% for attr in attributes | required | without_value %}{{attr.id | arg_name}}, {% endfor %}optAttrs, err := observer() - if err != nil { - return err - } - options := []metric.ObserveOption { - {% for attr in attributes | required | without_value %}metric.WithAttributes({{attr.id | arg_name}}.Attribute()),{% endfor %} - } - for _, opt := range optAttrs { - options = append(options, metric.WithAttributes(opt.Attribute())) - } - otelObserver.Observe(v, options...) - return nil - })) - if err != nil { - return err - } - return nil -} - -{% elif instrument == "updowncounter" %} -// ===== Synchronous UpDownCounter Declaration ===== -type Int64UpDownCounter_ struct { - ctx context.Context - counter metric.Int64UpDownCounter -} - -type Float64UpDownCounter_ struct { - ctx context.Context - counter metric.Float64UpDownCounter -} - -func Int64UpDownCounter() (*Int64UpDownCounter_, error) { - return Int64UpDownCounterWithContext(context.TODO()) -} - -func Int64UpDownCounterWithContext(ctx context.Context) (*Int64UpDownCounter_, error) { - counter, err := client.Meter.Int64UpDownCounter( - "{{name}}", - metric.WithDescription("{{brief}}"), - metric.WithUnit("{{unit}}"), - ) - if err != nil { - return nil, err - } - return &Int64UpDownCounter_{ - ctx: ctx, - counter: counter, - }, nil -} - -func (g *Int64UpDownCounter_) Add(incr uint64, {% for attr in attributes | required | without_value %}{{attr.id | arg_name}} {{attr.id | struct_name}}ReqAttrWrapper, {% endfor %}optAttrs ...OptionalMetricAttribute) { - options := []metric.AddOption { - {% for attr in attributes | required | without_value %}metric.WithAttributes({{attr.id | arg_name}}.Attribute()),{% endfor %} - } - for _, opt := range optAttrs { - options = append(options, metric.WithAttributes(opt.Attribute())) - } - g.counter.Add(g.ctx, int64(incr), options...) -} - -func (g *Int64UpDownCounter_) AddWithContext(ctx context.Context, incr uint64, {% for attr in attributes | required | without_value %}{{attr.id | arg_name}} {{attr.id | struct_name}}ReqAttrWrapper, {% endfor %}optAttrs ...OptionalMetricAttribute) { - options := []metric.AddOption { - {% for attr in attributes | required | without_value %}metric.WithAttributes({{attr.id | arg_name}}.Attribute()),{% endfor %} - } - for _, opt := range optAttrs { - options = append(options, metric.WithAttributes(opt.Attribute())) - } - g.counter.Add(ctx, int64(incr), options...) -} - -func Float64UpDownCounter() (*Float64UpDownCounter_, error) { - return Float64UpDownCounterWithContext(context.TODO()) -} - -func Float64UpDownCounterWithContext(ctx context.Context) (*Float64UpDownCounter_, error) { - counter, err := client.Meter.Float64UpDownCounter( - "{{name}}", - metric.WithDescription("{{brief}}"), - metric.WithUnit("{{unit}}"), - ) - if err != nil { - return nil, err - } - return &Float64UpDownCounter_{ - ctx: ctx, - counter: counter, - }, nil -} - -func (g *Float64UpDownCounter_) Add(incr float64, {% for attr in attributes | required | without_value %}{{attr.id | arg_name}} {{attr.id | struct_name}}ReqAttrWrapper, {% endfor %}optAttrs ...OptionalMetricAttribute) { - options := []metric.AddOption { - {% for attr in attributes | required | without_value %}metric.WithAttributes({{attr.id | arg_name}}.Attribute()),{% endfor %} - } - for _, opt := range optAttrs { - options = append(options, metric.WithAttributes(opt.Attribute())) - } - g.counter.Add(g.ctx, incr, options...) -} - -func (g *Float64UpDownCounter_) AddWithContext(ctx context.Context, incr float64, {% for attr in attributes | required | without_value %}{{attr.id | arg_name}} {{attr.id | struct_name}}ReqAttrWrapper, {% endfor %}optAttrs ...OptionalMetricAttribute) { - options := []metric.AddOption { - {% for attr in attributes | required | without_value %}metric.WithAttributes({{attr.id | arg_name}}.Attribute()),{% endfor %} - } - for _, opt := range optAttrs { - options = append(options, metric.WithAttributes(opt.Attribute())) - } - g.counter.Add(ctx, incr, options...) -} - -// ============================================ -// ===== Asynchronous UpDownCounter Declaration ===== -// ============================================ - -func Int64ObservableUpDownCounter(observer Int64Observer) error { - _, err := client.Meter.Int64ObservableUpDownCounter( - "{{name}}", - metric.WithDescription("{{brief}}"), - metric.WithUnit("{{unit}}"), - metric.WithInt64Callback(func(ctx context.Context, otelObserver metric.Int64Observer) error { - v, {% for attr in attributes | required | without_value %}{{attr.id | arg_name}}, {% endfor %}optAttrs, err := observer() - if err != nil { - return err - } - options := []metric.ObserveOption { - {% for attr in attributes | required | without_value %}metric.WithAttributes({{attr.id | arg_name}}.Attribute()),{% endfor %} - } - for _, opt := range optAttrs { - options = append(options, metric.WithAttributes(opt.Attribute())) - } - otelObserver.Observe(v, options...) - return nil - })) - if err != nil { - return err - } - return nil -} - -func Float64ObservableUpDownCounter(observer Float64Observer) error { - _, err := client.Meter.Float64ObservableUpDownCounter( - "{{name}}", - metric.WithDescription("{{brief}}"), - metric.WithUnit("{{unit}}"), - metric.WithFloat64Callback(func(ctx context.Context, otelObserver metric.Float64Observer) error { - v, {% for attr in attributes | required | without_value %}{{attr.id | arg_name}}, {% endfor %}optAttrs, err := observer() - if err != nil { - return err - } - options := []metric.ObserveOption { - {% for attr in attributes | required | without_value %}metric.WithAttributes({{attr.id | arg_name}}.Attribute()),{% endfor %} - } - for _, opt := range optAttrs { - options = append(options, metric.WithAttributes(opt.Attribute())) - } - otelObserver.Observe(v, options...) - return nil - })) - if err != nil { - return err - } - return nil -} - -{% elif instrument == "gauge" %} -// ========================================== -// ===== Asynchronous Gauge Declaration ===== -// ========================================== - -func Int64ObservableGauge(observer Int64Observer) error { - _, err := client.Meter.Int64ObservableGauge( - "{{name}}", - metric.WithDescription("{{brief}}"), - metric.WithUnit("{{unit}}"), - metric.WithInt64Callback(func(ctx context.Context, otelObserver metric.Int64Observer) error { - v, {% for attr in attributes | required | without_value %}{{attr.id | arg_name}}, {% endfor %}optAttrs, err := observer() - if err != nil { - return err - } - options := []metric.ObserveOption { - {% for attr in attributes | required | without_value %}metric.WithAttributes({{attr.id | arg_name}}.Attribute()),{% endfor %} - } - for _, opt := range optAttrs { - options = append(options, metric.WithAttributes(opt.Attribute())) - } - otelObserver.Observe(v, options...) - return nil - })) - if err != nil { - return err - } - return nil -} - -func Float64ObservableGauge(observer Float64Observer) error { - _, err := client.Meter.Float64ObservableGauge( - "{{name}}", - metric.WithDescription("{{brief}}"), - metric.WithUnit("{{unit}}"), - metric.WithFloat64Callback(func(ctx context.Context, otelObserver metric.Float64Observer) error { - v, {% for attr in attributes | required | without_value %}{{attr.id | arg_name}}, {% endfor %}optAttrs, err := observer() - if err != nil { - return err - } - options := []metric.ObserveOption { - {% for attr in attributes | required | without_value %}metric.WithAttributes({{attr.id | arg_name}}.Attribute()),{% endfor %} - } - for _, opt := range optAttrs { - options = append(options, metric.WithAttributes(opt.Attribute())) - } - otelObserver.Observe(v, options...) - return nil - })) - if err != nil { - return err - } - return nil -} - -{% elif instrument == "histogram" %} -// ============================================= -// ===== Synchronous Histogram Declaration ===== -// ============================================= - -type Int64Histogram_ struct { - ctx context.Context - histogram metric.Int64Histogram -} - -type Float64Histogram_ struct { - ctx context.Context - histogram metric.Float64Histogram -} - -func Int64Histogram() (*Int64Histogram_, error) { - return Int64HistogramWithContext(context.TODO()) -} - -func Int64HistogramWithContext(ctx context.Context) (*Int64Histogram_, error) { - histogram, err := client.Meter.Int64Histogram( - "{{name}}", - metric.WithDescription("{{brief}}"), - metric.WithUnit("{{unit}}"), - ) - if err != nil { - return nil, err - } - return &Int64Histogram_{ - ctx: ctx, - histogram: histogram, - }, nil -} - -func (g *Int64Histogram_) Record(incr uint64, {% for attr in attributes | required | without_value %}{{attr.id | arg_name}} {{attr.id | struct_name}}ReqAttrWrapper, {% endfor %}optAttrs ...OptionalMetricAttribute) { - options := []metric.RecordOption { - {% for attr in attributes | required | without_value %}metric.WithAttributes({{attr.id | arg_name}}.Attribute()),{% endfor %} - } - for _, opt := range optAttrs { - options = append(options, metric.WithAttributes(opt.Attribute())) - } - g.histogram.Record(g.ctx, int64(incr), options...) -} - -func (g *Int64Histogram_) RecordWithContext(ctx context.Context, incr uint64, {% for attr in attributes | required | without_value %}{{attr.id | arg_name}} {{attr.id | struct_name}}ReqAttrWrapper, {% endfor %}optAttrs ...OptionalMetricAttribute) { - options := []metric.RecordOption { - {% for attr in attributes | required | without_value %}metric.WithAttributes({{attr.id | arg_name}}.Attribute()),{% endfor %} - } - for _, opt := range optAttrs { - options = append(options, metric.WithAttributes(opt.Attribute())) - } - g.histogram.Record(ctx, int64(incr), options...) -} - -func Float64Histogram() (*Float64Histogram_, error) { - return Float64HistogramWithContext(context.TODO()) -} - -func Float64HistogramWithContext(ctx context.Context) (*Float64Histogram_, error) { - histogram, err := client.Meter.Float64Histogram( - "{{name}}", - metric.WithDescription("{{brief}}"), - metric.WithUnit("{{unit}}"), - ) - if err != nil { - return nil, err - } - return &Float64Histogram_{ - ctx: ctx, - histogram: histogram, - }, nil -} - -func (g *Float64Histogram_) Record(incr float64, {% for attr in attributes | required | without_value %}{{attr.id | arg_name}} {{attr.id | struct_name}}ReqAttrWrapper, {% endfor %}optAttrs ...OptionalMetricAttribute) { - options := []metric.RecordOption { - {% for attr in attributes | required | without_value %}metric.WithAttributes({{attr.id | arg_name}}.Attribute()),{% endfor %} - } - for _, opt := range optAttrs { - options = append(options, metric.WithAttributes(opt.Attribute())) - } - g.histogram.Record(g.ctx, incr, options...) -} - -func (g *Float64Histogram_) RecordWithContext(ctx context.Context, incr float64, {% for attr in attributes | required | without_value %}{{attr.id | arg_name}} {{attr.id | struct_name}}ReqAttrWrapper, {% endfor %}optAttrs ...OptionalMetricAttribute) { - options := []metric.RecordOption { - {% for attr in attributes | required | without_value %}metric.WithAttributes({{attr.id | arg_name}}.Attribute()),{% endfor %} - } - for _, opt := range optAttrs { - options = append(options, metric.WithAttributes(opt.Attribute())) - } - g.histogram.Record(ctx, incr, options...) -} - -{% endif %} - -{{ required::declare_attrs(attrs=attributes) }} -{{ optional::declare_attrs(marker="Metric", attrs=attributes) }} diff --git a/templates/schema/go/otel/meter/metric_group.tera b/templates/schema/go/otel/meter/metric_group.tera deleted file mode 100644 index 900dbad2..00000000 --- a/templates/schema/go/otel/meter/metric_group.tera +++ /dev/null @@ -1,20 +0,0 @@ -{% import "required_attrs.macro.tera" as required %} -{% import "optional_attrs.macro.tera" as optional %} -{# Define the file name for the generated code #} -{%- set file_name = name | file_name -%} -{{- config(file_name="otel/meter/metric_group_" ~ file_name ~ "/metric_group.go") -}} -// SPDX-License-Identifier: Apache-2.0 - -package {{ name | file_name }} - -import ( - otel_attr "go.opentelemetry.io/otel/attribute" - - "go_test/pkg/otel/attribute" -) - -type Int64Observer func() (int64, {% for attr in attributes | required | without_value %}{{attr.id | struct_name}}ReqAttrWrapper, {% endfor %}[]OptionalMetricAttribute, error) -type Float64Observer func() (float64, {% for attr in attributes | required | without_value %}{{attr.id | struct_name}}ReqAttrWrapper, {% endfor %}[]OptionalMetricAttribute, error) - -{{ required::declare_attrs(attrs=attributes) }} -{{ optional::declare_attrs(marker="Metric", attrs=attributes) }} diff --git a/templates/schema/go/otel/tracer/span.tera b/templates/schema/go/otel/tracer/span.tera deleted file mode 100644 index 0c4fd4ce..00000000 --- a/templates/schema/go/otel/tracer/span.tera +++ /dev/null @@ -1,160 +0,0 @@ -{% import "required_attrs.macro.tera" as required %} -{% import "optional_attrs.macro.tera" as optional %} -{# Define the file name for the generated code #} -{%- set file_name = span_name | file_name -%} -{{- config(file_name="otel/tracer/" ~ file_name ~ "/span.go") -}} -// SPDX-License-Identifier: Apache-2.0 - -package {{ span_name | file_name }} - -import ( - "context" - - otel_attr "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/codes" - "go.opentelemetry.io/otel/trace" - - client "go_test/pkg/otel" - "go_test/pkg/otel/attribute" -) - -{%- if attributes | required | without_value | length > 0 %} -// Start starts a new `{{ span_name }}` span with -// the given required attributes. -func Start( - {{- required::declare_args(attrs=attributes) }} - optionalAttributes ...{{ optional::attr_type(prefix="Span") }}, -) *{{span_name | struct_name}}Span { - return StartWithContext( - context.TODO(), - {%- for attr in attributes | required | without_value %} - {{attr.id | arg_name}}, - {%- endfor %} - optionalAttributes..., - ) -} - -// StartWithContext starts a new `{{ span_name }}` span with -// the given required attributes and context. -func StartWithContext( - ctx context.Context, - {{- required::declare_args(attrs=attributes) }} - optionalAttributes ...{{ optional::attr_type(prefix="Span") }}, -) *{{span_name | struct_name}}Span { - ctx, span := client.Tracer.Start(ctx, "{{ span_name }}", - {%- for attr in attributes | with_value %} - trace.WithAttributes(attribute.{{ attr.id | function_name }}Key.{{attr.type | type_mapping(enum=attr.id) | function_name}}({{attr.value | value}})), - {%- endfor %} - {%- for attr in attributes | required | without_value %} - trace.WithAttributes({{ attr.id | arg_name }}.Attribute()), - {%- endfor %} - ) - for _, opt := range optionalAttributes { - span.SetAttributes(opt.Attribute()) - } - return &{{span_name | struct_name}}Span { - ctx: ctx, - span: span, - } -} -{%- else %} -// Start starts a new named `{{ span_name }}` span. -func Start{{ span_name | function_name }}(ctx context.Context, optionalAttributes ...{{ optional::attr_type(prefix="Span") }}) *{{span_name | struct_name}}Span { - ctx, span := client.Tracer.Start(ctx, "{{ span_name }}") - for _, opt := range optionalAttributes { - span.SetAttributes(opt.Attribute()) - } - return &{{span_name | struct_name}}Span { - ctx: ctx, - span: span, - } -} -{%- endif %} - -{{ required::declare_attrs(attrs=attributes) }} -{{ optional::declare_attrs(marker="Span", attrs=attributes) }} - -// {{span_name | struct_name}}Span is a span for `{{ span_name }}`. -type {{span_name | struct_name}}Span struct { - ctx context.Context - span trace.Span -} - -{% if events | length > 0 -%} -// {{ span_name | struct_name }}Event is interface implemented by all events for `{{ span_name }}`. -type {{ span_name | struct_name }}Event interface { - EventOptions() []trace.EventOption -} - -{% for event in events -%} - -{% set event_name = event.event_name | function_name -%} -{{ required::declare_attrs(prefix="Event" ~ event_name, attrs=event.attributes) }} -{{ optional::declare_attrs(prefix="Event" ~ event_name, marker="Event" ~ event_name, attrs=event.attributes) }} - -// Event adds an event to the span. -func (s *{{span_name | struct_name}}Span) Event{{ event.event_name | function_name }}( - {%- for attr in event.attributes | required %} - {{attr.id | field_name}} Event{{ event.event_name | function_name }}{{attr.id | struct_name}}ReqAttrWrapper, - {%- endfor %} - optionalAttributes ...{{ optional::attr_type(prefix="Event" ~ event_name) }}, -) *{{span_name | struct_name}}Span { - eventOptions := []trace.EventOption{ - {%- for attr in event.attributes | with_value %} - trace.WithAttributes(attribute.{{ attr.id | function_name }}Key.{{attr.type | type_mapping(enum=attr.id) | function_name}}({{attr.value | value}})), - {%- endfor %} - {%- for attr in event.attributes | required %} - trace.WithAttributes({{ attr.id | field_name }}.Attribute()), - {%- endfor %} - } - for _, opt := range optionalAttributes { - eventOptions = append(eventOptions, trace.WithAttributes(opt.Attribute())) - } - s.span.AddEvent("{{ event.event_name }}", eventOptions...) - return s -} -{% endfor %} - -{%- endif %} - -{% for attr in attributes | not_required | without_value %} -// Attr{{ attr.id | function_name }} sets the optional attribute `{{ attr.id }}` for the span. -// {{ [attr.brief, attr.note, "", "# Examples", attr.examples] | comment(prefix="// ") }} -func (s *{{span_name | struct_name}}Span) {{attr.id | function_name}}OptAttr(value {{ attr.type | type_mapping(enum=attr.id | struct_name) }}) *{{span_name | struct_name}}Span { - s.span.SetAttributes(attribute.{{ attr.id | field_name }}Key.{{ attr.type | type_mapping(enum=attr.id) | function_name }}(value)) - return s -} -{% endfor %} - -func (s *{{span_name | struct_name}}Span) StatusOk() *{{span_name | struct_name}}Span { - s.span.SetStatus(codes.Ok, "") - return s -} - -// Error sets the error for the span. -func (s *{{span_name | struct_name}}Span) Error(err error, description string) *{{span_name | struct_name}}Span { - s.span.SetStatus(codes.Error, description) - s.span.RecordError(err) - return s -} - -// Context returns the context of the current span. -func (s *{{span_name | struct_name }}Span) Context() context.Context { return s.ctx } - -// End ends the span with status OK. -func (s *{{span_name | struct_name}}Span) EndWithOk() { - s.span.SetStatus(codes.Ok, "") - s.span.End() -} - -// End ends the span with status Error and a given description. -func (s *{{span_name | struct_name}}Span) EndWithError(err error, description string) { - s.span.SetStatus(codes.Error, description) - s.span.RecordError(err) - s.span.End() -} - -// End ends the span. -func (s *{{span_name | struct_name}}Span) End() { - s.span.End() -} diff --git a/templates/schema/go/required_attrs.macro.tera b/templates/schema/go/required_attrs.macro.tera deleted file mode 100644 index 793f628b..00000000 --- a/templates/schema/go/required_attrs.macro.tera +++ /dev/null @@ -1,54 +0,0 @@ -{% macro declare_args(attrs) -%} - {%- for attr in attrs | required | without_value %} - {{attr.id | arg_name}} {{attr.id | struct_name}}ReqAttrWrapper, - {%- endfor %} -{% endmacro declare_args %} - - -{% macro declare_attrs(prefix="", attrs) -%} -{% set require_attrs = attrs | required | without_value %} -{% if require_attrs | length > 0 -%} -// =============================================== -// ====== Definition of required attributes ====== -// =============================================== - -{% for attr in require_attrs | without_enum %} -// {{prefix}}{{attr.id | struct_name}}ReqAttr is a wrapper for a required attribute. -// {{ [attr.brief, attr.note, "", "# Examples", attr.examples] | comment(prefix="// ") }} -func {{prefix}}{{attr.id | struct_name}}ReqAttr(v {{ attr.type | type_mapping(enum=attr.id | struct_name) }}) {{prefix}}{{attr.id | struct_name}}ReqAttrWrapper { - return {{prefix}}{{attr.id | struct_name}}ReqAttrWrapper{v} -} -// {{prefix}}{{attr.id | struct_name}}ReqAttrWrapper is a wrapper for the attribute `{{attr.id}}`. -// Use the function {{prefix}}{{attr.id | struct_name}}ReqAttr(value) to create an instance. -type {{prefix}}{{attr.id | struct_name}}ReqAttrWrapper struct { {{ attr.type | type_mapping(enum=attr.id | struct_name) }} } -func (w {{prefix}}{{attr.id | struct_name}}ReqAttrWrapper) Attribute() otel_attr.KeyValue { - return attribute.{{ attr.id | field_name }}Key.String(w.{{ attr.type | type_mapping(enum=attr.id | struct_name) }}) -} - -{% endfor %} - -{% for attr in require_attrs | with_enum %} -// {{prefix}}{{attr.id | struct_name}}ReqAttr is a wrapper for a required attribute. -// {{ [attr.brief, attr.note, "", "# Examples", attr.examples] | comment(prefix="// ") }} -func {{prefix}}{{attr.id | struct_name}}ReqAttr(v {{ attr.type | type_mapping(enum=attr.id | struct_name) }}) {{prefix}}{{attr.id | struct_name}}ReqAttrWrapper { - return {{prefix}}{{attr.id | struct_name}}ReqAttrWrapper{v} -} -// {{prefix}}{{attr.id | struct_name}}ReqAttrWrapper is a wrapper for the attribute `{{attr.id}}`. -// Use the function {{prefix}}{{attr.id | struct_name}}ReqAttr(value) to create an instance. -type {{prefix}}{{attr.id | struct_name}}ReqAttrWrapper struct { {{ attr.type | type_mapping(enum=attr.id | struct_name) }} } -func (w {{prefix}}{{attr.id | struct_name}}ReqAttrWrapper) Attribute() otel_attr.KeyValue { - return attribute.{{ attr.id | field_name }}Key.String(w.{{ attr.type | type_mapping(enum=attr.id | struct_name) }}) -} - -type {{attr.id | struct_name}} string -const ( -{% for variant in attr.type.members %} - // {{variant.id | struct_name}} is a possible value of {{attr.id | struct_name}}. - // {{ [variant.brief, variant.note] | comment(prefix=" // ") }} - {{variant.id | struct_name}} {{attr.id | struct_name}} = "{{variant.id}}" -{%- endfor %} -) -{% endfor %} - -{%- endif %} -{% endmacro declare_attrs %} \ No newline at end of file diff --git a/templates/schema/rust/config.yaml b/templates/schema/rust/config.yaml deleted file mode 100644 index 72595c63..00000000 --- a/templates/schema/rust/config.yaml +++ /dev/null @@ -1,15 +0,0 @@ -file_name: snake_case -function_name: snake_case -arg_name: snake_case -struct_name: PascalCase -field_name: snake_case - -type_mapping: - int: i64 - double: f64 - boolean: bool - string: String - "int[]": "[i64]" - "double[]": "[f64]" - "boolean[]": "[bool]" - "string[]": "[String]" \ No newline at end of file diff --git a/templates/schema/rust/eventer/mod.rs.tera b/templates/schema/rust/eventer/mod.rs.tera deleted file mode 100644 index 6de050dc..00000000 --- a/templates/schema/rust/eventer/mod.rs.tera +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -//! Generated OTel Client Loggers API. - -{% if schema.resource_events is defined %} -{% for event in schema.resource_events.events %} -/// Events `{{ event.event_name }}` (domain `{{ event.domain }}`) with the given attributes. -pub fn event_{{ event.domain | function_name }}_{{ event.event_name | function_name }}(attrs: {{ event.domain | struct_name }}{{ event.event_name | struct_name }}Attrs) {} - -/// event attributes for `{{ event.event_name }}` (domain `{{ event.domain }}`). -pub struct {{ event.domain | struct_name }}{{ event.event_name | struct_name }}Attrs { - {%- for attr in event.attributes %} - /// {{ [attr.brief, attr.note, "", "# Examples", attr.examples] | comment(prefix=" /// ") }} - pub {{attr.id | field_name}}: {% if attr is required %}{{ attr.type | type_mapping }}{% else %}Option<{{ attr.type | type_mapping }}>{% endif %}, - {%- endfor %} -} - -{% endfor %} -{% endif %} \ No newline at end of file diff --git a/templates/schema/rust/meter/mod.rs.tera b/templates/schema/rust/meter/mod.rs.tera deleted file mode 100644 index d8f75f8f..00000000 --- a/templates/schema/rust/meter/mod.rs.tera +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -//! Generated OTel Client Loggers API. - -{% if schema.resource_metrics is defined %} -{% if schema.resource_metrics.metrics is defined %} -{% for metric in schema.resource_metrics.metrics %} -/// Metric `{{ metric.name }}` to report u64 values. -pub fn {{ metric.name | function_name }}_u64() -> {{ metric.name | struct_name }}U64{{ metric.instrument | instrument | struct_name }} { - {{ metric.name | struct_name }}U64{{ metric.instrument | instrument | struct_name }}{} -} - -/// Metric `{{ metric.name }}` to report f64 values. -pub fn {{ metric.name | function_name }}_f64() -> {{ metric.name | struct_name }}F64{{ metric.instrument | instrument | struct_name }} { - {{ metric.name | struct_name }}F64{{ metric.instrument | instrument | struct_name }}{} -} - -pub struct {{ metric.name | struct_name }}U64{{ metric.instrument | instrument | struct_name }} { -} - -pub struct {{ metric.name | struct_name }}F64{{ metric.instrument | instrument | struct_name }} { -} - -impl {{ metric.name | struct_name }}U64{{ metric.instrument | instrument | struct_name }} { - {% if metric.instrument == "counter" %} - pub fn add(&mut self, value: u64, attrs: {{ metric.name | struct_name }}Attrs) {} - {% elif metric.instrument == "updowncounter" %} - pub fn add(&mut self, value: u64, attrs: {{ metric.name | struct_name }}Attrs) {} - {% elif metric.instrument == "gauge" %} - pub fn add(&mut self, value: u64, attrs: {{ metric.name | struct_name }}Attrs) {} - {% elif metric.instrument == "histogram" %} - pub fn record(&mut self, value: u64, attrs: {{ metric.name | struct_name }}Attrs) {} - {% endif %} -} - -impl {{ metric.name | struct_name }}F64{{ metric.instrument | instrument | struct_name }} { - {% if metric.instrument == "counter" %} - pub fn add(&mut self, value: f64, attrs: {{ metric.name | struct_name }}Attrs) {} - {% elif metric.instrument == "updowncounter" %} - pub fn add(&mut self, value: f64, attrs: {{ metric.name | struct_name }}Attrs) {} - {% elif metric.instrument == "gauge" %} - pub fn add(&mut self, value: f64, attrs: {{ metric.name | struct_name }}Attrs) {} - {% elif metric.instrument == "histogram" %} - pub fn record(&mut self, value: f64, attrs: {{ metric.name | struct_name }}Attrs) {} - {% endif %} -} - -/// Metric attributes for `{{ metric.name }}`. -pub struct {{ metric.name | struct_name }}Attrs { - {%- for attr in metric.attributes %} - /// {{ [attr.brief, attr.note, "", "# Examples", attr.examples] | comment(prefix=" /// ") }} - pub {{attr.id | arg_name}}: {% if attr is required %}{{ attr.type | type_mapping }}{% else %}Option<{{ attr.type | type_mapping }}>{% endif %}, - {%- endfor %} -} - -{% endfor %} -{% endif %} -{% endif %} - - -{% if schema.resource_metrics is defined %} -{% if schema.resource_metrics.metric_groups is defined %} -{% for metric in schema.resource_metrics.metric_groups %} -/// Multivariate metric `{{ metric.id }}`. -pub fn {{ metric.id | function_name }}() -> {{ metric.id | struct_name }} { - {{ metric.id | struct_name }}{} -} - -pub struct {{ metric.id | struct_name }} { -} - -impl {{ metric.id | struct_name }} { - pub fn report(&mut self, metrics: {{ metric.id | struct_name }}Metrics, attrs: {{ metric.id | struct_name }}Attrs) {} -} - -/// Multivariate metrics for `{{ metric.id }}`. -pub struct {{ metric.id | struct_name }}Metrics { - {%- for metric in metric.metrics %} - /// {{ [metric.brief, metric.note] | comment(prefix=" /// ") }} - pub {{metric.name | arg_name}}: u64, - {%- endfor %} -} - -/// Metric attributes for `{{ metric.id }}`. -pub struct {{ metric.id | struct_name }}Attrs { - {%- for attr in metric.attributes %} - /// {{ [attr.brief, attr.note, "", "# Examples", attr.examples] | comment(prefix=" /// ") }} - pub {{attr.id | arg_name}}: {% if attr is required %}{{ attr.type | type_mapping }}{% else %}Option<{{ attr.type | type_mapping }}>{% endif %}, - {%- endfor %} -} - -{% endfor %} -{% endif %} -{% endif %} \ No newline at end of file diff --git a/templates/schema/rust/mod.rs.tera b/templates/schema/rust/mod.rs.tera deleted file mode 100644 index 26d821c5..00000000 --- a/templates/schema/rust/mod.rs.tera +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -//! Generated OTel Client API. - -pub mod meter; -pub mod eventer; -pub mod tracer; \ No newline at end of file diff --git a/templates/schema/rust/span.tera.bak b/templates/schema/rust/span.tera.bak deleted file mode 100644 index 9cd38e8b..00000000 --- a/templates/schema/rust/span.tera.bak +++ /dev/null @@ -1,142 +0,0 @@ -{# Define the file name for the generated code #} -{%- set file_name = id | file_name -%} -{{- config(file_name="tracers/" ~ file_name ~ ".rs") -}} -// SPDX-License-Identifier: Apache-2.0 - -//! Code generated by OTel Weaver to define the span `{{ id }}`. - -pub enum Status { - Unset, - Error, - Ok, -} - -{%- set required_attrs = attributes | required -%} -{%- set not_required_attrs = attributes | not_required -%} -{%- if required_attrs | length > 0 %} -/// Starts a new named `{{ id }}` span with the given required attributes. -pub fn start( - name: &str, - required_attrs: {{id | struct_name}}Attrs, -) -> {{id | struct_name}}Span { - {{id | struct_name}}Span { - {{id | field_name}}_attrs: required_attrs, - {{id | field_name}}_opt_attrs: Default::default(), - events: Vec::new(), - } -} - -/// Starts a new named `{{ id }}` span with the given required attributes -/// and the optional attributes. -pub fn start_with_opt_attrs( - name: &str, - required_attrs: {{id | struct_name}}Attrs, - optional_attrs: {{id | struct_name}}OptAttrs, - ) -> {{id | struct_name}}Span { - {{id | struct_name}}Span { - {{id | field_name}}_attrs: required_attrs, - {{id | field_name}}_opt_attrs: optional_attrs, - events: Vec::new(), - } -} -{%- else %} -/// Starts a new named `{{ id }}` span. -pub fn start(name: &str) -> {{id | struct_name}}Span { - {{id | struct_name}}Span { - {{id | field_name}}_opt_attrs: {{id | struct_name}}OptAttrs::default(), - } -} - -/// Starts a new named `{{ id }}` span with the given optional attributes. -pub fn start_with_opt_attrs( - name: &str, - optional_attrs: {{id | struct_name}}OptAttrs, - ) -> {{id | struct_name}}Span { - {{id | struct_name}}Span { - {{id | field_name}}_opt_attrs: optional_attrs, - } -} -{%- endif %} - -pub struct {{id | struct_name}}Span { -{%- if required_attrs | length > 0 %} - /// Required span attributes for `{{ id }}`. - {{id | field_name}}_attrs: {{id | struct_name}}Attrs, -{%- endif -%} -{%- if not_required_attrs | length > 0 %} - /// Optional span attributes for `{{ id }}`. - {{id | field_name}}_opt_attrs: {{id | struct_name}}OptAttrs, -{%- endif %} -{%- if events | length > 0 -%} - /// Events for `{{ id }}`. - events: Vec, -{%- endif %} -} - -{% if required_attrs | length > 0 -%} -/// Required span attributes for `{{ id }}`. -pub struct {{id | struct_name}}Attrs { -{%- for attr in required_attrs %} - /// {{ [attr.brief, attr.note, "", "# Examples", attr.examples] | comment(prefix=" /// ") }} - pub {{attr.id | arg_name}}: {{ attr.type | type_mapping }}, -{%- endfor %} -} -{%- endif %} - -{% if not_required_attrs | length > 0 -%} -/// Optional span attributes for `{{ id }}`. -#[derive(Default)] -pub struct {{id | struct_name}}OptAttrs { -{%- for attr in not_required_attrs %} - /// {{ [attr.brief, attr.note, "", "# Examples", attr.examples] | comment(prefix=" /// ") }} - pub {{attr.id | arg_name}}: Option<{{ attr.type | type_mapping }}>, -{%- endfor %} -} -{%- endif %} - -{% if events | length > 0 -%} -pub enum Event { - {% for event in events -%} - {{ event.id | struct_name}} { - {%- for attr in event.attributes %} - /// {{ [attr.brief, attr.note, "", "# Examples", attr.examples] | comment(prefix=" /// ") }} - {%- if attr is required %} - {{attr.id | field_name}}: {{ attr.type | type_mapping }}, - {% else %} - {{attr.id | field_name}}: Option<{{ attr.type | type_mapping }}>, - {% endif -%} - {% endfor %} - }, - {%- endfor %} -} -{%- endif %} - - -impl {{id | struct_name}}Span { - {%- for attr in not_required_attrs %} - /// {{ [attr.brief, attr.note, "", "# Examples", attr.examples] | comment(prefix=" /// ") }} - pub fn attr_{{attr.id | function_name}}(&mut self, value: {{ attr.type | type_mapping }}) { - self.{{id | field_name}}_opt_attrs.{{attr.id | field_name}} = Some(value); - } - {% endfor %} - - {% if events | length > 0 -%} - /// Adds an event to the span. - pub fn event(&mut self, event: Event) { - self.events.push(event); - } - {%- endif %} - - pub fn status(&self, status: Status) {} - pub fn error(&self, err: &dyn std::error::Error) {} - - /// Ends the span. - pub fn end(self) {} - - {%- if not_required_attrs | length > 0 %} - /// Ends the span with the optional attributes. - pub fn end_with_opt_attrs(mut self, optional_attrs: {{id | struct_name}}OptAttrs) { - self.{{id | field_name}}_opt_attrs = optional_attrs; - } - {%- endif %} -} \ No newline at end of file diff --git a/templates/schema/rust/tracer/mod.rs.tera b/templates/schema/rust/tracer/mod.rs.tera deleted file mode 100644 index 2ac39fb3..00000000 --- a/templates/schema/rust/tracer/mod.rs.tera +++ /dev/null @@ -1,142 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -//! Generated OTel Client Tracers API. - -pub enum Status { - Unset, - Error, - Ok, -} - -{% if schema.resource_spans is defined %} -{% for span in schema.resource_spans.spans %} - -{%- set required_attrs = span.attributes | required -%} -{%- set not_required_attrs = span.attributes | not_required -%} -{%- if required_attrs | length > 0 %} -/// Starts a new named `{{ span.span_name }}` span with the given required attributes. -pub fn start_{{ span.span_name | function_name }}( - required_attrs: {{span.span_name | struct_name}}Attrs, -) -> {{span.span_name | struct_name}}Span { - {{span.span_name | struct_name}}Span { - {{span.span_name | field_name}}_attrs: required_attrs, - {{span.span_name | field_name}}_opt_attrs: Default::default(), - events: Vec::new(), - } -} - -/// Starts a new named `{{ span.span_name }}` span with the given required attributes -/// and the optional attributes. -pub fn start_{{ span.span_name | function_name }}_with_opt_attrs( - required_attrs: {{span.span_name | struct_name}}Attrs, - optional_attrs: {{span.span_name | struct_name}}OptAttrs, -) -> {{span.span_name | struct_name}}Span { - {{span.span_name | struct_name}}Span { - {{span.span_name | field_name}}_attrs: required_attrs, - {{span.span_name | field_name}}_opt_attrs: optional_attrs, - events: Vec::new(), - } -} -{%- else %} -/// Starts a new named `{{ span.span_name }}` span. -pub fn start_{{ span.span_name | function_name }}() -> {{span.span_name | struct_name}}Span { - {{span.span_name | struct_name}}Span { - {{span.span_name | field_name}}_opt_attrs: {{span.span_name | struct_name}}OptAttrs::default(), - } -} - -/// Starts a new named `{{ span.span_name }}` span with the given optional attributes. -pub fn start_{{ span.span_name | function_name }}_with_opt_attrs( - optional_attrs: {{span.span_name | struct_name}}OptAttrs, -) -> {{span.span_name | struct_name}}Span { - {{span.span_name | struct_name}}Span { - {{span.span_name | field_name}}_opt_attrs: optional_attrs, - } -} -{%- endif %} - -/// {{span.span_name | struct_name}}Span is a span for `{{ span.span_name }}`. -pub struct {{span.span_name | struct_name}}Span { - {%- if required_attrs | length > 0 %} - /// Required span attributes for `{{ span.span_name }}`. - {{span.span_name | field_name}}_attrs: {{span.span_name | struct_name}}Attrs, - {%- endif -%} - {%- if not_required_attrs | length > 0 %} - /// Optional span attributes for `{{ span.span_name }}`. - {{span.span_name | field_name}}_opt_attrs: {{span.span_name | struct_name}}OptAttrs, - {%- endif %} - {%- if span.events | length > 0 %} - /// Events for `{{ span.span_name }}`. - events: Vec<{{ span.span_name | struct_name }}Event>, - {%- endif %} -} - -{% if required_attrs | length > 0 -%} -/// Required span attributes for `{{ span.span_name }}`. -pub struct {{span.span_name | struct_name}}Attrs { - {%- for attr in required_attrs %} - /// {{ [attr.brief, attr.note, "", "# Examples", attr.examples] | comment(prefix=" /// ") }} - pub {{attr.id | field_name}}: {{ attr.type | type_mapping }}, - {%- endfor %} -} -{%- endif %} - -{% if not_required_attrs | length > 0 -%} -/// Optional span attributes for `{{ span.span_name }}`. -#[derive(Default)] -pub struct {{span.span_name | struct_name}}OptAttrs { - {%- for attr in not_required_attrs %} - /// {{ [attr.brief, attr.note, "", "# Examples", attr.examples] | comment(prefix=" /// ") }} - pub {{attr.id | field_name}}: Option<{{ attr.type | type_mapping }}>, - {%- endfor %} -} -{%- endif %} - -{% if span.events | length > 0 -%} -pub enum {{ span.span_name | struct_name }}Event { -{% for event in span.events -%} -{{ event.event_name | struct_name}} { -{%- for attr in event.attributes %} -/// {{ [attr.brief, attr.note, "", "# Examples", attr.examples] | comment(prefix=" /// ") }} -{%- if attr is required %} -{{attr.id | field_name}}: {{ attr.type | type_mapping }}, -{% else %} -{{attr.id | field_name}}: Option<{{ attr.type | type_mapping }}>, -{% endif -%} -{% endfor %} -}, -{%- endfor %} -} -{%- endif %} - - -impl {{span.span_name | struct_name}}Span { - {%- for attr in not_required_attrs %} - /// {{ [attr.brief, attr.note, "", "# Examples", attr.examples] | comment(prefix=" /// ") }} - pub fn attr_{{attr.id | function_name}}(&mut self, value: {{ attr.type | type_mapping }}) { - self.{{span.span_name | field_name}}_opt_attrs.{{attr.id | field_name}} = Some(value); - } - {% endfor %} - - {% if span.events | length > 0 -%} - /// Adds an event to the span. - pub fn event(&mut self, event: {{ span.span_name | struct_name }}Event) { - self.events.push(event); - } - {%- endif %} - - pub fn status(&self, status: Status) {} - pub fn error(&self, err: &dyn std::error::Error) {} - - /// Ends the span. - pub fn end(self) {} - - {%- if not_required_attrs | length > 0 %} - /// Ends the span with the optional attributes. - pub fn end_with_opt_attrs(mut self, optional_attrs: {{span.span_name | struct_name}}OptAttrs) { - self.{{span.span_name | field_name}}_opt_attrs = optional_attrs; - } - {%- endif %} -} -{% endfor %} -{% endif %} \ No newline at end of file From 618b8d29c4c4f71a6b724b3a2cca4b5f61e0fd21 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Fri, 26 Apr 2024 16:55:48 -0700 Subject: [PATCH 04/39] feat(codegen): add support for semconv_experimental feature --- crates/weaver_forge/src/extensions/tests.rs | 87 +++++++++++++++---- crates/weaver_forge/src/lib.rs | 1 + .../registry/rust/semantic_attributes.rs.j2 | 10 ++- templates/registry/rust/weaver.yaml | 4 +- 4 files changed, 82 insertions(+), 20 deletions(-) diff --git a/crates/weaver_forge/src/extensions/tests.rs b/crates/weaver_forge/src/extensions/tests.rs index a6d892c5..5f1c0836 100644 --- a/crates/weaver_forge/src/extensions/tests.rs +++ b/crates/weaver_forge/src/extensions/tests.rs @@ -7,12 +7,24 @@ use minijinja::Value; /// Checks if the input value is an object with a field named "stability" that has the value "stable". /// Otherwise, it returns false. pub fn is_stable(input: Value) -> bool { - if let Some(object) = input.as_struct() { - let stability = object.get_field("stability"); - if let Some(stability) = stability { - if let Some(stability) = stability.as_str() { - return stability == "stable"; - } + let result = input.get_attr("stability"); + + if let Ok(stability) = result { + if let Some(stability) = stability.as_str() { + return stability == "stable"; + } + } + false +} + +/// Checks if the input value is an object with a field named "stability" that has the value +/// "experimental". Otherwise, it returns false. +pub fn is_experimental(input: Value) -> bool { + let result = input.get_attr("stability"); + + if let Ok(stability) = result { + if let Some(stability) = stability.as_str() { + return stability == "experimental"; } } false @@ -21,12 +33,11 @@ pub fn is_stable(input: Value) -> bool { /// Checks if the input value is an object with a field named "stability" that has the value "deprecated". /// Otherwise, it returns false. pub fn is_deprecated(input: Value) -> bool { - if let Some(object) = input.as_struct() { - let stability = object.get_field("stability"); - if let Some(stability) = stability { - if let Some(stability) = stability.as_str() { - return stability == "deprecated"; - } + let result = input.get_attr("deprecated"); + + if let Ok(deprecated) = result { + if let Some(deprecated) = deprecated.as_str() { + return deprecated.len() > 0; } } false @@ -42,6 +53,7 @@ mod tests { id: String, r#type: String, stability: String, + deprecated: Option, } impl StructObject for DynAttr { @@ -50,6 +62,7 @@ mod tests { "id" => Some(Value::from(self.id.as_str())), "type" => Some(Value::from(self.r#type.as_str())), "stability" => Some(Value::from(self.stability.as_str())), + "deprecated" => self.deprecated.as_ref().map(|s| Value::from(s.as_str())), _ => None, } } @@ -77,6 +90,7 @@ mod tests { id: "test".to_owned(), r#type: "test".to_owned(), stability: "stable".to_owned(), + deprecated: None, }); assert!(is_stable(attr)); @@ -85,6 +99,7 @@ mod tests { id: "test".to_owned(), r#type: "test".to_owned(), stability: "deprecated".to_owned(), + deprecated: None, }); assert!(!is_stable(attr)); @@ -97,28 +112,66 @@ mod tests { } #[test] - fn test_is_deprecated() { - // An attribute with stability "deprecated" + fn test_is_experimental() { + // An attribute with stability "experimental" let attr = Value::from_struct_object(DynAttr { id: "test".to_owned(), r#type: "test".to_owned(), - stability: "deprecated".to_owned(), + stability: "experimental".to_owned(), + deprecated: None, }); - assert!(is_deprecated(attr)); + assert!(is_experimental(attr)); // An attribute with stability "stable" let attr = Value::from_struct_object(DynAttr { id: "test".to_owned(), r#type: "test".to_owned(), stability: "stable".to_owned(), + deprecated: None, }); - assert!(!is_deprecated(attr)); + assert!(!is_experimental(attr)); // An object without a stability field let object = Value::from_struct_object(DynSomethingElse { id: "test".to_owned(), r#type: "test".to_owned(), }); + assert!(!is_experimental(object)); + } + + #[test] + fn test_is_deprecated() { + // An attribute with stability "experimental" and a deprecated field with a value + let attr = Value::from_struct_object(DynAttr { + id: "test".to_owned(), + r#type: "test".to_owned(), + stability: "experimental".to_owned(), + deprecated: Some("This is deprecated".to_owned()), + }); + assert!(is_deprecated(attr)); + + // An attribute with stability "stable" and a deprecated field with a value + let attr = Value::from_struct_object(DynAttr { + id: "test".to_owned(), + r#type: "test".to_owned(), + stability: "stable".to_owned(), + deprecated: Some("This is deprecated".to_owned()), + }); + assert!(is_deprecated(attr)); + + // An object without a deprecated field + let object = Value::from_struct_object(DynSomethingElse { + id: "test".to_owned(), + r#type: "test".to_owned(), + }); assert!(!is_deprecated(object)); + + let attr = Value::from_struct_object(DynAttr { + id: "test".to_owned(), + r#type: "test".to_owned(), + stability: "stable".to_owned(), + deprecated: None, + }); + assert!(!is_deprecated(attr)); } } \ No newline at end of file diff --git a/crates/weaver_forge/src/lib.rs b/crates/weaver_forge/src/lib.rs index 2e7701a2..bf2bcdc0 100644 --- a/crates/weaver_forge/src/lib.rs +++ b/crates/weaver_forge/src/lib.rs @@ -379,6 +379,7 @@ impl TemplateEngine { env.add_filter("comment_with_prefix", code::comment_with_prefix); env.add_test("stable", extensions::tests::is_stable); + env.add_test("experimental", extensions::tests::is_experimental); env.add_test("deprecated", extensions::tests::is_deprecated); // env.add_filter("unique_attributes", extensions::unique_attributes); diff --git a/templates/registry/rust/semantic_attributes.rs.j2 b/templates/registry/rust/semantic_attributes.rs.j2 index a1f476d8..c2623408 100644 --- a/templates/registry/rust/semantic_attributes.rs.j2 +++ b/templates/registry/rust/semantic_attributes.rs.j2 @@ -15,11 +15,19 @@ {%- for attribute in ctx.attributes %} +{%- if attribute.brief %} {{ attribute.brief | comment_with_prefix("/// ") }} +{%- endif %} {%- if attribute.note %} /// /// Notes: {{ attribute.note | comment_with_prefix("/// ") }} {%- endif %} +{%- if attribute is experimental %} +#[cfg(feature = "semconv_experimental")] +{%- endif %} +{%- if attribute is deprecated %} +#[deprecated(note="{{ attribute.deprecated }}")] +{%- endif %} pub const {{ attribute.name | screaming_snake_case }}: &str = "{{ attribute.name }}"; -{%- endfor %} \ No newline at end of file +{% endfor %} \ No newline at end of file diff --git a/templates/registry/rust/weaver.yaml b/templates/registry/rust/weaver.yaml index 3574d83b..e7ed6f73 100644 --- a/templates/registry/rust/weaver.yaml +++ b/templates/registry/rust/weaver.yaml @@ -1,7 +1,7 @@ templates: - pattern: lib.rs.j2 - filter: '.groups | map(select(.id | startswith("registry."))) | map(select(.type == "attribute_group" and .prefix != null and .prefix != "") | { id, type, brief, prefix, attributes: (.attributes | map(select(.stability == "stable")))}) | sort_by(.prefix // empty) | map(select(.attributes | length > 0))' + filter: '.groups | map(select(.id | startswith("registry."))) | map(select(.type == "attribute_group" and .prefix != null and .prefix != "") | { id, type, brief, prefix, attributes: (.attributes | map(select(.stability == "experimental" and .deprecated | not)))}) | sort_by(.prefix // empty) | map(select(.attributes | length > 0))' application_mode: single - pattern: semantic_attributes.rs.j2 - filter: '.groups | map(select(.id | startswith("registry."))) | map(select(.type == "attribute_group" and .prefix != null and .prefix != "") | { id, type, brief, prefix, attributes: (.attributes | map(select(.stability == "stable")))}) | sort_by(.prefix // empty) | map(select(.attributes | length > 0))' + filter: '.groups | map(select(.id | startswith("registry."))) | map(select(.type == "attribute_group" and .prefix != null and .prefix != "") | { id, type, brief, prefix, attributes: (.attributes | map(select(.stability == "experimental" and .deprecated | not)))}) | sort_by(.prefix // empty) | map(select(.attributes | length > 0))' application_mode: each From db4dec4ea66562078f6fc6d8bd844c0790125aa1 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Fri, 26 Apr 2024 17:01:49 -0700 Subject: [PATCH 05/39] chore: bump minijinja version to 1.0.21 --- Cargo.lock | 4 ++-- crates/weaver_forge/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 224d6851..406b796d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2054,9 +2054,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "minijinja" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5c5e3d2b4c0a6832bd3d571f7c19a7c1c1f05f11a6e85ae1a29f76be5f9455" +checksum = "55e877d961d4f96ce13615862322df7c0b6d169d40cab71a7ef3f9b9e594451e" dependencies = [ "aho-corasick", "memo-map", diff --git a/crates/weaver_forge/Cargo.toml b/crates/weaver_forge/Cargo.toml index e23b4f46..54809d1b 100644 --- a/crates/weaver_forge/Cargo.toml +++ b/crates/weaver_forge/Cargo.toml @@ -18,7 +18,7 @@ weaver_resolver = { path = "../weaver_resolver" } weaver_resolved_schema = { path = "../weaver_resolved_schema" } weaver_semconv = { path = "../weaver_semconv" } -minijinja = { version = "1.0.20", features = ["loader", "custom_syntax", "debug", "json"] } +minijinja = { version = "1.0.21", features = ["loader", "custom_syntax", "debug", "json"] } convert_case = "0.6.0" globset = { version = "0.4.14", features = ["serde1"] } jaq-core = "1.2.1" From d4041913d6935344dc0ec857ef9835891687252e Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Sat, 27 Apr 2024 14:09:49 -0700 Subject: [PATCH 06/39] chore: Fix fmt and clippy issues --- Cargo.lock | 57 +++++++++++-------- crates/weaver_forge/src/extensions/code.rs | 9 +-- crates/weaver_forge/src/extensions/mod.rs | 2 +- .../{tests.rs => test_stability.rs} | 13 +++-- crates/weaver_forge/src/lib.rs | 6 +- templates/registry/rust/lib.rs.j2 | 3 +- .../registry/rust/semantic_attributes.rs.j2 | 17 +++++- 7 files changed, 68 insertions(+), 39 deletions(-) rename crates/weaver_forge/src/extensions/{tests.rs => test_stability.rs} (95%) diff --git a/Cargo.lock b/Cargo.lock index 406b796d..43c81d1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -613,15 +613,15 @@ checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.4.1", "windows-sys 0.52.0", ] [[package]] name = "flate2" -version = "1.0.28" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "4556222738635b7a3417ae6130d8f52201e45a0c4d1a907f0826383adb5f85e7" dependencies = [ "crc32fast", "miniz_oxide", @@ -1959,9 +1959,9 @@ checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -2253,9 +2253,9 @@ checksum = "8fecab3723493c7851f292cb060f3ee1c42f19b8d749345d0d7eaf3fd19aa62d" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" dependencies = [ "lock_api", "parking_lot_core", @@ -2263,15 +2263,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.1", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.5", ] [[package]] @@ -2516,6 +2516,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +dependencies = [ + "bitflags 2.5.0", +] + [[package]] name = "redox_users" version = "0.4.5" @@ -2776,18 +2785,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.198" +version = "1.0.199" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" +checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.198" +version = "1.0.199" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" +checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc" dependencies = [ "proc-macro2", "quote", @@ -3307,9 +3316,9 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" [[package]] name = "unicode-xid" @@ -3331,11 +3340,11 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "2.9.6" +version = "2.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f214ce18d8b2cbe84ed3aa6486ed3f5b285cf8d8fbdbce9f3f767a724adc35" +checksum = "d11a831e3c0b56e438a28308e7c810799e3c118417f342d30ecec080105395cd" dependencies = [ - "base64 0.21.7", + "base64 0.22.0", "flate2", "log", "once_cell", @@ -3678,9 +3687,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134306a13c5647ad6453e8deaec55d3a44d6021970129e6188735e74bf546697" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ "windows-sys 0.52.0", ] @@ -3841,9 +3850,9 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c976aaaa0e1f90dbb21e9587cdaf1d9679a1cde8875c0d6bd83ab96a208352" +checksum = "14b9415ee827af173ebb3f15f9083df5a122eb93572ec28741fb153356ea2578" dependencies = [ "memchr", ] diff --git a/crates/weaver_forge/src/extensions/code.rs b/crates/weaver_forge/src/extensions/code.rs index cc0d6ef9..ea9ed959 100644 --- a/crates/weaver_forge/src/extensions/code.rs +++ b/crates/weaver_forge/src/extensions/code.rs @@ -3,11 +3,12 @@ //! Set of filters used to facilitate the generation of code. /// Converts the input string into a comment with a prefix. -pub fn comment_with_prefix(input: &str, prefix: &str) -> String { +#[must_use] +pub(crate) fn comment_with_prefix(input: &str, prefix: &str) -> String { let mut comment = String::new(); for line in input.lines() { if !comment.is_empty() { - comment.push_str("\n"); + comment.push('\n'); } comment.push_str(&format!("{}{}", prefix, line)); } @@ -29,13 +30,13 @@ connection (an exception is made for peer-to-peer communication over TCP where t 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."#; - let expected_brief = r#"/// These attributes may be used to describe the client in a connection-based network interaction + let expected_brief = r#"/// 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."#; - assert_eq!(comment_with_prefix(brief, "/// "), expected_brief); + assert_eq!(comment_with_prefix(brief, "/// "), expected_brief); } } diff --git a/crates/weaver_forge/src/extensions/mod.rs b/crates/weaver_forge/src/extensions/mod.rs index 3647ebff..7a0ad4bc 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 tests; +pub mod test_stability; diff --git a/crates/weaver_forge/src/extensions/tests.rs b/crates/weaver_forge/src/extensions/test_stability.rs similarity index 95% rename from crates/weaver_forge/src/extensions/tests.rs rename to crates/weaver_forge/src/extensions/test_stability.rs index 5f1c0836..c37ca680 100644 --- a/crates/weaver_forge/src/extensions/tests.rs +++ b/crates/weaver_forge/src/extensions/test_stability.rs @@ -6,7 +6,8 @@ use minijinja::Value; /// Checks if the input value is an object with a field named "stability" that has the value "stable". /// Otherwise, it returns false. -pub fn is_stable(input: Value) -> bool { +#[must_use] +pub(crate) fn is_stable(input: Value) -> bool { let result = input.get_attr("stability"); if let Ok(stability) = result { @@ -19,7 +20,8 @@ pub fn is_stable(input: Value) -> bool { /// Checks if the input value is an object with a field named "stability" that has the value /// "experimental". Otherwise, it returns false. -pub fn is_experimental(input: Value) -> bool { +#[must_use] +pub(crate) fn is_experimental(input: Value) -> bool { let result = input.get_attr("stability"); if let Ok(stability) = result { @@ -32,12 +34,13 @@ pub fn is_experimental(input: Value) -> bool { /// Checks if the input value is an object with a field named "stability" that has the value "deprecated". /// Otherwise, it returns false. -pub fn is_deprecated(input: Value) -> bool { +#[must_use] +pub(crate) fn is_deprecated(input: Value) -> bool { let result = input.get_attr("deprecated"); if let Ok(deprecated) = result { if let Some(deprecated) = deprecated.as_str() { - return deprecated.len() > 0; + return !deprecated.is_empty(); } } false @@ -174,4 +177,4 @@ mod tests { }); assert!(!is_deprecated(attr)); } -} \ No newline at end of file +} diff --git a/crates/weaver_forge/src/lib.rs b/crates/weaver_forge/src/lib.rs index bf2bcdc0..4990b045 100644 --- a/crates/weaver_forge/src/lib.rs +++ b/crates/weaver_forge/src/lib.rs @@ -378,9 +378,9 @@ impl TemplateEngine { env.add_filter("comment_with_prefix", code::comment_with_prefix); - env.add_test("stable", extensions::tests::is_stable); - env.add_test("experimental", extensions::tests::is_experimental); - env.add_test("deprecated", extensions::tests::is_deprecated); + env.add_test("stable", extensions::test_stability::is_stable); + env.add_test("experimental", extensions::test_stability::is_experimental); + env.add_test("deprecated", extensions::test_stability::is_deprecated); // env.add_filter("unique_attributes", extensions::unique_attributes); // env.add_filter("instrument", extensions::instrument); diff --git a/templates/registry/rust/lib.rs.j2 b/templates/registry/rust/lib.rs.j2 index 2a403395..d586a946 100644 --- a/templates/registry/rust/lib.rs.j2 +++ b/templates/registry/rust/lib.rs.j2 @@ -5,7 +5,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -//! # OpenTelemetry Semantic Convention Attributes +//! OpenTelemetry Semantic Convention Attributes +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 {% for group in ctx %} {{ group.brief | comment_with_prefix("/// ") }} diff --git a/templates/registry/rust/semantic_attributes.rs.j2 b/templates/registry/rust/semantic_attributes.rs.j2 index c2623408..8567486c 100644 --- a/templates/registry/rust/semantic_attributes.rs.j2 +++ b/templates/registry/rust/semantic_attributes.rs.j2 @@ -12,8 +12,9 @@ //! Notes: {{ ctx.note | comment_with_prefix("/// ") }} {%- endif %} +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 -{%- for attribute in ctx.attributes %} +{% for attribute in ctx.attributes %} {%- if attribute.brief %} {{ attribute.brief | comment_with_prefix("/// ") }} @@ -30,4 +31,18 @@ #[deprecated(note="{{ attribute.deprecated }}")] {%- endif %} pub const {{ attribute.name | screaming_snake_case }}: &str = "{{ attribute.name }}"; +{% if attribute.type.allow_custom_values %} +{%- if attribute.brief %} +{{ attribute.brief | comment_with_prefix("/// ") }} +{%- endif %} +pub enum {{ attribute.name | pascal_case }} { +{% for variant in attribute.type.members %} + {%- if variant.brief %}{{ variant.brief | comment_with_prefix(" /// ") }}{% endif %} + {%- if variant.note %}{{ variant.note | comment_with_prefix(" /// ") }}{% endif %} + {%- if variant is experimental %} + #[cfg(feature = "semconv_experimental")] {% endif %} + {{ variant.id | pascal_case }}, +{% endfor %} +} +{% endif %} {% endfor %} \ No newline at end of file From 628d46ec1720abc08cec176ededa3dabf35640c0 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Sat, 27 Apr 2024 22:55:49 -0700 Subject: [PATCH 07/39] feat(forge): Add type_mapping filter --- crates/weaver_forge/README.md | 17 +++------ crates/weaver_forge/src/extensions/code.rs | 40 ++++++++++++++++++++++ crates/weaver_forge/src/lib.rs | 16 ++++----- 3 files changed, 53 insertions(+), 20 deletions(-) diff --git a/crates/weaver_forge/README.md b/crates/weaver_forge/README.md index 2ced339e..81e2799d 100644 --- a/crates/weaver_forge/README.md +++ b/crates/weaver_forge/README.md @@ -178,16 +178,6 @@ template_syntax: # application_mode: single ``` -Supported case converters: -- lowercase -- UPPERCASE -- PascalCase -- camelCase -- snake_case -- SCREAMING_SNAKE_CASE -- kebab-case -- SCREAMING-KEBAB-CASE - ## Custom Filters All the filters available in the MiniJinja template engine are available. In @@ -215,7 +205,8 @@ in the `acronyms` section of the `weaver.yaml` configuration file. - `split_ids`: Splits a string by '.' creating a list of nested ids. - `flatten`: Converts a List of Lists into a single list with all elements. e.g. \[\[a,b\],\[c\]\] => \[a,b,c\] - +- `type_mapping`: Converts a semantic convention type to a target type (see weaver.yaml section `type_mapping`). +- `comment_with_prefix(prefix)`: Outputs a multiline comment with the given prefix. > Note 1: This project uses the [convert_case](https://crates.io/crates/convert_case) > crate to convert strings to different cases. @@ -236,4 +227,6 @@ All the tests available in the MiniJinja template engine are available. In addition, OTel Weaver provides a set of custom tests to facilitate the generation of assets. -Not yet implemented. \ No newline at end of file +- `stable`: Returns true if the object is stable (i.e. stability=stable). +- `experimental`: Returns true if the object is experimental (i.e. stability=experimental). +- `deprecated`: Returns true if the object is deprecated (i.e. deprecated is defined). \ No newline at end of file diff --git a/crates/weaver_forge/src/extensions/code.rs b/crates/weaver_forge/src/extensions/code.rs index ea9ed959..e93ca124 100644 --- a/crates/weaver_forge/src/extensions/code.rs +++ b/crates/weaver_forge/src/extensions/code.rs @@ -2,6 +2,8 @@ //! Set of filters used to facilitate the generation of code. +use std::collections::HashMap; + /// Converts the input string into a comment with a prefix. #[must_use] pub(crate) fn comment_with_prefix(input: &str, prefix: &str) -> String { @@ -15,6 +17,44 @@ pub(crate) fn comment_with_prefix(input: &str, prefix: &str) -> String { comment } +/// Create a filter that uses the type mapping defined in `weaver.yaml` to replace +/// the input string (i.e. OTel type) with the target type. +/// +/// # Example +/// +/// ```rust +/// use weaver_forge::extensions::code; +/// +/// let type_mapping = vec![ +/// ("string".to_owned(), "String".to_owned()), +/// ("int".to_owned(), "i64".to_owned()), +/// ("double".to_owned(), "f64".to_owned()), +/// ("boolean".to_owned(), "bool".to_owned()), +/// ]; +/// +/// let filter = code::type_mapping(type_mapping.into_iter().collect());; +/// +/// assert_eq!(filter("int"), "i64"); +/// assert_eq!(filter("double"), "f64"); +/// assert_eq!(filter("string"), "String"); +/// assert_eq!(filter("boolean"), "bool"); +/// assert_eq!(filter("something else"), "something else"); +/// ``` +/// +/// # Returns +/// +/// A function that takes an input string and returns a new string with the +/// data type replaced. +pub fn type_mapping(type_mapping: HashMap) -> impl Fn(&str) -> String { + move |input: &str| -> String { + if let Some(target_type) = type_mapping.get(input) { + target_type.clone() + } else { + input.to_owned() + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/weaver_forge/src/lib.rs b/crates/weaver_forge/src/lib.rs index 4990b045..3597ba57 100644 --- a/crates/weaver_forge/src/lib.rs +++ b/crates/weaver_forge/src/lib.rs @@ -334,7 +334,9 @@ impl TemplateEngine { error: e.to_string(), })?; - // Register case conversion filters based on the target configuration + // Register code-oriented filters + env.add_filter("comment_with_prefix", code::comment_with_prefix); + env.add_filter("type_mapping", code::type_mapping(self.target_config.type_mapping.clone())); env.add_filter( "file_name", case_converter(self.target_config.file_name.clone()), @@ -355,6 +357,8 @@ impl TemplateEngine { "field_name", case_converter(self.target_config.field_name.clone()), ); + + // Register case conversion filters env.add_filter("lower_case", case_converter(CaseConvention::LowerCase)); env.add_filter("upper_case", case_converter(CaseConvention::UpperCase)); env.add_filter("title_case", case_converter(CaseConvention::TitleCase)); @@ -376,22 +380,21 @@ impl TemplateEngine { env.add_filter("acronym", acronym(self.target_config.acronyms.clone())); - env.add_filter("comment_with_prefix", code::comment_with_prefix); + // ToDo required, not_required, stable, experimental, deprecated + // Register custom tests env.add_test("stable", extensions::test_stability::is_stable); env.add_test("experimental", extensions::test_stability::is_experimental); env.add_test("deprecated", extensions::test_stability::is_deprecated); + // ToDo required, not_required // env.add_filter("unique_attributes", extensions::unique_attributes); // env.add_filter("instrument", extensions::instrument); - // env.add_filter("required", extensions::required); - // env.add_filter("not_required", extensions::not_required); // env.add_filter("value", extensions::value); // env.add_filter("with_value", extensions::with_value); // env.add_filter("without_value", extensions::without_value); // env.add_filter("with_enum", extensions::with_enum); // env.add_filter("without_enum", extensions::without_enum); - // env.add_filter("comment", extensions::comment); // env.add_filter( // "type_mapping", // extensions::TypeMapping { @@ -399,9 +402,6 @@ impl TemplateEngine { // }, // ); - // Register custom testers - // tera.register_tester("required", testers::is_required); - // tera.register_tester("not_required", testers::is_not_required); Ok(env) } From 65c2464813505fc5483aca94d486808467d8fb3d Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Sun, 28 Apr 2024 08:11:47 -0700 Subject: [PATCH 08/39] doc(forge): Update documentation --- README.md | 2 +- crates/weaver_forge/README.md | 136 ++++++++---------- crates/weaver_forge/src/extensions/mod.rs | 2 +- .../extensions/{test_stability.rs => test.rs} | 0 crates/weaver_forge/src/lib.rs | 6 +- 5 files changed, 64 insertions(+), 82 deletions(-) rename crates/weaver_forge/src/extensions/{test_stability.rs => test.rs} (100%) diff --git a/README.md b/README.md index f6e93f90..01fa2df3 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![codecov](https://codecov.io/gh/open-telemetry/weaver/graph/badge.svg?token=tmWKFoMT2G)](https://codecov.io/gh/open-telemetry/weaver) [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) ---- -[Getting started](#getting-started) | [Main commands](#main-commands) | [Architecture](docs/architecture.md) | [Change log](CHANGELOG.md) | [Contributing](CONTRIBUTING.md) | [Links](#links) | +[Getting started](#getting-started) | [Main commands](#main-commands) | [Generate Doc & Code](crates/weaver_forge/README.md) | [Architecture](docs/architecture.md) | [Change log](CHANGELOG.md) | [Contributing](CONTRIBUTING.md) | [Links](#links) | ## What is OpenTelemetry Weaver? diff --git a/crates/weaver_forge/README.md b/crates/weaver_forge/README.md index 81e2799d..9dfef7da 100644 --- a/crates/weaver_forge/README.md +++ b/crates/weaver_forge/README.md @@ -1,5 +1,14 @@ # Weaver Forge - Template Engine +- [Introduction](#introduction) +- [Template Directory Structure and Naming Conventions](#template-directory-structure-and-naming-conventions) +- [Configuration File - `weaver.yaml`](#configuration-file---weaveryaml) +- [Jinja Filters](#jinja-filters) +- [Jinja Functions](#jinja-functions) +- [Jinja Tests](#jinja-tests) + +## Introduction + OTel Weaver is capable of generating documentation or code from a semantic convention registry or a telemetry schema (phase 2). To do this, OTel Weaver uses a template engine compatible with the Jinja2 syntax (see the @@ -20,34 +29,20 @@ current directory. ```plaintext templates/ registry/ - markdown/ <-- All the files in this directory are optional - attribute_group.md <-- will be evaluated for each attribute group - attribute_groups.md <-- will be evaluated once with all attribute groups - event.md <-- will be evaluated for each event - events.md <-- will be evaluated once with all events - group.md <-- will be evaluated for each group - groups.md <-- will be evaluated once with all groups - metric.md <-- will be evaluated for each metric - metrics.md <-- will be evaluated once with all metrics - metric_group.md <-- will be evaluated for each metric group - metric_groups.md <-- will be evaluated once with all metric groups - registry.md <-- will be evaluated once with the entire registry - resource.md <-- will be evaluated for each resource - resources.md <-- will be evaluated once with all resources - scope.md <-- will be evaluated for each scope - scopes.md <-- will be evaluated once with all scopes - span.md <-- will be evaluated for each span - spans.md <-- will be evaluated once with all spans - weaver.yaml <-- weaver configuration file (optional) - any_other_name.md <-- will be evaluated once with the entire registry - any_sub_dir/ <-- By default outputs to the same directory structure - any_file.md <-- will be evaluated once with the entire registry - html/ + go/ <-- Templates to generate the semantic conventions in Go + ... + html/ <-- Templates to generate the semantic conventions in HTML + ... + markdown/ <-- Templates to generate the semantic conventions in markdown + ... + rust/ <-- Templates to generate the semantic conventions in Rust ... + go/ <-- Templates to generate the semantic conventions in Go + ... schema/ - sdk-go/ + sdk-go/ <-- Templates to generate a Go Client SDK derived from the telemetry schema ... - sdk-rust/ + sdk-rust/ <-- Templates to generate a Rust Client SDK derived from the telemetry schema ... ``` @@ -71,43 +66,35 @@ produced from the template: {{- template.set_file_name("span/" ~ file_name ~ ".md") -}} ``` -## Configuration File +## Configuration File - `weaver.yaml` The configuration file `weaver.yaml` is optional. It allows configuring the following options: ```yaml -# Configuration of the naming convention filters. This is optional. -# Example: {{ group.id | file_name }} will be evaluated as group_id -file_name: snake_case -function_name: PascalCase -arg_name: camelCase -struct_name: PascalCase -field_name: PascalCase - # Configuration of the type mapping. This is useful to generate code in a # specific language. This is optional. # Example: {{ attribute.type | type_mapping }} will be evaluated as int64 # if the semconv attribute type is int. -type_mapping: - int: int64 - double: double - boolean: bool - string: string - "int[]": "[]int64" - "double[]": "[]double" - "boolean[]": "[]bool" - "string[]": "[]string" - # other mappings... +#type_mapping: +# int: int64 +# double: double +# boolean: bool +# string: string +# "int[]": "[]int64" +# "double[]": "[]double" +# "boolean[]": "[]bool" +# "string[]": "[]string" +# ... # Configuration of the template engine (optional) -template_syntax: - block_start: "{%" - block_end: "%}" - variable_start: "{{" - variable_end: "}}" - comment_start: "{#" - comment_end: "#}" +#template_syntax: +# block_start: "{%" +# block_end: "%}" +# variable_start: "{{" +# variable_end: "}}" +# comment_start: "{#" +# comment_end: "#}" # Please uncomment the following section to specify a list of acronyms that # will be interpreted by the acronym filter. This is optional. @@ -178,19 +165,15 @@ template_syntax: # application_mode: single ``` -## Custom Filters +## Jinja Filters -All the filters available in the MiniJinja template engine are available. In -addition, OTel Weaver provides a set of custom filters to facilitate the -generation of assets. +All the filters available in the MiniJinja template engine are available (see +this online [documentation](https://docs.rs/minijinja/latest/minijinja/filters/index.html)). + +In addition, OTel Weaver provides a set of custom filters to facilitate the +generation of documentation and code. The following filters are available: -- `file_name`: Converts a string to a file name. -- `function_name`: Converts a string to a function name. -- `arg_name`: Converts a string to an argument name. -- `struct_name`: Converts a string to a struct name. -- `field_name`: Converts a string to a field name. -- `type_mapping`: Converts a semantic convention type to a language type. - `lower_case`: Converts a string to lowercase. - `upper_case`: Converts a string to UPPERCASE. - `title_case`: Converts a string to TitleCase. @@ -200,33 +183,32 @@ The following filters are available: - `screaming_snake_case`: Converts a string to SCREAMING_SNAKE_CASE. - `kebab_case`: Converts a string to kebab-case. - `screaming_kebab_case`: Converts a string to SCREAMING-KEBAB-CASE. -- `acronym`: Replaces acronyms in the input string with the full name defined -in the `acronyms` section of the `weaver.yaml` configuration file. +- `acronym`: Replaces acronyms in the input string with the full name defined in the `acronyms` section of the `weaver.yaml` configuration file. - `split_ids`: Splits a string by '.' creating a list of nested ids. -- `flatten`: Converts a List of Lists into a single list with all elements. -e.g. \[\[a,b\],\[c\]\] => \[a,b,c\] +- `flatten`: Converts a List of Lists into a single list with all elements (e.g. \[\[a,b\],\[c\]\] => \[a,b,c\]). - `type_mapping`: Converts a semantic convention type to a target type (see weaver.yaml section `type_mapping`). - `comment_with_prefix(prefix)`: Outputs a multiline comment with the given prefix. -> Note 1: This project uses the [convert_case](https://crates.io/crates/convert_case) -> crate to convert strings to different cases. +> Please open an issue if you have any suggestions for new filters. They are easy to implement. -> Note 2: Other filters might be introduced in the future. +## Jinja Functions -## Custom Functions +All the functions available in the MiniJinja template engine are available (see +this online [documentation](https://docs.rs/minijinja/latest/minijinja/functions/index.html)). -All the functions available in the MiniJinja template engine are available. In -addition, OTel Weaver provides a set of custom functions to facilitate the -generation of assets. +Right now, OTel Weaver does not provide any custom functions but feel free to +open an issue if you have any suggestions. They are easy to implement. -Not yet implemented. +## Jinja Tests -## Custom Tests +All the tests available in the MiniJinja template engine are available (see +this online [documentation](https://docs.rs/minijinja/latest/minijinja/tests/index.html)). -All the tests available in the MiniJinja template engine are available. In -addition, OTel Weaver provides a set of custom tests to facilitate the +In addition, OTel Weaver provides a set of custom tests to facilitate the generation of assets. - `stable`: Returns true if the object is stable (i.e. stability=stable). - `experimental`: Returns true if the object is experimental (i.e. stability=experimental). -- `deprecated`: Returns true if the object is deprecated (i.e. deprecated is defined). \ No newline at end of file +- `deprecated`: Returns true if the object is deprecated (i.e. deprecated is defined). + +> Please open an issue if you have any suggestions for new tests. They are easy to implement. diff --git a/crates/weaver_forge/src/extensions/mod.rs b/crates/weaver_forge/src/extensions/mod.rs index 7a0ad4bc..cce185bd 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_stability; +pub mod test; diff --git a/crates/weaver_forge/src/extensions/test_stability.rs b/crates/weaver_forge/src/extensions/test.rs similarity index 100% rename from crates/weaver_forge/src/extensions/test_stability.rs rename to crates/weaver_forge/src/extensions/test.rs diff --git a/crates/weaver_forge/src/lib.rs b/crates/weaver_forge/src/lib.rs index 3597ba57..2723f559 100644 --- a/crates/weaver_forge/src/lib.rs +++ b/crates/weaver_forge/src/lib.rs @@ -383,9 +383,9 @@ impl TemplateEngine { // ToDo required, not_required, stable, experimental, deprecated // Register custom tests - env.add_test("stable", extensions::test_stability::is_stable); - env.add_test("experimental", extensions::test_stability::is_experimental); - env.add_test("deprecated", extensions::test_stability::is_deprecated); + 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 // env.add_filter("unique_attributes", extensions::unique_attributes); From 7d262266c7f1ac0d5ae9742fcb93e5b3d1f8a385 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Sun, 28 Apr 2024 08:20:26 -0700 Subject: [PATCH 09/39] chore(forge): Improve test coverage --- .gitignore | 6 +++++- Cargo.lock | 8 ++++---- crates/weaver_forge/src/extensions/code.rs | 19 +++++++++++++++++++ crates/weaver_forge/src/lib.rs | 5 ++++- 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index d3ff7e18..18f2c1c9 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,8 @@ just.zsh **/output/* # Coverage results -lcov.info \ No newline at end of file +lcov.info + +# Ignore the output of the `weaver resolve` command +output.json +resolved-schema.yaml \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 43c81d1a..791e0d49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -495,9 +495,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "deranged" @@ -601,9 +601,9 @@ checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183" [[package]] name = "fastrand" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "filetime" diff --git a/crates/weaver_forge/src/extensions/code.rs b/crates/weaver_forge/src/extensions/code.rs index e93ca124..9830b453 100644 --- a/crates/weaver_forge/src/extensions/code.rs +++ b/crates/weaver_forge/src/extensions/code.rs @@ -58,6 +58,7 @@ pub fn type_mapping(type_mapping: HashMap) -> impl Fn(&str) -> S #[cfg(test)] mod tests { use super::*; + use crate::extensions::code; #[test] fn test_comment() { @@ -79,4 +80,22 @@ This also covers UDP network interactions where one side initiates the interacti assert_eq!(comment_with_prefix(brief, "/// "), expected_brief); } + + #[test] + fn test_mapping() { + let type_mapping = vec![ + ("string".to_owned(), "String".to_owned()), + ("int".to_owned(), "i64".to_owned()), + ("double".to_owned(), "f64".to_owned()), + ("boolean".to_owned(), "bool".to_owned()), + ]; + + let filter = code::type_mapping(type_mapping.into_iter().collect()); + + assert_eq!(filter("int"), "i64"); + assert_eq!(filter("double"), "f64"); + assert_eq!(filter("string"), "String"); + assert_eq!(filter("boolean"), "bool"); + assert_eq!(filter("something else"), "something else"); + } } diff --git a/crates/weaver_forge/src/lib.rs b/crates/weaver_forge/src/lib.rs index 2723f559..3ca77537 100644 --- a/crates/weaver_forge/src/lib.rs +++ b/crates/weaver_forge/src/lib.rs @@ -336,7 +336,10 @@ impl TemplateEngine { // Register code-oriented filters env.add_filter("comment_with_prefix", code::comment_with_prefix); - env.add_filter("type_mapping", code::type_mapping(self.target_config.type_mapping.clone())); + env.add_filter( + "type_mapping", + code::type_mapping(self.target_config.type_mapping.clone()), + ); env.add_filter( "file_name", case_converter(self.target_config.file_name.clone()), From c821e55791467e8f2e64b3f578ccdd3aa43e2e41 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Mon, 29 Apr 2024 12:17:06 -0700 Subject: [PATCH 10/39] feat(forge): Improve SemConv codegen example for Rust --- crates/weaver_forge/README.md | 6 +- .../templates/registry/rust/lib.rs.j2 | 65 +++++++++++++++++++ .../registry/rust/semantic_attributes.rs.j2 | 10 ++- .../templates/registry/rust/weaver.yaml | 48 ++++++++++++++ crates/weaver_forge/src/extensions/code.rs | 56 +++++++--------- crates/weaver_forge/src/lib.rs | 7 ++ src/registry/generate.rs | 5 +- templates/registry/rust/lib.rs.j2 | 14 ---- templates/registry/rust/weaver.yaml | 7 -- 9 files changed, 158 insertions(+), 60 deletions(-) create mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/lib.rs.j2 rename {templates => crates/weaver_forge/codegen_examples/templates}/registry/rust/semantic_attributes.rs.j2 (66%) create mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml delete mode 100644 templates/registry/rust/lib.rs.j2 delete mode 100644 templates/registry/rust/weaver.yaml diff --git a/crates/weaver_forge/README.md b/crates/weaver_forge/README.md index 9dfef7da..eb12f47e 100644 --- a/crates/weaver_forge/README.md +++ b/crates/weaver_forge/README.md @@ -47,7 +47,7 @@ templates/ ``` The command `weaver generate registry markdown` will generate the markdown -files. +files based on the templates located in the `templates/registry/markdown`. When the name of a file (excluding the extension) matches a recognized pattern (e.g., attribute_group, groups, ...), OTel Weaver extracts the objects from the @@ -66,6 +66,10 @@ produced from the template: {{- template.set_file_name("span/" ~ file_name ~ ".md") -}} ``` +This mechanism allows the template to dynamically generate the name of the file +to be produced and to organize the generated files in a directory structure of +its choice. + ## Configuration File - `weaver.yaml` The configuration file `weaver.yaml` is optional. It allows configuring the 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 new file mode 100644 index 00000000..7f092619 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/lib.rs.j2 @@ -0,0 +1,65 @@ +{{- template.set_file_name("lib.rs") -}} + +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! OpenTelemetry Semantic Convention Attributes +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 + +use opentelemetry::{Key, KeyValue, StringValue}; + +{% for group in ctx %} +{{ group.brief | comment_with_prefix("/// ") }} +pub mod {{ group.prefix | snake_case }}; +{%- endfor %} + +/// A typed attribute key. +pub struct AttributeKey { + key: Key, + phantom: std::marker::PhantomData +} + +impl AttributeKey { + /// Returns a new [`AttributeKey`] with the given key. + pub(crate) const fn new(key: &'static str) -> AttributeKey { + Self { + key: Key::from_static_str(key), + phantom: std::marker::PhantomData + } + } + + /// Returns the key of the attribute. + pub fn key(&self) -> &Key { + &self.key + } +} + +impl AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: StringValue) -> KeyValue { + KeyValue::new(self.key.clone(), v) + } +} + +impl AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: i64) -> KeyValue { + KeyValue::new(self.key.clone(), v) + } +} + +impl AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: f64) -> KeyValue { + KeyValue::new(self.key.clone(), v) + } +} + +impl AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: bool) -> KeyValue { + KeyValue::new(self.key.clone(), v) + } +} diff --git a/templates/registry/rust/semantic_attributes.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/semantic_attributes.rs.j2 similarity index 66% rename from templates/registry/rust/semantic_attributes.rs.j2 rename to crates/weaver_forge/codegen_examples/templates/registry/rust/semantic_attributes.rs.j2 index 8567486c..3fe80687 100644 --- a/templates/registry/rust/semantic_attributes.rs.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/semantic_attributes.rs.j2 @@ -14,6 +14,9 @@ {%- 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 %} @@ -30,11 +33,14 @@ {%- if attribute is deprecated %} #[deprecated(note="{{ attribute.deprecated }}")] {%- endif %} -pub const {{ attribute.name | screaming_snake_case }}: &str = "{{ attribute.name }}"; -{% if attribute.type.allow_custom_values %} +{% 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 %} {%- if attribute.brief %} {{ attribute.brief | comment_with_prefix("/// ") }} {%- endif %} +#[non_exhaustive] pub enum {{ attribute.name | pascal_case }} { {% for variant in attribute.type.members %} {%- if variant.brief %}{{ variant.brief | comment_with_prefix(" /// ") }}{% endif %} diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml b/crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml new file mode 100644 index 00000000..debe625e --- /dev/null +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml @@ -0,0 +1,48 @@ +type_mapping: + int: i64 + double: f64 + boolean: bool + string: String + string[]: Vec + template[string]: String # Not yet properly handled in codegen + template[string[]]: Vec # Not yet properly handled in codegen + +templates: + - pattern: lib.rs.j2 + filter: > + .groups + | map(select(.id | startswith("registry."))) + | map(select(.type == "attribute_group" and .prefix != null and .prefix != "") + | { + id, + type, + brief, + prefix, + attributes: (.attributes + | map(select(.stability == "experimental" and .deprecated | not)))}) + | map(select(.attributes | length > 0)) + | map( # Transform the group into a more concise object + { + id, + type, + brief, + prefix + } + ) + | unique_by(.prefix) # Remove duplicate prefixes + | sort_by(.prefix) # Sort by prefix + application_mode: single + - pattern: semantic_attributes.rs.j2 + filter: > + .groups + | map(select(.id | startswith("registry."))) + | map(select(.type == "attribute_group" and .prefix != null and .prefix != "") + | { + id, + type, + brief, + prefix, + attributes: (.attributes | map(select(.stability == "experimental" and .deprecated | not)))}) + | sort_by(.prefix // empty) + | map(select(.attributes | length > 0)) + application_mode: each diff --git a/crates/weaver_forge/src/extensions/code.rs b/crates/weaver_forge/src/extensions/code.rs index 9830b453..b2611e41 100644 --- a/crates/weaver_forge/src/extensions/code.rs +++ b/crates/weaver_forge/src/extensions/code.rs @@ -4,6 +4,8 @@ use std::collections::HashMap; +use minijinja::Value; + /// Converts the input string into a comment with a prefix. #[must_use] pub(crate) fn comment_with_prefix(input: &str, prefix: &str) -> String { @@ -18,37 +20,21 @@ pub(crate) fn comment_with_prefix(input: &str, prefix: &str) -> String { } /// Create a filter that uses the type mapping defined in `weaver.yaml` to replace -/// the input string (i.e. OTel type) with the target type. -/// -/// # Example -/// -/// ```rust -/// use weaver_forge::extensions::code; -/// -/// let type_mapping = vec![ -/// ("string".to_owned(), "String".to_owned()), -/// ("int".to_owned(), "i64".to_owned()), -/// ("double".to_owned(), "f64".to_owned()), -/// ("boolean".to_owned(), "bool".to_owned()), -/// ]; -/// -/// let filter = code::type_mapping(type_mapping.into_iter().collect());; -/// -/// assert_eq!(filter("int"), "i64"); -/// assert_eq!(filter("double"), "f64"); -/// assert_eq!(filter("string"), "String"); -/// assert_eq!(filter("boolean"), "bool"); -/// assert_eq!(filter("something else"), "something else"); -/// ``` +/// the input value (i.e. OTel type) with the target type. /// /// # Returns /// -/// A function that takes an input string and returns a new string with the -/// data type replaced. -pub fn type_mapping(type_mapping: HashMap) -> impl Fn(&str) -> String { - move |input: &str| -> String { - if let Some(target_type) = type_mapping.get(input) { - target_type.clone() +/// A function that takes an input value and returns a new string value with the +/// data type replaced. If the input value is not found in the type mapping or is +/// not a string, the input value is returned as is. +pub fn type_mapping(type_mapping: HashMap) -> impl Fn(&Value) -> Value { + move |input: &Value| -> Value { + if let Some(input_as_str) = input.as_str() { + if let Some(target_type) = type_mapping.get(input_as_str) { + Value::from(target_type.as_str()) + } else { + input.to_owned() + } } else { input.to_owned() } @@ -57,9 +43,10 @@ pub fn type_mapping(type_mapping: HashMap) -> impl Fn(&str) -> S #[cfg(test)] mod tests { - use super::*; use crate::extensions::code; + use super::*; + #[test] fn test_comment() { assert_eq!(comment_with_prefix("test", "// "), "// test"); @@ -92,10 +79,11 @@ This also covers UDP network interactions where one side initiates the interacti let filter = code::type_mapping(type_mapping.into_iter().collect()); - assert_eq!(filter("int"), "i64"); - assert_eq!(filter("double"), "f64"); - assert_eq!(filter("string"), "String"); - assert_eq!(filter("boolean"), "bool"); - assert_eq!(filter("something else"), "something else"); + assert_eq!(filter(&Value::from("int")), Value::from("i64")); + assert_eq!(filter(&Value::from("double")), Value::from("f64")); + assert_eq!(filter(&Value::from("string")), Value::from("String")); + assert_eq!(filter(&Value::from("boolean")), Value::from("bool")); + assert_eq!(filter(&Value::from("something else")), Value::from("something else")); + assert_eq!(filter(&Value::from(12)), Value::from(12)); } } diff --git a/crates/weaver_forge/src/lib.rs b/crates/weaver_forge/src/lib.rs index 3ca77537..df447ca4 100644 --- a/crates/weaver_forge/src/lib.rs +++ b/crates/weaver_forge/src/lib.rs @@ -55,6 +55,13 @@ impl Default for GeneratorConfig { } } +impl GeneratorConfig { + /// Create a new generator configuration with the given root directory. + pub fn new(root_dir: PathBuf) -> Self { + Self { root_dir } + } +} + /// A template object accessible from the template. #[derive(Debug, Clone)] struct TemplateObject { diff --git a/src/registry/generate.rs b/src/registry/generate.rs index 758cb4b4..d87ab4e1 100644 --- a/src/registry/generate.rs +++ b/src/registry/generate.rs @@ -29,7 +29,7 @@ pub struct RegistryGenerateArgs { /// Path to the directory where the templates are located. /// Default is the `templates` directory. #[arg(short = 't', long, default_value = "templates")] - pub templates: String, + pub templates: PathBuf, /// Local path or Git URL of the semantic convention registry. #[arg( @@ -78,10 +78,11 @@ pub(crate) fn command( ); let mut registry = SemConvRegistry::from_semconv_specs(registry_id, semconv_specs); let schema = resolve_semconv_specs(&mut registry, logger.clone()); + let config = GeneratorConfig::new(args.templates.clone()); let engine = TemplateEngine::try_new( &format!("registry/{}", args.target), - GeneratorConfig::default(), + config, ) .exit_if_error(logger.clone()); diff --git a/templates/registry/rust/lib.rs.j2 b/templates/registry/rust/lib.rs.j2 deleted file mode 100644 index d586a946..00000000 --- a/templates/registry/rust/lib.rs.j2 +++ /dev/null @@ -1,14 +0,0 @@ -{{- template.set_file_name("lib.rs") -}} - -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! OpenTelemetry Semantic Convention Attributes -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 - -{% for group in ctx %} -{{ group.brief | comment_with_prefix("/// ") }} -pub mod {{ group.prefix | snake_case }}; -{%- endfor %} \ No newline at end of file diff --git a/templates/registry/rust/weaver.yaml b/templates/registry/rust/weaver.yaml deleted file mode 100644 index e7ed6f73..00000000 --- a/templates/registry/rust/weaver.yaml +++ /dev/null @@ -1,7 +0,0 @@ -templates: - - pattern: lib.rs.j2 - filter: '.groups | map(select(.id | startswith("registry."))) | map(select(.type == "attribute_group" and .prefix != null and .prefix != "") | { id, type, brief, prefix, attributes: (.attributes | map(select(.stability == "experimental" and .deprecated | not)))}) | sort_by(.prefix // empty) | map(select(.attributes | length > 0))' - application_mode: single - - pattern: semantic_attributes.rs.j2 - filter: '.groups | map(select(.id | startswith("registry."))) | map(select(.type == "attribute_group" and .prefix != null and .prefix != "") | { id, type, brief, prefix, attributes: (.attributes | map(select(.stability == "experimental" and .deprecated | not)))}) | sort_by(.prefix // empty) | map(select(.attributes | length > 0))' - application_mode: each From 00e11d2970a2141e9c0ab012b8fdc339e77c47fb Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Mon, 29 Apr 2024 12:32:14 -0700 Subject: [PATCH 11/39] chore(forge): Add mini registry and prepare for unit tests --- .../expected_codegen/client.rs | 26 ++ .../codegen_examples/expected_codegen/disk.rs | 29 +++ .../expected_codegen/error.rs | 45 ++++ .../expected_codegen/exception.rs | 48 ++++ .../codegen_examples/expected_codegen/http.rs | 139 +++++++++++ .../codegen_examples/expected_codegen/lib.rs | 78 ++++++ .../expected_codegen/network.rs | 233 +++++++++++++++++ .../codegen_examples/expected_codegen/os.rs | 80 ++++++ .../codegen_examples/expected_codegen/otel.rs | 31 +++ .../expected_codegen/otel_scope.rs | 21 ++ .../mini_registry/client.yaml | 28 +++ .../mini_registry/deprecated/network.yaml | 121 +++++++++ .../mini_registry/deprecated/otel.yaml | 18 ++ .../codegen_examples/mini_registry/disk.yaml | 20 ++ .../codegen_examples/mini_registry/error.yaml | 40 +++ .../mini_registry/exception.yaml | 54 ++++ .../codegen_examples/mini_registry/http.yaml | 174 +++++++++++++ .../mini_registry/network.yaml | 235 ++++++++++++++++++ .../codegen_examples/mini_registry/os.yaml | 85 +++++++ .../codegen_examples/mini_registry/otel.yaml | 40 +++ 20 files changed, 1545 insertions(+) create mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/client.rs create mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/disk.rs create mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/error.rs create mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/exception.rs create mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/http.rs create mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/lib.rs create mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/network.rs create mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/os.rs create mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/otel.rs create mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/otel_scope.rs create mode 100644 crates/weaver_forge/codegen_examples/mini_registry/client.yaml create mode 100644 crates/weaver_forge/codegen_examples/mini_registry/deprecated/network.yaml create mode 100644 crates/weaver_forge/codegen_examples/mini_registry/deprecated/otel.yaml create mode 100644 crates/weaver_forge/codegen_examples/mini_registry/disk.yaml create mode 100644 crates/weaver_forge/codegen_examples/mini_registry/error.yaml create mode 100644 crates/weaver_forge/codegen_examples/mini_registry/exception.yaml create mode 100644 crates/weaver_forge/codegen_examples/mini_registry/http.yaml create mode 100644 crates/weaver_forge/codegen_examples/mini_registry/network.yaml create mode 100644 crates/weaver_forge/codegen_examples/mini_registry/os.yaml create mode 100644 crates/weaver_forge/codegen_examples/mini_registry/otel.yaml diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/client.rs b/crates/weaver_forge/codegen_examples/expected_codegen/client.rs new file mode 100644 index 00000000..d0aa5790 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/expected_codegen/client.rs @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! 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"); + + + +/// Client port number. +/// +/// 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"); + diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/disk.rs b/crates/weaver_forge/codegen_examples/expected_codegen/disk.rs new file mode 100644 index 00000000..6ad2c037 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/expected_codegen/disk.rs @@ -0,0 +1,29 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! These attributes may be used for any disk related operation. +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 + +use opentelemetry::StringValue; +use crate::AttributeKey; + + +/// The disk IO operation direction. +#[cfg(feature = "semconv_experimental")] +pub const DISK_IO_DIRECTION: AttributeKey = AttributeKey::new("disk.io.direction"); + + +/// The disk IO operation direction. +#[non_exhaustive] +pub enum DiskIoDirection { + + #[cfg(feature = "semconv_experimental")] + Read, + + #[cfg(feature = "semconv_experimental")] + Write, + +} + diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/error.rs b/crates/weaver_forge/codegen_examples/expected_codegen/error.rs new file mode 100644 index 00000000..0434861f --- /dev/null +++ b/crates/weaver_forge/codegen_examples/expected_codegen/error.rs @@ -0,0 +1,45 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! This document defines the shared attributes used to report an error. +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 + +use opentelemetry::StringValue; +use crate::AttributeKey; + + +/// Describes a class of error the operation ended with. +/// +/// Notes: +/// The `error.type` SHOULD be predictable, and SHOULD have low cardinality. +/// +/// When `error.type` is set to a type (e.g., an exception type), its +/// canonical class name identifying the type within the artifact SHOULD be used. +/// +/// Instrumentations SHOULD document the list of errors they report. +/// +/// The cardinality of `error.type` within one instrumentation library SHOULD be low. +/// Telemetry consumers that aggregate data from multiple instrumentation libraries and applications +/// should be prepared for `error.type` to have high cardinality at query time when no +/// additional filters are applied. +/// +/// If the operation has completed successfully, instrumentations SHOULD NOT set `error.type`. +/// +/// If a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes), +/// it's RECOMMENDED to: +/// +/// * Use a domain-specific attribute +/// * Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. +pub const ERROR_TYPE: AttributeKey = AttributeKey::new("error.type"); + + +/// Describes a class of error the operation ended with. +#[non_exhaustive] +pub enum ErrorType { + /// A fallback error value to be used when the instrumentation doesn't define a custom value. + Other, + +} + diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/exception.rs b/crates/weaver_forge/codegen_examples/expected_codegen/exception.rs new file mode 100644 index 00000000..d283e009 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/expected_codegen/exception.rs @@ -0,0 +1,48 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! 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"); + + + +/// The exception message. +pub const EXCEPTION_MESSAGE: AttributeKey = 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"); + + + +/// SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span. +/// +/// Notes: +/// An exception is considered to have escaped (or left) the scope of a span, +/// if that span is ended while the exception is still logically "in flight". +/// This may be actually "in flight" in some languages (e.g. if the exception +/// is passed to a Context manager's `__exit__` method in Python) but will +/// usually be caught at the point of recording the exception in most languages. +/// +/// It is usually not possible to determine at the point where an exception is thrown +/// whether it will escape the scope of a span. +/// However, it is trivial to know that an exception +/// will escape, if one checks for an active exception just before ending the span, +/// as done in the [example for recording span exceptions](#recording-an-exception). +/// +/// It follows that an exception may still escape the scope of the span +/// 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"); + diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/http.rs b/crates/weaver_forge/codegen_examples/expected_codegen/http.rs new file mode 100644 index 00000000..c7c3f48a --- /dev/null +++ b/crates/weaver_forge/codegen_examples/expected_codegen/http.rs @@ -0,0 +1,139 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! 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"); + + +/// HTTP request headers, `` being the normalized HTTP Header name (lowercase), the value being the header values. +/// +/// Notes: +/// 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"); + + +/// HTTP request method. +/// +/// Notes: +/// HTTP request method value SHOULD be "known" to the instrumentation. +/// By default, this convention defines "known" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods) +/// and the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html). +/// +/// If the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`. +/// +/// If the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override +/// the list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named +/// OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods +/// (this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults). +/// +/// 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"); + + +/// HTTP request method. +#[non_exhaustive] +pub enum HttpRequestMethod { + /// CONNECT method. + Connect, + /// DELETE method. + Delete, + /// GET method. + Get, + /// HEAD method. + Head, + /// OPTIONS method. + Options, + /// PATCH method. + Patch, + /// POST method. + Post, + /// PUT method. + Put, + /// TRACE method. + Trace, + /// Any HTTP method that the instrumentation has no prior knowledge of. + Other, + +} + + +/// Original HTTP method sent by the client in the request line. +pub const HTTP_REQUEST_METHOD_ORIGINAL: AttributeKey = AttributeKey::new("http.request.method_original"); + + + +/// The ordinal number of request resending attempt (for any reason, including redirects). +/// +/// 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"); + + +/// 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"); + + +/// 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"); + + +/// HTTP response headers, `` being the normalized HTTP Header name (lowercase), the value being the header values. +/// +/// Notes: +/// 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"); + + +/// 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"); + + +/// [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"); + + +/// The matched route, that is, the path template in the format used by the respective server framework. +/// +/// 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"); + + + +/// 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"); + + +/// State of the HTTP connection in the HTTP connection pool. +#[non_exhaustive] +pub enum HttpConnectionState { + /// active state. + #[cfg(feature = "semconv_experimental")] + Active, + /// idle state. + #[cfg(feature = "semconv_experimental")] + Idle, + +} + diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/lib.rs b/crates/weaver_forge/codegen_examples/expected_codegen/lib.rs new file mode 100644 index 00000000..59c28764 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/expected_codegen/lib.rs @@ -0,0 +1,78 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! OpenTelemetry Semantic Convention Attributes +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 + +use opentelemetry::{Key, KeyValue, StringValue}; + + +/// 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. +pub mod client; +/// These attributes may be used for any disk related operation. +pub mod disk; +/// This document defines the shared attributes used to report an error. +pub mod error; +/// This document defines the shared attributes used to report a single exception associated with a span or log. +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 network; +/// The operating system (OS) on which the process represented by this resource is running. +pub mod os; +/// Attributes reserved for OpenTelemetry +pub mod otel; +/// Attributes used by non-OTLP exporters to represent OpenTelemetry Scope's concepts. +pub mod otel_scope; + +/// A typed attribute key. +pub struct AttributeKey { + key: Key, + phantom: std::marker::PhantomData +} + +impl AttributeKey { + /// Returns a new [`AttributeKey`] with the given key. + pub(crate) const fn new(key: &'static str) -> AttributeKey { + Self { + key: Key::from_static_str(key), + phantom: std::marker::PhantomData + } + } + + /// Returns the key of the attribute. + pub fn key(&self) -> &Key { + &self.key + } +} + +impl AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: StringValue) -> KeyValue { + KeyValue::new(self.key.clone(), v) + } +} + +impl AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: i64) -> KeyValue { + KeyValue::new(self.key.clone(), v) + } +} + +impl AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: f64) -> KeyValue { + KeyValue::new(self.key.clone(), v) + } +} + +impl AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: bool) -> KeyValue { + KeyValue::new(self.key.clone(), v) + } +} \ No newline at end of file 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..ab321ed2 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/expected_codegen/network.rs @@ -0,0 +1,233 @@ +/* + * 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; + + +/// The ISO 3166-1 alpha-2 2-character country code associated with the mobile carrier network. +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_CARRIER_ICC: AttributeKey = AttributeKey::new("network.carrier.icc"); + + + +/// The mobile carrier country code. +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_CARRIER_MCC: AttributeKey = AttributeKey::new("network.carrier.mcc"); + + + +/// The mobile carrier network code. +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_CARRIER_MNC: AttributeKey = AttributeKey::new("network.carrier.mnc"); + + + +/// The name of the mobile carrier. +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_CARRIER_NAME: AttributeKey = AttributeKey::new("network.carrier.name"); + + + +/// This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection. +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_CONNECTION_SUBTYPE: AttributeKey = AttributeKey::new("network.connection.subtype"); + + +/// This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection. +#[non_exhaustive] +pub enum NetworkConnectionSubtype { + /// GPRS + #[cfg(feature = "semconv_experimental")] + Gprs, + /// EDGE + #[cfg(feature = "semconv_experimental")] + Edge, + /// UMTS + #[cfg(feature = "semconv_experimental")] + Umts, + /// CDMA + #[cfg(feature = "semconv_experimental")] + Cdma, + /// EVDO Rel. 0 + #[cfg(feature = "semconv_experimental")] + Evdo0, + /// EVDO Rev. A + #[cfg(feature = "semconv_experimental")] + EvdoA, + /// CDMA2000 1XRTT + #[cfg(feature = "semconv_experimental")] + Cdma20001Xrtt, + /// HSDPA + #[cfg(feature = "semconv_experimental")] + Hsdpa, + /// HSUPA + #[cfg(feature = "semconv_experimental")] + Hsupa, + /// HSPA + #[cfg(feature = "semconv_experimental")] + Hspa, + /// IDEN + #[cfg(feature = "semconv_experimental")] + Iden, + /// EVDO Rev. B + #[cfg(feature = "semconv_experimental")] + EvdoB, + /// LTE + #[cfg(feature = "semconv_experimental")] + Lte, + /// EHRPD + #[cfg(feature = "semconv_experimental")] + Ehrpd, + /// HSPAP + #[cfg(feature = "semconv_experimental")] + Hspap, + /// GSM + #[cfg(feature = "semconv_experimental")] + Gsm, + /// TD-SCDMA + #[cfg(feature = "semconv_experimental")] + TdScdma, + /// IWLAN + #[cfg(feature = "semconv_experimental")] + Iwlan, + /// 5G NR (New Radio) + #[cfg(feature = "semconv_experimental")] + Nr, + /// 5G NRNSA (New Radio Non-Standalone) + #[cfg(feature = "semconv_experimental")] + Nrnsa, + /// LTE CA + #[cfg(feature = "semconv_experimental")] + LteCa, + +} + + +/// The internet connection type. +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_CONNECTION_TYPE: AttributeKey = AttributeKey::new("network.connection.type"); + + +/// The internet connection type. +#[non_exhaustive] +pub enum NetworkConnectionType { + + #[cfg(feature = "semconv_experimental")] + Wifi, + + #[cfg(feature = "semconv_experimental")] + Wired, + + #[cfg(feature = "semconv_experimental")] + Cell, + + #[cfg(feature = "semconv_experimental")] + Unavailable, + + #[cfg(feature = "semconv_experimental")] + Unknown, + +} + + +/// Local address of the network connection - IP address or Unix domain socket name. +pub const NETWORK_LOCAL_ADDRESS: AttributeKey = AttributeKey::new("network.local.address"); + + + +/// Local port number of the network connection. +pub const NETWORK_LOCAL_PORT: AttributeKey = AttributeKey::new("network.local.port"); + + +/// Peer address of the network connection - IP address or Unix domain socket name. +pub const NETWORK_PEER_ADDRESS: AttributeKey = AttributeKey::new("network.peer.address"); + + + +/// Peer port number of the network connection. +pub const NETWORK_PEER_PORT: AttributeKey = AttributeKey::new("network.peer.port"); + + +/// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. +/// +/// Notes: +/// The value SHOULD be normalized to lowercase. +pub const NETWORK_PROTOCOL_NAME: AttributeKey = AttributeKey::new("network.protocol.name"); + + + +/// The actual version of the protocol used for network communication. +/// +/// Notes: +/// If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, this attribute SHOULD NOT be set. +pub const NETWORK_PROTOCOL_VERSION: AttributeKey = AttributeKey::new("network.protocol.version"); + + + +/// [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). +/// +/// Notes: +/// The value SHOULD be normalized to lowercase. +/// +/// Consider always setting the transport when setting a port number, since +/// a port number is ambiguous without knowing the transport. For example +/// different processes could be listening on TCP port 12345 and UDP port 12345. +pub const NETWORK_TRANSPORT: AttributeKey = AttributeKey::new("network.transport"); + + +/// [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). +#[non_exhaustive] +pub enum NetworkTransport { + /// TCP + Tcp, + /// UDP + Udp, + /// Named or anonymous pipe. + Pipe, + /// Unix domain socket + Unix, + +} + + +/// [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. +/// +/// Notes: +/// The value SHOULD be normalized to lowercase. +pub const NETWORK_TYPE: AttributeKey = AttributeKey::new("network.type"); + + +/// [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. +#[non_exhaustive] +pub enum NetworkType { + /// IPv4 + Ipv4, + /// IPv6 + Ipv6, + +} + + +/// The network IO operation direction. +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_IO_DIRECTION: AttributeKey = AttributeKey::new("network.io.direction"); + + +/// The network IO operation direction. +#[non_exhaustive] +pub enum NetworkIoDirection { + + #[cfg(feature = "semconv_experimental")] + Transmit, + + #[cfg(feature = "semconv_experimental")] + Receive, + +} + diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/os.rs b/crates/weaver_forge/codegen_examples/expected_codegen/os.rs new file mode 100644 index 00000000..ae39f23f --- /dev/null +++ b/crates/weaver_forge/codegen_examples/expected_codegen/os.rs @@ -0,0 +1,80 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! The operating system (OS) on which the process represented by this resource is running. +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 + +use opentelemetry::StringValue; +use crate::AttributeKey; + + +/// The operating system type. +#[cfg(feature = "semconv_experimental")] +pub const OS_TYPE: AttributeKey = AttributeKey::new("os.type"); + + +/// The operating system type. +#[non_exhaustive] +pub enum OsType { + /// Microsoft Windows + #[cfg(feature = "semconv_experimental")] + Windows, + /// Linux + #[cfg(feature = "semconv_experimental")] + Linux, + /// Apple Darwin + #[cfg(feature = "semconv_experimental")] + Darwin, + /// FreeBSD + #[cfg(feature = "semconv_experimental")] + Freebsd, + /// NetBSD + #[cfg(feature = "semconv_experimental")] + Netbsd, + /// OpenBSD + #[cfg(feature = "semconv_experimental")] + Openbsd, + /// DragonFly BSD + #[cfg(feature = "semconv_experimental")] + Dragonflybsd, + /// HP-UX (Hewlett Packard Unix) + #[cfg(feature = "semconv_experimental")] + Hpux, + /// AIX (Advanced Interactive eXecutive) + #[cfg(feature = "semconv_experimental")] + Aix, + /// SunOS, Oracle Solaris + #[cfg(feature = "semconv_experimental")] + Solaris, + /// IBM z/OS + #[cfg(feature = "semconv_experimental")] + ZOs, + +} + + +/// Human readable (not intended to be parsed) OS version information, like e.g. reported by `ver` or `lsb_release -a` commands. +#[cfg(feature = "semconv_experimental")] +pub const OS_DESCRIPTION: AttributeKey = AttributeKey::new("os.description"); + + + +/// Human readable operating system name. +#[cfg(feature = "semconv_experimental")] +pub const OS_NAME: AttributeKey = AttributeKey::new("os.name"); + + + +/// The version string of the operating system as defined in [Version Attributes](/docs/resource/README.md#version-attributes). +#[cfg(feature = "semconv_experimental")] +pub const OS_VERSION: AttributeKey = AttributeKey::new("os.version"); + + + +/// Unique identifier for a particular build or compilation of the operating system. +#[cfg(feature = "semconv_experimental")] +pub const OS_BUILD_ID: AttributeKey = AttributeKey::new("os.build_id"); + + diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/otel.rs b/crates/weaver_forge/codegen_examples/expected_codegen/otel.rs new file mode 100644 index 00000000..c6837841 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/expected_codegen/otel.rs @@ -0,0 +1,31 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Attributes reserved for OpenTelemetry +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 + +use opentelemetry::StringValue; +use crate::AttributeKey; + + +/// Name of the code, either "OK" or "ERROR". MUST NOT be set if the status code is UNSET. +pub const OTEL_STATUS_CODE: AttributeKey = AttributeKey::new("otel.status_code"); + + +/// Name of the code, either "OK" or "ERROR". MUST NOT be set if the status code is UNSET. +#[non_exhaustive] +pub enum OtelStatusCode { + /// The operation has been validated by an Application developer or Operator to have completed successfully. + Ok, + /// The operation contains an error. + Error, + +} + + +/// Description of the Status if it has a value, otherwise not set. +pub const OTEL_STATUS_DESCRIPTION: AttributeKey = AttributeKey::new("otel.status_description"); + + diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/otel_scope.rs b/crates/weaver_forge/codegen_examples/expected_codegen/otel_scope.rs new file mode 100644 index 00000000..3e374c5c --- /dev/null +++ b/crates/weaver_forge/codegen_examples/expected_codegen/otel_scope.rs @@ -0,0 +1,21 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Attributes used by non-OTLP exporters to represent OpenTelemetry Scope's concepts. +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 + +use opentelemetry::StringValue; +use crate::AttributeKey; + + +/// The name of the instrumentation scope - (`InstrumentationScope.Name` in OTLP). +pub const OTEL_SCOPE_NAME: AttributeKey = AttributeKey::new("otel.scope.name"); + + + +/// The version of the instrumentation scope - (`InstrumentationScope.Version` in OTLP). +pub const OTEL_SCOPE_VERSION: AttributeKey = AttributeKey::new("otel.scope.version"); + + diff --git a/crates/weaver_forge/codegen_examples/mini_registry/client.yaml b/crates/weaver_forge/codegen_examples/mini_registry/client.yaml new file mode 100644 index 00000000..3b17ed8b --- /dev/null +++ b/crates/weaver_forge/codegen_examples/mini_registry/client.yaml @@ -0,0 +1,28 @@ +groups: + - id: registry.client + prefix: client + type: attribute_group + brief: > + 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. + attributes: + - id: address + stability: stable + type: string + brief: "Client address - domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name." + note: > + 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. + examples: ['client.example.com', '10.1.2.80', '/tmp/my.sock'] + - id: port + stability: stable + type: int + brief: Client port number. + examples: [65123] + note: > + 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. diff --git a/crates/weaver_forge/codegen_examples/mini_registry/deprecated/network.yaml b/crates/weaver_forge/codegen_examples/mini_registry/deprecated/network.yaml new file mode 100644 index 00000000..66144671 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/mini_registry/deprecated/network.yaml @@ -0,0 +1,121 @@ +groups: + - id: registry.network.deprecated + prefix: net + type: attribute_group + brief: > + These attributes may be used for any network related operation. + attributes: + - id: sock.peer.name + type: string + deprecated: "Removed." + stability: experimental + brief: Deprecated, no replacement at this time. + examples: ['/var/my.sock'] + - id: sock.peer.addr + type: string + deprecated: "Replaced by `network.peer.address`." + stability: experimental + brief: Deprecated, use `network.peer.address`. + examples: ['192.168.0.1'] + - id: sock.peer.port + type: int + deprecated: "Replaced by `network.peer.port`." + stability: experimental + examples: [65531] + brief: Deprecated, use `network.peer.port`. + - id: peer.name + type: string + deprecated: "Replaced by `server.address` on client spans and `client.address` on server spans." + stability: experimental + brief: Deprecated, use `server.address` on client spans and `client.address` on server spans. + examples: ['example.com'] + - id: peer.port + type: int + deprecated: "Replaced by `server.port` on client spans and `client.port` on server spans." + stability: experimental + brief: Deprecated, use `server.port` on client spans and `client.port` on server spans. + examples: [8080] + - id: host.name + type: string + deprecated: "Replaced by `server.address`." + stability: experimental + brief: Deprecated, use `server.address`. + examples: ['example.com'] + - id: host.port + type: int + deprecated: "Replaced by `server.port`." + stability: experimental + brief: Deprecated, use `server.port`. + examples: [8080] + - id: sock.host.addr + type: string + deprecated: "Replaced by `network.local.address`." + stability: experimental + brief: Deprecated, use `network.local.address`. + examples: ['/var/my.sock'] + - id: sock.host.port + type: int + deprecated: "Replaced by `network.local.port`." + stability: experimental + brief: Deprecated, use `network.local.port`. + examples: [8080] + - id: transport + type: + allow_custom_values: true + members: + - id: ip_tcp + value: "ip_tcp" + stability: experimental + - id: ip_udp + value: "ip_udp" + stability: experimental + - id: pipe + value: "pipe" + brief: 'Named or anonymous pipe.' + stability: experimental + - id: inproc + value: "inproc" + brief: 'In-process communication.' + stability: experimental + note: > + 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. + - id: other + value: "other" + stability: experimental + brief: 'Something else (non IP-based).' + deprecated: "Replaced by `network.transport`." + stability: experimental + brief: Deprecated, use `network.transport`. + - id: protocol.name + type: string + deprecated: "Replaced by `network.protocol.name`." + stability: experimental + brief: Deprecated, use `network.protocol.name`. + examples: ['amqp', 'http', 'mqtt'] + - id: protocol.version + type: string + deprecated: "Replaced by `network.protocol.version`." + stability: experimental + brief: Deprecated, use `network.protocol.version`. + examples: '3.1.1' + - id: sock.family + type: + allow_custom_values: true + members: + - id: inet + value: 'inet' + brief: "IPv4 address" + stability: experimental + - id: inet6 + value: 'inet6' + brief: "IPv6 address" + stability: experimental + - id: unix + value: 'unix' + brief: "Unix domain socket path" + stability: experimental + deprecated: "Split to `network.transport` and `network.type`." + stability: experimental + brief: Deprecated, use `network.transport` and `network.type`. diff --git a/crates/weaver_forge/codegen_examples/mini_registry/deprecated/otel.yaml b/crates/weaver_forge/codegen_examples/mini_registry/deprecated/otel.yaml new file mode 100644 index 00000000..c52a51fe --- /dev/null +++ b/crates/weaver_forge/codegen_examples/mini_registry/deprecated/otel.yaml @@ -0,0 +1,18 @@ +groups: + - id: registry.otel.library.deprecated + prefix: otel.library + type: attribute_group + brief: "Describes deprecated otel.library attributes." + attributes: + - id: name + type: string + deprecated: use the `otel.scope.name` attribute. + stability: experimental + brief: + examples: ['io.opentelemetry.contrib.mongodb'] + - id: version + type: string + deprecated: use the `otel.scope.version` attribute. + stability: experimental + brief: + examples: ['1.0.0'] diff --git a/crates/weaver_forge/codegen_examples/mini_registry/disk.yaml b/crates/weaver_forge/codegen_examples/mini_registry/disk.yaml new file mode 100644 index 00000000..aa8c0911 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/mini_registry/disk.yaml @@ -0,0 +1,20 @@ +groups: + - id: registry.disk + prefix: disk + type: attribute_group + brief: > + These attributes may be used for any disk related operation. + attributes: + - id: io.direction + type: + allow_custom_values: false + members: + - id: read + value: 'read' + stability: experimental + - id: write + value: 'write' + stability: experimental + stability: experimental + brief: "The disk IO operation direction." + examples: ["read"] diff --git a/crates/weaver_forge/codegen_examples/mini_registry/error.yaml b/crates/weaver_forge/codegen_examples/mini_registry/error.yaml new file mode 100644 index 00000000..68bde170 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/mini_registry/error.yaml @@ -0,0 +1,40 @@ +groups: + - id: registry.error + type: attribute_group + prefix: error + brief: > + This document defines the shared attributes used to report an error. + attributes: + - id: type + stability: stable + brief: > + Describes a class of error the operation ended with. + type: + allow_custom_values: true + members: + - id: other + value: "_OTHER" + stability: stable + brief: > + A fallback error value to be used when the instrumentation doesn't define a custom value. + examples: ['timeout', 'java.net.UnknownHostException', 'server_certificate_invalid', '500'] + note: | + The `error.type` SHOULD be predictable, and SHOULD have low cardinality. + + When `error.type` is set to a type (e.g., an exception type), its + canonical class name identifying the type within the artifact SHOULD be used. + + Instrumentations SHOULD document the list of errors they report. + + The cardinality of `error.type` within one instrumentation library SHOULD be low. + Telemetry consumers that aggregate data from multiple instrumentation libraries and applications + should be prepared for `error.type` to have high cardinality at query time when no + additional filters are applied. + + If the operation has completed successfully, instrumentations SHOULD NOT set `error.type`. + + If a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes), + it's RECOMMENDED to: + + * Use a domain-specific attribute + * Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. diff --git a/crates/weaver_forge/codegen_examples/mini_registry/exception.yaml b/crates/weaver_forge/codegen_examples/mini_registry/exception.yaml new file mode 100644 index 00000000..7e1b0118 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/mini_registry/exception.yaml @@ -0,0 +1,54 @@ +groups: + - id: registry.exception + type: attribute_group + prefix: exception + brief: > + This document defines the shared attributes used to + report a single exception associated with a span or log. + attributes: + - id: type + type: string + stability: stable + brief: > + 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. + examples: ["java.net.ConnectException", "OSError"] + - id: message + type: string + stability: stable + brief: The exception message. + examples: ["Division by zero", "Can't convert 'int' object to str implicitly"] + - id: stacktrace + type: string + stability: stable + brief: > + 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. + examples: 'Exception in thread "main" java.lang.RuntimeException: Test exception\n + at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n + at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n + at com.example.GenerateTrace.main(GenerateTrace.java:5)' + - id: escaped + type: boolean + stability: stable + brief: > + SHOULD be set to true if the exception event is recorded at a point where + it is known that the exception is escaping the scope of the span. + note: |- + An exception is considered to have escaped (or left) the scope of a span, + if that span is ended while the exception is still logically "in flight". + This may be actually "in flight" in some languages (e.g. if the exception + is passed to a Context manager's `__exit__` method in Python) but will + usually be caught at the point of recording the exception in most languages. + + It is usually not possible to determine at the point where an exception is thrown + whether it will escape the scope of a span. + However, it is trivial to know that an exception + will escape, if one checks for an active exception just before ending the span, + as done in the [example for recording span exceptions](#recording-an-exception). + + It follows that an exception may still escape the scope of the span + 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. diff --git a/crates/weaver_forge/codegen_examples/mini_registry/http.yaml b/crates/weaver_forge/codegen_examples/mini_registry/http.yaml new file mode 100644 index 00000000..e013704a --- /dev/null +++ b/crates/weaver_forge/codegen_examples/mini_registry/http.yaml @@ -0,0 +1,174 @@ +groups: + - id: registry.http + prefix: http + type: attribute_group + brief: 'This document defines semantic convention attributes in the HTTP namespace.' + attributes: + - id: request.body.size + type: int + brief: > + 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. + examples: 3495 + stability: experimental # this should not be marked stable with other HTTP attributes + - id: request.header + stability: stable + type: template[string[]] + brief: > + HTTP request headers, `` being the normalized HTTP Header name (lowercase), the value being the header values. + note: > + 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. + examples: ['http.request.header.content-type=["application/json"]', 'http.request.header.x-forwarded-for=["1.2.3.4", "1.2.3.5"]'] + - id: request.method + stability: stable + type: + allow_custom_values: true + members: + - id: connect + value: "CONNECT" + brief: 'CONNECT method.' + stability: stable + - id: delete + value: "DELETE" + brief: 'DELETE method.' + stability: stable + - id: get + value: "GET" + brief: 'GET method.' + stability: stable + - id: head + value: "HEAD" + brief: 'HEAD method.' + stability: stable + - id: options + value: "OPTIONS" + brief: 'OPTIONS method.' + stability: stable + - id: patch + value: "PATCH" + brief: 'PATCH method.' + stability: stable + - id: post + value: "POST" + brief: 'POST method.' + stability: stable + - id: put + value: "PUT" + brief: 'PUT method.' + stability: stable + - id: trace + value: "TRACE" + brief: 'TRACE method.' + stability: stable + - id: other + value: "_OTHER" + brief: 'Any HTTP method that the instrumentation has no prior knowledge of.' + stability: stable + brief: 'HTTP request method.' + examples: ["GET", "POST", "HEAD"] + note: | + HTTP request method value SHOULD be "known" to the instrumentation. + By default, this convention defines "known" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods) + and the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html). + + If the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`. + + If the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override + the list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named + OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods + (this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults). + + 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. + - id: request.method_original + stability: stable + type: string + brief: Original HTTP method sent by the client in the request line. + examples: ["GeT", "ACL", "foo"] + - id: request.resend_count + stability: stable + type: int + brief: > + The ordinal number of request resending attempt (for any reason, including redirects). + note: > + 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). + examples: 3 + - id: request.size + type: int + brief: > + 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. + examples: 1437 + stability: experimental + - id: response.body.size + type: int + brief: > + 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. + examples: 3495 + stability: experimental # this should not be marked stable with other HTTP attributes + - id: response.header + stability: stable + type: template[string[]] + brief: > + HTTP response headers, `` being the normalized HTTP Header name (lowercase), the value being the header values. + note: > + 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. + examples: ['http.response.header.content-type=["application/json"]', 'http.response.header.my-custom-header=["abc", "def"]'] + - id: response.size + type: int + brief: > + 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. + examples: 1437 + stability: experimental + - id: response.status_code + stability: stable + type: int + brief: '[HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6).' + examples: [200] + - id: route + stability: stable + type: string + brief: > + The matched route, that is, the path template in the format used by the respective server framework. + examples: ['/users/:userID?', '{controller}/{action}/{id?}'] + note: > + 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. + - id: connection.state + type: + allow_custom_values: true + members: + - id: active + value: "active" + brief: 'active state.' + stability: experimental + - id: idle + value: "idle" + brief: 'idle state.' + stability: experimental + brief: State of the HTTP connection in the HTTP connection pool. + stability: experimental + examples: ["active", "idle"] diff --git a/crates/weaver_forge/codegen_examples/mini_registry/network.yaml b/crates/weaver_forge/codegen_examples/mini_registry/network.yaml new file mode 100644 index 00000000..2f3f1957 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/mini_registry/network.yaml @@ -0,0 +1,235 @@ +groups: + - id: registry.network + prefix: network + type: attribute_group + brief: > + These attributes may be used for any network related operation. + attributes: + - id: carrier.icc + type: string + stability: experimental + brief: "The ISO 3166-1 alpha-2 2-character country code associated with the mobile carrier network." + examples: "DE" + - id: carrier.mcc + type: string + stability: experimental + brief: "The mobile carrier country code." + examples: "310" + - id: carrier.mnc + type: string + stability: experimental + brief: "The mobile carrier network code." + examples: "001" + - id: carrier.name + type: string + stability: experimental + brief: "The name of the mobile carrier." + examples: "sprint" + - id: connection.subtype + type: + allow_custom_values: true + members: + - id: gprs + brief: GPRS + value: "gprs" + stability: experimental + - id: edge + brief: EDGE + value: "edge" + stability: experimental + - id: umts + brief: UMTS + value: "umts" + stability: experimental + - id: cdma + brief: CDMA + value: "cdma" + stability: experimental + - id: evdo_0 + brief: EVDO Rel. 0 + value: "evdo_0" + stability: experimental + - id: evdo_a + brief: "EVDO Rev. A" + value: "evdo_a" + stability: experimental + - id: cdma2000_1xrtt + brief: CDMA2000 1XRTT + value: "cdma2000_1xrtt" + stability: experimental + - id: hsdpa + brief: HSDPA + value: "hsdpa" + stability: experimental + - id: hsupa + brief: HSUPA + value: "hsupa" + stability: experimental + - id: hspa + brief: HSPA + value: "hspa" + stability: experimental + - id: iden + brief: IDEN + value: "iden" + stability: experimental + - id: evdo_b + brief: "EVDO Rev. B" + value: "evdo_b" + stability: experimental + - id: lte + brief: LTE + value: "lte" + stability: experimental + - id: ehrpd + brief: EHRPD + value: "ehrpd" + stability: experimental + - id: hspap + brief: HSPAP + value: "hspap" + stability: experimental + - id: gsm + brief: GSM + value: "gsm" + stability: experimental + - id: td_scdma + brief: TD-SCDMA + value: "td_scdma" + stability: experimental + - id: iwlan + brief: IWLAN + value: "iwlan" + stability: experimental + - id: nr + brief: "5G NR (New Radio)" + value: "nr" + stability: experimental + - id: nrnsa + brief: "5G NRNSA (New Radio Non-Standalone)" + value: "nrnsa" + stability: experimental + - id: lte_ca + brief: LTE CA + value: "lte_ca" + stability: experimental + stability: experimental + brief: 'This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection.' + examples: 'LTE' + - id: connection.type + type: + allow_custom_values: true + members: + - id: wifi + value: "wifi" + stability: experimental + - id: wired + value: "wired" + stability: experimental + - id: cell + value: "cell" + stability: experimental + - id: unavailable + value: "unavailable" + stability: experimental + - id: unknown + value: "unknown" + stability: experimental + stability: experimental + brief: 'The internet connection type.' + examples: 'wifi' + - id: local.address + stability: stable + type: string + brief: Local address of the network connection - IP address or Unix domain socket name. + examples: ['10.1.2.80', '/tmp/my.sock'] + - id: local.port + stability: stable + type: int + brief: Local port number of the network connection. + examples: [65123] + - id: peer.address + stability: stable + type: string + brief: Peer address of the network connection - IP address or Unix domain socket name. + examples: ['10.1.2.80', '/tmp/my.sock'] + - id: peer.port + stability: stable + type: int + brief: Peer port number of the network connection. + examples: [65123] + - id: protocol.name + stability: stable + type: string + brief: '[OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent.' + note: The value SHOULD be normalized to lowercase. + examples: ['amqp', 'http', 'mqtt'] + - id: protocol.version + stability: stable + type: string + brief: The actual version of the protocol used for network communication. + examples: ['1.1', '2'] + note: > + If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), + this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, + this attribute SHOULD NOT be set. + - id: transport + stability: stable + type: + allow_custom_values: true + members: + - id: tcp + value: 'tcp' + brief: "TCP" + stability: stable + - id: udp + value: 'udp' + brief: "UDP" + stability: stable + - id: pipe + value: "pipe" + brief: 'Named or anonymous pipe.' + stability: stable + - id: unix + value: 'unix' + brief: "Unix domain socket" + stability: stable + brief: > + [OSI transport layer](https://osi-model.com/transport-layer/) or + [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). + note: | + The value SHOULD be normalized to lowercase. + + Consider always setting the transport when setting a port number, since + a port number is ambiguous without knowing the transport. For example + different processes could be listening on TCP port 12345 and UDP port 12345. + examples: ['tcp', 'udp'] + - id: type + stability: stable + type: + allow_custom_values: true + members: + - id: ipv4 + value: 'ipv4' + brief: "IPv4" + stability: stable + - id: ipv6 + value: 'ipv6' + brief: "IPv6" + stability: stable + brief: '[OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent.' + note: The value SHOULD be normalized to lowercase. + examples: ['ipv4', 'ipv6'] + - id: io.direction + type: + allow_custom_values: false + members: + - id: transmit + value: 'transmit' + stability: experimental + - id: receive + value: 'receive' + stability: experimental + stability: experimental + brief: "The network IO operation direction." + examples: ["transmit"] diff --git a/crates/weaver_forge/codegen_examples/mini_registry/os.yaml b/crates/weaver_forge/codegen_examples/mini_registry/os.yaml new file mode 100644 index 00000000..3317958f --- /dev/null +++ b/crates/weaver_forge/codegen_examples/mini_registry/os.yaml @@ -0,0 +1,85 @@ +groups: + - id: registry.os + prefix: os + type: attribute_group + brief: > + The operating system (OS) on which the process represented by this resource is running. + note: > + In case of virtualized environments, this is the operating system as it is observed by + the process, i.e., the virtualized guest rather than the underlying host. + attributes: + - id: type + type: + allow_custom_values: true + members: + - id: windows + value: 'windows' + brief: "Microsoft Windows" + stability: experimental + - id: linux + value: 'linux' + brief: "Linux" + stability: experimental + - id: darwin + value: 'darwin' + brief: "Apple Darwin" + stability: experimental + - id: freebsd + value: 'freebsd' + brief: "FreeBSD" + stability: experimental + - id: netbsd + value: 'netbsd' + brief: "NetBSD" + stability: experimental + - id: openbsd + value: 'openbsd' + brief: "OpenBSD" + stability: experimental + - id: dragonflybsd + value: 'dragonflybsd' + brief: "DragonFly BSD" + stability: experimental + - id: hpux + value: 'hpux' + brief: "HP-UX (Hewlett Packard Unix)" + stability: experimental + - id: aix + value: 'aix' + brief: "AIX (Advanced Interactive eXecutive)" + stability: experimental + - id: solaris + value: 'solaris' + brief: "SunOS, Oracle Solaris" + stability: experimental + - id: z_os + value: 'z_os' + brief: "IBM z/OS" + stability: experimental + brief: > + The operating system type. + stability: experimental + - id: description + type: string + stability: experimental + brief: > + Human readable (not intended to be parsed) OS version information, + like e.g. reported by `ver` or `lsb_release -a` commands. + examples: ['Microsoft Windows [Version 10.0.18363.778]', 'Ubuntu 18.04.1 LTS'] + - id: name + type: string + stability: experimental + brief: 'Human readable operating system name.' + examples: ['iOS', 'Android', 'Ubuntu'] + - id: version + type: string + stability: experimental + brief: > + The version string of the operating system as defined in + [Version Attributes](/docs/resource/README.md#version-attributes). + examples: ['14.2.1', '18.04.1'] + - id: build_id + type: string + stability: experimental + brief: 'Unique identifier for a particular build or compilation of the operating system.' + examples: ['TQ3C.230805.001.B2', '20E247', '22621'] diff --git a/crates/weaver_forge/codegen_examples/mini_registry/otel.yaml b/crates/weaver_forge/codegen_examples/mini_registry/otel.yaml new file mode 100644 index 00000000..76286cdc --- /dev/null +++ b/crates/weaver_forge/codegen_examples/mini_registry/otel.yaml @@ -0,0 +1,40 @@ +groups: + - id: registry.otel + prefix: otel + type: attribute_group + brief: Attributes reserved for OpenTelemetry + attributes: + - id: status_code + type: + allow_custom_values: true + members: + - id: ok + value: OK + brief: 'The operation has been validated by an Application developer or Operator to have completed successfully.' + stability: stable + - id: error + value: ERROR + brief: 'The operation contains an error.' + stability: stable + brief: Name of the code, either "OK" or "ERROR". MUST NOT be set if the status code is UNSET. + stability: stable + - id: status_description + type: string + brief: "Description of the Status if it has a value, otherwise not set." + examples: ['resource not found'] + stability: stable + - id: registry.otel.scope + prefix: otel.scope + type: attribute_group + brief: Attributes used by non-OTLP exporters to represent OpenTelemetry Scope's concepts. + attributes: + - id: name + type: string + brief: The name of the instrumentation scope - (`InstrumentationScope.Name` in OTLP). + examples: ['io.opentelemetry.contrib.mongodb'] + stability: stable + - id: version + type: string + brief: The version of the instrumentation scope - (`InstrumentationScope.Version` in OTLP). + examples: ['1.0.0'] + stability: stable From 37acc4b68523fadcf654abf3a7be1cd70205a716 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Mon, 29 Apr 2024 14:32:55 -0700 Subject: [PATCH 12/39] chore(forge): Simplify mini_registry --- .../codegen_examples/expected_codegen/disk.rs | 29 --- .../expected_codegen/error.rs | 45 ---- .../codegen_examples/expected_codegen/lib.rs | 12 - .../expected_codegen/network.rs | 233 ----------------- .../codegen_examples/expected_codegen/os.rs | 80 ------ .../codegen_examples/expected_codegen/otel.rs | 31 --- .../expected_codegen/otel_scope.rs | 21 -- .../mini_registry/deprecated/otel.yaml | 18 -- .../codegen_examples/mini_registry/disk.yaml | 20 -- .../codegen_examples/mini_registry/error.yaml | 40 --- .../mini_registry/network.yaml | 235 ------------------ .../codegen_examples/mini_registry/os.yaml | 85 ------- .../codegen_examples/mini_registry/otel.yaml | 40 --- 13 files changed, 889 deletions(-) delete mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/disk.rs delete mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/error.rs delete mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/network.rs delete mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/os.rs delete mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/otel.rs delete mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/otel_scope.rs delete mode 100644 crates/weaver_forge/codegen_examples/mini_registry/deprecated/otel.yaml delete mode 100644 crates/weaver_forge/codegen_examples/mini_registry/disk.yaml delete mode 100644 crates/weaver_forge/codegen_examples/mini_registry/error.yaml delete mode 100644 crates/weaver_forge/codegen_examples/mini_registry/network.yaml delete mode 100644 crates/weaver_forge/codegen_examples/mini_registry/os.yaml delete mode 100644 crates/weaver_forge/codegen_examples/mini_registry/otel.yaml diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/disk.rs b/crates/weaver_forge/codegen_examples/expected_codegen/disk.rs deleted file mode 100644 index 6ad2c037..00000000 --- a/crates/weaver_forge/codegen_examples/expected_codegen/disk.rs +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! These attributes may be used for any disk related operation. -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 - -use opentelemetry::StringValue; -use crate::AttributeKey; - - -/// The disk IO operation direction. -#[cfg(feature = "semconv_experimental")] -pub const DISK_IO_DIRECTION: AttributeKey = AttributeKey::new("disk.io.direction"); - - -/// The disk IO operation direction. -#[non_exhaustive] -pub enum DiskIoDirection { - - #[cfg(feature = "semconv_experimental")] - Read, - - #[cfg(feature = "semconv_experimental")] - Write, - -} - diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/error.rs b/crates/weaver_forge/codegen_examples/expected_codegen/error.rs deleted file mode 100644 index 0434861f..00000000 --- a/crates/weaver_forge/codegen_examples/expected_codegen/error.rs +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! This document defines the shared attributes used to report an error. -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 - -use opentelemetry::StringValue; -use crate::AttributeKey; - - -/// Describes a class of error the operation ended with. -/// -/// Notes: -/// The `error.type` SHOULD be predictable, and SHOULD have low cardinality. -/// -/// When `error.type` is set to a type (e.g., an exception type), its -/// canonical class name identifying the type within the artifact SHOULD be used. -/// -/// Instrumentations SHOULD document the list of errors they report. -/// -/// The cardinality of `error.type` within one instrumentation library SHOULD be low. -/// Telemetry consumers that aggregate data from multiple instrumentation libraries and applications -/// should be prepared for `error.type` to have high cardinality at query time when no -/// additional filters are applied. -/// -/// If the operation has completed successfully, instrumentations SHOULD NOT set `error.type`. -/// -/// If a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes), -/// it's RECOMMENDED to: -/// -/// * Use a domain-specific attribute -/// * Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. -pub const ERROR_TYPE: AttributeKey = AttributeKey::new("error.type"); - - -/// Describes a class of error the operation ended with. -#[non_exhaustive] -pub enum ErrorType { - /// A fallback error value to be used when the instrumentation doesn't define a custom value. - Other, - -} - diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/lib.rs b/crates/weaver_forge/codegen_examples/expected_codegen/lib.rs index 59c28764..170f234b 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/lib.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/lib.rs @@ -11,22 +11,10 @@ use opentelemetry::{Key, KeyValue, StringValue}; /// 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. pub mod client; -/// These attributes may be used for any disk related operation. -pub mod disk; -/// This document defines the shared attributes used to report an error. -pub mod error; /// This document defines the shared attributes used to report a single exception associated with a span or log. 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 network; -/// The operating system (OS) on which the process represented by this resource is running. -pub mod os; -/// Attributes reserved for OpenTelemetry -pub mod otel; -/// Attributes used by non-OTLP exporters to represent OpenTelemetry Scope's concepts. -pub mod otel_scope; /// A typed attribute key. pub struct AttributeKey { diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/network.rs b/crates/weaver_forge/codegen_examples/expected_codegen/network.rs deleted file mode 100644 index ab321ed2..00000000 --- a/crates/weaver_forge/codegen_examples/expected_codegen/network.rs +++ /dev/null @@ -1,233 +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; - - -/// The ISO 3166-1 alpha-2 2-character country code associated with the mobile carrier network. -#[cfg(feature = "semconv_experimental")] -pub const NETWORK_CARRIER_ICC: AttributeKey = AttributeKey::new("network.carrier.icc"); - - - -/// The mobile carrier country code. -#[cfg(feature = "semconv_experimental")] -pub const NETWORK_CARRIER_MCC: AttributeKey = AttributeKey::new("network.carrier.mcc"); - - - -/// The mobile carrier network code. -#[cfg(feature = "semconv_experimental")] -pub const NETWORK_CARRIER_MNC: AttributeKey = AttributeKey::new("network.carrier.mnc"); - - - -/// The name of the mobile carrier. -#[cfg(feature = "semconv_experimental")] -pub const NETWORK_CARRIER_NAME: AttributeKey = AttributeKey::new("network.carrier.name"); - - - -/// This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection. -#[cfg(feature = "semconv_experimental")] -pub const NETWORK_CONNECTION_SUBTYPE: AttributeKey = AttributeKey::new("network.connection.subtype"); - - -/// This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection. -#[non_exhaustive] -pub enum NetworkConnectionSubtype { - /// GPRS - #[cfg(feature = "semconv_experimental")] - Gprs, - /// EDGE - #[cfg(feature = "semconv_experimental")] - Edge, - /// UMTS - #[cfg(feature = "semconv_experimental")] - Umts, - /// CDMA - #[cfg(feature = "semconv_experimental")] - Cdma, - /// EVDO Rel. 0 - #[cfg(feature = "semconv_experimental")] - Evdo0, - /// EVDO Rev. A - #[cfg(feature = "semconv_experimental")] - EvdoA, - /// CDMA2000 1XRTT - #[cfg(feature = "semconv_experimental")] - Cdma20001Xrtt, - /// HSDPA - #[cfg(feature = "semconv_experimental")] - Hsdpa, - /// HSUPA - #[cfg(feature = "semconv_experimental")] - Hsupa, - /// HSPA - #[cfg(feature = "semconv_experimental")] - Hspa, - /// IDEN - #[cfg(feature = "semconv_experimental")] - Iden, - /// EVDO Rev. B - #[cfg(feature = "semconv_experimental")] - EvdoB, - /// LTE - #[cfg(feature = "semconv_experimental")] - Lte, - /// EHRPD - #[cfg(feature = "semconv_experimental")] - Ehrpd, - /// HSPAP - #[cfg(feature = "semconv_experimental")] - Hspap, - /// GSM - #[cfg(feature = "semconv_experimental")] - Gsm, - /// TD-SCDMA - #[cfg(feature = "semconv_experimental")] - TdScdma, - /// IWLAN - #[cfg(feature = "semconv_experimental")] - Iwlan, - /// 5G NR (New Radio) - #[cfg(feature = "semconv_experimental")] - Nr, - /// 5G NRNSA (New Radio Non-Standalone) - #[cfg(feature = "semconv_experimental")] - Nrnsa, - /// LTE CA - #[cfg(feature = "semconv_experimental")] - LteCa, - -} - - -/// The internet connection type. -#[cfg(feature = "semconv_experimental")] -pub const NETWORK_CONNECTION_TYPE: AttributeKey = AttributeKey::new("network.connection.type"); - - -/// The internet connection type. -#[non_exhaustive] -pub enum NetworkConnectionType { - - #[cfg(feature = "semconv_experimental")] - Wifi, - - #[cfg(feature = "semconv_experimental")] - Wired, - - #[cfg(feature = "semconv_experimental")] - Cell, - - #[cfg(feature = "semconv_experimental")] - Unavailable, - - #[cfg(feature = "semconv_experimental")] - Unknown, - -} - - -/// Local address of the network connection - IP address or Unix domain socket name. -pub const NETWORK_LOCAL_ADDRESS: AttributeKey = AttributeKey::new("network.local.address"); - - - -/// Local port number of the network connection. -pub const NETWORK_LOCAL_PORT: AttributeKey = AttributeKey::new("network.local.port"); - - -/// Peer address of the network connection - IP address or Unix domain socket name. -pub const NETWORK_PEER_ADDRESS: AttributeKey = AttributeKey::new("network.peer.address"); - - - -/// Peer port number of the network connection. -pub const NETWORK_PEER_PORT: AttributeKey = AttributeKey::new("network.peer.port"); - - -/// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. -/// -/// Notes: -/// The value SHOULD be normalized to lowercase. -pub const NETWORK_PROTOCOL_NAME: AttributeKey = AttributeKey::new("network.protocol.name"); - - - -/// The actual version of the protocol used for network communication. -/// -/// Notes: -/// If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, this attribute SHOULD NOT be set. -pub const NETWORK_PROTOCOL_VERSION: AttributeKey = AttributeKey::new("network.protocol.version"); - - - -/// [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). -/// -/// Notes: -/// The value SHOULD be normalized to lowercase. -/// -/// Consider always setting the transport when setting a port number, since -/// a port number is ambiguous without knowing the transport. For example -/// different processes could be listening on TCP port 12345 and UDP port 12345. -pub const NETWORK_TRANSPORT: AttributeKey = AttributeKey::new("network.transport"); - - -/// [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). -#[non_exhaustive] -pub enum NetworkTransport { - /// TCP - Tcp, - /// UDP - Udp, - /// Named or anonymous pipe. - Pipe, - /// Unix domain socket - Unix, - -} - - -/// [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. -/// -/// Notes: -/// The value SHOULD be normalized to lowercase. -pub const NETWORK_TYPE: AttributeKey = AttributeKey::new("network.type"); - - -/// [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. -#[non_exhaustive] -pub enum NetworkType { - /// IPv4 - Ipv4, - /// IPv6 - Ipv6, - -} - - -/// The network IO operation direction. -#[cfg(feature = "semconv_experimental")] -pub const NETWORK_IO_DIRECTION: AttributeKey = AttributeKey::new("network.io.direction"); - - -/// The network IO operation direction. -#[non_exhaustive] -pub enum NetworkIoDirection { - - #[cfg(feature = "semconv_experimental")] - Transmit, - - #[cfg(feature = "semconv_experimental")] - Receive, - -} - diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/os.rs b/crates/weaver_forge/codegen_examples/expected_codegen/os.rs deleted file mode 100644 index ae39f23f..00000000 --- a/crates/weaver_forge/codegen_examples/expected_codegen/os.rs +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! The operating system (OS) on which the process represented by this resource is running. -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 - -use opentelemetry::StringValue; -use crate::AttributeKey; - - -/// The operating system type. -#[cfg(feature = "semconv_experimental")] -pub const OS_TYPE: AttributeKey = AttributeKey::new("os.type"); - - -/// The operating system type. -#[non_exhaustive] -pub enum OsType { - /// Microsoft Windows - #[cfg(feature = "semconv_experimental")] - Windows, - /// Linux - #[cfg(feature = "semconv_experimental")] - Linux, - /// Apple Darwin - #[cfg(feature = "semconv_experimental")] - Darwin, - /// FreeBSD - #[cfg(feature = "semconv_experimental")] - Freebsd, - /// NetBSD - #[cfg(feature = "semconv_experimental")] - Netbsd, - /// OpenBSD - #[cfg(feature = "semconv_experimental")] - Openbsd, - /// DragonFly BSD - #[cfg(feature = "semconv_experimental")] - Dragonflybsd, - /// HP-UX (Hewlett Packard Unix) - #[cfg(feature = "semconv_experimental")] - Hpux, - /// AIX (Advanced Interactive eXecutive) - #[cfg(feature = "semconv_experimental")] - Aix, - /// SunOS, Oracle Solaris - #[cfg(feature = "semconv_experimental")] - Solaris, - /// IBM z/OS - #[cfg(feature = "semconv_experimental")] - ZOs, - -} - - -/// Human readable (not intended to be parsed) OS version information, like e.g. reported by `ver` or `lsb_release -a` commands. -#[cfg(feature = "semconv_experimental")] -pub const OS_DESCRIPTION: AttributeKey = AttributeKey::new("os.description"); - - - -/// Human readable operating system name. -#[cfg(feature = "semconv_experimental")] -pub const OS_NAME: AttributeKey = AttributeKey::new("os.name"); - - - -/// The version string of the operating system as defined in [Version Attributes](/docs/resource/README.md#version-attributes). -#[cfg(feature = "semconv_experimental")] -pub const OS_VERSION: AttributeKey = AttributeKey::new("os.version"); - - - -/// Unique identifier for a particular build or compilation of the operating system. -#[cfg(feature = "semconv_experimental")] -pub const OS_BUILD_ID: AttributeKey = AttributeKey::new("os.build_id"); - - diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/otel.rs b/crates/weaver_forge/codegen_examples/expected_codegen/otel.rs deleted file mode 100644 index c6837841..00000000 --- a/crates/weaver_forge/codegen_examples/expected_codegen/otel.rs +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! Attributes reserved for OpenTelemetry -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 - -use opentelemetry::StringValue; -use crate::AttributeKey; - - -/// Name of the code, either "OK" or "ERROR". MUST NOT be set if the status code is UNSET. -pub const OTEL_STATUS_CODE: AttributeKey = AttributeKey::new("otel.status_code"); - - -/// Name of the code, either "OK" or "ERROR". MUST NOT be set if the status code is UNSET. -#[non_exhaustive] -pub enum OtelStatusCode { - /// The operation has been validated by an Application developer or Operator to have completed successfully. - Ok, - /// The operation contains an error. - Error, - -} - - -/// Description of the Status if it has a value, otherwise not set. -pub const OTEL_STATUS_DESCRIPTION: AttributeKey = AttributeKey::new("otel.status_description"); - - diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/otel_scope.rs b/crates/weaver_forge/codegen_examples/expected_codegen/otel_scope.rs deleted file mode 100644 index 3e374c5c..00000000 --- a/crates/weaver_forge/codegen_examples/expected_codegen/otel_scope.rs +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! Attributes used by non-OTLP exporters to represent OpenTelemetry Scope's concepts. -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 - -use opentelemetry::StringValue; -use crate::AttributeKey; - - -/// The name of the instrumentation scope - (`InstrumentationScope.Name` in OTLP). -pub const OTEL_SCOPE_NAME: AttributeKey = AttributeKey::new("otel.scope.name"); - - - -/// The version of the instrumentation scope - (`InstrumentationScope.Version` in OTLP). -pub const OTEL_SCOPE_VERSION: AttributeKey = AttributeKey::new("otel.scope.version"); - - diff --git a/crates/weaver_forge/codegen_examples/mini_registry/deprecated/otel.yaml b/crates/weaver_forge/codegen_examples/mini_registry/deprecated/otel.yaml deleted file mode 100644 index c52a51fe..00000000 --- a/crates/weaver_forge/codegen_examples/mini_registry/deprecated/otel.yaml +++ /dev/null @@ -1,18 +0,0 @@ -groups: - - id: registry.otel.library.deprecated - prefix: otel.library - type: attribute_group - brief: "Describes deprecated otel.library attributes." - attributes: - - id: name - type: string - deprecated: use the `otel.scope.name` attribute. - stability: experimental - brief: - examples: ['io.opentelemetry.contrib.mongodb'] - - id: version - type: string - deprecated: use the `otel.scope.version` attribute. - stability: experimental - brief: - examples: ['1.0.0'] diff --git a/crates/weaver_forge/codegen_examples/mini_registry/disk.yaml b/crates/weaver_forge/codegen_examples/mini_registry/disk.yaml deleted file mode 100644 index aa8c0911..00000000 --- a/crates/weaver_forge/codegen_examples/mini_registry/disk.yaml +++ /dev/null @@ -1,20 +0,0 @@ -groups: - - id: registry.disk - prefix: disk - type: attribute_group - brief: > - These attributes may be used for any disk related operation. - attributes: - - id: io.direction - type: - allow_custom_values: false - members: - - id: read - value: 'read' - stability: experimental - - id: write - value: 'write' - stability: experimental - stability: experimental - brief: "The disk IO operation direction." - examples: ["read"] diff --git a/crates/weaver_forge/codegen_examples/mini_registry/error.yaml b/crates/weaver_forge/codegen_examples/mini_registry/error.yaml deleted file mode 100644 index 68bde170..00000000 --- a/crates/weaver_forge/codegen_examples/mini_registry/error.yaml +++ /dev/null @@ -1,40 +0,0 @@ -groups: - - id: registry.error - type: attribute_group - prefix: error - brief: > - This document defines the shared attributes used to report an error. - attributes: - - id: type - stability: stable - brief: > - Describes a class of error the operation ended with. - type: - allow_custom_values: true - members: - - id: other - value: "_OTHER" - stability: stable - brief: > - A fallback error value to be used when the instrumentation doesn't define a custom value. - examples: ['timeout', 'java.net.UnknownHostException', 'server_certificate_invalid', '500'] - note: | - The `error.type` SHOULD be predictable, and SHOULD have low cardinality. - - When `error.type` is set to a type (e.g., an exception type), its - canonical class name identifying the type within the artifact SHOULD be used. - - Instrumentations SHOULD document the list of errors they report. - - The cardinality of `error.type` within one instrumentation library SHOULD be low. - Telemetry consumers that aggregate data from multiple instrumentation libraries and applications - should be prepared for `error.type` to have high cardinality at query time when no - additional filters are applied. - - If the operation has completed successfully, instrumentations SHOULD NOT set `error.type`. - - If a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes), - it's RECOMMENDED to: - - * Use a domain-specific attribute - * Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. diff --git a/crates/weaver_forge/codegen_examples/mini_registry/network.yaml b/crates/weaver_forge/codegen_examples/mini_registry/network.yaml deleted file mode 100644 index 2f3f1957..00000000 --- a/crates/weaver_forge/codegen_examples/mini_registry/network.yaml +++ /dev/null @@ -1,235 +0,0 @@ -groups: - - id: registry.network - prefix: network - type: attribute_group - brief: > - These attributes may be used for any network related operation. - attributes: - - id: carrier.icc - type: string - stability: experimental - brief: "The ISO 3166-1 alpha-2 2-character country code associated with the mobile carrier network." - examples: "DE" - - id: carrier.mcc - type: string - stability: experimental - brief: "The mobile carrier country code." - examples: "310" - - id: carrier.mnc - type: string - stability: experimental - brief: "The mobile carrier network code." - examples: "001" - - id: carrier.name - type: string - stability: experimental - brief: "The name of the mobile carrier." - examples: "sprint" - - id: connection.subtype - type: - allow_custom_values: true - members: - - id: gprs - brief: GPRS - value: "gprs" - stability: experimental - - id: edge - brief: EDGE - value: "edge" - stability: experimental - - id: umts - brief: UMTS - value: "umts" - stability: experimental - - id: cdma - brief: CDMA - value: "cdma" - stability: experimental - - id: evdo_0 - brief: EVDO Rel. 0 - value: "evdo_0" - stability: experimental - - id: evdo_a - brief: "EVDO Rev. A" - value: "evdo_a" - stability: experimental - - id: cdma2000_1xrtt - brief: CDMA2000 1XRTT - value: "cdma2000_1xrtt" - stability: experimental - - id: hsdpa - brief: HSDPA - value: "hsdpa" - stability: experimental - - id: hsupa - brief: HSUPA - value: "hsupa" - stability: experimental - - id: hspa - brief: HSPA - value: "hspa" - stability: experimental - - id: iden - brief: IDEN - value: "iden" - stability: experimental - - id: evdo_b - brief: "EVDO Rev. B" - value: "evdo_b" - stability: experimental - - id: lte - brief: LTE - value: "lte" - stability: experimental - - id: ehrpd - brief: EHRPD - value: "ehrpd" - stability: experimental - - id: hspap - brief: HSPAP - value: "hspap" - stability: experimental - - id: gsm - brief: GSM - value: "gsm" - stability: experimental - - id: td_scdma - brief: TD-SCDMA - value: "td_scdma" - stability: experimental - - id: iwlan - brief: IWLAN - value: "iwlan" - stability: experimental - - id: nr - brief: "5G NR (New Radio)" - value: "nr" - stability: experimental - - id: nrnsa - brief: "5G NRNSA (New Radio Non-Standalone)" - value: "nrnsa" - stability: experimental - - id: lte_ca - brief: LTE CA - value: "lte_ca" - stability: experimental - stability: experimental - brief: 'This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection.' - examples: 'LTE' - - id: connection.type - type: - allow_custom_values: true - members: - - id: wifi - value: "wifi" - stability: experimental - - id: wired - value: "wired" - stability: experimental - - id: cell - value: "cell" - stability: experimental - - id: unavailable - value: "unavailable" - stability: experimental - - id: unknown - value: "unknown" - stability: experimental - stability: experimental - brief: 'The internet connection type.' - examples: 'wifi' - - id: local.address - stability: stable - type: string - brief: Local address of the network connection - IP address or Unix domain socket name. - examples: ['10.1.2.80', '/tmp/my.sock'] - - id: local.port - stability: stable - type: int - brief: Local port number of the network connection. - examples: [65123] - - id: peer.address - stability: stable - type: string - brief: Peer address of the network connection - IP address or Unix domain socket name. - examples: ['10.1.2.80', '/tmp/my.sock'] - - id: peer.port - stability: stable - type: int - brief: Peer port number of the network connection. - examples: [65123] - - id: protocol.name - stability: stable - type: string - brief: '[OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent.' - note: The value SHOULD be normalized to lowercase. - examples: ['amqp', 'http', 'mqtt'] - - id: protocol.version - stability: stable - type: string - brief: The actual version of the protocol used for network communication. - examples: ['1.1', '2'] - note: > - If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), - this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, - this attribute SHOULD NOT be set. - - id: transport - stability: stable - type: - allow_custom_values: true - members: - - id: tcp - value: 'tcp' - brief: "TCP" - stability: stable - - id: udp - value: 'udp' - brief: "UDP" - stability: stable - - id: pipe - value: "pipe" - brief: 'Named or anonymous pipe.' - stability: stable - - id: unix - value: 'unix' - brief: "Unix domain socket" - stability: stable - brief: > - [OSI transport layer](https://osi-model.com/transport-layer/) or - [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). - note: | - The value SHOULD be normalized to lowercase. - - Consider always setting the transport when setting a port number, since - a port number is ambiguous without knowing the transport. For example - different processes could be listening on TCP port 12345 and UDP port 12345. - examples: ['tcp', 'udp'] - - id: type - stability: stable - type: - allow_custom_values: true - members: - - id: ipv4 - value: 'ipv4' - brief: "IPv4" - stability: stable - - id: ipv6 - value: 'ipv6' - brief: "IPv6" - stability: stable - brief: '[OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent.' - note: The value SHOULD be normalized to lowercase. - examples: ['ipv4', 'ipv6'] - - id: io.direction - type: - allow_custom_values: false - members: - - id: transmit - value: 'transmit' - stability: experimental - - id: receive - value: 'receive' - stability: experimental - stability: experimental - brief: "The network IO operation direction." - examples: ["transmit"] diff --git a/crates/weaver_forge/codegen_examples/mini_registry/os.yaml b/crates/weaver_forge/codegen_examples/mini_registry/os.yaml deleted file mode 100644 index 3317958f..00000000 --- a/crates/weaver_forge/codegen_examples/mini_registry/os.yaml +++ /dev/null @@ -1,85 +0,0 @@ -groups: - - id: registry.os - prefix: os - type: attribute_group - brief: > - The operating system (OS) on which the process represented by this resource is running. - note: > - In case of virtualized environments, this is the operating system as it is observed by - the process, i.e., the virtualized guest rather than the underlying host. - attributes: - - id: type - type: - allow_custom_values: true - members: - - id: windows - value: 'windows' - brief: "Microsoft Windows" - stability: experimental - - id: linux - value: 'linux' - brief: "Linux" - stability: experimental - - id: darwin - value: 'darwin' - brief: "Apple Darwin" - stability: experimental - - id: freebsd - value: 'freebsd' - brief: "FreeBSD" - stability: experimental - - id: netbsd - value: 'netbsd' - brief: "NetBSD" - stability: experimental - - id: openbsd - value: 'openbsd' - brief: "OpenBSD" - stability: experimental - - id: dragonflybsd - value: 'dragonflybsd' - brief: "DragonFly BSD" - stability: experimental - - id: hpux - value: 'hpux' - brief: "HP-UX (Hewlett Packard Unix)" - stability: experimental - - id: aix - value: 'aix' - brief: "AIX (Advanced Interactive eXecutive)" - stability: experimental - - id: solaris - value: 'solaris' - brief: "SunOS, Oracle Solaris" - stability: experimental - - id: z_os - value: 'z_os' - brief: "IBM z/OS" - stability: experimental - brief: > - The operating system type. - stability: experimental - - id: description - type: string - stability: experimental - brief: > - Human readable (not intended to be parsed) OS version information, - like e.g. reported by `ver` or `lsb_release -a` commands. - examples: ['Microsoft Windows [Version 10.0.18363.778]', 'Ubuntu 18.04.1 LTS'] - - id: name - type: string - stability: experimental - brief: 'Human readable operating system name.' - examples: ['iOS', 'Android', 'Ubuntu'] - - id: version - type: string - stability: experimental - brief: > - The version string of the operating system as defined in - [Version Attributes](/docs/resource/README.md#version-attributes). - examples: ['14.2.1', '18.04.1'] - - id: build_id - type: string - stability: experimental - brief: 'Unique identifier for a particular build or compilation of the operating system.' - examples: ['TQ3C.230805.001.B2', '20E247', '22621'] diff --git a/crates/weaver_forge/codegen_examples/mini_registry/otel.yaml b/crates/weaver_forge/codegen_examples/mini_registry/otel.yaml deleted file mode 100644 index 76286cdc..00000000 --- a/crates/weaver_forge/codegen_examples/mini_registry/otel.yaml +++ /dev/null @@ -1,40 +0,0 @@ -groups: - - id: registry.otel - prefix: otel - type: attribute_group - brief: Attributes reserved for OpenTelemetry - attributes: - - id: status_code - type: - allow_custom_values: true - members: - - id: ok - value: OK - brief: 'The operation has been validated by an Application developer or Operator to have completed successfully.' - stability: stable - - id: error - value: ERROR - brief: 'The operation contains an error.' - stability: stable - brief: Name of the code, either "OK" or "ERROR". MUST NOT be set if the status code is UNSET. - stability: stable - - id: status_description - type: string - brief: "Description of the Status if it has a value, otherwise not set." - examples: ['resource not found'] - stability: stable - - id: registry.otel.scope - prefix: otel.scope - type: attribute_group - brief: Attributes used by non-OTLP exporters to represent OpenTelemetry Scope's concepts. - attributes: - - id: name - type: string - brief: The name of the instrumentation scope - (`InstrumentationScope.Name` in OTLP). - examples: ['io.opentelemetry.contrib.mongodb'] - stability: stable - - id: version - type: string - brief: The version of the instrumentation scope - (`InstrumentationScope.Version` in OTLP). - examples: ['1.0.0'] - stability: stable From 074fe69e70616171fbfbd242e440330cf043a7c7 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Mon, 29 Apr 2024 15:27:54 -0700 Subject: [PATCH 13/39] doc(forge): Add documentation on the JQ filter. --- .../templates/registry/rust/weaver.yaml | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) 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 debe625e..3227521f 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml @@ -9,6 +9,13 @@ type_mapping: templates: - pattern: lib.rs.j2 + # The following JQ filter extracts the id, type, brief, and prefix of groups matching the following criteria: + # - groups with an id starting with the prefix `registry.` + # - groups of the type `attribute_group`. + # - groups with a well-defined prefix. + # - groups with a non-empty list of attributes that are neither deprecated nor experimental. + # - groups are deduplicated by prefix. + # - groups are sorted by prefix. filter: > .groups | map(select(.id | startswith("registry."))) @@ -21,7 +28,7 @@ templates: attributes: (.attributes | map(select(.stability == "experimental" and .deprecated | not)))}) | map(select(.attributes | length > 0)) - | map( # Transform the group into a more concise object + | map( { id, type, @@ -29,10 +36,17 @@ templates: prefix } ) - | unique_by(.prefix) # Remove duplicate prefixes - | sort_by(.prefix) # Sort by prefix + | unique_by(.prefix) + | sort_by(.prefix) 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 + # criteria: + # - groups with an id starting with the prefix `registry.` + # - groups of the type `attribute_group`. + # - groups with a well-defined prefix. + # - groups with a non-empty list of attributes that are neither deprecated nor experimental. + # - groups are sorted by prefix. filter: > .groups | map(select(.id | startswith("registry."))) From f930e80da9cb03814b39c50c9f99b1b4248accbe Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Mon, 29 Apr 2024 17:50:12 -0700 Subject: [PATCH 14/39] chore(forge): Fix clippy issue --- Cargo.lock | 16 ++++++++-------- crates/weaver_forge/src/extensions/code.rs | 5 ++++- crates/weaver_forge/src/lib.rs | 1 + src/registry/generate.rs | 7 ++----- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 791e0d49..566457f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -619,9 +619,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.29" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4556222738635b7a3417ae6130d8f52201e45a0c4d1a907f0826383adb5f85e7" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "miniz_oxide", @@ -1539,9 +1539,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", "allocator-api2", @@ -1931,9 +1931,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" [[package]] name = "libm" @@ -2929,9 +2929,9 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "socket2" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", diff --git a/crates/weaver_forge/src/extensions/code.rs b/crates/weaver_forge/src/extensions/code.rs index b2611e41..aac60848 100644 --- a/crates/weaver_forge/src/extensions/code.rs +++ b/crates/weaver_forge/src/extensions/code.rs @@ -83,7 +83,10 @@ This also covers UDP network interactions where one side initiates the interacti assert_eq!(filter(&Value::from("double")), Value::from("f64")); assert_eq!(filter(&Value::from("string")), Value::from("String")); assert_eq!(filter(&Value::from("boolean")), Value::from("bool")); - assert_eq!(filter(&Value::from("something else")), Value::from("something else")); + assert_eq!( + filter(&Value::from("something else")), + Value::from("something else") + ); assert_eq!(filter(&Value::from(12)), Value::from(12)); } } diff --git a/crates/weaver_forge/src/lib.rs b/crates/weaver_forge/src/lib.rs index df447ca4..b7fbffd0 100644 --- a/crates/weaver_forge/src/lib.rs +++ b/crates/weaver_forge/src/lib.rs @@ -57,6 +57,7 @@ impl Default for GeneratorConfig { impl GeneratorConfig { /// Create a new generator configuration with the given root directory. + #[must_use] pub fn new(root_dir: PathBuf) -> Self { Self { root_dir } } diff --git a/src/registry/generate.rs b/src/registry/generate.rs index d87ab4e1..5a76697e 100644 --- a/src/registry/generate.rs +++ b/src/registry/generate.rs @@ -80,11 +80,8 @@ pub(crate) fn command( let schema = resolve_semconv_specs(&mut registry, logger.clone()); let config = GeneratorConfig::new(args.templates.clone()); - let engine = TemplateEngine::try_new( - &format!("registry/{}", args.target), - config, - ) - .exit_if_error(logger.clone()); + let engine = TemplateEngine::try_new(&format!("registry/{}", args.target), config) + .exit_if_error(logger.clone()); let template_registry = TemplateRegistry::try_from_resolved_registry( schema From 30876fc845a6bb71e1c8373f6094af920635bf32 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Mon, 29 Apr 2024 23:19:24 -0700 Subject: [PATCH 15/39] chore(forge): Add experimental and deprecated attributes in the generated code. --- .../weaver_forge/allowed-external-types.toml | 1 + .../codegen_examples/expected_codegen/lib.rs | 2 + .../codegen_examples/expected_codegen/net.rs | 134 ++++++++++++++++++ .../templates/registry/rust/weaver.yaml | 68 +++++++-- 4 files changed, 191 insertions(+), 14 deletions(-) create mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/net.rs diff --git a/crates/weaver_forge/allowed-external-types.toml b/crates/weaver_forge/allowed-external-types.toml index 07f5e8b9..4333d3a1 100644 --- a/crates/weaver_forge/allowed-external-types.toml +++ b/crates/weaver_forge/allowed-external-types.toml @@ -9,4 +9,5 @@ allowed_external_types = [ "weaver_common::*", "weaver_resolved_schema::*", "weaver_semconv::*", + "minijinja::value::Value", ] \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/lib.rs b/crates/weaver_forge/codegen_examples/expected_codegen/lib.rs index 170f234b..b997ff69 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/lib.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/lib.rs @@ -15,6 +15,8 @@ pub mod client; 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; /// 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 new file mode 100644 index 00000000..477f41f2 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/expected_codegen/net.rs @@ -0,0 +1,134 @@ +/* + * 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/templates/registry/rust/weaver.yaml b/crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml index 3227521f..7b3d872e 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml @@ -24,18 +24,7 @@ templates: id, type, brief, - prefix, - attributes: (.attributes - | map(select(.stability == "experimental" and .deprecated | not)))}) - | map(select(.attributes | length > 0)) - | map( - { - id, - type, - brief, - prefix - } - ) + prefix}) | unique_by(.prefix) | sort_by(.prefix) application_mode: single @@ -56,7 +45,58 @@ templates: type, brief, prefix, - attributes: (.attributes | map(select(.stability == "experimental" and .deprecated | not)))}) + attributes}) | sort_by(.prefix // empty) - | map(select(.attributes | length > 0)) application_mode: each + +# Other examples of filters + +# The following JQ filter extracts the id, type, brief, and prefix of groups matching the following criteria: +# - groups with an id starting with the prefix `registry.` +# - groups of the type `attribute_group`. +# - groups with a well-defined prefix. +# - groups with a non-empty list of attributes that are neither deprecated nor experimental. +# - groups are deduplicated by prefix. +# - groups are sorted by prefix. +# filter: > +# .groups +# | map(select(.id | startswith("registry."))) +# | map(select(.type == "attribute_group" and .prefix != null and .prefix != "") +# | { +# id, +# type, +# brief, +# prefix, +# attributes: (.attributes +# | map(select(.stability == "experimental" and .deprecated | not)))}) +# | map(select(.attributes | length > 0)) +# | map( +# { +# id, +# type, +# brief, +# prefix +# } +# ) +# | unique_by(.prefix) +# | sort_by(.prefix) + + +# The following JQ filter extracts the id, type, brief, prefix, and attributes of groups matching the following +# criteria: +# - groups with an id starting with the prefix `registry.` +# - groups of the type `attribute_group`. +# - groups with a well-defined prefix. +# - groups with a non-empty list of attributes that are neither deprecated nor experimental. +# - groups are sorted by prefix. +# filter: > +# .groups +# | map(select(.id | startswith("registry."))) +# | map(select(.type == "attribute_group" and .prefix != null and .prefix != "") +# | { +# id, +# type, +# brief, +# prefix, +# attributes: (.attributes | map(select(.stability == "experimental" and .deprecated | not)))}) +# | sort_by(.prefix // empty) \ No newline at end of file From 9483d63349c12aaa53da99c3a6002f6eaab7aef9 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Tue, 30 Apr 2024 08:54:15 -0700 Subject: [PATCH 16/39] feat(forge): Add enum string representation support. --- .../templates/registry/rust/README.md | 20 +++++++++++++++ .../registry/rust/semantic_attributes.rs.j2 | 25 +++++++++++++++++++ .../templates/registry/rust/weaver.yaml | 3 +++ 3 files changed, 48 insertions(+) create mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/README.md diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/README.md b/crates/weaver_forge/codegen_examples/templates/registry/rust/README.md new file mode 100644 index 00000000..e5f4ef77 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/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/templates/registry/rust/semantic_attributes.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/semantic_attributes.rs.j2 index 3fe80687..a9000b34 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 @@ -36,6 +36,7 @@ use crate::AttributeKey; {% 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 %} {%- if attribute.brief %} {{ attribute.brief | comment_with_prefix("/// ") }} @@ -50,5 +51,29 @@ pub enum {{ attribute.name | pascal_case }} { {{ variant.id | pascal_case }}, {% endfor %} } + +impl {{ attribute.name | pascal_case }} { + /// Returns the string representation of the [`{{ attribute.name | pascal_case }}`]. + pub fn as_str(&self) -> &'static str { + match self { + {%- for variant in attribute.type.members %} + {%- if variant is experimental %} + #[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. + _ => unreachable!(), + } + } +} + +impl core::fmt::Display for {{ attribute.name | pascal_case }} { + /// Formats the value using the given formatter. + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } +} {% endif %} {% endfor %} \ No newline at end of file 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 7b3d872e..c451b703 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml @@ -8,6 +8,9 @@ type_mapping: template[string[]]: Vec # Not yet properly handled in codegen templates: + - pattern: README.md + filter: . + application_mode: single - pattern: lib.rs.j2 # The following JQ filter extracts the id, type, brief, and prefix of groups matching the following criteria: # - groups with an id starting with the prefix `registry.` From e2e2df1ac292633b873d8319938bebe15c53151f Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Tue, 30 Apr 2024 11:36:35 -0700 Subject: [PATCH 17/39] feat(forge): Use attribute registry namespace instead of group prefix. --- .../expected_codegen/README.md | 20 ++ .../expected_codegen/client.rs | 9 +- .../expected_codegen/exception.rs | 15 +- .../codegen_examples/expected_codegen/http.rs | 93 ++++++-- .../codegen_examples/expected_codegen/lib.rs | 2 +- .../codegen_examples/expected_codegen/net.rs | 134 ------------ .../expected_codegen/network.rs | 200 ++++++++++++++++++ .../templates/registry/rust/lib.rs.j2 | 2 +- .../registry/rust/semantic_attributes.rs.j2 | 18 +- .../templates/registry/rust/weaver.yaml | 12 +- crates/weaver_forge/src/extensions/mod.rs | 2 +- .../src/extensions/{test.rs => otel.rs} | 120 ++++++++++- crates/weaver_forge/src/lib.rs | 25 ++- 13 files changed, 464 insertions(+), 188 deletions(-) create mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/README.md delete mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/net.rs create mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/network.rs rename crates/weaver_forge/src/extensions/{test.rs => otel.rs} (53%) 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); From 8f6826bae5d4221453f56c66b696379de629665f Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Tue, 30 Apr 2024 23:35:39 -0700 Subject: [PATCH 18/39] feat(forge): Generate metrics and attributes --- .../{ => attributes}/client.rs | 6 +- .../expected_codegen/attributes/error.rs | 64 +++ .../{ => attributes}/exception.rs | 10 +- .../expected_codegen/{ => attributes}/http.rs | 26 +- .../expected_codegen/attributes/mod.rs | 74 ++++ .../expected_codegen/attributes/network.rs | 407 ++++++++++++++++++ .../expected_codegen/attributes/server.rs | 25 ++ .../expected_codegen/attributes/url.rs | 116 +++++ .../codegen_examples/expected_codegen/lib.rs | 62 +-- .../expected_codegen/metrics/http.rs | 213 +++++++++ .../expected_codegen/metrics/mod.rs | 11 + .../expected_codegen/network.rs | 200 --------- .../mini_registry/http-common.yaml | 87 ++++ .../mini_registry/metrics/http.yaml | 192 +++++++++ .../mini_registry/{ => registry}/client.yaml | 0 .../{ => registry}/deprecated/network.yaml | 0 .../mini_registry/registry/error.yaml | 40 ++ .../{ => registry}/exception.yaml | 0 .../mini_registry/{ => registry}/http.yaml | 0 .../mini_registry/registry/network.yaml | 235 ++++++++++ .../mini_registry/registry/server.yaml | 28 ++ .../mini_registry/registry/url.yaml | 116 +++++ .../attributes.rs.j2} | 10 +- .../rust/{lib.rs.j2 => attributes/mod.rs.j2} | 6 +- .../templates/registry/rust/lib.rs | 13 + .../registry/rust/metrics/counter.j2 | 25 ++ .../templates/registry/rust/metrics/gauge.j2 | 39 ++ .../registry/rust/metrics/histogram.j2 | 25 ++ .../registry/rust/metrics/metrics.rs.j2 | 21 + .../templates/registry/rust/metrics/mod.rs.j2 | 14 + .../registry/rust/metrics/updowncounter.j2 | 25 ++ .../templates/registry/rust/weaver.yaml | 59 ++- crates/weaver_forge/src/extensions/otel.rs | 36 +- crates/weaver_forge/src/lib.rs | 1 + 34 files changed, 1885 insertions(+), 301 deletions(-) rename crates/weaver_forge/codegen_examples/expected_codegen/{ => attributes}/client.rs (81%) create mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/attributes/error.rs rename crates/weaver_forge/codegen_examples/expected_codegen/{ => attributes}/exception.rs (75%) rename crates/weaver_forge/codegen_examples/expected_codegen/{ => attributes}/http.rs (82%) create mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/attributes/mod.rs create mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/attributes/network.rs create mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/attributes/server.rs create mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/attributes/url.rs create mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/metrics/http.rs create mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/metrics/mod.rs delete mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/network.rs create mode 100644 crates/weaver_forge/codegen_examples/mini_registry/http-common.yaml create mode 100644 crates/weaver_forge/codegen_examples/mini_registry/metrics/http.yaml rename crates/weaver_forge/codegen_examples/mini_registry/{ => registry}/client.yaml (100%) rename crates/weaver_forge/codegen_examples/mini_registry/{ => registry}/deprecated/network.yaml (100%) create mode 100644 crates/weaver_forge/codegen_examples/mini_registry/registry/error.yaml rename crates/weaver_forge/codegen_examples/mini_registry/{ => registry}/exception.yaml (100%) rename crates/weaver_forge/codegen_examples/mini_registry/{ => registry}/http.yaml (100%) create mode 100644 crates/weaver_forge/codegen_examples/mini_registry/registry/network.yaml create mode 100644 crates/weaver_forge/codegen_examples/mini_registry/registry/server.yaml create mode 100644 crates/weaver_forge/codegen_examples/mini_registry/registry/url.yaml rename crates/weaver_forge/codegen_examples/templates/registry/rust/{semantic_attributes.rs.j2 => attributes/attributes.rs.j2} (81%) rename crates/weaver_forge/codegen_examples/templates/registry/rust/{lib.rs.j2 => attributes/mod.rs.j2} (90%) create mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/lib.rs create mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/counter.j2 create mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/gauge.j2 create mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 create mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 create mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/mod.rs.j2 create mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/updowncounter.j2 diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/client.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/client.rs similarity index 81% rename from crates/weaver_forge/codegen_examples/expected_codegen/client.rs rename to crates/weaver_forge/codegen_examples/expected_codegen/attributes/client.rs index edec5e7c..d0c1918e 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/client.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/client.rs @@ -4,14 +4,14 @@ */ //! 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 +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/attributes/attributes.rs.j2 /// 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: crate::AttributeKey = crate::AttributeKey::new("client.address"); +pub const CLIENT_ADDRESS: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("client.address"); @@ -20,6 +20,6 @@ pub const CLIENT_ADDRESS: crate::AttributeKey = crat /// /// 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: crate::AttributeKey = crate::AttributeKey::new("client.port"); +pub const CLIENT_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("client.port"); diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/error.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/error.rs new file mode 100644 index 00000000..07f0eb33 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/error.rs @@ -0,0 +1,64 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! This document defines the shared attributes used to report an error. +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/attributes/attributes.rs.j2 + + +/// Describes a class of error the operation ended with. +/// +/// Notes: +/// The `error.type` SHOULD be predictable, and SHOULD have low cardinality. +/// +/// When `error.type` is set to a type (e.g., an exception type), its +/// canonical class name identifying the type within the artifact SHOULD be used. +/// +/// Instrumentations SHOULD document the list of errors they report. +/// +/// The cardinality of `error.type` within one instrumentation library SHOULD be low. +/// Telemetry consumers that aggregate data from multiple instrumentation libraries and applications +/// should be prepared for `error.type` to have high cardinality at query time when no +/// additional filters are applied. +/// +/// If the operation has completed successfully, instrumentations SHOULD NOT set `error.type`. +/// +/// If a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes), +/// it's RECOMMENDED to: +/// +/// * Use a domain-specific attribute +/// * Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. +pub const ERROR_TYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("error.type"); + + + +/// Describes a class of error the operation ended with. +#[non_exhaustive] +pub enum ErrorType { + /// A fallback error value to be used when the instrumentation doesn't define a custom value. + Other, + +} + +impl ErrorType { + /// Returns the string representation of the [`ErrorType`]. + pub fn as_str(&self) -> &'static str { + match self { + ErrorType::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 ErrorType { + /// 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/exception.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/exception.rs similarity index 75% rename from crates/weaver_forge/codegen_examples/expected_codegen/exception.rs rename to crates/weaver_forge/codegen_examples/expected_codegen/attributes/exception.rs index f907c364..76517ba5 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/exception.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/exception.rs @@ -4,23 +4,23 @@ */ //! 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 +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/attributes/attributes.rs.j2 /// 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: crate::AttributeKey = crate::AttributeKey::new("exception.type"); +pub const EXCEPTION_TYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("exception.type"); /// The exception message. -pub const EXCEPTION_MESSAGE: crate::AttributeKey = crate::AttributeKey::new("exception.message"); +pub const EXCEPTION_MESSAGE: crate::attributes::AttributeKey = crate::attributes::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: crate::AttributeKey = crate::AttributeKey::new("exception.stacktrace"); +pub const EXCEPTION_STACKTRACE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("exception.stacktrace"); @@ -44,6 +44,6 @@ pub const EXCEPTION_STACKTRACE: crate::AttributeKey /// 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: crate::AttributeKey = crate::AttributeKey::new("exception.escaped"); +pub const EXCEPTION_ESCAPED: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("exception.escaped"); diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/http.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/http.rs similarity index 82% rename from crates/weaver_forge/codegen_examples/expected_codegen/http.rs rename to crates/weaver_forge/codegen_examples/expected_codegen/attributes/http.rs index ca045c86..2aefb064 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/http.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/http.rs @@ -4,12 +4,12 @@ */ //! 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 +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/attributes/attributes.rs.j2 /// 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: crate::AttributeKey = crate::AttributeKey::new("http.request.body.size"); +pub const HTTP_REQUEST_BODY_SIZE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.request.body.size"); @@ -19,7 +19,7 @@ pub const HTTP_REQUEST_BODY_SIZE: crate::AttributeKey = crate::AttributeKey /// 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: crate::AttributeKey> = crate::AttributeKey::new("http.request.header"); +pub const HTTP_REQUEST_HEADER: crate::attributes::AttributeKey> = crate::attributes::AttributeKey::new("http.request.header"); @@ -40,7 +40,7 @@ pub const HTTP_REQUEST_HEADER: crate::AttributeKey> = crate::Attribu /// 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: crate::AttributeKey = crate::AttributeKey::new("http.request.method"); +pub const HTTP_REQUEST_METHOD: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.request.method"); @@ -102,7 +102,7 @@ impl core::fmt::Display for HttpRequestMethod { /// Original HTTP method sent by the client in the request line. -pub const HTTP_REQUEST_METHOD_ORIGINAL: crate::AttributeKey = crate::AttributeKey::new("http.request.method_original"); +pub const HTTP_REQUEST_METHOD_ORIGINAL: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.request.method_original"); @@ -111,19 +111,19 @@ pub const HTTP_REQUEST_METHOD_ORIGINAL: crate::AttributeKey = crate::AttributeKey::new("http.request.resend_count"); +pub const HTTP_REQUEST_RESEND_COUNT: crate::attributes::AttributeKey = crate::attributes::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: crate::AttributeKey = crate::AttributeKey::new("http.request.size"); +pub const HTTP_REQUEST_SIZE: crate::attributes::AttributeKey = crate::attributes::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: crate::AttributeKey = crate::AttributeKey::new("http.response.body.size"); +pub const HTTP_RESPONSE_BODY_SIZE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.response.body.size"); @@ -133,18 +133,18 @@ pub const HTTP_RESPONSE_BODY_SIZE: crate::AttributeKey = crate::AttributeKe /// 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: crate::AttributeKey> = crate::AttributeKey::new("http.response.header"); +pub const HTTP_RESPONSE_HEADER: crate::attributes::AttributeKey> = crate::attributes::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: crate::AttributeKey = crate::AttributeKey::new("http.response.size"); +pub const HTTP_RESPONSE_SIZE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.response.size"); /// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). -pub const HTTP_RESPONSE_STATUS_CODE: crate::AttributeKey = crate::AttributeKey::new("http.response.status_code"); +pub const HTTP_RESPONSE_STATUS_CODE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.response.status_code"); @@ -153,14 +153,14 @@ pub const HTTP_RESPONSE_STATUS_CODE: crate::AttributeKey = crate::Attribute /// 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: crate::AttributeKey = crate::AttributeKey::new("http.route"); +pub const HTTP_ROUTE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.route"); /// State of the HTTP connection in the HTTP connection pool. #[cfg(feature = "semconv_experimental")] -pub const HTTP_CONNECTION_STATE: crate::AttributeKey = crate::AttributeKey::new("http.connection.state"); +pub const HTTP_CONNECTION_STATE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.connection.state"); diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/mod.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/mod.rs new file mode 100644 index 00000000..b3ddedc0 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/mod.rs @@ -0,0 +1,74 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! OpenTelemetry Semantic Convention Attributes +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/attributes/mod.rs.j2 + +use opentelemetry::{Key, KeyValue, StringValue}; + + +/// Attributes for the `client` namespace. +pub mod client; +/// Attributes for the `error` namespace. +pub mod error; +/// Attributes for the `exception` namespace. +pub mod exception; +/// Attributes for the `http` namespace. +pub mod http; +/// Attributes for the `network` namespace. +pub mod network; +/// Attributes for the `server` namespace. +pub mod server; +/// Attributes for the `url` namespace. +pub mod url; + +/// A typed attribute key. +pub struct AttributeKey { + key: Key, + phantom: std::marker::PhantomData +} + +impl AttributeKey { + /// Returns a new [`AttributeKey`] with the given key. + pub(crate) const fn new(key: &'static str) -> AttributeKey { + Self { + key: Key::from_static_str(key), + phantom: std::marker::PhantomData + } + } + + /// Returns the key of the attribute. + pub fn key(&self) -> &Key { + &self.key + } +} + +impl AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: StringValue) -> KeyValue { + KeyValue::new(self.key.clone(), v) + } +} + +impl AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: i64) -> KeyValue { + KeyValue::new(self.key.clone(), v) + } +} + +impl AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: f64) -> KeyValue { + KeyValue::new(self.key.clone(), v) + } +} + +impl AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: bool) -> KeyValue { + KeyValue::new(self.key.clone(), v) + } +} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/network.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/network.rs new file mode 100644 index 00000000..c37f5372 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/network.rs @@ -0,0 +1,407 @@ +/* + * 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/attributes/attributes.rs.j2 + + +/// The ISO 3166-1 alpha-2 2-character country code associated with the mobile carrier network. +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_CARRIER_ICC: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.icc"); + + + + +/// The mobile carrier country code. +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_CARRIER_MCC: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.mcc"); + + + + +/// The mobile carrier network code. +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_CARRIER_MNC: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.mnc"); + + + + +/// The name of the mobile carrier. +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_CARRIER_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.name"); + + + + +/// This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection. +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_CONNECTION_SUBTYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.connection.subtype"); + + + +/// This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection. +#[non_exhaustive] +pub enum NetworkConnectionSubtype { + /// GPRS + #[cfg(feature = "semconv_experimental")] + Gprs, + /// EDGE + #[cfg(feature = "semconv_experimental")] + Edge, + /// UMTS + #[cfg(feature = "semconv_experimental")] + Umts, + /// CDMA + #[cfg(feature = "semconv_experimental")] + Cdma, + /// EVDO Rel. 0 + #[cfg(feature = "semconv_experimental")] + Evdo0, + /// EVDO Rev. A + #[cfg(feature = "semconv_experimental")] + EvdoA, + /// CDMA2000 1XRTT + #[cfg(feature = "semconv_experimental")] + Cdma20001Xrtt, + /// HSDPA + #[cfg(feature = "semconv_experimental")] + Hsdpa, + /// HSUPA + #[cfg(feature = "semconv_experimental")] + Hsupa, + /// HSPA + #[cfg(feature = "semconv_experimental")] + Hspa, + /// IDEN + #[cfg(feature = "semconv_experimental")] + Iden, + /// EVDO Rev. B + #[cfg(feature = "semconv_experimental")] + EvdoB, + /// LTE + #[cfg(feature = "semconv_experimental")] + Lte, + /// EHRPD + #[cfg(feature = "semconv_experimental")] + Ehrpd, + /// HSPAP + #[cfg(feature = "semconv_experimental")] + Hspap, + /// GSM + #[cfg(feature = "semconv_experimental")] + Gsm, + /// TD-SCDMA + #[cfg(feature = "semconv_experimental")] + TdScdma, + /// IWLAN + #[cfg(feature = "semconv_experimental")] + Iwlan, + /// 5G NR (New Radio) + #[cfg(feature = "semconv_experimental")] + Nr, + /// 5G NRNSA (New Radio Non-Standalone) + #[cfg(feature = "semconv_experimental")] + Nrnsa, + /// LTE CA + #[cfg(feature = "semconv_experimental")] + LteCa, + +} + +impl NetworkConnectionSubtype { + /// Returns the string representation of the [`NetworkConnectionSubtype`]. + pub fn as_str(&self) -> &'static str { + match self { + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Gprs => "gprs", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Edge => "edge", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Umts => "umts", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Cdma => "cdma", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Evdo0 => "evdo_0", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::EvdoA => "evdo_a", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Cdma20001Xrtt => "cdma2000_1xrtt", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Hsdpa => "hsdpa", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Hsupa => "hsupa", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Hspa => "hspa", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Iden => "iden", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::EvdoB => "evdo_b", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Lte => "lte", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Ehrpd => "ehrpd", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Hspap => "hspap", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Gsm => "gsm", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::TdScdma => "td_scdma", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Iwlan => "iwlan", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Nr => "nr", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Nrnsa => "nrnsa", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::LteCa => "lte_ca", + // 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 NetworkConnectionSubtype { + /// Formats the value using the given formatter. + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } +} + + +/// The internet connection type. +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_CONNECTION_TYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.connection.type"); + + + +/// The internet connection type. +#[non_exhaustive] +pub enum NetworkConnectionType { + + #[cfg(feature = "semconv_experimental")] + Wifi, + + #[cfg(feature = "semconv_experimental")] + Wired, + + #[cfg(feature = "semconv_experimental")] + Cell, + + #[cfg(feature = "semconv_experimental")] + Unavailable, + + #[cfg(feature = "semconv_experimental")] + Unknown, + +} + +impl NetworkConnectionType { + /// Returns the string representation of the [`NetworkConnectionType`]. + pub fn as_str(&self) -> &'static str { + match self { + #[cfg(feature = "semconv_experimental")] + NetworkConnectionType::Wifi => "wifi", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionType::Wired => "wired", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionType::Cell => "cell", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionType::Unavailable => "unavailable", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionType::Unknown => "unknown", + // 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 NetworkConnectionType { + /// Formats the value using the given formatter. + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } +} + + +/// Local address of the network connection - IP address or Unix domain socket name. +pub const NETWORK_LOCAL_ADDRESS: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.local.address"); + + + + +/// Local port number of the network connection. +pub const NETWORK_LOCAL_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.local.port"); + + + +/// Peer address of the network connection - IP address or Unix domain socket name. +pub const NETWORK_PEER_ADDRESS: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.peer.address"); + + + + +/// Peer port number of the network connection. +pub const NETWORK_PEER_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.peer.port"); + + + +/// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. +/// +/// Notes: +/// The value SHOULD be normalized to lowercase. +pub const NETWORK_PROTOCOL_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.protocol.name"); + + + + +/// The actual version of the protocol used for network communication. +/// +/// Notes: +/// If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, this attribute SHOULD NOT be set. +pub const NETWORK_PROTOCOL_VERSION: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.protocol.version"); + + + + +/// [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). +/// +/// Notes: +/// The value SHOULD be normalized to lowercase. +/// +/// Consider always setting the transport when setting a port number, since +/// a port number is ambiguous without knowing the transport. For example +/// different processes could be listening on TCP port 12345 and UDP port 12345. +pub const NETWORK_TRANSPORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.transport"); + + + +/// [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). +#[non_exhaustive] +pub enum NetworkTransport { + /// TCP + Tcp, + /// UDP + Udp, + /// Named or anonymous pipe. + Pipe, + /// Unix domain socket + Unix, + +} + +impl NetworkTransport { + /// Returns the string representation of the [`NetworkTransport`]. + pub fn as_str(&self) -> &'static str { + match self { + NetworkTransport::Tcp => "tcp", + NetworkTransport::Udp => "udp", + NetworkTransport::Pipe => "pipe", + NetworkTransport::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 NetworkTransport { + /// Formats the value using the given formatter. + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } +} + + +/// [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. +/// +/// Notes: +/// The value SHOULD be normalized to lowercase. +pub const NETWORK_TYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.type"); + + + +/// [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. +#[non_exhaustive] +pub enum NetworkType { + /// IPv4 + Ipv4, + /// IPv6 + Ipv6, + +} + +impl NetworkType { + /// Returns the string representation of the [`NetworkType`]. + pub fn as_str(&self) -> &'static str { + match self { + NetworkType::Ipv4 => "ipv4", + NetworkType::Ipv6 => "ipv6", + // 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 NetworkType { + /// Formats the value using the given formatter. + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } +} + + +/// The network IO operation direction. +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_IO_DIRECTION: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.io.direction"); + + + +/// The network IO operation direction. +#[non_exhaustive] +pub enum NetworkIoDirection { + + #[cfg(feature = "semconv_experimental")] + Transmit, + + #[cfg(feature = "semconv_experimental")] + Receive, + +} + +impl NetworkIoDirection { + /// Returns the string representation of the [`NetworkIoDirection`]. + pub fn as_str(&self) -> &'static str { + match self { + #[cfg(feature = "semconv_experimental")] + NetworkIoDirection::Transmit => "transmit", + #[cfg(feature = "semconv_experimental")] + NetworkIoDirection::Receive => "receive", + // 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 NetworkIoDirection { + /// 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/attributes/server.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/server.rs new file mode 100644 index 00000000..e9ca9c55 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/server.rs @@ -0,0 +1,25 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! These attributes may be used to describe the server 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/attributes/attributes.rs.j2 + + +/// Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. +/// +/// Notes: +/// When observed from the client side, and when communicating through an intermediary, `server.address` SHOULD represent the server address behind any intermediaries, for example proxies, if it's available. +pub const SERVER_ADDRESS: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("server.address"); + + + + +/// Server port number. +/// +/// Notes: +/// When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent the server port behind any intermediaries, for example proxies, if it's available. +pub const SERVER_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("server.port"); + + diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/url.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/url.rs new file mode 100644 index 00000000..5f4daa72 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/url.rs @@ -0,0 +1,116 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Attributes describing URL. +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/attributes/attributes.rs.j2 + + +/// Domain extracted from the `url.full`, such as "opentelemetry.io". +/// +/// Notes: +/// In some cases a URL may refer to an IP and/or port directly, without a domain name. In this case, the IP address would go to the domain field. If the URL contains a [literal IPv6 address](https://www.rfc-editor.org/rfc/rfc2732#section-2) enclosed by `[` and `]`, the `[` and `]` characters should also be captured in the domain field. +#[cfg(feature = "semconv_experimental")] +pub const URL_DOMAIN: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.domain"); + + + + +/// The file extension extracted from the `url.full`, excluding the leading dot. +/// +/// Notes: +/// The file extension is only set if it exists, as not every url has a file extension. When the file name has multiple extensions `example.tar.gz`, only the last one should be captured `gz`, not `tar.gz`. +#[cfg(feature = "semconv_experimental")] +pub const URL_EXTENSION: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.extension"); + + + + +/// The [URI fragment](https://www.rfc-editor.org/rfc/rfc3986#section-3.5) component +pub const URL_FRAGMENT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.fragment"); + + + + +/// Absolute URL describing a network resource according to [RFC3986](https://www.rfc-editor.org/rfc/rfc3986) +/// +/// Notes: +/// For network calls, URL usually has `scheme://host[:port][path][?query][#fragment]` format, where the fragment is not transmitted over HTTP, but if it is known, it SHOULD be included nevertheless. +/// `url.full` MUST NOT contain credentials passed via URL in form of `https://username:password@www.example.com/`. In such case username and password SHOULD be redacted and attribute's value SHOULD be `https://REDACTED:REDACTED@www.example.com/`. +/// `url.full` SHOULD capture the absolute URL when it is available (or can be reconstructed). Sensitive content provided in `url.full` SHOULD be scrubbed when instrumentations can identify it. +pub const URL_FULL: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.full"); + + + + +/// Unmodified original URL as seen in the event source. +/// +/// Notes: +/// In network monitoring, the observed URL may be a full URL, whereas in access logs, the URL is often just represented as a path. This field is meant to represent the URL as it was observed, complete or not. +/// `url.original` might contain credentials passed via URL in form of `https://username:password@www.example.com/`. In such case password and username SHOULD NOT be redacted and attribute's value SHOULD remain the same. +#[cfg(feature = "semconv_experimental")] +pub const URL_ORIGINAL: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.original"); + + + + +/// The [URI path](https://www.rfc-editor.org/rfc/rfc3986#section-3.3) component +/// +/// Notes: +/// Sensitive content provided in `url.path` SHOULD be scrubbed when instrumentations can identify it. +pub const URL_PATH: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.path"); + + + + +/// Port extracted from the `url.full` +#[cfg(feature = "semconv_experimental")] +pub const URL_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.port"); + + + +/// The [URI query](https://www.rfc-editor.org/rfc/rfc3986#section-3.4) component +/// +/// Notes: +/// Sensitive content provided in `url.query` SHOULD be scrubbed when instrumentations can identify it. +pub const URL_QUERY: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.query"); + + + + +/// The highest registered url domain, stripped of the subdomain. +/// +/// Notes: +/// This value can be determined precisely with the [public suffix list](http://publicsuffix.org). For example, the registered domain for `foo.example.com` is `example.com`. Trying to approximate this by simply taking the last two labels will not work well for TLDs such as `co.uk`. +#[cfg(feature = "semconv_experimental")] +pub const URL_REGISTERED_DOMAIN: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.registered_domain"); + + + + +/// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. +pub const URL_SCHEME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.scheme"); + + + + +/// The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. +/// +/// Notes: +/// The subdomain portion of `www.east.mydomain.co.uk` is `east`. If the domain has multiple levels of subdomain, such as `sub2.sub1.example.com`, the subdomain field should contain `sub2.sub1`, with no trailing period. +#[cfg(feature = "semconv_experimental")] +pub const URL_SUBDOMAIN: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.subdomain"); + + + + +/// The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is `com`. +/// +/// Notes: +/// This value can be determined precisely with the [public suffix list](http://publicsuffix.org). +#[cfg(feature = "semconv_experimental")] +pub const URL_TOP_LEVEL_DOMAIN: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.top_level_domain"); + + + diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/lib.rs b/crates/weaver_forge/codegen_examples/expected_codegen/lib.rs index 35c0717c..ae1281bf 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/lib.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/lib.rs @@ -6,63 +6,5 @@ //! OpenTelemetry Semantic Convention Attributes //! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 -use opentelemetry::{Key, KeyValue, StringValue}; - - -/// 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. -pub mod client; -/// This document defines the shared attributes used to report a single exception associated with a span or log. -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 network; - -/// A typed attribute key. -pub struct AttributeKey { - key: Key, - phantom: std::marker::PhantomData -} - -impl AttributeKey { - /// Returns a new [`AttributeKey`] with the given key. - pub(crate) const fn new(key: &'static str) -> AttributeKey { - Self { - key: Key::from_static_str(key), - phantom: std::marker::PhantomData - } - } - - /// Returns the key of the attribute. - pub fn key(&self) -> &Key { - &self.key - } -} - -impl AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: StringValue) -> KeyValue { - KeyValue::new(self.key.clone(), v) - } -} - -impl AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: i64) -> KeyValue { - KeyValue::new(self.key.clone(), v) - } -} - -impl AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: f64) -> KeyValue { - KeyValue::new(self.key.clone(), v) - } -} - -impl AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: bool) -> KeyValue { - KeyValue::new(self.key.clone(), v) - } -} \ No newline at end of file +pub mod attributes; +pub mod metrics; diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/metrics/http.rs b/crates/weaver_forge/codegen_examples/expected_codegen/metrics/http.rs new file mode 100644 index 00000000..74ec64db --- /dev/null +++ b/crates/weaver_forge/codegen_examples/expected_codegen/metrics/http.rs @@ -0,0 +1,213 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/metrics/metrics.rs.j2 + + + +/// Duration of HTTP server requests. +pub fn create_u64_http_server_request_duration(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { + meter.u64_histogram("http.server.request.duration") + .with_description("Duration of HTTP server requests.") + .with_unit(opentelemetry::metrics::Unit::new("s")) + .init() +} + + +/// Duration of HTTP server requests. +pub fn create_f64_http_server_request_duration(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { + meter.f64_histogram("http.server.request.duration") + .with_description("Duration of HTTP server requests.") + .with_unit(opentelemetry::metrics::Unit::new("s")) + .init() +} + + + +/// Number of active HTTP server requests. +#[cfg(feature = "semconv_experimental")] +pub fn create_i64_http_server_active_requests(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter { + meter.i64_up_down_counter("http.server.active_requests") + .with_description("Number of active HTTP server requests.") + .with_unit(opentelemetry::metrics::Unit::new("{request}")) + .init() +} + + +/// Number of active HTTP server requests. +#[cfg(feature = "semconv_experimental")] +pub fn create_f64_http_server_active_requests(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter { + meter.f64_up_down_counter("http.server.active_requests") + .with_description("Number of active HTTP server requests.") + .with_unit(opentelemetry::metrics::Unit::new("{request}")) + .init() +} + + + +/// Size of HTTP server request bodies. +#[cfg(feature = "semconv_experimental")] +pub fn create_u64_http_server_request_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { + meter.u64_histogram("http.server.request.body.size") + .with_description("Size of HTTP server request bodies.") + .with_unit(opentelemetry::metrics::Unit::new("By")) + .init() +} + + +/// Size of HTTP server request bodies. +#[cfg(feature = "semconv_experimental")] +pub fn create_f64_http_server_request_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { + meter.f64_histogram("http.server.request.body.size") + .with_description("Size of HTTP server request bodies.") + .with_unit(opentelemetry::metrics::Unit::new("By")) + .init() +} + + + +/// Size of HTTP server response bodies. +#[cfg(feature = "semconv_experimental")] +pub fn create_u64_http_server_response_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { + meter.u64_histogram("http.server.response.body.size") + .with_description("Size of HTTP server response bodies.") + .with_unit(opentelemetry::metrics::Unit::new("By")) + .init() +} + + +/// Size of HTTP server response bodies. +#[cfg(feature = "semconv_experimental")] +pub fn create_f64_http_server_response_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { + meter.f64_histogram("http.server.response.body.size") + .with_description("Size of HTTP server response bodies.") + .with_unit(opentelemetry::metrics::Unit::new("By")) + .init() +} + + + +/// Duration of HTTP client requests. +pub fn create_u64_http_client_request_duration(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { + meter.u64_histogram("http.client.request.duration") + .with_description("Duration of HTTP client requests.") + .with_unit(opentelemetry::metrics::Unit::new("s")) + .init() +} + + +/// Duration of HTTP client requests. +pub fn create_f64_http_client_request_duration(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { + meter.f64_histogram("http.client.request.duration") + .with_description("Duration of HTTP client requests.") + .with_unit(opentelemetry::metrics::Unit::new("s")) + .init() +} + + + +/// Size of HTTP client request bodies. +#[cfg(feature = "semconv_experimental")] +pub fn create_u64_http_client_request_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { + meter.u64_histogram("http.client.request.body.size") + .with_description("Size of HTTP client request bodies.") + .with_unit(opentelemetry::metrics::Unit::new("By")) + .init() +} + + +/// Size of HTTP client request bodies. +#[cfg(feature = "semconv_experimental")] +pub fn create_f64_http_client_request_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { + meter.f64_histogram("http.client.request.body.size") + .with_description("Size of HTTP client request bodies.") + .with_unit(opentelemetry::metrics::Unit::new("By")) + .init() +} + + + +/// Size of HTTP client response bodies. +#[cfg(feature = "semconv_experimental")] +pub fn create_u64_http_client_response_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { + meter.u64_histogram("http.client.response.body.size") + .with_description("Size of HTTP client response bodies.") + .with_unit(opentelemetry::metrics::Unit::new("By")) + .init() +} + + +/// Size of HTTP client response bodies. +#[cfg(feature = "semconv_experimental")] +pub fn create_f64_http_client_response_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { + meter.f64_histogram("http.client.response.body.size") + .with_description("Size of HTTP client response bodies.") + .with_unit(opentelemetry::metrics::Unit::new("By")) + .init() +} + + + +/// Number of outbound HTTP connections that are currently active or idle on the client. +#[cfg(feature = "semconv_experimental")] +pub fn create_i64_http_client_open_connections(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter { + meter.i64_up_down_counter("http.client.open_connections") + .with_description("Number of outbound HTTP connections that are currently active or idle on the client.") + .with_unit(opentelemetry::metrics::Unit::new("{connection}")) + .init() +} + + +/// Number of outbound HTTP connections that are currently active or idle on the client. +#[cfg(feature = "semconv_experimental")] +pub fn create_f64_http_client_open_connections(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter { + meter.f64_up_down_counter("http.client.open_connections") + .with_description("Number of outbound HTTP connections that are currently active or idle on the client.") + .with_unit(opentelemetry::metrics::Unit::new("{connection}")) + .init() +} + + + +/// The duration of the successfully established outbound HTTP connections. +#[cfg(feature = "semconv_experimental")] +pub fn create_u64_http_client_connection_duration(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { + meter.u64_histogram("http.client.connection.duration") + .with_description("The duration of the successfully established outbound HTTP connections.") + .with_unit(opentelemetry::metrics::Unit::new("s")) + .init() +} + + +/// The duration of the successfully established outbound HTTP connections. +#[cfg(feature = "semconv_experimental")] +pub fn create_f64_http_client_connection_duration(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { + meter.f64_histogram("http.client.connection.duration") + .with_description("The duration of the successfully established outbound HTTP connections.") + .with_unit(opentelemetry::metrics::Unit::new("s")) + .init() +} + + + +/// Number of active HTTP requests. +#[cfg(feature = "semconv_experimental")] +pub fn create_i64_http_client_active_requests(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter { + meter.i64_up_down_counter("http.client.active_requests") + .with_description("Number of active HTTP requests.") + .with_unit(opentelemetry::metrics::Unit::new("{request}")) + .init() +} + + +/// Number of active HTTP requests. +#[cfg(feature = "semconv_experimental")] +pub fn create_f64_http_client_active_requests(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter { + meter.f64_up_down_counter("http.client.active_requests") + .with_description("Number of active HTTP requests.") + .with_unit(opentelemetry::metrics::Unit::new("{request}")) + .init() +} + diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/metrics/mod.rs b/crates/weaver_forge/codegen_examples/expected_codegen/metrics/mod.rs new file mode 100644 index 00000000..4137fa8e --- /dev/null +++ b/crates/weaver_forge/codegen_examples/expected_codegen/metrics/mod.rs @@ -0,0 +1,11 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! OpenTelemetry Semantic Convention Metrics +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/metrics/mod.rs.j2 + + +/// Metrics for the `http` namespace. +pub mod http; \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/network.rs b/crates/weaver_forge/codegen_examples/expected_codegen/network.rs deleted file mode 100644 index ba6f96da..00000000 --- a/crates/weaver_forge/codegen_examples/expected_codegen/network.rs +++ /dev/null @@ -1,200 +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 - - -/// 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/mini_registry/http-common.yaml b/crates/weaver_forge/codegen_examples/mini_registry/http-common.yaml new file mode 100644 index 00000000..f175215f --- /dev/null +++ b/crates/weaver_forge/codegen_examples/mini_registry/http-common.yaml @@ -0,0 +1,87 @@ +groups: + - id: attributes.http.common + type: attribute_group + brief: "Describes HTTP attributes." + attributes: + - ref: http.request.method + requirement_level: required + - ref: http.response.status_code + requirement_level: + conditionally_required: If and only if one was received/sent. + - ref: error.type + requirement_level: + conditionally_required: If request has ended with an error. + examples: ['timeout', 'java.net.UnknownHostException', 'server_certificate_invalid', '500'] + note: | + If the request fails with an error before response status code was sent or received, + `error.type` SHOULD be set to exception type (its fully-qualified class name, if applicable) + or a component-specific low cardinality error identifier. + + If response status code was sent or received and status indicates an error according to [HTTP span status definition](/docs/http/http-spans.md), + `error.type` SHOULD be set to the status code number (represented as a string), an exception type (if thrown) or a component-specific error identifier. + + The `error.type` value SHOULD be predictable and SHOULD have low cardinality. + Instrumentations SHOULD document the list of errors they report. + + The cardinality of `error.type` within one instrumentation library SHOULD be low, but + telemetry consumers that aggregate data from multiple instrumentation libraries and applications + should be prepared for `error.type` to have high cardinality at query time, when no + additional filters are applied. + + If the request has completed successfully, instrumentations SHOULD NOT set `error.type`. + - ref: network.protocol.name + examples: ['http', 'spdy'] + requirement_level: + conditionally_required: If not `http` and `network.protocol.version` is set. + - ref: network.protocol.version + examples: ['1.0', '1.1', '2', '3'] + + - id: attributes.http.client + type: attribute_group + brief: 'HTTP Client attributes' + extends: attributes.http.common + attributes: + - ref: server.address + requirement_level: required + brief: > + Host identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. + note: > + If an HTTP client request is explicitly made to an IP address, e.g. `http://x.x.x.x:8080`, then + `server.address` SHOULD be the IP address `x.x.x.x`. A DNS lookup SHOULD NOT be used. + - ref: server.port + requirement_level: required + brief: > + Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. + - ref: url.scheme + requirement_level: opt_in + examples: ["http", "https"] + + - id: attributes.http.server + type: attribute_group + brief: 'HTTP Server attributes' + extends: attributes.http.common + attributes: + - ref: http.route + requirement_level: + conditionally_required: If and only if it's available + - ref: server.address + brief: > + Name of the local HTTP server that received the request. + note: > + See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). + - ref: server.port + brief: > + Port of the local HTTP server that received the request. + note: > + See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). + requirement_level: + conditionally_required: If `server.address` is set. + - ref: url.scheme + requirement_level: required + examples: ["http", "https"] + note: > + The scheme of the original client request, if known + (e.g. from [Forwarded#proto](https://developer.mozilla.org/docs/Web/HTTP/Headers/Forwarded#proto), + [X-Forwarded-Proto](https://developer.mozilla.org/docs/Web/HTTP/Headers/X-Forwarded-Proto), + or a similar header). + Otherwise, the scheme of the immediate peer request. \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/mini_registry/metrics/http.yaml b/crates/weaver_forge/codegen_examples/mini_registry/metrics/http.yaml new file mode 100644 index 00000000..3172c9e9 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/mini_registry/metrics/http.yaml @@ -0,0 +1,192 @@ +groups: + - id: metric_attributes.http.server + type: attribute_group + brief: 'HTTP server attributes' + extends: attributes.http.server + attributes: + - ref: server.address + requirement_level: opt_in + note: | + See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). + > **Warning** + > Since this attribute is based on HTTP headers, opting in to it may allow an attacker + > to trigger cardinality limits, degrading the usefulness of the metric. + - ref: server.port + requirement_level: opt_in + note: | + See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). + > **Warning** + > Since this attribute is based on HTTP headers, opting in to it may allow an attacker + > to trigger cardinality limits, degrading the usefulness of the metric. + - id: metric_attributes.http.client + type: attribute_group + brief: 'HTTP client attributes' + extends: attributes.http.client + + - id: metric.http.server.request.duration + type: metric + metric_name: http.server.request.duration + brief: "Duration of HTTP server requests." + instrument: histogram + unit: "s" + stability: stable + extends: metric_attributes.http.server + + - id: metric.http.server.active_requests + type: metric + metric_name: http.server.active_requests + stability: experimental + brief: "Number of active HTTP server requests." + instrument: updowncounter + unit: "{request}" + attributes: + - ref: http.request.method + requirement_level: required + - ref: url.scheme + requirement_level: required + examples: ["http", "https"] + - ref: server.address + requirement_level: opt_in + brief: > + Name of the local HTTP server that received the request. + note: | + See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). + > **Warning** + > Since this attribute is based on HTTP headers, opting in to it may allow an attacker + > to trigger cardinality limits, degrading the usefulness of the metric. + - ref: server.port + requirement_level: opt_in + brief: > + Port of the local HTTP server that received the request. + note: | + See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). + > **Warning** + > Since this attribute is based on HTTP headers, opting in to it may allow an attacker + > to trigger cardinality limits, degrading the usefulness of the metric. + + - id: metric.http.server.request.body.size + type: metric + metric_name: http.server.request.body.size + stability: experimental + brief: "Size of HTTP server request bodies." + instrument: histogram + unit: "By" + note: > + 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. + extends: metric_attributes.http.server + + - id: metric.http.server.response.body.size + type: metric + metric_name: http.server.response.body.size + stability: experimental + brief: "Size of HTTP server response bodies." + instrument: histogram + unit: "By" + note: > + 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. + extends: metric_attributes.http.server + + - id: metric.http.client.request.duration + type: metric + metric_name: http.client.request.duration + brief: "Duration of HTTP client requests." + instrument: histogram + unit: "s" + stability: stable + extends: metric_attributes.http.client + + - id: metric.http.client.request.body.size + type: metric + metric_name: http.client.request.body.size + stability: experimental + brief: "Size of HTTP client request bodies." + instrument: histogram + unit: "By" + note: > + 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. + extends: metric_attributes.http.client + + - id: metric.http.client.response.body.size + type: metric + metric_name: http.client.response.body.size + stability: experimental + brief: "Size of HTTP client response bodies." + instrument: histogram + unit: "By" + note: > + 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. + extends: metric_attributes.http.client + + - id: metric.http.client.open_connections + type: metric + metric_name: http.client.open_connections + stability: experimental + brief: "Number of outbound HTTP connections that are currently active or idle on the client." + instrument: updowncounter + unit: "{connection}" + attributes: + - ref: http.connection.state + requirement_level: required + - ref: network.peer.address + requirement_level: recommended + - ref: network.protocol.version + requirement_level: recommended + - ref: server.address + requirement_level: required + - ref: server.port + requirement_level: required + brief: > + Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. + - ref: url.scheme + requirement_level: opt_in + examples: ["http", "https"] + + - id: metric.http.client.connection.duration + type: metric + metric_name: http.client.connection.duration + stability: experimental + brief: "The duration of the successfully established outbound HTTP connections." + instrument: histogram + unit: "s" + attributes: + - ref: network.peer.address + requirement_level: recommended + - ref: network.protocol.version + requirement_level: recommended + - ref: server.address + requirement_level: required + - ref: server.port + requirement_level: required + brief: > + Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. + - ref: url.scheme + requirement_level: opt_in + examples: ["http", "https"] + + - id: metric.http.client.active_requests + type: metric + metric_name: http.client.active_requests + stability: experimental + brief: "Number of active HTTP requests." + instrument: updowncounter + unit: "{request}" + attributes: + - ref: http.request.method + requirement_level: recommended + - ref: server.address + requirement_level: required + - ref: server.port + requirement_level: required + brief: > + Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. + - ref: url.scheme + requirement_level: opt_in + examples: ["http", "https"] \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/mini_registry/client.yaml b/crates/weaver_forge/codegen_examples/mini_registry/registry/client.yaml similarity index 100% rename from crates/weaver_forge/codegen_examples/mini_registry/client.yaml rename to crates/weaver_forge/codegen_examples/mini_registry/registry/client.yaml diff --git a/crates/weaver_forge/codegen_examples/mini_registry/deprecated/network.yaml b/crates/weaver_forge/codegen_examples/mini_registry/registry/deprecated/network.yaml similarity index 100% rename from crates/weaver_forge/codegen_examples/mini_registry/deprecated/network.yaml rename to crates/weaver_forge/codegen_examples/mini_registry/registry/deprecated/network.yaml diff --git a/crates/weaver_forge/codegen_examples/mini_registry/registry/error.yaml b/crates/weaver_forge/codegen_examples/mini_registry/registry/error.yaml new file mode 100644 index 00000000..621022f6 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/mini_registry/registry/error.yaml @@ -0,0 +1,40 @@ +groups: + - id: registry.error + type: attribute_group + prefix: error + brief: > + This document defines the shared attributes used to report an error. + attributes: + - id: type + stability: stable + brief: > + Describes a class of error the operation ended with. + type: + allow_custom_values: true + members: + - id: other + value: "_OTHER" + stability: stable + brief: > + A fallback error value to be used when the instrumentation doesn't define a custom value. + examples: ['timeout', 'java.net.UnknownHostException', 'server_certificate_invalid', '500'] + note: | + The `error.type` SHOULD be predictable, and SHOULD have low cardinality. + + When `error.type` is set to a type (e.g., an exception type), its + canonical class name identifying the type within the artifact SHOULD be used. + + Instrumentations SHOULD document the list of errors they report. + + The cardinality of `error.type` within one instrumentation library SHOULD be low. + Telemetry consumers that aggregate data from multiple instrumentation libraries and applications + should be prepared for `error.type` to have high cardinality at query time when no + additional filters are applied. + + If the operation has completed successfully, instrumentations SHOULD NOT set `error.type`. + + If a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes), + it's RECOMMENDED to: + + * Use a domain-specific attribute + * Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/mini_registry/exception.yaml b/crates/weaver_forge/codegen_examples/mini_registry/registry/exception.yaml similarity index 100% rename from crates/weaver_forge/codegen_examples/mini_registry/exception.yaml rename to crates/weaver_forge/codegen_examples/mini_registry/registry/exception.yaml diff --git a/crates/weaver_forge/codegen_examples/mini_registry/http.yaml b/crates/weaver_forge/codegen_examples/mini_registry/registry/http.yaml similarity index 100% rename from crates/weaver_forge/codegen_examples/mini_registry/http.yaml rename to crates/weaver_forge/codegen_examples/mini_registry/registry/http.yaml diff --git a/crates/weaver_forge/codegen_examples/mini_registry/registry/network.yaml b/crates/weaver_forge/codegen_examples/mini_registry/registry/network.yaml new file mode 100644 index 00000000..591a0188 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/mini_registry/registry/network.yaml @@ -0,0 +1,235 @@ +groups: + - id: registry.network + prefix: network + type: attribute_group + brief: > + These attributes may be used for any network related operation. + attributes: + - id: carrier.icc + type: string + stability: experimental + brief: "The ISO 3166-1 alpha-2 2-character country code associated with the mobile carrier network." + examples: "DE" + - id: carrier.mcc + type: string + stability: experimental + brief: "The mobile carrier country code." + examples: "310" + - id: carrier.mnc + type: string + stability: experimental + brief: "The mobile carrier network code." + examples: "001" + - id: carrier.name + type: string + stability: experimental + brief: "The name of the mobile carrier." + examples: "sprint" + - id: connection.subtype + type: + allow_custom_values: true + members: + - id: gprs + brief: GPRS + value: "gprs" + stability: experimental + - id: edge + brief: EDGE + value: "edge" + stability: experimental + - id: umts + brief: UMTS + value: "umts" + stability: experimental + - id: cdma + brief: CDMA + value: "cdma" + stability: experimental + - id: evdo_0 + brief: EVDO Rel. 0 + value: "evdo_0" + stability: experimental + - id: evdo_a + brief: "EVDO Rev. A" + value: "evdo_a" + stability: experimental + - id: cdma2000_1xrtt + brief: CDMA2000 1XRTT + value: "cdma2000_1xrtt" + stability: experimental + - id: hsdpa + brief: HSDPA + value: "hsdpa" + stability: experimental + - id: hsupa + brief: HSUPA + value: "hsupa" + stability: experimental + - id: hspa + brief: HSPA + value: "hspa" + stability: experimental + - id: iden + brief: IDEN + value: "iden" + stability: experimental + - id: evdo_b + brief: "EVDO Rev. B" + value: "evdo_b" + stability: experimental + - id: lte + brief: LTE + value: "lte" + stability: experimental + - id: ehrpd + brief: EHRPD + value: "ehrpd" + stability: experimental + - id: hspap + brief: HSPAP + value: "hspap" + stability: experimental + - id: gsm + brief: GSM + value: "gsm" + stability: experimental + - id: td_scdma + brief: TD-SCDMA + value: "td_scdma" + stability: experimental + - id: iwlan + brief: IWLAN + value: "iwlan" + stability: experimental + - id: nr + brief: "5G NR (New Radio)" + value: "nr" + stability: experimental + - id: nrnsa + brief: "5G NRNSA (New Radio Non-Standalone)" + value: "nrnsa" + stability: experimental + - id: lte_ca + brief: LTE CA + value: "lte_ca" + stability: experimental + stability: experimental + brief: 'This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection.' + examples: 'LTE' + - id: connection.type + type: + allow_custom_values: true + members: + - id: wifi + value: "wifi" + stability: experimental + - id: wired + value: "wired" + stability: experimental + - id: cell + value: "cell" + stability: experimental + - id: unavailable + value: "unavailable" + stability: experimental + - id: unknown + value: "unknown" + stability: experimental + stability: experimental + brief: 'The internet connection type.' + examples: 'wifi' + - id: local.address + stability: stable + type: string + brief: Local address of the network connection - IP address or Unix domain socket name. + examples: ['10.1.2.80', '/tmp/my.sock'] + - id: local.port + stability: stable + type: int + brief: Local port number of the network connection. + examples: [65123] + - id: peer.address + stability: stable + type: string + brief: Peer address of the network connection - IP address or Unix domain socket name. + examples: ['10.1.2.80', '/tmp/my.sock'] + - id: peer.port + stability: stable + type: int + brief: Peer port number of the network connection. + examples: [65123] + - id: protocol.name + stability: stable + type: string + brief: '[OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent.' + note: The value SHOULD be normalized to lowercase. + examples: ['amqp', 'http', 'mqtt'] + - id: protocol.version + stability: stable + type: string + brief: The actual version of the protocol used for network communication. + examples: ['1.1', '2'] + note: > + If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), + this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, + this attribute SHOULD NOT be set. + - id: transport + stability: stable + type: + allow_custom_values: true + members: + - id: tcp + value: 'tcp' + brief: "TCP" + stability: stable + - id: udp + value: 'udp' + brief: "UDP" + stability: stable + - id: pipe + value: "pipe" + brief: 'Named or anonymous pipe.' + stability: stable + - id: unix + value: 'unix' + brief: "Unix domain socket" + stability: stable + brief: > + [OSI transport layer](https://osi-model.com/transport-layer/) or + [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). + note: | + The value SHOULD be normalized to lowercase. + + Consider always setting the transport when setting a port number, since + a port number is ambiguous without knowing the transport. For example + different processes could be listening on TCP port 12345 and UDP port 12345. + examples: ['tcp', 'udp'] + - id: type + stability: stable + type: + allow_custom_values: true + members: + - id: ipv4 + value: 'ipv4' + brief: "IPv4" + stability: stable + - id: ipv6 + value: 'ipv6' + brief: "IPv6" + stability: stable + brief: '[OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent.' + note: The value SHOULD be normalized to lowercase. + examples: ['ipv4', 'ipv6'] + - id: io.direction + type: + allow_custom_values: false + members: + - id: transmit + value: 'transmit' + stability: experimental + - id: receive + value: 'receive' + stability: experimental + stability: experimental + brief: "The network IO operation direction." + examples: ["transmit"] \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/mini_registry/registry/server.yaml b/crates/weaver_forge/codegen_examples/mini_registry/registry/server.yaml new file mode 100644 index 00000000..0afe3fab --- /dev/null +++ b/crates/weaver_forge/codegen_examples/mini_registry/registry/server.yaml @@ -0,0 +1,28 @@ +groups: + - id: registry.server + prefix: server + type: attribute_group + brief: > + These attributes may be used to describe the server 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. + attributes: + - id: address + stability: stable + type: string + brief: "Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name." + note: > + When observed from the client side, and when communicating through an intermediary, `server.address` SHOULD represent + the server address behind any intermediaries, for example proxies, if it's available. + examples: ['example.com', '10.1.2.80', '/tmp/my.sock'] + - id: port + stability: stable + type: int + brief: Server port number. + note: > + When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent + the server port behind any intermediaries, for example proxies, if it's available. + examples: [80, 8080, 443] \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/mini_registry/registry/url.yaml b/crates/weaver_forge/codegen_examples/mini_registry/registry/url.yaml new file mode 100644 index 00000000..7c132dae --- /dev/null +++ b/crates/weaver_forge/codegen_examples/mini_registry/registry/url.yaml @@ -0,0 +1,116 @@ +groups: + - id: registry.url + brief: Attributes describing URL. + type: attribute_group + prefix: url + attributes: + - id: domain + type: string + stability: experimental + brief: > + Domain extracted from the `url.full`, such as "opentelemetry.io". + note: > + In some cases a URL may refer to an IP and/or port directly, + without a domain name. In this case, the IP address would go to the domain field. + If the URL contains a [literal IPv6 address](https://www.rfc-editor.org/rfc/rfc2732#section-2) + enclosed by `[` and `]`, the `[` and `]` characters should also be captured in the domain field. + examples: ["www.foo.bar", "opentelemetry.io", "3.12.167.2", "[1080:0:0:0:8:800:200C:417A]"] + - id: extension + type: string + stability: experimental + brief: > + The file extension extracted from the `url.full`, excluding the leading dot. + note: > + The file extension is only set if it exists, as not every url has a file extension. + When the file name has multiple extensions `example.tar.gz`, only the last one should be captured `gz`, not `tar.gz`. + examples: [ "png", "gz" ] + - id: fragment + stability: stable + type: string + brief: > + The [URI fragment](https://www.rfc-editor.org/rfc/rfc3986#section-3.5) component + examples: ["SemConv"] + - id: full + stability: stable + type: string + brief: Absolute URL describing a network resource according to [RFC3986](https://www.rfc-editor.org/rfc/rfc3986) + note: > + For network calls, URL usually has `scheme://host[:port][path][?query][#fragment]` format, where the fragment + is not transmitted over HTTP, but if it is known, it SHOULD be included nevertheless. + + `url.full` MUST NOT contain credentials passed via URL in form of `https://username:password@www.example.com/`. + In such case username and password SHOULD be redacted and attribute's value SHOULD be `https://REDACTED:REDACTED@www.example.com/`. + + `url.full` SHOULD capture the absolute URL when it is available (or can be reconstructed). + Sensitive content provided in `url.full` SHOULD be scrubbed when instrumentations can identify it. + examples: ['https://www.foo.bar/search?q=OpenTelemetry#SemConv', '//localhost'] + - id: original + type: string + stability: experimental + brief: > + Unmodified original URL as seen in the event source. + note: > + In network monitoring, the observed URL may be a full URL, whereas in access logs, the URL is often + just represented as a path. This field is meant to represent the URL as it was observed, complete or not. + + `url.original` might contain credentials passed via URL in form of `https://username:password@www.example.com/`. + In such case password and username SHOULD NOT be redacted and attribute's value SHOULD remain the same. + examples: ["https://www.foo.bar/search?q=OpenTelemetry#SemConv", "search?q=OpenTelemetry"] + - id: path + stability: stable + type: string + brief: > + The [URI path](https://www.rfc-editor.org/rfc/rfc3986#section-3.3) component + examples: ["/search"] + note: > + Sensitive content provided in `url.path` SHOULD be scrubbed when instrumentations can identify it. + - id: port + type: int + stability: experimental + brief: > + Port extracted from the `url.full` + examples: [443] + - id: query + stability: stable + type: string + brief: > + The [URI query](https://www.rfc-editor.org/rfc/rfc3986#section-3.4) component + examples: ["q=OpenTelemetry"] + note: > + Sensitive content provided in `url.query` SHOULD be scrubbed when instrumentations can identify it. + - id: registered_domain + type: string + stability: experimental + brief: > + The highest registered url domain, stripped of the subdomain. + examples: ["example.com", "foo.co.uk"] + note: > + This value can be determined precisely with the [public suffix list](http://publicsuffix.org). + For example, the registered domain for `foo.example.com` is `example.com`. + Trying to approximate this by simply taking the last two labels will not work well for TLDs such as `co.uk`. + - id: scheme + stability: stable + type: string + brief: > + The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. + examples: ["https", "ftp", "telnet"] + - id: subdomain + type: string + stability: experimental + brief: > + The subdomain portion of a fully qualified domain name includes all of the names except the host name + under the registered_domain. In a partially qualified domain, or if the qualification level of the + full name cannot be determined, subdomain contains all of the names below the registered domain. + examples: ["east", "sub2.sub1"] + note: > + The subdomain portion of `www.east.mydomain.co.uk` is `east`. If the domain has multiple levels of subdomain, + such as `sub2.sub1.example.com`, the subdomain field should contain `sub2.sub1`, with no trailing period. + - id: top_level_domain + type: string + stability: experimental + brief: > + The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. + For example, the top level domain for example.com is `com`. + examples: ["com", "co.uk"] + note: > + This value can be determined precisely with the [public suffix list](http://publicsuffix.org). \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/semantic_attributes.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 similarity index 81% rename from crates/weaver_forge/codegen_examples/templates/registry/rust/semantic_attributes.rs.j2 rename to crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 index 1f8f55d0..36813a3d 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/semantic_attributes.rs.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 @@ -1,5 +1,5 @@ {%- set file_name = ctx.id | attribute_registry_namespace | snake_case -%} -{{- template.set_file_name(file_name ~ ".rs") -}} +{{- template.set_file_name("attributes/" ~ file_name ~ ".rs") -}} /* * Copyright The OpenTelemetry Authors @@ -12,7 +12,7 @@ //! Notes: {{ ctx.note | comment_with_prefix("/// ") }} {%- endif %} -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/attributes/attributes.rs.j2 {% for attribute in ctx.attributes %} @@ -30,9 +30,9 @@ {%- if attribute is deprecated %} #[deprecated(note="{{ attribute.deprecated }}")] {%- 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 %}pub const {{ attribute.name | screaming_snake_case }}: crate::attributes::AttributeKey<{{ attribute.name | pascal_case }}> = crate::attributes::AttributeKey::new("{{ attribute.name }}"); +{% elif attribute.type == "string" %}pub const {{ attribute.name | screaming_snake_case }}: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("{{ attribute.name }}"); +{% else %}pub const {{ attribute.name | screaming_snake_case }}: crate::attributes::AttributeKey<{{ attribute.type | type_mapping }}> = crate::attributes::AttributeKey::new("{{ attribute.name }}");{% endif %} {% if attribute.type.allow_custom_values is defined %} {%- if attribute.brief %} diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/lib.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/mod.rs.j2 similarity index 90% rename from crates/weaver_forge/codegen_examples/templates/registry/rust/lib.rs.j2 rename to crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/mod.rs.j2 index d16af4cd..7a1d419e 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/lib.rs.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/mod.rs.j2 @@ -1,4 +1,4 @@ -{{- template.set_file_name("lib.rs") -}} +{{- template.set_file_name("attributes/mod.rs") -}} /* * Copyright The OpenTelemetry Authors @@ -6,12 +6,12 @@ */ //! OpenTelemetry Semantic Convention Attributes -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/attributes/mod.rs.j2 use opentelemetry::{Key, KeyValue, StringValue}; {% for group in ctx %} -{{ group.brief | comment_with_prefix("/// ") }} +/// Attributes for the `{{ group.id | attribute_registry_namespace }}` namespace. pub mod {{ group.id | attribute_registry_namespace | snake_case }}; {%- endfor %} diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/lib.rs b/crates/weaver_forge/codegen_examples/templates/registry/rust/lib.rs new file mode 100644 index 00000000..529fc3b2 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/lib.rs @@ -0,0 +1,13 @@ +{{- template.set_file_name("lib.rs") -}} + +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! OpenTelemetry Semantic Convention Attributes +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 + +pub mod attributes; +pub mod metrics; + diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/counter.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/counter.j2 new file mode 100644 index 00000000..e0f9a7a0 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/counter.j2 @@ -0,0 +1,25 @@ +{%- if metric.brief %} +{{ metric.brief | comment_with_prefix("/// ") }} +{%- endif %} +{%- if metric is experimental %} +#[cfg(feature = "semconv_experimental")] +{%- endif %} +pub fn create_u64_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Counter { + meter.u64_counter("{{ metric.metric_name }}") + .with_description("{{ metric.brief }}") + .with_unit(opentelemetry::metrics::Unit::new("{{ metric.unit }}")) + .init() +} + +{% if metric.brief %} +{{ metric.brief | comment_with_prefix("/// ") }} +{%- endif %} +{%- if metric is experimental %} +#[cfg(feature = "semconv_experimental")] +{%- endif %} +pub fn create_f64_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Counter { + meter.f64_counter("{{ metric.metric_name }}") + .with_description("{{ metric.brief }}") + .with_unit(opentelemetry::metrics::Unit::new("{{ metric.unit }}")) + .init() +} diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/gauge.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/gauge.j2 new file mode 100644 index 00000000..1b8fea10 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/gauge.j2 @@ -0,0 +1,39 @@ +{%- if metric.brief %} +{{ metric.brief | comment_with_prefix("/// ") }} +{%- endif %} +{%- if metric is experimental %} +#[cfg(feature = "semconv_experimental")] +{%- endif %} +pub fn create_u64_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Gauge { + meter.u64_gauge("{{ metric.metric_name }}") + .with_description("{{ metric.brief }}") + .with_unit(opentelemetry::metrics::Unit::new("{{ metric.unit }}")) + .init() +} + +{% if metric.brief %} +{{ metric.brief | comment_with_prefix("/// ") }} +{%- endif %} +{%- if metric is experimental %} +#[cfg(feature = "semconv_experimental")] +{%- endif %} +pub fn create_i64_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Gauge { + meter.i64_gauge("{{ metric.metric_name }}") + .with_description("{{ metric.brief }}") + .with_unit(opentelemetry::metrics::Unit::new("{{ metric.unit }}")) + .init() +} + + +{% if metric.brief %} +{{ metric.brief | comment_with_prefix("/// ") }} +{%- endif %} +{%- if metric is experimental %} +#[cfg(feature = "semconv_experimental")] +{%- endif %} +pub fn create_f64_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Gauge { + meter.f64_gauge("{{ metric.metric_name }}") + .with_description("{{ metric.brief }}") + .with_unit(opentelemetry::metrics::Unit::new("{{ metric.unit }}")) + .init() +} diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 new file mode 100644 index 00000000..d32a5bfb --- /dev/null +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 @@ -0,0 +1,25 @@ +{%- if metric.brief %} +{{ metric.brief | comment_with_prefix("/// ") }} +{%- endif %} +{%- if metric is experimental %} +#[cfg(feature = "semconv_experimental")] +{%- endif %} +pub fn create_u64_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { + meter.u64_histogram("{{ metric.metric_name }}") + .with_description("{{ metric.brief }}") + .with_unit(opentelemetry::metrics::Unit::new("{{ metric.unit }}")) + .init() +} + +{% if metric.brief %} +{{ metric.brief | comment_with_prefix("/// ") }} +{%- endif %} +{%- if metric is experimental %} +#[cfg(feature = "semconv_experimental")] +{%- endif %} +pub fn create_f64_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { + meter.f64_histogram("{{ metric.metric_name }}") + .with_description("{{ metric.brief }}") + .with_unit(opentelemetry::metrics::Unit::new("{{ metric.unit }}")) + .init() +} diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 new file mode 100644 index 00000000..c2a1fa13 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 @@ -0,0 +1,21 @@ +{%- set file_name = ctx.prefix | snake_case -%} +{{- template.set_file_name("metrics/" ~ file_name ~ ".rs") -}} + +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/metrics/metrics.rs.j2 + +{% for metric in ctx.groups %} +{% if metric.instrument == "histogram" %} +{%- include "metrics/histogram.j2" %} +{% elif metric.instrument == "counter" %} +{%- include "metrics/counter.j2" %} +{% elif metric.instrument == "gauge" %} +{%- include "metrics/gauge.j2" %} +{% elif metric.instrument == "updowncounter" %} +{%- include "metrics/updowncounter.j2" %} +{% endif %} +{% endfor %} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/mod.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/mod.rs.j2 new file mode 100644 index 00000000..f574f857 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/mod.rs.j2 @@ -0,0 +1,14 @@ +{{- template.set_file_name("metrics/mod.rs") -}} + +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! OpenTelemetry Semantic Convention Metrics +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/metrics/mod.rs.j2 + +{% for group in ctx %} +/// Metrics for the `{{ group.id | metric_namespace }}` namespace. +pub mod {{ group.id | metric_namespace | snake_case }}; +{%- endfor %} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/updowncounter.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/updowncounter.j2 new file mode 100644 index 00000000..1786e0e6 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/updowncounter.j2 @@ -0,0 +1,25 @@ +{%- if metric.brief %} +{{ metric.brief | comment_with_prefix("/// ") }} +{%- endif %} +{%- if metric is experimental %} +#[cfg(feature = "semconv_experimental")] +{%- endif %} +pub fn create_i64_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter { + meter.i64_up_down_counter("{{ metric.metric_name }}") + .with_description("{{ metric.brief }}") + .with_unit(opentelemetry::metrics::Unit::new("{{ metric.unit }}")) + .init() +} + +{% if metric.brief %} +{{ metric.brief | comment_with_prefix("/// ") }} +{%- endif %} +{%- if metric is experimental %} +#[cfg(feature = "semconv_experimental")] +{%- endif %} +pub fn create_f64_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter { + meter.f64_up_down_counter("{{ metric.metric_name }}") + .with_description("{{ metric.brief }}") + .with_unit(opentelemetry::metrics::Unit::new("{{ metric.unit }}")) + .init() +} 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 77be059d..dd2e0ec4 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml @@ -11,18 +11,21 @@ templates: - pattern: README.md filter: . application_mode: single - - pattern: lib.rs.j2 + - pattern: lib.rs + filter: . + application_mode: single + + # Templates for the `attribute_group` group type + - pattern: attributes/mod.rs.j2 # The following JQ filter extracts the id, type, brief, and prefix of groups matching the following criteria: # - groups with an id starting with the prefix `registry.` # - groups of the type `attribute_group`. - # - groups with a well-defined prefix. - # - groups with a non-empty list of attributes that are neither deprecated nor experimental. - # - groups are deduplicated by prefix. - # - groups are sorted by prefix. + # - groups are deduplicated by namespace. + # - groups are sorted by namespace. filter: > .groups | map(select(.id | startswith("registry."))) - | map(select(.type == "attribute_group" and .prefix != null and .prefix != "") + | map(select(.type == "attribute_group") | { id, type, @@ -31,18 +34,16 @@ templates: | unique_by(.id | split(".") | .[1]) | sort_by(.id | split(".") | .[1]) application_mode: single - - pattern: semantic_attributes.rs.j2 + - pattern: attributes/attributes.rs.j2 # The following JQ filter extracts the id, type, brief, prefix, and attributes of groups matching the following # criteria: # - groups with an id starting with the prefix `registry.` # - groups of the type `attribute_group`. - # - groups with a well-defined prefix. - # - groups with a non-empty list of attributes that are neither deprecated nor experimental. - # - groups are sorted by prefix. + # - groups are sorted by namespace. filter: > .groups | map(select(.id | startswith("registry."))) - | map(select(.type == "attribute_group" and .prefix != null and .prefix != "") + | map(select(.type == "attribute_group") | { id, type, @@ -52,6 +53,42 @@ templates: | sort_by(.id | split(".") | .[1]) application_mode: each + # Templates for the `metric` group type + - pattern: metrics/mod.rs.j2 + # The following JQ filter extracts the id, type, brief, and prefix of groups matching the following criteria: + # - groups with an id starting with the prefix `metric.` + # - groups of the type `metric`. + # - groups are deduplicated by namespace. + # - groups are sorted by prefix. + filter: > + .groups + | map(select(.id | startswith("metric."))) + | map(select(.type == "metric") + | { + id, + type, + brief, + prefix}) + | unique_by(.id | split(".") | .[1]) + | sort_by(.id | split(".") | .[1]) + application_mode: single + - pattern: metrics/metrics.rs.j2 + # The following JQ filter extracts the id, type, brief, prefix, and attributes of groups matching the following + # criteria: + # - groups with an id starting with the prefix `metric.` + # - groups of the type `metric`. + # - groups are sorted by namespace. + filter: > + .groups + | map(select(.id | startswith("metric."))) + | group_by(.id | split(".") | .[1]) + | map({ + prefix: .[0].id | split(".") | .[1], + groups: . + }) + application_mode: each + + # .groups # | map(select(.type == "attribute_group")) # | map(select(.id | startswith("registry"))) diff --git a/crates/weaver_forge/src/extensions/otel.rs b/crates/weaver_forge/src/extensions/otel.rs index b8db0f42..ced47faa 100644 --- a/crates/weaver_forge/src/extensions/otel.rs +++ b/crates/weaver_forge/src/extensions/otel.rs @@ -53,6 +53,21 @@ pub(crate) fn attribute_registry_file(input: &str) -> Result Result { + let parts: Vec<&str> = input.split('.').collect(); + if parts.len() < 2 || parts[0] != "metric" { + return Err(minijinja::Error::new( + ErrorKind::InvalidOperation, + format!("This metric id `{}` is invalid", input), + )); + } + Ok(parts[1].to_owned()) +} + /// Checks if the input value is an object with a field named "stability" that has the value "stable". /// Otherwise, it returns false. #[must_use] @@ -99,7 +114,7 @@ pub(crate) fn is_deprecated(input: Value) -> bool { mod tests { use crate::extensions::otel::{ attribute_registry_file, attribute_registry_namespace, attribute_registry_title, - is_deprecated, is_experimental, is_stable, + is_deprecated, is_experimental, is_stable, metric_namespace, }; use minijinja::value::StructObject; use minijinja::Value; @@ -198,6 +213,25 @@ mod tests { assert!(attribute_registry_file(input).is_err()); } + #[test] + fn test_metric_namespace() { + // A string that does not start with "registry" + let input = "test"; + assert!(metric_namespace(input).is_err()); + + // A string that starts with "registry" but does not have at least two parts + let input = "metric"; + assert!(metric_namespace(input).is_err()); + + // A string that starts with "registry" and has at least two parts + let input = "metric.namespace.other.components"; + assert_eq!(metric_namespace(input).unwrap(), "namespace"); + + // An empty string + let input = ""; + assert!(metric_namespace(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 b6189803..947c1464 100644 --- a/crates/weaver_forge/src/lib.rs +++ b/crates/weaver_forge/src/lib.rs @@ -404,6 +404,7 @@ impl TemplateEngine { "attribute_registry_file", extensions::otel::attribute_registry_file, ); + env.add_filter("metric_namespace", extensions::otel::metric_namespace); // 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); From 48403fc0ce9c141d77afb2a02e60dda713c5d426 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Thu, 2 May 2024 14:05:51 -0700 Subject: [PATCH 19/39] feat(forge): Generate type-safe API for metrics --- .../expected_codegen/attributes/error.rs | 1 + .../expected_codegen/attributes/http.rs | 2 + .../expected_codegen/attributes/network.rs | 5 + .../expected_codegen/metrics/http.rs | 416 ++++++++++++------ .../expected_codegen/metrics/mod.rs | 58 ++- .../registry/rust/attributes/attributes.rs.j2 | 3 +- .../registry/rust/metrics/histogram.j2 | 82 +++- .../registry/rust/metrics/metrics.rs.j2 | 12 +- .../templates/registry/rust/metrics/mod.rs.j2 | 58 ++- .../registry/rust/metrics/updowncounter.j2 | 23 +- crates/weaver_forge/src/extensions/otel.rs | 15 + crates/weaver_forge/src/lib.rs | 1 + 12 files changed, 493 insertions(+), 183 deletions(-) diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/error.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/error.rs index 07f0eb33..521c8111 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/error.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/error.rs @@ -34,6 +34,7 @@ pub const ERROR_TYPE: crate::attributes::AttributeKey = crate::attrib /// Describes a class of error the operation ended with. +#[derive(Debug, Clone)] #[non_exhaustive] pub enum ErrorType { /// A fallback error value to be used when the instrumentation doesn't define a custom value. diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/http.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/http.rs index 2aefb064..57aead25 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/http.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/http.rs @@ -45,6 +45,7 @@ pub const HTTP_REQUEST_METHOD: crate::attributes::AttributeKey = /// [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). +#[derive(Debug, Clone)] #[non_exhaustive] pub enum NetworkTransport { /// TCP @@ -331,6 +334,7 @@ pub const NETWORK_TYPE: crate::attributes::AttributeKey = crate::at /// [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. +#[derive(Debug, Clone)] #[non_exhaustive] pub enum NetworkType { /// IPv4 @@ -370,6 +374,7 @@ pub const NETWORK_IO_DIRECTION: crate::attributes::AttributeKey opentelemetry::metrics::Histogram { - meter.u64_histogram("http.server.request.duration") - .with_description("Duration of HTTP server requests.") - .with_unit(opentelemetry::metrics::Unit::new("s")) - .init() +pub fn create_http_server_request_duration(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram + where opentelemetry::metrics::Meter: HistogramProvider { + meter.create_histogram("http.server.request.duration", "Duration of HTTP server requests.", "s") } - -/// Duration of HTTP server requests. -pub fn create_f64_http_server_request_duration(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { - meter.f64_histogram("http.server.request.duration") - .with_description("Duration of HTTP server requests.") - .with_unit(opentelemetry::metrics::Unit::new("s")) - .init() +/// Metric: http.server.request.duration +/// Brief: Duration of HTTP server requests. +/// Unit: s +#[derive(Debug)] +pub struct HttpServerRequestDuration(opentelemetry::metrics::Histogram); + +/// Attributes for the `http.server.request.duration` metric. +#[derive(Debug, Clone)] +pub struct HttpServerRequestDurationAttributes { + /// HTTP request method. + pub http_request_method: crate::attributes::http::HttpRequestMethod, + /// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). + pub http_response_status_code: Option, + /// The matched route, that is, the path template in the format used by the respective server framework. + pub http_route: Option, + /// Describes a class of error the operation ended with. + pub error_type: Option, + /// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. + pub network_protocol_name: Option, + /// The actual version of the protocol used for network communication. + pub network_protocol_version: Option, + /// Name of the local HTTP server that received the request. + pub server_address: Option, + /// Port of the local HTTP server that received the request. + pub server_port: Option, + /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. + pub url_scheme: String, + } +impl HttpServerRequestDuration { + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: HistogramProvider{ + Self(meter.create_histogram("http.server.request.duration", "Duration of HTTP server requests.", "s")) + } - -/// Number of active HTTP server requests. -#[cfg(feature = "semconv_experimental")] -pub fn create_i64_http_server_active_requests(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter { - meter.i64_up_down_counter("http.server.active_requests") - .with_description("Number of active HTTP server requests.") - .with_unit(opentelemetry::metrics::Unit::new("{request}")) - .init() + /// Adds an additional value to the distribution. + pub fn record(&self, value: T, attributes: HttpServerRequestDurationAttributes) { + // self.0.record(value, attributes.into()) + } } - /// Number of active HTTP server requests. #[cfg(feature = "semconv_experimental")] -pub fn create_f64_http_server_active_requests(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter { - meter.f64_up_down_counter("http.server.active_requests") - .with_description("Number of active HTTP server requests.") - .with_unit(opentelemetry::metrics::Unit::new("{request}")) - .init() +pub fn create_http_server_active_requests(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter + where opentelemetry::metrics::Meter: UpDownCounterProvider { + meter.create_up_down_counter("http.server.active_requests", "Number of active HTTP server requests.", "{request}") } - - /// Size of HTTP server request bodies. #[cfg(feature = "semconv_experimental")] -pub fn create_u64_http_server_request_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { - meter.u64_histogram("http.server.request.body.size") - .with_description("Size of HTTP server request bodies.") - .with_unit(opentelemetry::metrics::Unit::new("By")) - .init() +pub fn create_http_server_request_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram + where opentelemetry::metrics::Meter: HistogramProvider { + meter.create_histogram("http.server.request.body.size", "Size of HTTP server request bodies.", "By") } - -/// Size of HTTP server request bodies. -#[cfg(feature = "semconv_experimental")] -pub fn create_f64_http_server_request_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { - meter.f64_histogram("http.server.request.body.size") - .with_description("Size of HTTP server request bodies.") - .with_unit(opentelemetry::metrics::Unit::new("By")) - .init() +/// Metric: http.server.request.body.size +/// Brief: Size of HTTP server request bodies. +/// Unit: By +#[derive(Debug)] +pub struct HttpServerRequestBodySize(opentelemetry::metrics::Histogram); + +/// Attributes for the `http.server.request.body.size` metric. +#[derive(Debug, Clone)] +pub struct HttpServerRequestBodySizeAttributes { + /// HTTP request method. + pub http_request_method: crate::attributes::http::HttpRequestMethod, + /// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). + pub http_response_status_code: Option, + /// The matched route, that is, the path template in the format used by the respective server framework. + pub http_route: Option, + /// Describes a class of error the operation ended with. + pub error_type: Option, + /// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. + pub network_protocol_name: Option, + /// The actual version of the protocol used for network communication. + pub network_protocol_version: Option, + /// Name of the local HTTP server that received the request. + pub server_address: Option, + /// Port of the local HTTP server that received the request. + pub server_port: Option, + /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. + pub url_scheme: String, + } +impl HttpServerRequestBodySize { + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: HistogramProvider{ + Self(meter.create_histogram("http.server.request.body.size", "Size of HTTP server request bodies.", "By")) + } - -/// Size of HTTP server response bodies. -#[cfg(feature = "semconv_experimental")] -pub fn create_u64_http_server_response_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { - meter.u64_histogram("http.server.response.body.size") - .with_description("Size of HTTP server response bodies.") - .with_unit(opentelemetry::metrics::Unit::new("By")) - .init() + /// Adds an additional value to the distribution. + pub fn record(&self, value: T, attributes: HttpServerRequestBodySizeAttributes) { + // self.0.record(value, attributes.into()) + } } - /// Size of HTTP server response bodies. #[cfg(feature = "semconv_experimental")] -pub fn create_f64_http_server_response_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { - meter.f64_histogram("http.server.response.body.size") - .with_description("Size of HTTP server response bodies.") - .with_unit(opentelemetry::metrics::Unit::new("By")) - .init() +pub fn create_http_server_response_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram + where opentelemetry::metrics::Meter: HistogramProvider { + meter.create_histogram("http.server.response.body.size", "Size of HTTP server response bodies.", "By") } +/// Metric: http.server.response.body.size +/// Brief: Size of HTTP server response bodies. +/// Unit: By +#[derive(Debug)] +pub struct HttpServerResponseBodySize(opentelemetry::metrics::Histogram); + +/// Attributes for the `http.server.response.body.size` metric. +#[derive(Debug, Clone)] +pub struct HttpServerResponseBodySizeAttributes { + /// HTTP request method. + pub http_request_method: crate::attributes::http::HttpRequestMethod, + /// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). + pub http_response_status_code: Option, + /// The matched route, that is, the path template in the format used by the respective server framework. + pub http_route: Option, + /// Describes a class of error the operation ended with. + pub error_type: Option, + /// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. + pub network_protocol_name: Option, + /// The actual version of the protocol used for network communication. + pub network_protocol_version: Option, + /// Name of the local HTTP server that received the request. + pub server_address: Option, + /// Port of the local HTTP server that received the request. + pub server_port: Option, + /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. + pub url_scheme: String, + +} +impl HttpServerResponseBodySize { + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: HistogramProvider{ + Self(meter.create_histogram("http.server.response.body.size", "Size of HTTP server response bodies.", "By")) + } -/// Duration of HTTP client requests. -pub fn create_u64_http_client_request_duration(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { - meter.u64_histogram("http.client.request.duration") - .with_description("Duration of HTTP client requests.") - .with_unit(opentelemetry::metrics::Unit::new("s")) - .init() + /// Adds an additional value to the distribution. + pub fn record(&self, value: T, attributes: HttpServerResponseBodySizeAttributes) { + // self.0.record(value, attributes.into()) + } } - /// Duration of HTTP client requests. -pub fn create_f64_http_client_request_duration(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { - meter.f64_histogram("http.client.request.duration") - .with_description("Duration of HTTP client requests.") - .with_unit(opentelemetry::metrics::Unit::new("s")) - .init() +pub fn create_http_client_request_duration(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram + where opentelemetry::metrics::Meter: HistogramProvider { + meter.create_histogram("http.client.request.duration", "Duration of HTTP client requests.", "s") } +/// Metric: http.client.request.duration +/// Brief: Duration of HTTP client requests. +/// Unit: s +#[derive(Debug)] +pub struct HttpClientRequestDuration(opentelemetry::metrics::Histogram); + +/// Attributes for the `http.client.request.duration` metric. +#[derive(Debug, Clone)] +pub struct HttpClientRequestDurationAttributes { + /// HTTP request method. + pub http_request_method: crate::attributes::http::HttpRequestMethod, + /// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). + pub http_response_status_code: Option, + /// Describes a class of error the operation ended with. + pub error_type: Option, + /// Host identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. + pub server_address: String, + /// Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. + pub server_port: i64, + /// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. + pub network_protocol_name: Option, + /// The actual version of the protocol used for network communication. + pub network_protocol_version: Option, + /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. + pub url_scheme: Option, + +} +impl HttpClientRequestDuration { + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: HistogramProvider{ + Self(meter.create_histogram("http.client.request.duration", "Duration of HTTP client requests.", "s")) + } -/// Size of HTTP client request bodies. -#[cfg(feature = "semconv_experimental")] -pub fn create_u64_http_client_request_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { - meter.u64_histogram("http.client.request.body.size") - .with_description("Size of HTTP client request bodies.") - .with_unit(opentelemetry::metrics::Unit::new("By")) - .init() + /// Adds an additional value to the distribution. + pub fn record(&self, value: T, attributes: HttpClientRequestDurationAttributes) { + // self.0.record(value, attributes.into()) + } } - /// Size of HTTP client request bodies. #[cfg(feature = "semconv_experimental")] -pub fn create_f64_http_client_request_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { - meter.f64_histogram("http.client.request.body.size") - .with_description("Size of HTTP client request bodies.") - .with_unit(opentelemetry::metrics::Unit::new("By")) - .init() +pub fn create_http_client_request_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram + where opentelemetry::metrics::Meter: HistogramProvider { + meter.create_histogram("http.client.request.body.size", "Size of HTTP client request bodies.", "By") } +/// Metric: http.client.request.body.size +/// Brief: Size of HTTP client request bodies. +/// Unit: By +#[derive(Debug)] +pub struct HttpClientRequestBodySize(opentelemetry::metrics::Histogram); + +/// Attributes for the `http.client.request.body.size` metric. +#[derive(Debug, Clone)] +pub struct HttpClientRequestBodySizeAttributes { + /// HTTP request method. + pub http_request_method: crate::attributes::http::HttpRequestMethod, + /// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). + pub http_response_status_code: Option, + /// Describes a class of error the operation ended with. + pub error_type: Option, + /// Host identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. + pub server_address: String, + /// Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. + pub server_port: i64, + /// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. + pub network_protocol_name: Option, + /// The actual version of the protocol used for network communication. + pub network_protocol_version: Option, + /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. + pub url_scheme: Option, + +} +impl HttpClientRequestBodySize { + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: HistogramProvider{ + Self(meter.create_histogram("http.client.request.body.size", "Size of HTTP client request bodies.", "By")) + } -/// Size of HTTP client response bodies. -#[cfg(feature = "semconv_experimental")] -pub fn create_u64_http_client_response_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { - meter.u64_histogram("http.client.response.body.size") - .with_description("Size of HTTP client response bodies.") - .with_unit(opentelemetry::metrics::Unit::new("By")) - .init() + /// Adds an additional value to the distribution. + pub fn record(&self, value: T, attributes: HttpClientRequestBodySizeAttributes) { + // self.0.record(value, attributes.into()) + } } - /// Size of HTTP client response bodies. #[cfg(feature = "semconv_experimental")] -pub fn create_f64_http_client_response_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { - meter.f64_histogram("http.client.response.body.size") - .with_description("Size of HTTP client response bodies.") - .with_unit(opentelemetry::metrics::Unit::new("By")) - .init() +pub fn create_http_client_response_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram + where opentelemetry::metrics::Meter: HistogramProvider { + meter.create_histogram("http.client.response.body.size", "Size of HTTP client response bodies.", "By") } +/// Metric: http.client.response.body.size +/// Brief: Size of HTTP client response bodies. +/// Unit: By +#[derive(Debug)] +pub struct HttpClientResponseBodySize(opentelemetry::metrics::Histogram); + +/// Attributes for the `http.client.response.body.size` metric. +#[derive(Debug, Clone)] +pub struct HttpClientResponseBodySizeAttributes { + /// HTTP request method. + pub http_request_method: crate::attributes::http::HttpRequestMethod, + /// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). + pub http_response_status_code: Option, + /// Describes a class of error the operation ended with. + pub error_type: Option, + /// Host identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. + pub server_address: String, + /// Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. + pub server_port: i64, + /// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. + pub network_protocol_name: Option, + /// The actual version of the protocol used for network communication. + pub network_protocol_version: Option, + /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. + pub url_scheme: Option, + +} +impl HttpClientResponseBodySize { + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: HistogramProvider{ + Self(meter.create_histogram("http.client.response.body.size", "Size of HTTP client response bodies.", "By")) + } -/// Number of outbound HTTP connections that are currently active or idle on the client. -#[cfg(feature = "semconv_experimental")] -pub fn create_i64_http_client_open_connections(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter { - meter.i64_up_down_counter("http.client.open_connections") - .with_description("Number of outbound HTTP connections that are currently active or idle on the client.") - .with_unit(opentelemetry::metrics::Unit::new("{connection}")) - .init() + /// Adds an additional value to the distribution. + pub fn record(&self, value: T, attributes: HttpClientResponseBodySizeAttributes) { + // self.0.record(value, attributes.into()) + } } - /// Number of outbound HTTP connections that are currently active or idle on the client. #[cfg(feature = "semconv_experimental")] -pub fn create_f64_http_client_open_connections(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter { - meter.f64_up_down_counter("http.client.open_connections") - .with_description("Number of outbound HTTP connections that are currently active or idle on the client.") - .with_unit(opentelemetry::metrics::Unit::new("{connection}")) - .init() +pub fn create_http_client_open_connections(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter + where opentelemetry::metrics::Meter: UpDownCounterProvider { + meter.create_up_down_counter("http.client.open_connections", "Number of outbound HTTP connections that are currently active or idle on the client.", "{connection}") } - - /// The duration of the successfully established outbound HTTP connections. #[cfg(feature = "semconv_experimental")] -pub fn create_u64_http_client_connection_duration(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { - meter.u64_histogram("http.client.connection.duration") - .with_description("The duration of the successfully established outbound HTTP connections.") - .with_unit(opentelemetry::metrics::Unit::new("s")) - .init() +pub fn create_http_client_connection_duration(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram + where opentelemetry::metrics::Meter: HistogramProvider { + meter.create_histogram("http.client.connection.duration", "The duration of the successfully established outbound HTTP connections.", "s") } - -/// The duration of the successfully established outbound HTTP connections. -#[cfg(feature = "semconv_experimental")] -pub fn create_f64_http_client_connection_duration(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { - meter.f64_histogram("http.client.connection.duration") - .with_description("The duration of the successfully established outbound HTTP connections.") - .with_unit(opentelemetry::metrics::Unit::new("s")) - .init() +/// Metric: http.client.connection.duration +/// Brief: The duration of the successfully established outbound HTTP connections. +/// Unit: s +#[derive(Debug)] +pub struct HttpClientConnectionDuration(opentelemetry::metrics::Histogram); + +/// Attributes for the `http.client.connection.duration` metric. +#[derive(Debug, Clone)] +pub struct HttpClientConnectionDurationAttributes { + /// Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. + pub server_port: i64, + /// Peer address of the network connection - IP address or Unix domain socket name. + pub network_peer_address: Option, + /// The actual version of the protocol used for network communication. + pub network_protocol_version: Option, + /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. + pub url_scheme: Option, + /// Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. + pub server_address: String, + } +impl HttpClientConnectionDuration { + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: HistogramProvider{ + Self(meter.create_histogram("http.client.connection.duration", "The duration of the successfully established outbound HTTP connections.", "s")) + } - -/// Number of active HTTP requests. -#[cfg(feature = "semconv_experimental")] -pub fn create_i64_http_client_active_requests(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter { - meter.i64_up_down_counter("http.client.active_requests") - .with_description("Number of active HTTP requests.") - .with_unit(opentelemetry::metrics::Unit::new("{request}")) - .init() + /// Adds an additional value to the distribution. + pub fn record(&self, value: T, attributes: HttpClientConnectionDurationAttributes) { + // self.0.record(value, attributes.into()) + } } - /// Number of active HTTP requests. #[cfg(feature = "semconv_experimental")] -pub fn create_f64_http_client_active_requests(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter { - meter.f64_up_down_counter("http.client.active_requests") - .with_description("Number of active HTTP requests.") - .with_unit(opentelemetry::metrics::Unit::new("{request}")) - .init() +pub fn create_http_client_active_requests(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter + where opentelemetry::metrics::Meter: UpDownCounterProvider { + meter.create_up_down_counter("http.client.active_requests", "Number of active HTTP requests.", "{request}") } - diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/metrics/mod.rs b/crates/weaver_forge/codegen_examples/expected_codegen/metrics/mod.rs index 4137fa8e..c8b7c989 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/metrics/mod.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/metrics/mod.rs @@ -8,4 +8,60 @@ /// Metrics for the `http` namespace. -pub mod http; \ No newline at end of file +pub mod http; + +/// A trait implemented by histogram providers (e.g. `Meter`). +pub trait HistogramProvider { + /// Creates a new histogram with the given name, description, and unit. + fn create_histogram(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Histogram; +} + +/// This implementation specifies that a Meter is able to create u64 histograms. +impl HistogramProvider for opentelemetry::metrics::Meter { + /// Creates a new u64 histogram with the given name, description, and unit. + fn create_histogram(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Histogram { + self.u64_histogram(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// This implementation specifies that a Meter is able to create u64 histograms. +impl HistogramProvider for opentelemetry::metrics::Meter { + /// Creates a new f64 histogram with the given name, description, and unit. + fn create_histogram(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Histogram { + self.f64_histogram(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// A trait implemented by up-down-counter providers (e.g. `Meter`). +pub trait UpDownCounterProvider { + /// Creates a new up-down-counter with the given name, description, and unit. + fn create_up_down_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::UpDownCounter; +} + +/// This implementation specifies that a Meter is able to create i64 up-down-counters. +impl UpDownCounterProvider for opentelemetry::metrics::Meter { + /// Creates a new i64 up-down-counter with the given name, description, and unit. + fn create_up_down_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::UpDownCounter { + self.i64_up_down_counter(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// This implementation specifies that a Meter is able to create f64 up-down-counters. +impl UpDownCounterProvider for opentelemetry::metrics::Meter { + /// Creates a new f64 up-down-counter with the given name, description, and unit. + fn create_up_down_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::UpDownCounter { + self.f64_up_down_counter(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 index 36813a3d..d87734ef 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 @@ -34,10 +34,11 @@ {% elif attribute.type == "string" %}pub const {{ attribute.name | screaming_snake_case }}: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("{{ attribute.name }}"); {% else %}pub const {{ attribute.name | screaming_snake_case }}: crate::attributes::AttributeKey<{{ attribute.type | type_mapping }}> = crate::attributes::AttributeKey::new("{{ attribute.name }}");{% endif %} -{% if attribute.type.allow_custom_values is defined %} +{% if attribute.type.members is defined %} {%- if attribute.brief %} {{ attribute.brief | comment_with_prefix("/// ") }} {%- endif %} +#[derive(Debug, Clone)] #[non_exhaustive] pub enum {{ attribute.name | pascal_case }} { {% for variant in attribute.type.members %} diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 index d32a5bfb..1f9d3caa 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 @@ -4,22 +4,72 @@ {%- if metric is experimental %} #[cfg(feature = "semconv_experimental")] {%- endif %} -pub fn create_u64_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { - meter.u64_histogram("{{ metric.metric_name }}") - .with_description("{{ metric.brief }}") - .with_unit(opentelemetry::metrics::Unit::new("{{ metric.unit }}")) - .init() +pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram + where opentelemetry::metrics::Meter: HistogramProvider { + meter.create_histogram("{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") } -{% if metric.brief %} -{{ metric.brief | comment_with_prefix("/// ") }} -{%- endif %} -{%- if metric is experimental %} -#[cfg(feature = "semconv_experimental")] -{%- endif %} -pub fn create_f64_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram { - meter.f64_histogram("{{ metric.metric_name }}") - .with_description("{{ metric.brief }}") - .with_unit(opentelemetry::metrics::Unit::new("{{ metric.unit }}")) - .init() +/// Metric: {{ metric.metric_name }} +/// Brief: {{ metric.brief }} +/// Unit: {{ metric.unit }} +#[derive(Debug)] +pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::Histogram); + +{% set required_attributes = metric.attributes | required %} +{% set optional_attributes = metric.attributes | optional %} + +{% if required_attributes %} +/// Attributes for the `{{ metric.metric_name }}` metric. +#[derive(Debug, Clone)] +pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { + {% for attribute in metric.attributes %} + {{- attribute.brief | comment_with_prefix("/// ") }} + {%- if attribute.requirement_level == "required" %} + {%- if attribute.type.members is defined %} + pub {{ attribute.name | snake_case }}: crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | pascal_case }}, + {% else %} + pub {{ attribute.name | snake_case }}: {{ attribute.type | type_mapping }}, + {% endif %} + {%- else %} + {%- if attribute.type.members is defined %} + pub {{ attribute.name | snake_case }}: Option, + {% else %} + pub {{ attribute.name | snake_case }}: Option<{{ attribute.type | type_mapping }}>, + {% endif %} + {%- endif %} + {%- endfor %} +} +{% endif %} +{% if optional_attributes %} +#[derive(Debug, Clone, Default)] +pub struct {{ metric.metric_name | pascal_case }}OptAttributes { + {% for attribute in metric.attributes %} + {{- attribute.brief | comment_with_prefix("/// ") }} + {%- if attribute.requirement_level == "required" %} + {%- if attribute.type.members is defined %} + pub {{ attribute.name | snake_case }}: crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | pascal_case }}, + {% else %} + pub {{ attribute.name | snake_case }}: {{ attribute.type | type_mapping }}, + {% endif %} + {%- else %} + {%- if attribute.type.members is defined %} + pub {{ attribute.name | snake_case }}: Option, + {% else %} + pub {{ attribute.name | snake_case }}: Option<{{ attribute.type | type_mapping }}>, + {% endif %} + {%- endif %} + {%- endfor %} } +{% endif %} + +impl {{ metric.metric_name | pascal_case }} { + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: HistogramProvider{ + Self(meter.create_histogram("{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) + } + + /// Adds an additional value to the distribution. + pub fn record(&self, value: T, attributes: {{ metric.metric_name | pascal_case }}Attributes) { + // self.0.record(value, attributes.into()) + } +} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 index c2a1fa13..f79ae7db 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 @@ -8,14 +8,8 @@ //! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/metrics/metrics.rs.j2 +use crate::metrics::{HistogramProvider, UpDownCounterProvider}; + {% for metric in ctx.groups %} -{% if metric.instrument == "histogram" %} -{%- include "metrics/histogram.j2" %} -{% elif metric.instrument == "counter" %} -{%- include "metrics/counter.j2" %} -{% elif metric.instrument == "gauge" %} -{%- include "metrics/gauge.j2" %} -{% elif metric.instrument == "updowncounter" %} -{%- include "metrics/updowncounter.j2" %} -{% endif %} +{%- include "metrics/" ~ metric.instrument ~ ".j2" %} {% endfor %} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/mod.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/mod.rs.j2 index f574f857..913f2c46 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/mod.rs.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/mod.rs.j2 @@ -11,4 +11,60 @@ {% for group in ctx %} /// Metrics for the `{{ group.id | metric_namespace }}` namespace. pub mod {{ group.id | metric_namespace | snake_case }}; -{%- endfor %} \ No newline at end of file +{%- endfor %} + +/// A trait implemented by histogram providers (e.g. `Meter`). +pub trait HistogramProvider { + /// Creates a new histogram with the given name, description, and unit. + fn create_histogram(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Histogram; +} + +/// This implementation specifies that a Meter is able to create u64 histograms. +impl HistogramProvider for opentelemetry::metrics::Meter { + /// Creates a new u64 histogram with the given name, description, and unit. + fn create_histogram(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Histogram { + self.u64_histogram(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// This implementation specifies that a Meter is able to create u64 histograms. +impl HistogramProvider for opentelemetry::metrics::Meter { + /// Creates a new f64 histogram with the given name, description, and unit. + fn create_histogram(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Histogram { + self.f64_histogram(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// A trait implemented by up-down-counter providers (e.g. `Meter`). +pub trait UpDownCounterProvider { + /// Creates a new up-down-counter with the given name, description, and unit. + fn create_up_down_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::UpDownCounter; +} + +/// This implementation specifies that a Meter is able to create i64 up-down-counters. +impl UpDownCounterProvider for opentelemetry::metrics::Meter { + /// Creates a new i64 up-down-counter with the given name, description, and unit. + fn create_up_down_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::UpDownCounter { + self.i64_up_down_counter(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// This implementation specifies that a Meter is able to create f64 up-down-counters. +impl UpDownCounterProvider for opentelemetry::metrics::Meter { + /// Creates a new f64 up-down-counter with the given name, description, and unit. + fn create_up_down_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::UpDownCounter { + self.f64_up_down_counter(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/updowncounter.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/updowncounter.j2 index 1786e0e6..53234fe6 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/updowncounter.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/updowncounter.j2 @@ -4,22 +4,7 @@ {%- if metric is experimental %} #[cfg(feature = "semconv_experimental")] {%- endif %} -pub fn create_i64_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter { - meter.i64_up_down_counter("{{ metric.metric_name }}") - .with_description("{{ metric.brief }}") - .with_unit(opentelemetry::metrics::Unit::new("{{ metric.unit }}")) - .init() -} - -{% if metric.brief %} -{{ metric.brief | comment_with_prefix("/// ") }} -{%- endif %} -{%- if metric is experimental %} -#[cfg(feature = "semconv_experimental")] -{%- endif %} -pub fn create_f64_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter { - meter.f64_up_down_counter("{{ metric.metric_name }}") - .with_description("{{ metric.brief }}") - .with_unit(opentelemetry::metrics::Unit::new("{{ metric.unit }}")) - .init() -} +pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter + where opentelemetry::metrics::Meter: UpDownCounterProvider { + meter.create_up_down_counter("{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") +} \ No newline at end of file diff --git a/crates/weaver_forge/src/extensions/otel.rs b/crates/weaver_forge/src/extensions/otel.rs index ced47faa..61c7f297 100644 --- a/crates/weaver_forge/src/extensions/otel.rs +++ b/crates/weaver_forge/src/extensions/otel.rs @@ -68,6 +68,21 @@ pub(crate) fn metric_namespace(input: &str) -> Result Ok(parts[1].to_owned()) } +/// Converts {namespace}.{attribute_id} to {namespace}. +/// +/// A [`minijinja::Error`] is returned if the input does not have +/// at least two parts. Otherwise, it returns the namespace (first part of the input). +pub(crate) fn attribute_namespace(input: &str) -> Result { + let parts: Vec<&str> = input.split('.').collect(); + if parts.len() < 2 { + return Err(minijinja::Error::new( + ErrorKind::InvalidOperation, + format!("This attribute name `{}` is invalid", input), + )); + } + Ok(parts[0].to_owned()) +} + /// Checks if the input value is an object with a field named "stability" that has the value "stable". /// Otherwise, it returns false. #[must_use] diff --git a/crates/weaver_forge/src/lib.rs b/crates/weaver_forge/src/lib.rs index 947c1464..3d36aebd 100644 --- a/crates/weaver_forge/src/lib.rs +++ b/crates/weaver_forge/src/lib.rs @@ -392,6 +392,7 @@ impl TemplateEngine { env.add_filter("acronym", acronym(self.target_config.acronyms.clone())); // Register custom OpenTelemetry filters and tests + env.add_filter("attribute_namespace", extensions::otel::attribute_namespace); env.add_filter( "attribute_registry_namespace", extensions::otel::attribute_registry_namespace, From ecbd76d2b75a028448149d86ec20b78a80ac455f Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Thu, 2 May 2024 16:01:07 -0700 Subject: [PATCH 20/39] feat(forge): Separate required from optional attributes in the generate public API --- crates/weaver_forge/Cargo.toml | 2 +- .../registry/rust/metrics/histogram.j2 | 28 ++----- crates/weaver_forge/src/extensions/otel.rs | 84 +++++++++++++++++++ crates/weaver_forge/src/lib.rs | 4 +- 4 files changed, 97 insertions(+), 21 deletions(-) diff --git a/crates/weaver_forge/Cargo.toml b/crates/weaver_forge/Cargo.toml index 54809d1b..1661b28d 100644 --- a/crates/weaver_forge/Cargo.toml +++ b/crates/weaver_forge/Cargo.toml @@ -18,7 +18,7 @@ weaver_resolver = { path = "../weaver_resolver" } weaver_resolved_schema = { path = "../weaver_resolved_schema" } weaver_semconv = { path = "../weaver_semconv" } -minijinja = { version = "1.0.21", features = ["loader", "custom_syntax", "debug", "json"] } +minijinja = { version = "1.0.21", features = ["loader", "custom_syntax", "debug", "json", "macros"] } convert_case = "0.6.0" globset = { version = "0.4.14", features = ["serde1"] } jaq-core = "1.2.1" diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 index 1f9d3caa..a26815a8 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 @@ -22,42 +22,27 @@ pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::His /// Attributes for the `{{ metric.metric_name }}` metric. #[derive(Debug, Clone)] pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { - {% for attribute in metric.attributes %} + {% for attribute in required_attributes %} {{- attribute.brief | comment_with_prefix("/// ") }} - {%- if attribute.requirement_level == "required" %} {%- if attribute.type.members is defined %} pub {{ attribute.name | snake_case }}: crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | pascal_case }}, {% else %} pub {{ attribute.name | snake_case }}: {{ attribute.type | type_mapping }}, {% endif %} - {%- else %} - {%- if attribute.type.members is defined %} - pub {{ attribute.name | snake_case }}: Option, - {% else %} - pub {{ attribute.name | snake_case }}: Option<{{ attribute.type | type_mapping }}>, - {% endif %} - {%- endif %} {%- endfor %} } {% endif %} + {% if optional_attributes %} #[derive(Debug, Clone, Default)] pub struct {{ metric.metric_name | pascal_case }}OptAttributes { - {% for attribute in metric.attributes %} + {% for attribute in optional_attributes %} {{- attribute.brief | comment_with_prefix("/// ") }} - {%- if attribute.requirement_level == "required" %} - {%- if attribute.type.members is defined %} - pub {{ attribute.name | snake_case }}: crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | pascal_case }}, - {% else %} - pub {{ attribute.name | snake_case }}: {{ attribute.type | type_mapping }}, - {% endif %} - {%- else %} {%- if attribute.type.members is defined %} pub {{ attribute.name | snake_case }}: Option, {% else %} pub {{ attribute.name | snake_case }}: Option<{{ attribute.type | type_mapping }}>, {% endif %} - {%- endif %} {%- endfor %} } {% endif %} @@ -69,7 +54,12 @@ impl {{ metric.metric_name | pascal_case }} { } /// Adds an additional value to the distribution. - pub fn record(&self, value: T, attributes: {{ metric.metric_name | pascal_case }}Attributes) { + pub fn record( + &self, + value: T, + {% if required_attributes %}required_attributes: &{{ metric.metric_name | pascal_case }}ReqAttributes,{% endif %} + {% if optional_attributes %}optional_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} + ) { // self.0.record(value, attributes.into()) } } \ No newline at end of file diff --git a/crates/weaver_forge/src/extensions/otel.rs b/crates/weaver_forge/src/extensions/otel.rs index 61c7f297..6c8cd63e 100644 --- a/crates/weaver_forge/src/extensions/otel.rs +++ b/crates/weaver_forge/src/extensions/otel.rs @@ -5,6 +5,34 @@ use crate::config::CaseConvention; use minijinja::{ErrorKind, Value}; +/// Filters the input value to only include the required "object". +/// A required object is one that has a field named "requirement_level" with the value "required". +pub(crate) fn required(input: Value) -> Result, minijinja::Error> { + let mut rv = vec![]; + + for value in input.try_iter()? { + let required = value.get_attr("requirement_level")?; + if required.as_str() == Some("required") { + rv.push(value); + } + } + Ok(rv) +} + +/// Filters the input value to only include the non-required "object". +/// A optional object is one that has a field named "requirement_level" which is not "required". +pub(crate) fn optional(input: Value) -> Result, minijinja::Error> { + let mut rv = vec![]; + + for value in input.try_iter()? { + let required = value.get_attr("requirement_level")?; + if required.as_str() != Some("required") { + rv.push(value); + } + } + Ok(rv) +} + /// Converts registry.{namespace}.{other}.{components} to {namespace}. /// /// A [`minijinja::Error`] is returned if the input does not start with "registry" or does not have @@ -133,6 +161,8 @@ mod tests { }; use minijinja::value::StructObject; use minijinja::Value; + use weaver_resolved_schema::attribute::Attribute; + use weaver_semconv::attribute::{AttributeType, BasicRequirementLevelSpec, PrimitiveOrArrayTypeSpec, RequirementLevel}; struct DynAttr { id: String, @@ -338,4 +368,58 @@ mod tests { }); assert!(!is_deprecated(attr)); } + + #[test] + fn test_required_and_optional_filters() { + let attrs = vec![ + Attribute { + name: "attr1".to_string(), + r#type: AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::String), + brief: "".to_string(), + examples: None, + tag: None, + requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Required), + sampling_relevant: None, + note: "".to_string(), + stability: None, + deprecated: None, + tags: None, + value: None, + }, + Attribute { + name: "attr2".to_string(), + r#type: AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::Int), + brief: "".to_string(), + examples: None, + tag: None, + requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Recommended), + sampling_relevant: None, + note: "".to_string(), + stability: None, + deprecated: None, + tags: None, + value: None, + }, + Attribute { + name: "attr3".to_string(), + r#type: AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::String), + brief: "".to_string(), + examples: None, + tag: None, + requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Required), + sampling_relevant: None, + note: "".to_string(), + stability: None, + deprecated: None, + tags: None, + value: None, + }, + ]; + + let result = super::required(Value::from_serialize(&attrs)).unwrap(); + assert_eq!(result.len(), 2); + + let result = super::optional(Value::from_serialize(&attrs)).unwrap(); + assert_eq!(result.len(), 1); + } } diff --git a/crates/weaver_forge/src/lib.rs b/crates/weaver_forge/src/lib.rs index 31fe4e02..ef7760a8 100644 --- a/crates/weaver_forge/src/lib.rs +++ b/crates/weaver_forge/src/lib.rs @@ -433,7 +433,9 @@ impl TemplateEngine { extensions::otel::attribute_registry_file, ); env.add_filter("metric_namespace", extensions::otel::metric_namespace); - // ToDo Implement more filters: required, not_required, stable, experimental, deprecated + env.add_filter("required", extensions::otel::required); + env.add_filter("optional", extensions::otel::optional); + // ToDo Implement more filters: 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); From 34db6adee19faa843440983ad0150cac50da4f01 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Fri, 3 May 2024 13:42:42 -0700 Subject: [PATCH 21/39] feat(forge): Improve metrics type-safe API --- .../registry/rust/attribute_macros.j2 | 22 ++++++++ .../registry/rust/attributes/attributes.rs.j2 | 22 ++++---- .../registry/rust/metrics/histogram.j2 | 52 +++++++++++++++---- .../registry/rust/metrics/metrics.rs.j2 | 6 +-- .../templates/registry/rust/weaver.yaml | 8 +++ crates/weaver_forge/src/extensions/code.rs | 14 +++-- 6 files changed, 96 insertions(+), 28 deletions(-) create mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/attribute_macros.j2 diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/attribute_macros.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/attribute_macros.j2 new file mode 100644 index 00000000..0e99922a --- /dev/null +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/attribute_macros.j2 @@ -0,0 +1,22 @@ +{%- macro comments(attribute, prefix) -%} +{%- if attribute.brief %} +{{ attribute.brief | comment_with_prefix(prefix ~ " ") }} +{%- endif %} +{%- if attribute.note %} +{{ prefix }} +{{ prefix }} Notes: +{{ attribute.note | comment_with_prefix(prefix ~ " ") }} +{%- endif %} +{%- if attribute.examples %} +{%- if attribute.examples is sequence %} +{{ prefix }} +{{ prefix }} Examples: +{%- for example in attribute.examples %} +{{ example | comment_with_prefix(prefix ~ " - ") }} +{%- endfor %} +{%- else %} +{{ prefix }} +{{ prefix }} Example: {{ attribute.examples | trim }} +{%- endif %} +{%- endif %} +{%- endmacro %} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 index d87734ef..6da15faa 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 @@ -1,5 +1,6 @@ {%- set file_name = ctx.id | attribute_registry_namespace | snake_case -%} {{- template.set_file_name("attributes/" ~ file_name ~ ".rs") -}} +{%- import 'attribute_macros.j2' as attribute_macros %} /* * Copyright The OpenTelemetry Authors @@ -16,14 +17,7 @@ {% for attribute in ctx.attributes %} -{%- if attribute.brief %} -{{ attribute.brief | comment_with_prefix("/// ") }} -{%- endif %} -{%- if attribute.note %} -/// -/// Notes: -{{ attribute.note | comment_with_prefix("/// ") }} -{%- endif %} +{{ attribute_macros.comments(attribute, "///") }} {%- if attribute is experimental %} #[cfg(feature = "semconv_experimental")] {%- endif %} @@ -48,17 +42,20 @@ pub enum {{ attribute.name | pascal_case }} { #[cfg(feature = "semconv_experimental")] {% endif %} {{ variant.id | pascal_case }}, {% endfor %} + /// This variant allows defining a custom entry in the enum. + _Custom(String), } impl {{ attribute.name | pascal_case }} { /// Returns the string representation of the [`{{ attribute.name | pascal_case }}`]. - pub fn as_str(&self) -> &'static str { + pub fn as_str(&self) -> &str { match self { {%- for variant in attribute.type.members %} {%- if variant is experimental %} #[cfg(feature = "semconv_experimental")] {% endif %} {{ attribute.name | pascal_case }}::{{ variant.id | pascal_case }} => "{{ variant.value }}", {%- endfor %} + {{ attribute.name | pascal_case }}::_Custom(v) => v.as_str(), // 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. @@ -74,5 +71,12 @@ impl core::fmt::Display for {{ attribute.name | pascal_case }} { write!(f, "{}", self.as_str()) } } + +impl crate::attributes::AttributeKey<{{ attribute.name | pascal_case }}> { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &{{ attribute.name | pascal_case }}) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} {% endif %} {% endfor %} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 index a26815a8..c9b62327 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 @@ -1,3 +1,4 @@ +{%- import 'attribute_macros.j2' as attribute_macros %} {%- if metric.brief %} {{ metric.brief | comment_with_prefix("/// ") }} {%- endif %} @@ -15,20 +16,20 @@ pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::me #[derive(Debug)] pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::Histogram); -{% set required_attributes = metric.attributes | required %} -{% set optional_attributes = metric.attributes | optional %} +{%- set required_attributes = metric.attributes | required %} +{%- set optional_attributes = metric.attributes | optional %} {% if required_attributes %} /// Attributes for the `{{ metric.metric_name }}` metric. #[derive(Debug, Clone)] pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { - {% for attribute in required_attributes %} - {{- attribute.brief | comment_with_prefix("/// ") }} + {%- for attribute in required_attributes %} + {{ attribute_macros.comments(attribute, " ///") }} {%- if attribute.type.members is defined %} pub {{ attribute.name | snake_case }}: crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | pascal_case }}, - {% else %} + {%- else %} pub {{ attribute.name | snake_case }}: {{ attribute.type | type_mapping }}, - {% endif %} + {%- endif %} {%- endfor %} } {% endif %} @@ -36,13 +37,13 @@ pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { {% if optional_attributes %} #[derive(Debug, Clone, Default)] pub struct {{ metric.metric_name | pascal_case }}OptAttributes { - {% for attribute in optional_attributes %} - {{- attribute.brief | comment_with_prefix("/// ") }} + {%- for attribute in optional_attributes %} + {{ attribute_macros.comments(attribute, " ///") }} {%- if attribute.type.members is defined %} pub {{ attribute.name | snake_case }}: Option, - {% else %} + {%- else %} pub {{ attribute.name | snake_case }}: Option<{{ attribute.type | type_mapping }}>, - {% endif %} + {%- endif %} {%- endfor %} } {% endif %} @@ -60,6 +61,35 @@ impl {{ metric.metric_name | pascal_case }} { {% if required_attributes %}required_attributes: &{{ metric.metric_name | pascal_case }}ReqAttributes,{% endif %} {% if optional_attributes %}optional_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} ) { - // self.0.record(value, attributes.into()) + let mut attributes = vec![ + {%- for attribute in required_attributes %} + {%- if attribute.type.members is defined %} + crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(&required_attributes.{{ attribute.name | snake_case }}), + {%- elif attribute.type == "string" %} + crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(required_attributes.{{ attribute.name | snake_case }}.to_string().into()), + {%- else %} + crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(required_attributes.{{ attribute.name | snake_case }}), + {%- endif %} + {%- endfor %} + ]; + + if let Some(value) = &optional_attributes { + {%- for attribute in optional_attributes %} + {%- if attribute.type.members is defined %} + if let Some({{ attribute.name | snake_case }}) = &value.{{ attribute.name | snake_case }} { + attributes.push(crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value({{ attribute.name | snake_case }})); + } + {%- elif attribute.type == "string" %} + if let Some({{ attribute.name | snake_case }}) = &value.{{ attribute.name | snake_case }} { + attributes.push(crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value({{ attribute.name | snake_case }}.to_string().into())); + } + {%- else %} + if let Some({{ attribute.name | snake_case }}) = value.{{ attribute.name | snake_case }} { + attributes.push(crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value({{ attribute.name | snake_case }})); + } + {%- endif %} + {%- endfor %} + } + self.0.record(value, &attributes) } } \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 index f79ae7db..66e44015 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 @@ -10,6 +10,6 @@ use crate::metrics::{HistogramProvider, UpDownCounterProvider}; -{% for metric in ctx.groups %} -{%- include "metrics/" ~ metric.instrument ~ ".j2" %} -{% endfor %} \ No newline at end of file +{%- for metric in ctx.groups %} +{% include "metrics/" ~ metric.instrument ~ ".j2" %} +{%- endfor %} \ No newline at end of file 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 dd2e0ec4..eeb0fc6b 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml @@ -50,6 +50,14 @@ templates: brief, prefix, attributes}) + | group_by(.id | split(".") | .[1]) + | map({ + id: (map(select(.id | endswith(".deprecated") | not)) | first).id, + type: (map(select(.id | endswith(".deprecated") | not)) | first).type, + brief: (map(select(.id | endswith(".deprecated") | not)) | first).brief, + prefix: (map(select(.id | endswith(".deprecated") | not)) | first).prefix, + attributes: map(.attributes) | add + }) | sort_by(.id | split(".") | .[1]) application_mode: each diff --git a/crates/weaver_forge/src/extensions/code.rs b/crates/weaver_forge/src/extensions/code.rs index 7ae7189b..6a03a945 100644 --- a/crates/weaver_forge/src/extensions/code.rs +++ b/crates/weaver_forge/src/extensions/code.rs @@ -6,11 +6,12 @@ use std::collections::HashMap; use minijinja::Value; -/// Converts the input string into a comment with a prefix. +/// Converts the input into a string comment with a prefix. #[must_use] -pub(crate) fn comment_with_prefix(input: &str, prefix: &str) -> String { +pub(crate) fn comment_with_prefix(input: &Value, prefix: &str) -> String { let mut comment = String::new(); - for line in input.lines() { + + for line in input.to_string().lines() { if !comment.is_empty() { comment.push('\n'); } @@ -49,7 +50,8 @@ mod tests { #[test] fn test_comment() { - assert_eq!(comment_with_prefix("test", "// "), "// test"); + assert_eq!(comment_with_prefix(&Value::from("test"), "// "), "// test"); + assert_eq!(comment_with_prefix(&Value::from(12), "// "), "// 12"); let brief = r#"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). @@ -65,7 +67,9 @@ This also covers UDP network interactions where one side initiates the interacti /// 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."#; - assert_eq!(comment_with_prefix(brief, "/// "), expected_brief); + assert_eq!(comment_with_prefix(&Value::from(brief), "/// "), expected_brief); + + } #[test] From 581c08c25fbc1b358c0340dbaa0157c55c472e4e Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Fri, 3 May 2024 16:46:36 -0700 Subject: [PATCH 22/39] feat(forge): Add support for Counter and Gauge --- .../mini_registry/metrics/http.yaml | 130 ------------------ .../mini_registry/metrics/system-metrics.yaml | 38 +++++ .../mini_registry/registry/system.yaml | 69 ++++++++++ .../registry/rust/attribute_macros.j2 | 38 +++++ .../registry/rust/attributes/attributes.rs.j2 | 31 +++-- .../registry/rust/metrics/counter.j2 | 74 +++++++--- .../templates/registry/rust/metrics/gauge.j2 | 84 +++++++---- .../registry/rust/metrics/histogram.j2 | 34 +---- .../registry/rust/metrics/metrics.rs.j2 | 2 +- .../templates/registry/rust/metrics/mod.rs.j2 | 67 +++++++++ .../registry/rust/metrics/updowncounter.j2 | 57 ++++++++ 11 files changed, 403 insertions(+), 221 deletions(-) create mode 100644 crates/weaver_forge/codegen_examples/mini_registry/metrics/system-metrics.yaml create mode 100644 crates/weaver_forge/codegen_examples/mini_registry/registry/system.yaml diff --git a/crates/weaver_forge/codegen_examples/mini_registry/metrics/http.yaml b/crates/weaver_forge/codegen_examples/mini_registry/metrics/http.yaml index 3172c9e9..9d24d884 100644 --- a/crates/weaver_forge/codegen_examples/mini_registry/metrics/http.yaml +++ b/crates/weaver_forge/codegen_examples/mini_registry/metrics/http.yaml @@ -32,64 +32,6 @@ groups: stability: stable extends: metric_attributes.http.server - - id: metric.http.server.active_requests - type: metric - metric_name: http.server.active_requests - stability: experimental - brief: "Number of active HTTP server requests." - instrument: updowncounter - unit: "{request}" - attributes: - - ref: http.request.method - requirement_level: required - - ref: url.scheme - requirement_level: required - examples: ["http", "https"] - - ref: server.address - requirement_level: opt_in - brief: > - Name of the local HTTP server that received the request. - note: | - See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). - > **Warning** - > Since this attribute is based on HTTP headers, opting in to it may allow an attacker - > to trigger cardinality limits, degrading the usefulness of the metric. - - ref: server.port - requirement_level: opt_in - brief: > - Port of the local HTTP server that received the request. - note: | - See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). - > **Warning** - > Since this attribute is based on HTTP headers, opting in to it may allow an attacker - > to trigger cardinality limits, degrading the usefulness of the metric. - - - id: metric.http.server.request.body.size - type: metric - metric_name: http.server.request.body.size - stability: experimental - brief: "Size of HTTP server request bodies." - instrument: histogram - unit: "By" - note: > - 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. - extends: metric_attributes.http.server - - - id: metric.http.server.response.body.size - type: metric - metric_name: http.server.response.body.size - stability: experimental - brief: "Size of HTTP server response bodies." - instrument: histogram - unit: "By" - note: > - 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. - extends: metric_attributes.http.server - - id: metric.http.client.request.duration type: metric metric_name: http.client.request.duration @@ -99,78 +41,6 @@ groups: stability: stable extends: metric_attributes.http.client - - id: metric.http.client.request.body.size - type: metric - metric_name: http.client.request.body.size - stability: experimental - brief: "Size of HTTP client request bodies." - instrument: histogram - unit: "By" - note: > - 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. - extends: metric_attributes.http.client - - - id: metric.http.client.response.body.size - type: metric - metric_name: http.client.response.body.size - stability: experimental - brief: "Size of HTTP client response bodies." - instrument: histogram - unit: "By" - note: > - 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. - extends: metric_attributes.http.client - - - id: metric.http.client.open_connections - type: metric - metric_name: http.client.open_connections - stability: experimental - brief: "Number of outbound HTTP connections that are currently active or idle on the client." - instrument: updowncounter - unit: "{connection}" - attributes: - - ref: http.connection.state - requirement_level: required - - ref: network.peer.address - requirement_level: recommended - - ref: network.protocol.version - requirement_level: recommended - - ref: server.address - requirement_level: required - - ref: server.port - requirement_level: required - brief: > - Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. - - ref: url.scheme - requirement_level: opt_in - examples: ["http", "https"] - - - id: metric.http.client.connection.duration - type: metric - metric_name: http.client.connection.duration - stability: experimental - brief: "The duration of the successfully established outbound HTTP connections." - instrument: histogram - unit: "s" - attributes: - - ref: network.peer.address - requirement_level: recommended - - ref: network.protocol.version - requirement_level: recommended - - ref: server.address - requirement_level: required - - ref: server.port - requirement_level: required - brief: > - Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. - - ref: url.scheme - requirement_level: opt_in - examples: ["http", "https"] - - id: metric.http.client.active_requests type: metric metric_name: http.client.active_requests diff --git a/crates/weaver_forge/codegen_examples/mini_registry/metrics/system-metrics.yaml b/crates/weaver_forge/codegen_examples/mini_registry/metrics/system-metrics.yaml new file mode 100644 index 00000000..0afa0b2b --- /dev/null +++ b/crates/weaver_forge/codegen_examples/mini_registry/metrics/system-metrics.yaml @@ -0,0 +1,38 @@ +groups: + # system.cpu.* metrics + - id: metric.system.cpu.time + type: metric + metric_name: system.cpu.time + stability: experimental + brief: "Seconds each logical CPU spent on each mode" + instrument: counter + unit: "s" + attributes: + - ref: system.cpu.state + brief: "The CPU state for this data point. A system's CPU SHOULD be characterized *either* by data points with no `state` labels, *or only* data points with `state` labels." + - ref: system.cpu.logical_number + + - id: metric.system.cpu.utilization + type: metric + metric_name: system.cpu.utilization + stability: experimental + brief: "Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs" + instrument: gauge + unit: "1" + attributes: + - ref: system.cpu.state + brief: "The CPU state for this data point. A system's CPU SHOULD be characterized *either* by data points with no `state` labels, *or only* data points with `state` labels." + - ref: system.cpu.logical_number + + - id: metric.system.memory.usage + type: metric + metric_name: system.memory.usage + stability: experimental + brief: "Reports memory in use by state." + note: | + The sum over all `system.memory.state` values SHOULD equal the total memory + available on the system, that is `system.memory.limit`. + instrument: updowncounter + unit: "By" + attributes: + - ref: system.memory.state \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/mini_registry/registry/system.yaml b/crates/weaver_forge/codegen_examples/mini_registry/registry/system.yaml new file mode 100644 index 00000000..6637b716 --- /dev/null +++ b/crates/weaver_forge/codegen_examples/mini_registry/registry/system.yaml @@ -0,0 +1,69 @@ +groups: + # system.cpu.* attribute group + - id: registry.system.cpu + prefix: system.cpu + type: attribute_group + brief: "Describes System CPU attributes" + attributes: + - id: state + type: + allow_custom_values: true + members: + - id: user + value: 'user' + stability: experimental + - id: system + value: 'system' + stability: experimental + - id: nice + value: 'nice' + stability: experimental + - id: idle + value: 'idle' + stability: experimental + - id: iowait + value: 'iowait' + stability: experimental + - id: interrupt + value: 'interrupt' + stability: experimental + - id: steal + value: 'steal' + stability: experimental + brief: "The state of the CPU" + stability: experimental + examples: ["idle", "interrupt"] + - id: logical_number + type: int + stability: experimental + brief: "The logical CPU number [0..n-1]" + examples: [1] + # sytem.memory.* attribute group + - id: registry.system.memory + prefix: system.memory + type: attribute_group + brief: "Describes System Memory attributes" + attributes: + - id: state + type: + allow_custom_values: true + members: + - id: used + value: 'used' + stability: experimental + - id: free + value: 'free' + stability: experimental + - id: shared + value: 'shared' + stability: experimental + deprecated: 'Removed, report shared memory usage with `metric.system.memory.shared` metric' + - id: buffers + value: 'buffers' + stability: experimental + - id: cached + value: 'cached' + stability: experimental + stability: experimental + brief: "The memory state" + examples: ["free", "cached"] \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/attribute_macros.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/attribute_macros.j2 index 0e99922a..c71281e6 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/attribute_macros.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/attribute_macros.j2 @@ -19,4 +19,42 @@ {{ prefix }} Example: {{ attribute.examples | trim }} {%- endif %} {%- endif %} +{%- endmacro %} + +{%- macro attributes_to_key_values(required_attributes, optional_attributes) -%} + let mut attributes = vec![ + {%- for attribute in required_attributes | attribute_sort %} + {%- if attribute is experimental %} + #[cfg(feature = "semconv_experimental")] + {%- endif %} + {%- if attribute.type.members is defined %} + crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(&required_attributes.{{ attribute.name | snake_case }}), + {%- elif attribute.type == "string" %} + crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(required_attributes.{{ attribute.name | snake_case }}.to_string().into()), + {%- else %} + crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(required_attributes.{{ attribute.name | snake_case }}), + {%- endif %} + {%- endfor %} + ]; + + if let Some(value) = &optional_attributes { + {%- for attribute in optional_attributes | attribute_sort %} + {%- if attribute is experimental %} + #[cfg(feature = "semconv_experimental")] + {%- endif %} + {%- if attribute.type.members is defined %} + if let Some({{ attribute.name | snake_case }}) = &value.{{ attribute.name | snake_case }} { + attributes.push(crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value({{ attribute.name | snake_case }})); + } + {%- elif attribute.type == "string" %} + if let Some({{ attribute.name | snake_case }}) = &value.{{ attribute.name | snake_case }} { + attributes.push(crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value({{ attribute.name | snake_case }}.to_string().into())); + } + {%- else %} + if let Some({{ attribute.name | snake_case }}) = value.{{ attribute.name | snake_case }} { + attributes.push(crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value({{ attribute.name | snake_case }})); + } + {%- endif %} + {%- endfor %} + } {%- endmacro %} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 index 6da15faa..806addfb 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 @@ -1,6 +1,6 @@ {%- set file_name = ctx.id | attribute_registry_namespace | snake_case -%} {{- template.set_file_name("attributes/" ~ file_name ~ ".rs") -}} -{%- import 'attribute_macros.j2' as attribute_macros %} +{%- import 'attribute_macros.j2' as attribute_macros -%} /* * Copyright The OpenTelemetry Authors @@ -11,12 +11,11 @@ {%- if ctx.note %} //! //! Notes: -{{ ctx.note | comment_with_prefix("/// ") }} +{{ ctx.note | comment_with_prefix("//! ") }} {%- endif %} //! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/attributes/attributes.rs.j2 -{% for attribute in ctx.attributes %} - +{%- for attribute in ctx.attributes | attribute_sort %} {{ attribute_macros.comments(attribute, "///") }} {%- if attribute is experimental %} #[cfg(feature = "semconv_experimental")] @@ -24,24 +23,26 @@ {%- if attribute is deprecated %} #[deprecated(note="{{ attribute.deprecated }}")] {%- endif %} -{% if attribute.type.allow_custom_values is defined %}pub const {{ attribute.name | screaming_snake_case }}: crate::attributes::AttributeKey<{{ attribute.name | pascal_case }}> = crate::attributes::AttributeKey::new("{{ attribute.name }}"); -{% elif attribute.type == "string" %}pub const {{ attribute.name | screaming_snake_case }}: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("{{ attribute.name }}"); -{% else %}pub const {{ attribute.name | screaming_snake_case }}: crate::attributes::AttributeKey<{{ attribute.type | type_mapping }}> = crate::attributes::AttributeKey::new("{{ attribute.name }}");{% endif %} - -{% if attribute.type.members is defined %} -{%- if attribute.brief %} -{{ attribute.brief | comment_with_prefix("/// ") }} +{%- if attribute.type.allow_custom_values is defined %} +pub const {{ attribute.name | screaming_snake_case }}: crate::attributes::AttributeKey<{{ attribute.name | pascal_case }}> = crate::attributes::AttributeKey::new("{{ attribute.name }}"); +{%- elif attribute.type == "string" %} +pub const {{ attribute.name | screaming_snake_case }}: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("{{ attribute.name }}"); +{%- else %} +pub const {{ attribute.name | screaming_snake_case }}: crate::attributes::AttributeKey<{{ attribute.type | type_mapping }}> = crate::attributes::AttributeKey::new("{{ attribute.name }}"); {%- endif %} +{%- if attribute.type.members is defined %} + +{% if attribute.brief %}{{ attribute.brief | comment_with_prefix("/// ") }}{%- endif %} #[derive(Debug, Clone)] #[non_exhaustive] pub enum {{ attribute.name | pascal_case }} { -{% for variant in attribute.type.members %} +{%- for variant in attribute.type.members %} {%- if variant.brief %}{{ variant.brief | comment_with_prefix(" /// ") }}{% endif %} {%- if variant.note %}{{ variant.note | comment_with_prefix(" /// ") }}{% endif %} {%- if variant is experimental %} #[cfg(feature = "semconv_experimental")] {% endif %} {{ variant.id | pascal_case }}, -{% endfor %} +{%- endfor %} /// This variant allows defining a custom entry in the enum. _Custom(String), } @@ -78,5 +79,5 @@ impl crate::attributes::AttributeKey<{{ attribute.name | pascal_case }}> { opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) } } -{% endif %} -{% endfor %} \ No newline at end of file +{%- endif %} +{%- endfor %} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/counter.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/counter.j2 index e0f9a7a0..d541789a 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/counter.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/counter.j2 @@ -1,25 +1,67 @@ +{%- import 'attribute_macros.j2' as attribute_macros %} {%- if metric.brief %} {{ metric.brief | comment_with_prefix("/// ") }} {%- endif %} {%- if metric is experimental %} #[cfg(feature = "semconv_experimental")] {%- endif %} -pub fn create_u64_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Counter { - meter.u64_counter("{{ metric.metric_name }}") - .with_description("{{ metric.brief }}") - .with_unit(opentelemetry::metrics::Unit::new("{{ metric.unit }}")) - .init() +pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Counter + where opentelemetry::metrics::Meter: CounterProvider { + meter.create_counter("{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") } -{% if metric.brief %} -{{ metric.brief | comment_with_prefix("/// ") }} -{%- endif %} -{%- if metric is experimental %} -#[cfg(feature = "semconv_experimental")] -{%- endif %} -pub fn create_f64_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Counter { - meter.f64_counter("{{ metric.metric_name }}") - .with_description("{{ metric.brief }}") - .with_unit(opentelemetry::metrics::Unit::new("{{ metric.unit }}")) - .init() +/// Metric: {{ metric.metric_name }} +/// Brief: {{ metric.brief }} +/// Unit: {{ metric.unit }} +#[derive(Debug)] +pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::Counter); + +{%- set required_attributes = metric.attributes | required %} +{%- set optional_attributes = metric.attributes | optional %} + +{% if required_attributes %} +/// Attributes for the `{{ metric.metric_name }}` metric. +#[derive(Debug, Clone)] +pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { + {%- for attribute in required_attributes | attribute_sort %} + {{ attribute_macros.comments(attribute, " ///") }} + {%- if attribute.type.members is defined %} + pub {{ attribute.name | snake_case }}: crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | pascal_case }}, + {%- else %} + pub {{ attribute.name | snake_case }}: {{ attribute.type | type_mapping }}, + {%- endif %} + {%- endfor %} +} +{% endif %} + +{% if optional_attributes %} +#[derive(Debug, Clone, Default)] +pub struct {{ metric.metric_name | pascal_case }}OptAttributes { + {%- for attribute in optional_attributes | attribute_sort %} + {{ attribute_macros.comments(attribute, " ///") }} + {%- if attribute.type.members is defined %} + pub {{ attribute.name | snake_case }}: Option, + {%- else %} + pub {{ attribute.name | snake_case }}: Option<{{ attribute.type | type_mapping }}>, + {%- endif %} + {%- endfor %} } +{% endif %} + +impl {{ metric.metric_name | pascal_case }} { + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: CounterProvider{ + Self(meter.create_counter("{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) + } + + /// Adds an additional value to the counter. + pub fn add( + &self, + value: T, + {% if required_attributes %}required_attributes: &{{ metric.metric_name | pascal_case }}ReqAttributes,{% endif %} + {% if optional_attributes %}optional_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} + ) { + {{ attribute_macros.attributes_to_key_values(required_attributes, optional_attributes) }} + self.0.add(value, &attributes) + } +} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/gauge.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/gauge.j2 index 1b8fea10..833b48bc 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/gauge.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/gauge.j2 @@ -1,39 +1,67 @@ +{%- import 'attribute_macros.j2' as attribute_macros %} {%- if metric.brief %} {{ metric.brief | comment_with_prefix("/// ") }} {%- endif %} {%- if metric is experimental %} #[cfg(feature = "semconv_experimental")] {%- endif %} -pub fn create_u64_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Gauge { - meter.u64_gauge("{{ metric.metric_name }}") - .with_description("{{ metric.brief }}") - .with_unit(opentelemetry::metrics::Unit::new("{{ metric.unit }}")) - .init() +pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Gauge + where opentelemetry::metrics::Meter: GaugeProvider { + meter.create_gauge("{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") } -{% if metric.brief %} -{{ metric.brief | comment_with_prefix("/// ") }} -{%- endif %} -{%- if metric is experimental %} -#[cfg(feature = "semconv_experimental")] -{%- endif %} -pub fn create_i64_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Gauge { - meter.i64_gauge("{{ metric.metric_name }}") - .with_description("{{ metric.brief }}") - .with_unit(opentelemetry::metrics::Unit::new("{{ metric.unit }}")) - .init() -} +/// Metric: {{ metric.metric_name }} +/// Brief: {{ metric.brief }} +/// Unit: {{ metric.unit }} +#[derive(Debug)] +pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::Gauge); +{%- set required_attributes = metric.attributes | required %} +{%- set optional_attributes = metric.attributes | optional %} -{% if metric.brief %} -{{ metric.brief | comment_with_prefix("/// ") }} -{%- endif %} -{%- if metric is experimental %} -#[cfg(feature = "semconv_experimental")] -{%- endif %} -pub fn create_f64_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Gauge { - meter.f64_gauge("{{ metric.metric_name }}") - .with_description("{{ metric.brief }}") - .with_unit(opentelemetry::metrics::Unit::new("{{ metric.unit }}")) - .init() +{% if required_attributes %} +/// Attributes for the `{{ metric.metric_name }}` metric. +#[derive(Debug, Clone)] +pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { + {%- for attribute in required_attributes | attribute_sort %} + {{ attribute_macros.comments(attribute, " ///") }} + {%- if attribute.type.members is defined %} + pub {{ attribute.name | snake_case }}: crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | pascal_case }}, + {%- else %} + pub {{ attribute.name | snake_case }}: {{ attribute.type | type_mapping }}, + {%- endif %} + {%- endfor %} } +{% endif %} + +{% if optional_attributes %} +#[derive(Debug, Clone, Default)] +pub struct {{ metric.metric_name | pascal_case }}OptAttributes { + {%- for attribute in optional_attributes | attribute_sort %} + {{ attribute_macros.comments(attribute, " ///") }} + {%- if attribute.type.members is defined %} + pub {{ attribute.name | snake_case }}: Option, + {%- else %} + pub {{ attribute.name | snake_case }}: Option<{{ attribute.type | type_mapping }}>, + {%- endif %} + {%- endfor %} +} +{% endif %} + +impl {{ metric.metric_name | pascal_case }} { + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: GaugeProvider{ + Self(meter.create_gauge("{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) + } + + /// Records an additional value to the gauge. + pub fn record( + &self, + value: T, + {% if required_attributes %}required_attributes: &{{ metric.metric_name | pascal_case }}ReqAttributes,{% endif %} + {% if optional_attributes %}optional_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} + ) { + {{ attribute_macros.attributes_to_key_values(required_attributes, optional_attributes) }} + self.0.record(value, &attributes) + } +} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 index c9b62327..69991810 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 @@ -23,7 +23,7 @@ pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::His /// Attributes for the `{{ metric.metric_name }}` metric. #[derive(Debug, Clone)] pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { - {%- for attribute in required_attributes %} + {%- for attribute in required_attributes | attribute_sort %} {{ attribute_macros.comments(attribute, " ///") }} {%- if attribute.type.members is defined %} pub {{ attribute.name | snake_case }}: crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | pascal_case }}, @@ -37,7 +37,7 @@ pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { {% if optional_attributes %} #[derive(Debug, Clone, Default)] pub struct {{ metric.metric_name | pascal_case }}OptAttributes { - {%- for attribute in optional_attributes %} + {%- for attribute in optional_attributes | attribute_sort %} {{ attribute_macros.comments(attribute, " ///") }} {%- if attribute.type.members is defined %} pub {{ attribute.name | snake_case }}: Option, @@ -61,35 +61,7 @@ impl {{ metric.metric_name | pascal_case }} { {% if required_attributes %}required_attributes: &{{ metric.metric_name | pascal_case }}ReqAttributes,{% endif %} {% if optional_attributes %}optional_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} ) { - let mut attributes = vec![ - {%- for attribute in required_attributes %} - {%- if attribute.type.members is defined %} - crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(&required_attributes.{{ attribute.name | snake_case }}), - {%- elif attribute.type == "string" %} - crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(required_attributes.{{ attribute.name | snake_case }}.to_string().into()), - {%- else %} - crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(required_attributes.{{ attribute.name | snake_case }}), - {%- endif %} - {%- endfor %} - ]; - - if let Some(value) = &optional_attributes { - {%- for attribute in optional_attributes %} - {%- if attribute.type.members is defined %} - if let Some({{ attribute.name | snake_case }}) = &value.{{ attribute.name | snake_case }} { - attributes.push(crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value({{ attribute.name | snake_case }})); - } - {%- elif attribute.type == "string" %} - if let Some({{ attribute.name | snake_case }}) = &value.{{ attribute.name | snake_case }} { - attributes.push(crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value({{ attribute.name | snake_case }}.to_string().into())); - } - {%- else %} - if let Some({{ attribute.name | snake_case }}) = value.{{ attribute.name | snake_case }} { - attributes.push(crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value({{ attribute.name | snake_case }})); - } - {%- endif %} - {%- endfor %} - } + {{ attribute_macros.attributes_to_key_values(required_attributes, optional_attributes) }} self.0.record(value, &attributes) } } \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 index 66e44015..70241b89 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 @@ -8,7 +8,7 @@ //! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/metrics/metrics.rs.j2 -use crate::metrics::{HistogramProvider, UpDownCounterProvider}; +use crate::metrics::{CounterProvider, GaugeProvider, HistogramProvider, UpDownCounterProvider}; {%- for metric in ctx.groups %} {% include "metrics/" ~ metric.instrument ~ ".j2" %} diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/mod.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/mod.rs.j2 index 913f2c46..c7bf41ef 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/mod.rs.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/mod.rs.j2 @@ -67,4 +67,71 @@ impl UpDownCounterProvider for opentelemetry::metrics::Meter { .with_unit(opentelemetry::metrics::Unit::new(unit)) .init() } +} + +/// A trait implemented by counter providers (e.g. `Meter`). +pub trait CounterProvider { + /// Creates a new counter with the given name, description, and unit. + fn create_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Counter; +} + +/// This implementation specifies that a Meter is able to create u64 counters. +impl CounterProvider for opentelemetry::metrics::Meter { + /// Creates a new u64 counter with the given name, description, and unit. + fn create_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Counter { + self.u64_counter(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// This implementation specifies that a Meter is able to create f64 counters. +impl CounterProvider for opentelemetry::metrics::Meter { + /// Creates a new f64 counter with the given name, description, and unit. + fn create_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Counter { + self.f64_counter(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// A trait implemented by gauge providers (e.g. `Meter`). +pub trait GaugeProvider { + /// Creates a new gauge with the given name, description, and unit. + fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge; +} + +/// This implementation specifies that a Meter is able to create u64 gauges. +impl GaugeProvider for opentelemetry::metrics::Meter { + /// Creates a new u64 gauge with the given name, description, and unit. + fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge { + self.u64_gauge(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// This implementation specifies that a Meter is able to create i64 gauges. +impl GaugeProvider for opentelemetry::metrics::Meter { + /// Creates a new i64 gauge with the given name, description, and unit. + fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge { + self.i64_gauge(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// This implementation specifies that a Meter is able to create f64 gauges. +impl GaugeProvider for opentelemetry::metrics::Meter { + /// Creates a new f64 gauge with the given name, description, and unit. + fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge { + self.f64_gauge(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } } \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/updowncounter.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/updowncounter.j2 index 53234fe6..062b307d 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/updowncounter.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/updowncounter.j2 @@ -1,3 +1,4 @@ +{%- import 'attribute_macros.j2' as attribute_macros %} {%- if metric.brief %} {{ metric.brief | comment_with_prefix("/// ") }} {%- endif %} @@ -7,4 +8,60 @@ pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter where opentelemetry::metrics::Meter: UpDownCounterProvider { meter.create_up_down_counter("{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") +} + +/// Metric: {{ metric.metric_name }} +/// Brief: {{ metric.brief }} +/// Unit: {{ metric.unit }} +#[derive(Debug)] +pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::UpDownCounter); + +{%- set required_attributes = metric.attributes | required %} +{%- set optional_attributes = metric.attributes | optional %} + +{% if required_attributes %} +/// Attributes for the `{{ metric.metric_name }}` metric. +#[derive(Debug, Clone)] +pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { + {%- for attribute in required_attributes | attribute_sort %} + {{ attribute_macros.comments(attribute, " ///") }} + {%- if attribute.type.members is defined %} + pub {{ attribute.name | snake_case }}: crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | pascal_case }}, + {%- else %} + pub {{ attribute.name | snake_case }}: {{ attribute.type | type_mapping }}, + {%- endif %} + {%- endfor %} +} +{% endif %} + +{% if optional_attributes %} +#[derive(Debug, Clone, Default)] +pub struct {{ metric.metric_name | pascal_case }}OptAttributes { + {%- for attribute in optional_attributes | attribute_sort %} + {{ attribute_macros.comments(attribute, " ///") }} + {%- if attribute.type.members is defined %} + pub {{ attribute.name | snake_case }}: Option, + {%- else %} + pub {{ attribute.name | snake_case }}: Option<{{ attribute.type | type_mapping }}>, + {%- endif %} + {%- endfor %} +} +{% endif %} + +impl {{ metric.metric_name | pascal_case }} { + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: UpDownCounterProvider{ + Self(meter.create_up_down_counter("{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) + } + + /// Adds an additional value to the up-down-counter. + pub fn add( + &self, + value: T, + {% if required_attributes %}required_attributes: &{{ metric.metric_name | pascal_case }}ReqAttributes,{% endif %} + {% if optional_attributes %}optional_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} + ) { + {{ attribute_macros.attributes_to_key_values(required_attributes, optional_attributes) }} + self.0.add(value, &attributes) + } } \ No newline at end of file From 0832fb22fed4b39f879f0ceb763e2774303e2b5a Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Fri, 3 May 2024 16:50:18 -0700 Subject: [PATCH 23/39] feat(forge): Update generated code --- .../expected_codegen/attributes/client.rs | 16 +- .../expected_codegen/attributes/error.rs | 24 +- .../expected_codegen/attributes/exception.rs | 36 +- .../expected_codegen/attributes/http.rs | 198 +++--- .../expected_codegen/attributes/mod.rs | 2 + .../expected_codegen/attributes/network.rs | 498 ++++++++++---- .../expected_codegen/attributes/server.rs | 18 +- .../expected_codegen/attributes/system.rs | 150 +++++ .../expected_codegen/attributes/url.rs | 85 +-- .../expected_codegen/metrics/http.rs | 609 +++++++++++------- .../expected_codegen/metrics/mod.rs | 69 ++ .../expected_codegen/metrics/system.rs | 190 ++++++ .../templates/registry/rust/README.md | 120 +++- 13 files changed, 1454 insertions(+), 561 deletions(-) create mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/attributes/system.rs create mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/metrics/system.rs diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/client.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/client.rs index d0c1918e..4c69c8ac 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/client.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/client.rs @@ -6,20 +6,22 @@ //! 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/attributes/attributes.rs.j2 - /// 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. +/// +/// Examples: +/// - client.example.com +/// - 10.1.2.80 +/// - /tmp/my.sock pub const CLIENT_ADDRESS: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("client.address"); - - - /// Client port number. /// /// 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: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("client.port"); - - +/// +/// Examples: +/// - 65123 +pub const CLIENT_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("client.port"); \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/error.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/error.rs index 521c8111..1091cc6e 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/error.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/error.rs @@ -6,7 +6,6 @@ //! This document defines the shared attributes used to report an error. //! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/attributes/attributes.rs.j2 - /// Describes a class of error the operation ended with. /// /// Notes: @@ -29,24 +28,29 @@ /// /// * Use a domain-specific attribute /// * Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. +/// +/// Examples: +/// - timeout +/// - java.net.UnknownHostException +/// - server_certificate_invalid +/// - 500 pub const ERROR_TYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("error.type"); - - /// Describes a class of error the operation ended with. #[derive(Debug, Clone)] #[non_exhaustive] -pub enum ErrorType { - /// A fallback error value to be used when the instrumentation doesn't define a custom value. +pub enum ErrorType { /// A fallback error value to be used when the instrumentation doesn't define a custom value. Other, - + /// This variant allows defining a custom entry in the enum. + _Custom(String), } impl ErrorType { /// Returns the string representation of the [`ErrorType`]. - pub fn as_str(&self) -> &'static str { + pub fn as_str(&self) -> &str { match self { ErrorType::Other => "_OTHER", + ErrorType::_Custom(v) => v.as_str(), // 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. @@ -63,3 +67,9 @@ impl core::fmt::Display for ErrorType { } } +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &ErrorType) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/exception.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/exception.rs index 76517ba5..2d13b70b 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/exception.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/exception.rs @@ -6,25 +6,6 @@ //! 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/attributes/attributes.rs.j2 - -/// 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: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("exception.type"); - - - - -/// The exception message. -pub const EXCEPTION_MESSAGE: crate::attributes::AttributeKey = crate::attributes::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: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("exception.stacktrace"); - - - - /// SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span. /// /// Notes: @@ -46,4 +27,21 @@ pub const EXCEPTION_STACKTRACE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("exception.escaped"); +/// The exception message. +/// +/// Examples: +/// - Division by zero +/// - Can't convert 'int' object to str implicitly +pub const EXCEPTION_MESSAGE: crate::attributes::AttributeKey = crate::attributes::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. +/// +/// Example: Exception in thread "main" java.lang.RuntimeException: Test exception\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n at com.example.GenerateTrace.main(GenerateTrace.java:5) +pub const EXCEPTION_STACKTRACE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("exception.stacktrace"); + +/// 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. +/// +/// Examples: +/// - java.net.ConnectException +/// - OSError +pub const EXCEPTION_TYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("exception.type"); \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/http.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/http.rs index 57aead25..bab1a220 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/http.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/http.rs @@ -6,23 +6,76 @@ //! This document defines semantic convention attributes in the HTTP namespace. //! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/attributes/attributes.rs.j2 +/// State of the HTTP connection in the HTTP connection pool. +/// +/// Examples: +/// - active +/// - idle +#[cfg(feature = "semconv_experimental")] +pub const HTTP_CONNECTION_STATE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.connection.state"); + +/// State of the HTTP connection in the HTTP connection pool. +#[derive(Debug, Clone)] +#[non_exhaustive] +pub enum HttpConnectionState { /// active state. + #[cfg(feature = "semconv_experimental")] + Active, /// idle state. + #[cfg(feature = "semconv_experimental")] + Idle, + /// This variant allows defining a custom entry in the enum. + _Custom(String), +} + +impl HttpConnectionState { + /// Returns the string representation of the [`HttpConnectionState`]. + pub fn as_str(&self) -> &str { + match self { + #[cfg(feature = "semconv_experimental")] + HttpConnectionState::Active => "active", + #[cfg(feature = "semconv_experimental")] + HttpConnectionState::Idle => "idle", + HttpConnectionState::_Custom(v) => v.as_str(), + // 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()) + } +} + +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &HttpConnectionState) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} /// 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. +/// +/// Example: 3495 #[cfg(feature = "semconv_experimental")] pub const HTTP_REQUEST_BODY_SIZE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.request.body.size"); - - /// HTTP request headers, `` being the normalized HTTP Header name (lowercase), the value being the header values. /// /// Notes: /// 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. +/// +/// Examples: +/// - http.request.header.content-type=["application/json"] +/// - http.request.header.x-forwarded-for=["1.2.3.4", "1.2.3.5"] pub const HTTP_REQUEST_HEADER: crate::attributes::AttributeKey> = crate::attributes::AttributeKey::new("http.request.header"); - - /// HTTP request method. /// /// Notes: @@ -40,40 +93,34 @@ pub const HTTP_REQUEST_HEADER: crate::attributes::AttributeKey> = cr /// 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. +/// +/// Examples: +/// - GET +/// - POST +/// - HEAD pub const HTTP_REQUEST_METHOD: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.request.method"); - - /// HTTP request method. #[derive(Debug, Clone)] #[non_exhaustive] -pub enum HttpRequestMethod { - /// CONNECT method. - Connect, - /// DELETE method. - Delete, - /// GET method. - Get, - /// HEAD method. - Head, - /// OPTIONS method. - Options, - /// PATCH method. - Patch, - /// POST method. - Post, - /// PUT method. - Put, - /// TRACE method. - Trace, - /// Any HTTP method that the instrumentation has no prior knowledge of. +pub enum HttpRequestMethod { /// CONNECT method. + Connect, /// DELETE method. + Delete, /// GET method. + Get, /// HEAD method. + Head, /// OPTIONS method. + Options, /// PATCH method. + Patch, /// POST method. + Post, /// PUT method. + Put, /// TRACE method. + Trace, /// Any HTTP method that the instrumentation has no prior knowledge of. Other, - + /// This variant allows defining a custom entry in the enum. + _Custom(String), } impl HttpRequestMethod { /// Returns the string representation of the [`HttpRequestMethod`]. - pub fn as_str(&self) -> &'static str { + pub fn as_str(&self) -> &str { match self { HttpRequestMethod::Connect => "CONNECT", HttpRequestMethod::Delete => "DELETE", @@ -85,6 +132,7 @@ impl HttpRequestMethod { HttpRequestMethod::Put => "PUT", HttpRequestMethod::Trace => "TRACE", HttpRequestMethod::Other => "_OTHER", + HttpRequestMethod::_Custom(v) => v.as_str(), // 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. @@ -101,104 +149,72 @@ impl core::fmt::Display for HttpRequestMethod { } } +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &HttpRequestMethod) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} /// Original HTTP method sent by the client in the request line. +/// +/// Examples: +/// - GeT +/// - ACL +/// - foo pub const HTTP_REQUEST_METHOD_ORIGINAL: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.request.method_original"); - - - /// The ordinal number of request resending attempt (for any reason, including redirects). /// /// 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). +/// +/// Example: 3 pub const HTTP_REQUEST_RESEND_COUNT: crate::attributes::AttributeKey = crate::attributes::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. +/// +/// Example: 1437 #[cfg(feature = "semconv_experimental")] pub const HTTP_REQUEST_SIZE: crate::attributes::AttributeKey = crate::attributes::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. +/// +/// Example: 3495 #[cfg(feature = "semconv_experimental")] pub const HTTP_RESPONSE_BODY_SIZE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.response.body.size"); - - /// HTTP response headers, `` being the normalized HTTP Header name (lowercase), the value being the header values. /// /// Notes: /// 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. +/// +/// Examples: +/// - http.response.header.content-type=["application/json"] +/// - http.response.header.my-custom-header=["abc", "def"] pub const HTTP_RESPONSE_HEADER: crate::attributes::AttributeKey> = crate::attributes::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. +/// +/// Example: 1437 #[cfg(feature = "semconv_experimental")] pub const HTTP_RESPONSE_SIZE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.response.size"); - - /// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). +/// +/// Examples: +/// - 200 pub const HTTP_RESPONSE_STATUS_CODE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.response.status_code"); - - /// The matched route, that is, the path template in the format used by the respective server framework. /// /// 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: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.route"); - - - - -/// State of the HTTP connection in the HTTP connection pool. -#[cfg(feature = "semconv_experimental")] -pub const HTTP_CONNECTION_STATE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.connection.state"); - - - -/// State of the HTTP connection in the HTTP connection pool. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum HttpConnectionState { - /// active state. - #[cfg(feature = "semconv_experimental")] - Active, - /// idle state. - #[cfg(feature = "semconv_experimental")] - Idle, - -} - -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()) - } -} - +/// +/// Examples: +/// - /users/:userID? +/// - {controller}/{action}/{id?} +pub const HTTP_ROUTE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.route"); \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/mod.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/mod.rs index b3ddedc0..26e301b8 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/mod.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/mod.rs @@ -21,6 +21,8 @@ pub mod http; pub mod network; /// Attributes for the `server` namespace. pub mod server; +/// Attributes for the `system` namespace. +pub mod system; /// Attributes for the `url` namespace. pub mod url; diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/network.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/network.rs index 0a069ded..10e6a8a2 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/network.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/network.rs @@ -6,114 +6,292 @@ //! These attributes may be used for any network related operation. //! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/attributes/attributes.rs.j2 +/// Deprecated, use `server.address`. +/// +/// Examples: +/// - example.com +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `server.address`.")] +pub const NET_HOST_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.host.name"); -/// The ISO 3166-1 alpha-2 2-character country code associated with the mobile carrier network. +/// Deprecated, use `server.port`. +/// +/// Examples: +/// - 8080 #[cfg(feature = "semconv_experimental")] -pub const NETWORK_CARRIER_ICC: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.icc"); +#[deprecated(note="Replaced by `server.port`.")] +pub const NET_HOST_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.host.port"); +/// Deprecated, use `server.address` on client spans and `client.address` on server spans. +/// +/// Examples: +/// - example.com +#[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::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.peer.name"); +/// Deprecated, use `server.port` on client spans and `client.port` on server spans. +/// +/// Examples: +/// - 8080 +#[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::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.peer.port"); +/// Deprecated, use `network.protocol.name`. +/// +/// Examples: +/// - amqp +/// - http +/// - mqtt +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `network.protocol.name`.")] +pub const NET_PROTOCOL_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.protocol.name"); -/// The mobile carrier country code. +/// Deprecated, use `network.protocol.version`. +/// +/// Example: 3.1.1 #[cfg(feature = "semconv_experimental")] -pub const NETWORK_CARRIER_MCC: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.mcc"); +#[deprecated(note="Replaced by `network.protocol.version`.")] +pub const NET_PROTOCOL_VERSION: crate::attributes::AttributeKey = crate::attributes::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::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.family"); +/// Deprecated, use `network.transport` and `network.type`. +#[derive(Debug, Clone)] +#[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, + /// This variant allows defining a custom entry in the enum. + _Custom(String), +} + +impl NetSockFamily { + /// Returns the string representation of the [`NetSockFamily`]. + pub fn as_str(&self) -> &str { + match self { + #[cfg(feature = "semconv_experimental")] + NetSockFamily::Inet => "inet", + #[cfg(feature = "semconv_experimental")] + NetSockFamily::Inet6 => "inet6", + #[cfg(feature = "semconv_experimental")] + NetSockFamily::Unix => "unix", + NetSockFamily::_Custom(v) => v.as_str(), + // 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()) + } +} +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &NetSockFamily) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} -/// The mobile carrier network code. +/// Deprecated, use `network.local.address`. +/// +/// Examples: +/// - /var/my.sock #[cfg(feature = "semconv_experimental")] -pub const NETWORK_CARRIER_MNC: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.mnc"); +#[deprecated(note="Replaced by `network.local.address`.")] +pub const NET_SOCK_HOST_ADDR: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.host.addr"); +/// Deprecated, use `network.local.port`. +/// +/// Examples: +/// - 8080 +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `network.local.port`.")] +pub const NET_SOCK_HOST_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.host.port"); +/// Deprecated, use `network.peer.address`. +/// +/// Examples: +/// - 192.168.0.1 +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `network.peer.address`.")] +pub const NET_SOCK_PEER_ADDR: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.peer.addr"); +/// Deprecated, no replacement at this time. +/// +/// Examples: +/// - /var/my.sock +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Removed.")] +pub const NET_SOCK_PEER_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.peer.name"); -/// The name of the mobile carrier. +/// Deprecated, use `network.peer.port`. +/// +/// Examples: +/// - 65531 #[cfg(feature = "semconv_experimental")] -pub const NETWORK_CARRIER_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.name"); +#[deprecated(note="Replaced by `network.peer.port`.")] +pub const NET_SOCK_PEER_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.peer.port"); +/// Deprecated, use `network.transport`. +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `network.transport`.")] +pub const NET_TRANSPORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.transport"); +/// Deprecated, use `network.transport`. +#[derive(Debug, Clone)] +#[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, + /// This variant allows defining a custom entry in the enum. + _Custom(String), +} + +impl NetTransport { + /// Returns the string representation of the [`NetTransport`]. + pub fn as_str(&self) -> &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", + NetTransport::_Custom(v) => v.as_str(), + // 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()) + } +} -/// This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection. +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &NetTransport) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} + +/// The ISO 3166-1 alpha-2 2-character country code associated with the mobile carrier network. +/// +/// Example: DE #[cfg(feature = "semconv_experimental")] -pub const NETWORK_CONNECTION_SUBTYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.connection.subtype"); +pub const NETWORK_CARRIER_ICC: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.icc"); +/// The mobile carrier country code. +/// +/// Example: 310 +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_CARRIER_MCC: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.mcc"); +/// The mobile carrier network code. +/// +/// Example: 001 +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_CARRIER_MNC: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.mnc"); + +/// The name of the mobile carrier. +/// +/// Example: sprint +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_CARRIER_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.name"); + +/// This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection. +/// +/// Example: LTE +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_CONNECTION_SUBTYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.connection.subtype"); /// This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection. #[derive(Debug, Clone)] #[non_exhaustive] -pub enum NetworkConnectionSubtype { - /// GPRS +pub enum NetworkConnectionSubtype { /// GPRS #[cfg(feature = "semconv_experimental")] - Gprs, - /// EDGE + Gprs, /// EDGE #[cfg(feature = "semconv_experimental")] - Edge, - /// UMTS + Edge, /// UMTS #[cfg(feature = "semconv_experimental")] - Umts, - /// CDMA + Umts, /// CDMA #[cfg(feature = "semconv_experimental")] - Cdma, - /// EVDO Rel. 0 + Cdma, /// EVDO Rel. 0 #[cfg(feature = "semconv_experimental")] - Evdo0, - /// EVDO Rev. A + Evdo0, /// EVDO Rev. A #[cfg(feature = "semconv_experimental")] - EvdoA, - /// CDMA2000 1XRTT + EvdoA, /// CDMA2000 1XRTT #[cfg(feature = "semconv_experimental")] - Cdma20001Xrtt, - /// HSDPA + Cdma20001Xrtt, /// HSDPA #[cfg(feature = "semconv_experimental")] - Hsdpa, - /// HSUPA + Hsdpa, /// HSUPA #[cfg(feature = "semconv_experimental")] - Hsupa, - /// HSPA + Hsupa, /// HSPA #[cfg(feature = "semconv_experimental")] - Hspa, - /// IDEN + Hspa, /// IDEN #[cfg(feature = "semconv_experimental")] - Iden, - /// EVDO Rev. B + Iden, /// EVDO Rev. B #[cfg(feature = "semconv_experimental")] - EvdoB, - /// LTE + EvdoB, /// LTE #[cfg(feature = "semconv_experimental")] - Lte, - /// EHRPD + Lte, /// EHRPD #[cfg(feature = "semconv_experimental")] - Ehrpd, - /// HSPAP + Ehrpd, /// HSPAP #[cfg(feature = "semconv_experimental")] - Hspap, - /// GSM + Hspap, /// GSM #[cfg(feature = "semconv_experimental")] - Gsm, - /// TD-SCDMA + Gsm, /// TD-SCDMA #[cfg(feature = "semconv_experimental")] - TdScdma, - /// IWLAN + TdScdma, /// IWLAN #[cfg(feature = "semconv_experimental")] - Iwlan, - /// 5G NR (New Radio) + Iwlan, /// 5G NR (New Radio) #[cfg(feature = "semconv_experimental")] - Nr, - /// 5G NRNSA (New Radio Non-Standalone) + Nr, /// 5G NRNSA (New Radio Non-Standalone) #[cfg(feature = "semconv_experimental")] - Nrnsa, - /// LTE CA + Nrnsa, /// LTE CA #[cfg(feature = "semconv_experimental")] LteCa, - + /// This variant allows defining a custom entry in the enum. + _Custom(String), } impl NetworkConnectionSubtype { /// Returns the string representation of the [`NetworkConnectionSubtype`]. - pub fn as_str(&self) -> &'static str { + pub fn as_str(&self) -> &str { match self { #[cfg(feature = "semconv_experimental")] NetworkConnectionSubtype::Gprs => "gprs", @@ -157,6 +335,7 @@ impl NetworkConnectionSubtype { NetworkConnectionSubtype::Nrnsa => "nrnsa", #[cfg(feature = "semconv_experimental")] NetworkConnectionSubtype::LteCa => "lte_ca", + NetworkConnectionSubtype::_Custom(v) => v.as_str(), // 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. @@ -173,38 +352,40 @@ impl core::fmt::Display for NetworkConnectionSubtype { } } +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &NetworkConnectionSubtype) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} /// The internet connection type. +/// +/// Example: wifi #[cfg(feature = "semconv_experimental")] pub const NETWORK_CONNECTION_TYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.connection.type"); - - /// The internet connection type. #[derive(Debug, Clone)] #[non_exhaustive] pub enum NetworkConnectionType { - #[cfg(feature = "semconv_experimental")] Wifi, - #[cfg(feature = "semconv_experimental")] Wired, - #[cfg(feature = "semconv_experimental")] Cell, - #[cfg(feature = "semconv_experimental")] Unavailable, - #[cfg(feature = "semconv_experimental")] Unknown, - + /// This variant allows defining a custom entry in the enum. + _Custom(String), } impl NetworkConnectionType { /// Returns the string representation of the [`NetworkConnectionType`]. - pub fn as_str(&self) -> &'static str { + pub fn as_str(&self) -> &str { match self { #[cfg(feature = "semconv_experimental")] NetworkConnectionType::Wifi => "wifi", @@ -216,6 +397,7 @@ impl NetworkConnectionType { NetworkConnectionType::Unavailable => "unavailable", #[cfg(feature = "semconv_experimental")] NetworkConnectionType::Unknown => "unknown", + NetworkConnectionType::_Custom(v) => v.as_str(), // 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. @@ -232,47 +414,111 @@ impl core::fmt::Display for NetworkConnectionType { } } +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &NetworkConnectionType) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} -/// Local address of the network connection - IP address or Unix domain socket name. -pub const NETWORK_LOCAL_ADDRESS: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.local.address"); +/// The network IO operation direction. +/// +/// Examples: +/// - transmit +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_IO_DIRECTION: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.io.direction"); +/// The network IO operation direction. +#[derive(Debug, Clone)] +#[non_exhaustive] +pub enum NetworkIoDirection { + #[cfg(feature = "semconv_experimental")] + Transmit, + #[cfg(feature = "semconv_experimental")] + Receive, + /// This variant allows defining a custom entry in the enum. + _Custom(String), +} +impl NetworkIoDirection { + /// Returns the string representation of the [`NetworkIoDirection`]. + pub fn as_str(&self) -> &str { + match self { + #[cfg(feature = "semconv_experimental")] + NetworkIoDirection::Transmit => "transmit", + #[cfg(feature = "semconv_experimental")] + NetworkIoDirection::Receive => "receive", + NetworkIoDirection::_Custom(v) => v.as_str(), + // 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 NetworkIoDirection { + /// Formats the value using the given formatter. + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } +} -/// Local port number of the network connection. -pub const NETWORK_LOCAL_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.local.port"); +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &NetworkIoDirection) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} +/// Local address of the network connection - IP address or Unix domain socket name. +/// +/// Examples: +/// - 10.1.2.80 +/// - /tmp/my.sock +pub const NETWORK_LOCAL_ADDRESS: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.local.address"); +/// Local port number of the network connection. +/// +/// Examples: +/// - 65123 +pub const NETWORK_LOCAL_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.local.port"); /// Peer address of the network connection - IP address or Unix domain socket name. +/// +/// Examples: +/// - 10.1.2.80 +/// - /tmp/my.sock pub const NETWORK_PEER_ADDRESS: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.peer.address"); - - - /// Peer port number of the network connection. +/// +/// Examples: +/// - 65123 pub const NETWORK_PEER_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.peer.port"); - - /// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. /// /// Notes: /// The value SHOULD be normalized to lowercase. +/// +/// Examples: +/// - amqp +/// - http +/// - mqtt pub const NETWORK_PROTOCOL_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.protocol.name"); - - - /// The actual version of the protocol used for network communication. /// /// Notes: /// If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, this attribute SHOULD NOT be set. +/// +/// Examples: +/// - 1.1 +/// - 2 pub const NETWORK_PROTOCOL_VERSION: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.protocol.version"); - - - /// [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). /// /// Notes: @@ -281,33 +527,33 @@ pub const NETWORK_PROTOCOL_VERSION: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.transport"); - - /// [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). #[derive(Debug, Clone)] #[non_exhaustive] -pub enum NetworkTransport { - /// TCP - Tcp, - /// UDP - Udp, - /// Named or anonymous pipe. - Pipe, - /// Unix domain socket +pub enum NetworkTransport { /// TCP + Tcp, /// UDP + Udp, /// Named or anonymous pipe. + Pipe, /// Unix domain socket Unix, - + /// This variant allows defining a custom entry in the enum. + _Custom(String), } impl NetworkTransport { /// Returns the string representation of the [`NetworkTransport`]. - pub fn as_str(&self) -> &'static str { + pub fn as_str(&self) -> &str { match self { NetworkTransport::Tcp => "tcp", NetworkTransport::Udp => "udp", NetworkTransport::Pipe => "pipe", NetworkTransport::Unix => "unix", + NetworkTransport::_Custom(v) => v.as_str(), // 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. @@ -324,32 +570,40 @@ impl core::fmt::Display for NetworkTransport { } } +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &NetworkTransport) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} /// [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. /// /// Notes: /// The value SHOULD be normalized to lowercase. +/// +/// Examples: +/// - ipv4 +/// - ipv6 pub const NETWORK_TYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.type"); - - /// [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. #[derive(Debug, Clone)] #[non_exhaustive] -pub enum NetworkType { - /// IPv4 - Ipv4, - /// IPv6 +pub enum NetworkType { /// IPv4 + Ipv4, /// IPv6 Ipv6, - + /// This variant allows defining a custom entry in the enum. + _Custom(String), } impl NetworkType { /// Returns the string representation of the [`NetworkType`]. - pub fn as_str(&self) -> &'static str { + pub fn as_str(&self) -> &str { match self { NetworkType::Ipv4 => "ipv4", NetworkType::Ipv6 => "ipv6", + NetworkType::_Custom(v) => v.as_str(), // 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. @@ -366,47 +620,9 @@ impl core::fmt::Display for NetworkType { } } - -/// The network IO operation direction. -#[cfg(feature = "semconv_experimental")] -pub const NETWORK_IO_DIRECTION: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.io.direction"); - - - -/// The network IO operation direction. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum NetworkIoDirection { - - #[cfg(feature = "semconv_experimental")] - Transmit, - - #[cfg(feature = "semconv_experimental")] - Receive, - -} - -impl NetworkIoDirection { - /// Returns the string representation of the [`NetworkIoDirection`]. - pub fn as_str(&self) -> &'static str { - match self { - #[cfg(feature = "semconv_experimental")] - NetworkIoDirection::Transmit => "transmit", - #[cfg(feature = "semconv_experimental")] - NetworkIoDirection::Receive => "receive", - // 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 NetworkIoDirection { - /// Formats the value using the given formatter. - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.as_str()) +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &NetworkType) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) } -} - +} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/server.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/server.rs index e9ca9c55..9b894160 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/server.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/server.rs @@ -6,20 +6,24 @@ //! These attributes may be used to describe the server 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/attributes/attributes.rs.j2 - /// Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. /// /// Notes: /// When observed from the client side, and when communicating through an intermediary, `server.address` SHOULD represent the server address behind any intermediaries, for example proxies, if it's available. +/// +/// Examples: +/// - example.com +/// - 10.1.2.80 +/// - /tmp/my.sock pub const SERVER_ADDRESS: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("server.address"); - - - /// Server port number. /// /// Notes: /// When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent the server port behind any intermediaries, for example proxies, if it's available. -pub const SERVER_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("server.port"); - - +/// +/// Examples: +/// - 80 +/// - 8080 +/// - 443 +pub const SERVER_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("server.port"); \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/system.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/system.rs new file mode 100644 index 00000000..77838d2a --- /dev/null +++ b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/system.rs @@ -0,0 +1,150 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Describes System CPU attributes +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/attributes/attributes.rs.j2 + +/// The logical CPU number [0..n-1] +/// +/// Examples: +/// - 1 +#[cfg(feature = "semconv_experimental")] +pub const SYSTEM_CPU_LOGICAL_NUMBER: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("system.cpu.logical_number"); + +/// The state of the CPU +/// +/// Examples: +/// - idle +/// - interrupt +#[cfg(feature = "semconv_experimental")] +pub const SYSTEM_CPU_STATE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("system.cpu.state"); + +/// The state of the CPU +#[derive(Debug, Clone)] +#[non_exhaustive] +pub enum SystemCpuState { + #[cfg(feature = "semconv_experimental")] + User, + #[cfg(feature = "semconv_experimental")] + System, + #[cfg(feature = "semconv_experimental")] + Nice, + #[cfg(feature = "semconv_experimental")] + Idle, + #[cfg(feature = "semconv_experimental")] + Iowait, + #[cfg(feature = "semconv_experimental")] + Interrupt, + #[cfg(feature = "semconv_experimental")] + Steal, + /// This variant allows defining a custom entry in the enum. + _Custom(String), +} + +impl SystemCpuState { + /// Returns the string representation of the [`SystemCpuState`]. + pub fn as_str(&self) -> &str { + match self { + #[cfg(feature = "semconv_experimental")] + SystemCpuState::User => "user", + #[cfg(feature = "semconv_experimental")] + SystemCpuState::System => "system", + #[cfg(feature = "semconv_experimental")] + SystemCpuState::Nice => "nice", + #[cfg(feature = "semconv_experimental")] + SystemCpuState::Idle => "idle", + #[cfg(feature = "semconv_experimental")] + SystemCpuState::Iowait => "iowait", + #[cfg(feature = "semconv_experimental")] + SystemCpuState::Interrupt => "interrupt", + #[cfg(feature = "semconv_experimental")] + SystemCpuState::Steal => "steal", + SystemCpuState::_Custom(v) => v.as_str(), + // 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 SystemCpuState { + /// Formats the value using the given formatter. + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &SystemCpuState) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} + +/// The memory state +/// +/// Examples: +/// - free +/// - cached +#[cfg(feature = "semconv_experimental")] +pub const SYSTEM_MEMORY_STATE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("system.memory.state"); + +/// The memory state +#[derive(Debug, Clone)] +#[non_exhaustive] +pub enum SystemMemoryState { + #[cfg(feature = "semconv_experimental")] + Used, + #[cfg(feature = "semconv_experimental")] + Free, + #[cfg(feature = "semconv_experimental")] + Shared, + #[cfg(feature = "semconv_experimental")] + Buffers, + #[cfg(feature = "semconv_experimental")] + Cached, + /// This variant allows defining a custom entry in the enum. + _Custom(String), +} + +impl SystemMemoryState { + /// Returns the string representation of the [`SystemMemoryState`]. + pub fn as_str(&self) -> &str { + match self { + #[cfg(feature = "semconv_experimental")] + SystemMemoryState::Used => "used", + #[cfg(feature = "semconv_experimental")] + SystemMemoryState::Free => "free", + #[cfg(feature = "semconv_experimental")] + SystemMemoryState::Shared => "shared", + #[cfg(feature = "semconv_experimental")] + SystemMemoryState::Buffers => "buffers", + #[cfg(feature = "semconv_experimental")] + SystemMemoryState::Cached => "cached", + SystemMemoryState::_Custom(v) => v.as_str(), + // 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 SystemMemoryState { + /// Formats the value using the given formatter. + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &SystemMemoryState) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/url.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/url.rs index 5f4daa72..ac5f9d1b 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/url.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/url.rs @@ -6,111 +6,122 @@ //! Attributes describing URL. //! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/attributes/attributes.rs.j2 - /// Domain extracted from the `url.full`, such as "opentelemetry.io". /// /// Notes: /// In some cases a URL may refer to an IP and/or port directly, without a domain name. In this case, the IP address would go to the domain field. If the URL contains a [literal IPv6 address](https://www.rfc-editor.org/rfc/rfc2732#section-2) enclosed by `[` and `]`, the `[` and `]` characters should also be captured in the domain field. +/// +/// Examples: +/// - www.foo.bar +/// - opentelemetry.io +/// - 3.12.167.2 +/// - [1080:0:0:0:8:800:200C:417A] #[cfg(feature = "semconv_experimental")] pub const URL_DOMAIN: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.domain"); - - - /// The file extension extracted from the `url.full`, excluding the leading dot. /// /// Notes: /// The file extension is only set if it exists, as not every url has a file extension. When the file name has multiple extensions `example.tar.gz`, only the last one should be captured `gz`, not `tar.gz`. +/// +/// Examples: +/// - png +/// - gz #[cfg(feature = "semconv_experimental")] pub const URL_EXTENSION: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.extension"); - - - /// The [URI fragment](https://www.rfc-editor.org/rfc/rfc3986#section-3.5) component +/// +/// Examples: +/// - SemConv pub const URL_FRAGMENT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.fragment"); - - - /// Absolute URL describing a network resource according to [RFC3986](https://www.rfc-editor.org/rfc/rfc3986) /// /// Notes: /// For network calls, URL usually has `scheme://host[:port][path][?query][#fragment]` format, where the fragment is not transmitted over HTTP, but if it is known, it SHOULD be included nevertheless. /// `url.full` MUST NOT contain credentials passed via URL in form of `https://username:password@www.example.com/`. In such case username and password SHOULD be redacted and attribute's value SHOULD be `https://REDACTED:REDACTED@www.example.com/`. /// `url.full` SHOULD capture the absolute URL when it is available (or can be reconstructed). Sensitive content provided in `url.full` SHOULD be scrubbed when instrumentations can identify it. +/// +/// Examples: +/// - https://www.foo.bar/search?q=OpenTelemetry#SemConv +/// - //localhost pub const URL_FULL: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.full"); - - - /// Unmodified original URL as seen in the event source. /// /// Notes: /// In network monitoring, the observed URL may be a full URL, whereas in access logs, the URL is often just represented as a path. This field is meant to represent the URL as it was observed, complete or not. /// `url.original` might contain credentials passed via URL in form of `https://username:password@www.example.com/`. In such case password and username SHOULD NOT be redacted and attribute's value SHOULD remain the same. +/// +/// Examples: +/// - https://www.foo.bar/search?q=OpenTelemetry#SemConv +/// - search?q=OpenTelemetry #[cfg(feature = "semconv_experimental")] pub const URL_ORIGINAL: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.original"); - - - /// The [URI path](https://www.rfc-editor.org/rfc/rfc3986#section-3.3) component /// /// Notes: /// Sensitive content provided in `url.path` SHOULD be scrubbed when instrumentations can identify it. +/// +/// Examples: +/// - /search pub const URL_PATH: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.path"); - - - /// Port extracted from the `url.full` +/// +/// Examples: +/// - 443 #[cfg(feature = "semconv_experimental")] pub const URL_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.port"); - - /// The [URI query](https://www.rfc-editor.org/rfc/rfc3986#section-3.4) component /// /// Notes: /// Sensitive content provided in `url.query` SHOULD be scrubbed when instrumentations can identify it. +/// +/// Examples: +/// - q=OpenTelemetry pub const URL_QUERY: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.query"); - - - /// The highest registered url domain, stripped of the subdomain. /// /// Notes: /// This value can be determined precisely with the [public suffix list](http://publicsuffix.org). For example, the registered domain for `foo.example.com` is `example.com`. Trying to approximate this by simply taking the last two labels will not work well for TLDs such as `co.uk`. +/// +/// Examples: +/// - example.com +/// - foo.co.uk #[cfg(feature = "semconv_experimental")] pub const URL_REGISTERED_DOMAIN: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.registered_domain"); - - - /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. +/// +/// Examples: +/// - https +/// - ftp +/// - telnet pub const URL_SCHEME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.scheme"); - - - /// The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. /// /// Notes: /// The subdomain portion of `www.east.mydomain.co.uk` is `east`. If the domain has multiple levels of subdomain, such as `sub2.sub1.example.com`, the subdomain field should contain `sub2.sub1`, with no trailing period. +/// +/// Examples: +/// - east +/// - sub2.sub1 #[cfg(feature = "semconv_experimental")] pub const URL_SUBDOMAIN: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.subdomain"); - - - /// The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is `com`. /// /// Notes: /// This value can be determined precisely with the [public suffix list](http://publicsuffix.org). +/// +/// Examples: +/// - com +/// - co.uk #[cfg(feature = "semconv_experimental")] -pub const URL_TOP_LEVEL_DOMAIN: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.top_level_domain"); - - - +pub const URL_TOP_LEVEL_DOMAIN: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.top_level_domain"); \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/metrics/http.rs b/crates/weaver_forge/codegen_examples/expected_codegen/metrics/http.rs index 0e50626d..016c30cb 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/metrics/http.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/metrics/http.rs @@ -5,8 +5,7 @@ //! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/metrics/metrics.rs.j2 -use crate::metrics::{HistogramProvider, UpDownCounterProvider}; - +use crate::metrics::{CounterProvider, GaugeProvider, HistogramProvider, UpDownCounterProvider}; /// Duration of HTTP server requests. pub fn create_http_server_request_duration(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram @@ -20,144 +19,189 @@ pub fn create_http_server_request_duration(meter: &opentelemetry::metrics::Me #[derive(Debug)] pub struct HttpServerRequestDuration(opentelemetry::metrics::Histogram); + /// Attributes for the `http.server.request.duration` metric. #[derive(Debug, Clone)] -pub struct HttpServerRequestDurationAttributes { +pub struct HttpServerRequestDurationReqAttributes { + /// HTTP request method. + /// + /// Notes: + /// HTTP request method value SHOULD be "known" to the instrumentation. + /// By default, this convention defines "known" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods) + /// and the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html). + /// + /// If the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`. + /// + /// If the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override + /// the list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named + /// OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods + /// (this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults). + /// + /// 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. + /// + /// Examples: + /// - GET + /// - POST + /// - HEAD pub http_request_method: crate::attributes::http::HttpRequestMethod, - /// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). - pub http_response_status_code: Option, - /// The matched route, that is, the path template in the format used by the respective server framework. - pub http_route: Option, - /// Describes a class of error the operation ended with. - pub error_type: Option, - /// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. - pub network_protocol_name: Option, - /// The actual version of the protocol used for network communication. - pub network_protocol_version: Option, - /// Name of the local HTTP server that received the request. - pub server_address: Option, - /// Port of the local HTTP server that received the request. - pub server_port: Option, + /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. + /// + /// Notes: + /// The scheme of the original client request, if known (e.g. from [Forwarded#proto](https://developer.mozilla.org/docs/Web/HTTP/Headers/Forwarded#proto), [X-Forwarded-Proto](https://developer.mozilla.org/docs/Web/HTTP/Headers/X-Forwarded-Proto), or a similar header). Otherwise, the scheme of the immediate peer request. + /// + /// Examples: + /// - http + /// - https pub url_scheme: String, - -} - -impl HttpServerRequestDuration { - pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: HistogramProvider{ - Self(meter.create_histogram("http.server.request.duration", "Duration of HTTP server requests.", "s")) - } - - /// Adds an additional value to the distribution. - pub fn record(&self, value: T, attributes: HttpServerRequestDurationAttributes) { - // self.0.record(value, attributes.into()) - } } -/// Number of active HTTP server requests. -#[cfg(feature = "semconv_experimental")] -pub fn create_http_server_active_requests(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter - where opentelemetry::metrics::Meter: UpDownCounterProvider { - meter.create_up_down_counter("http.server.active_requests", "Number of active HTTP server requests.", "{request}") -} -/// Size of HTTP server request bodies. -#[cfg(feature = "semconv_experimental")] -pub fn create_http_server_request_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram - where opentelemetry::metrics::Meter: HistogramProvider { - meter.create_histogram("http.server.request.body.size", "Size of HTTP server request bodies.", "By") -} -/// Metric: http.server.request.body.size -/// Brief: Size of HTTP server request bodies. -/// Unit: By -#[derive(Debug)] -pub struct HttpServerRequestBodySize(opentelemetry::metrics::Histogram); - -/// Attributes for the `http.server.request.body.size` metric. -#[derive(Debug, Clone)] -pub struct HttpServerRequestBodySizeAttributes { - /// HTTP request method. - pub http_request_method: crate::attributes::http::HttpRequestMethod, - /// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). - pub http_response_status_code: Option, - /// The matched route, that is, the path template in the format used by the respective server framework. - pub http_route: Option, +#[derive(Debug, Clone, Default)] +pub struct HttpServerRequestDurationOptAttributes { + /// Describes a class of error the operation ended with. + /// + /// Notes: + /// If the request fails with an error before response status code was sent or received, + /// `error.type` SHOULD be set to exception type (its fully-qualified class name, if applicable) + /// or a component-specific low cardinality error identifier. + /// + /// If response status code was sent or received and status indicates an error according to [HTTP span status definition](/docs/http/http-spans.md), + /// `error.type` SHOULD be set to the status code number (represented as a string), an exception type (if thrown) or a component-specific error identifier. + /// + /// The `error.type` value SHOULD be predictable and SHOULD have low cardinality. + /// Instrumentations SHOULD document the list of errors they report. + /// + /// The cardinality of `error.type` within one instrumentation library SHOULD be low, but + /// telemetry consumers that aggregate data from multiple instrumentation libraries and applications + /// should be prepared for `error.type` to have high cardinality at query time, when no + /// additional filters are applied. + /// + /// If the request has completed successfully, instrumentations SHOULD NOT set `error.type`. + /// + /// Examples: + /// - timeout + /// - java.net.UnknownHostException + /// - server_certificate_invalid + /// - 500 pub error_type: Option, - /// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. - pub network_protocol_name: Option, - /// The actual version of the protocol used for network communication. - pub network_protocol_version: Option, - /// Name of the local HTTP server that received the request. - pub server_address: Option, - /// Port of the local HTTP server that received the request. - pub server_port: Option, - /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. - pub url_scheme: String, -} - -impl HttpServerRequestBodySize { - pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: HistogramProvider{ - Self(meter.create_histogram("http.server.request.body.size", "Size of HTTP server request bodies.", "By")) - } - - /// Adds an additional value to the distribution. - pub fn record(&self, value: T, attributes: HttpServerRequestBodySizeAttributes) { - // self.0.record(value, attributes.into()) - } -} - -/// Size of HTTP server response bodies. -#[cfg(feature = "semconv_experimental")] -pub fn create_http_server_response_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram - where opentelemetry::metrics::Meter: HistogramProvider { - meter.create_histogram("http.server.response.body.size", "Size of HTTP server response bodies.", "By") -} - -/// Metric: http.server.response.body.size -/// Brief: Size of HTTP server response bodies. -/// Unit: By -#[derive(Debug)] -pub struct HttpServerResponseBodySize(opentelemetry::metrics::Histogram); - -/// Attributes for the `http.server.response.body.size` metric. -#[derive(Debug, Clone)] -pub struct HttpServerResponseBodySizeAttributes { - /// HTTP request method. - pub http_request_method: crate::attributes::http::HttpRequestMethod, /// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). + /// + /// Examples: + /// - 200 pub http_response_status_code: Option, + /// The matched route, that is, the path template in the format used by the respective server framework. + /// + /// 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. + /// + /// Examples: + /// - /users/:userID? + /// - {controller}/{action}/{id?} pub http_route: Option, - /// Describes a class of error the operation ended with. - pub error_type: Option, + /// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. + /// + /// Notes: + /// The value SHOULD be normalized to lowercase. + /// + /// Examples: + /// - http + /// - spdy pub network_protocol_name: Option, + /// The actual version of the protocol used for network communication. + /// + /// Notes: + /// If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, this attribute SHOULD NOT be set. + /// + /// Examples: + /// - 1.0 + /// - 1.1 + /// - 2 + /// - 3 pub network_protocol_version: Option, + /// Name of the local HTTP server that received the request. + /// + /// Notes: + /// See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). + /// > **Warning** + /// > Since this attribute is based on HTTP headers, opting in to it may allow an attacker + /// > to trigger cardinality limits, degrading the usefulness of the metric. + /// + /// Examples: + /// - example.com + /// - 10.1.2.80 + /// - /tmp/my.sock pub server_address: Option, + /// Port of the local HTTP server that received the request. + /// + /// Notes: + /// See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). + /// > **Warning** + /// > Since this attribute is based on HTTP headers, opting in to it may allow an attacker + /// > to trigger cardinality limits, degrading the usefulness of the metric. + /// + /// Examples: + /// - 80 + /// - 8080 + /// - 443 pub server_port: Option, - /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. - pub url_scheme: String, - } -impl HttpServerResponseBodySize { + +impl HttpServerRequestDuration { pub fn new(meter: &opentelemetry::metrics::Meter) -> Self where opentelemetry::metrics::Meter: HistogramProvider{ - Self(meter.create_histogram("http.server.response.body.size", "Size of HTTP server response bodies.", "By")) + Self(meter.create_histogram("http.server.request.duration", "Duration of HTTP server requests.", "s")) } /// Adds an additional value to the distribution. - pub fn record(&self, value: T, attributes: HttpServerResponseBodySizeAttributes) { - // self.0.record(value, attributes.into()) + pub fn record( + &self, + value: T, + required_attributes: &HttpServerRequestDurationReqAttributes, + optional_attributes: Option<&HttpServerRequestDurationOptAttributes>, + ) { + let mut attributes = vec![ + crate::attributes::http::HTTP_REQUEST_METHOD.value(&required_attributes.http_request_method), + crate::attributes::url::URL_SCHEME.value(required_attributes.url_scheme.to_string().into()), + ]; + + if let Some(value) = &optional_attributes { + if let Some(error_type) = &value.error_type { + attributes.push(crate::attributes::error::ERROR_TYPE.value(error_type)); + } + if let Some(http_response_status_code) = value.http_response_status_code { + attributes.push(crate::attributes::http::HTTP_RESPONSE_STATUS_CODE.value(http_response_status_code)); + } + if let Some(http_route) = &value.http_route { + attributes.push(crate::attributes::http::HTTP_ROUTE.value(http_route.to_string().into())); + } + if let Some(network_protocol_name) = &value.network_protocol_name { + attributes.push(crate::attributes::network::NETWORK_PROTOCOL_NAME.value(network_protocol_name.to_string().into())); + } + if let Some(network_protocol_version) = &value.network_protocol_version { + attributes.push(crate::attributes::network::NETWORK_PROTOCOL_VERSION.value(network_protocol_version.to_string().into())); + } + if let Some(server_address) = &value.server_address { + attributes.push(crate::attributes::server::SERVER_ADDRESS.value(server_address.to_string().into())); + } + if let Some(server_port) = value.server_port { + attributes.push(crate::attributes::server::SERVER_PORT.value(server_port)); + } + } + self.0.record(value, &attributes) } } @@ -173,185 +217,272 @@ pub fn create_http_client_request_duration(meter: &opentelemetry::metrics::Me #[derive(Debug)] pub struct HttpClientRequestDuration(opentelemetry::metrics::Histogram); + /// Attributes for the `http.client.request.duration` metric. #[derive(Debug, Clone)] -pub struct HttpClientRequestDurationAttributes { +pub struct HttpClientRequestDurationReqAttributes { + /// HTTP request method. + /// + /// Notes: + /// HTTP request method value SHOULD be "known" to the instrumentation. + /// By default, this convention defines "known" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods) + /// and the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html). + /// + /// If the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`. + /// + /// If the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override + /// the list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named + /// OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods + /// (this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults). + /// + /// 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. + /// + /// Examples: + /// - GET + /// - POST + /// - HEAD pub http_request_method: crate::attributes::http::HttpRequestMethod, - /// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). - pub http_response_status_code: Option, - /// Describes a class of error the operation ended with. - pub error_type: Option, + /// Host identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. + /// + /// Notes: + /// If an HTTP client request is explicitly made to an IP address, e.g. `http://x.x.x.x:8080`, then `server.address` SHOULD be the IP address `x.x.x.x`. A DNS lookup SHOULD NOT be used. + /// + /// Examples: + /// - example.com + /// - 10.1.2.80 + /// - /tmp/my.sock pub server_address: String, + /// Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. + /// + /// Notes: + /// When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent the server port behind any intermediaries, for example proxies, if it's available. + /// + /// Examples: + /// - 80 + /// - 8080 + /// - 443 pub server_port: i64, - /// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. - pub network_protocol_name: Option, - /// The actual version of the protocol used for network communication. - pub network_protocol_version: Option, - /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. - pub url_scheme: Option, - } -impl HttpClientRequestDuration { - pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: HistogramProvider{ - Self(meter.create_histogram("http.client.request.duration", "Duration of HTTP client requests.", "s")) - } - /// Adds an additional value to the distribution. - pub fn record(&self, value: T, attributes: HttpClientRequestDurationAttributes) { - // self.0.record(value, attributes.into()) - } -} -/// Size of HTTP client request bodies. -#[cfg(feature = "semconv_experimental")] -pub fn create_http_client_request_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram - where opentelemetry::metrics::Meter: HistogramProvider { - meter.create_histogram("http.client.request.body.size", "Size of HTTP client request bodies.", "By") -} - -/// Metric: http.client.request.body.size -/// Brief: Size of HTTP client request bodies. -/// Unit: By -#[derive(Debug)] -pub struct HttpClientRequestBodySize(opentelemetry::metrics::Histogram); - -/// Attributes for the `http.client.request.body.size` metric. -#[derive(Debug, Clone)] -pub struct HttpClientRequestBodySizeAttributes { - /// HTTP request method. - pub http_request_method: crate::attributes::http::HttpRequestMethod, - /// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). - pub http_response_status_code: Option, +#[derive(Debug, Clone, Default)] +pub struct HttpClientRequestDurationOptAttributes { + /// Describes a class of error the operation ended with. + /// + /// Notes: + /// If the request fails with an error before response status code was sent or received, + /// `error.type` SHOULD be set to exception type (its fully-qualified class name, if applicable) + /// or a component-specific low cardinality error identifier. + /// + /// If response status code was sent or received and status indicates an error according to [HTTP span status definition](/docs/http/http-spans.md), + /// `error.type` SHOULD be set to the status code number (represented as a string), an exception type (if thrown) or a component-specific error identifier. + /// + /// The `error.type` value SHOULD be predictable and SHOULD have low cardinality. + /// Instrumentations SHOULD document the list of errors they report. + /// + /// The cardinality of `error.type` within one instrumentation library SHOULD be low, but + /// telemetry consumers that aggregate data from multiple instrumentation libraries and applications + /// should be prepared for `error.type` to have high cardinality at query time, when no + /// additional filters are applied. + /// + /// If the request has completed successfully, instrumentations SHOULD NOT set `error.type`. + /// + /// Examples: + /// - timeout + /// - java.net.UnknownHostException + /// - server_certificate_invalid + /// - 500 pub error_type: Option, - /// Host identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. - pub server_address: String, - /// Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. - pub server_port: i64, + + /// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). + /// + /// Examples: + /// - 200 + pub http_response_status_code: Option, + /// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. + /// + /// Notes: + /// The value SHOULD be normalized to lowercase. + /// + /// Examples: + /// - http + /// - spdy pub network_protocol_name: Option, + /// The actual version of the protocol used for network communication. + /// + /// Notes: + /// If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, this attribute SHOULD NOT be set. + /// + /// Examples: + /// - 1.0 + /// - 1.1 + /// - 2 + /// - 3 pub network_protocol_version: Option, + /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. + /// + /// Examples: + /// - http + /// - https pub url_scheme: Option, - } -impl HttpClientRequestBodySize { + +impl HttpClientRequestDuration { pub fn new(meter: &opentelemetry::metrics::Meter) -> Self where opentelemetry::metrics::Meter: HistogramProvider{ - Self(meter.create_histogram("http.client.request.body.size", "Size of HTTP client request bodies.", "By")) + Self(meter.create_histogram("http.client.request.duration", "Duration of HTTP client requests.", "s")) } /// Adds an additional value to the distribution. - pub fn record(&self, value: T, attributes: HttpClientRequestBodySizeAttributes) { - // self.0.record(value, attributes.into()) + pub fn record( + &self, + value: T, + required_attributes: &HttpClientRequestDurationReqAttributes, + optional_attributes: Option<&HttpClientRequestDurationOptAttributes>, + ) { + let mut attributes = vec![ + crate::attributes::http::HTTP_REQUEST_METHOD.value(&required_attributes.http_request_method), + crate::attributes::server::SERVER_ADDRESS.value(required_attributes.server_address.to_string().into()), + crate::attributes::server::SERVER_PORT.value(required_attributes.server_port), + ]; + + if let Some(value) = &optional_attributes { + if let Some(error_type) = &value.error_type { + attributes.push(crate::attributes::error::ERROR_TYPE.value(error_type)); + } + if let Some(http_response_status_code) = value.http_response_status_code { + attributes.push(crate::attributes::http::HTTP_RESPONSE_STATUS_CODE.value(http_response_status_code)); + } + if let Some(network_protocol_name) = &value.network_protocol_name { + attributes.push(crate::attributes::network::NETWORK_PROTOCOL_NAME.value(network_protocol_name.to_string().into())); + } + if let Some(network_protocol_version) = &value.network_protocol_version { + attributes.push(crate::attributes::network::NETWORK_PROTOCOL_VERSION.value(network_protocol_version.to_string().into())); + } + if let Some(url_scheme) = &value.url_scheme { + attributes.push(crate::attributes::url::URL_SCHEME.value(url_scheme.to_string().into())); + } + } + self.0.record(value, &attributes) } } -/// Size of HTTP client response bodies. +/// Number of active HTTP requests. #[cfg(feature = "semconv_experimental")] -pub fn create_http_client_response_body_size(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram - where opentelemetry::metrics::Meter: HistogramProvider { - meter.create_histogram("http.client.response.body.size", "Size of HTTP client response bodies.", "By") +pub fn create_http_client_active_requests(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter + where opentelemetry::metrics::Meter: UpDownCounterProvider { + meter.create_up_down_counter("http.client.active_requests", "Number of active HTTP requests.", "{request}") } -/// Metric: http.client.response.body.size -/// Brief: Size of HTTP client response bodies. -/// Unit: By +/// Metric: http.client.active_requests +/// Brief: Number of active HTTP requests. +/// Unit: {request} #[derive(Debug)] -pub struct HttpClientResponseBodySize(opentelemetry::metrics::Histogram); +pub struct HttpClientActiveRequests(opentelemetry::metrics::UpDownCounter); + -/// Attributes for the `http.client.response.body.size` metric. +/// Attributes for the `http.client.active_requests` metric. #[derive(Debug, Clone)] -pub struct HttpClientResponseBodySizeAttributes { - /// HTTP request method. - pub http_request_method: crate::attributes::http::HttpRequestMethod, - /// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). - pub http_response_status_code: Option, - /// Describes a class of error the operation ended with. - pub error_type: Option, - /// Host identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. +pub struct HttpClientActiveRequestsReqAttributes { + + /// Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. + /// + /// Notes: + /// When observed from the client side, and when communicating through an intermediary, `server.address` SHOULD represent the server address behind any intermediaries, for example proxies, if it's available. + /// + /// Examples: + /// - example.com + /// - 10.1.2.80 + /// - /tmp/my.sock pub server_address: String, + /// Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. + /// + /// Notes: + /// When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent the server port behind any intermediaries, for example proxies, if it's available. + /// + /// Examples: + /// - 80 + /// - 8080 + /// - 443 pub server_port: i64, - /// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. - pub network_protocol_name: Option, - /// The actual version of the protocol used for network communication. - pub network_protocol_version: Option, - /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. - pub url_scheme: Option, - } -impl HttpClientResponseBodySize { - pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: HistogramProvider{ - Self(meter.create_histogram("http.client.response.body.size", "Size of HTTP client response bodies.", "By")) - } - /// Adds an additional value to the distribution. - pub fn record(&self, value: T, attributes: HttpClientResponseBodySizeAttributes) { - // self.0.record(value, attributes.into()) - } -} - -/// Number of outbound HTTP connections that are currently active or idle on the client. -#[cfg(feature = "semconv_experimental")] -pub fn create_http_client_open_connections(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter - where opentelemetry::metrics::Meter: UpDownCounterProvider { - meter.create_up_down_counter("http.client.open_connections", "Number of outbound HTTP connections that are currently active or idle on the client.", "{connection}") -} - -/// The duration of the successfully established outbound HTTP connections. -#[cfg(feature = "semconv_experimental")] -pub fn create_http_client_connection_duration(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram - where opentelemetry::metrics::Meter: HistogramProvider { - meter.create_histogram("http.client.connection.duration", "The duration of the successfully established outbound HTTP connections.", "s") -} -/// Metric: http.client.connection.duration -/// Brief: The duration of the successfully established outbound HTTP connections. -/// Unit: s -#[derive(Debug)] -pub struct HttpClientConnectionDuration(opentelemetry::metrics::Histogram); - -/// Attributes for the `http.client.connection.duration` metric. -#[derive(Debug, Clone)] -pub struct HttpClientConnectionDurationAttributes { - /// Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. - pub server_port: i64, - /// Peer address of the network connection - IP address or Unix domain socket name. - pub network_peer_address: Option, - /// The actual version of the protocol used for network communication. - pub network_protocol_version: Option, +#[derive(Debug, Clone, Default)] +pub struct HttpClientActiveRequestsOptAttributes { + + /// HTTP request method. + /// + /// Notes: + /// HTTP request method value SHOULD be "known" to the instrumentation. + /// By default, this convention defines "known" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods) + /// and the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html). + /// + /// If the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`. + /// + /// If the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override + /// the list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named + /// OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods + /// (this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults). + /// + /// 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. + /// + /// Examples: + /// - GET + /// - POST + /// - HEAD + pub http_request_method: Option, + /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. + /// + /// Examples: + /// - http + /// - https pub url_scheme: Option, - /// Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. - pub server_address: String, - } -impl HttpClientConnectionDuration { + +impl HttpClientActiveRequests { pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: HistogramProvider{ - Self(meter.create_histogram("http.client.connection.duration", "The duration of the successfully established outbound HTTP connections.", "s")) + where opentelemetry::metrics::Meter: UpDownCounterProvider{ + Self(meter.create_up_down_counter("http.client.active_requests", "Number of active HTTP requests.", "{request}")) } - /// Adds an additional value to the distribution. - pub fn record(&self, value: T, attributes: HttpClientConnectionDurationAttributes) { - // self.0.record(value, attributes.into()) + /// Adds an additional value to the up-down-counter. + pub fn add( + &self, + value: T, + required_attributes: &HttpClientActiveRequestsReqAttributes, + optional_attributes: Option<&HttpClientActiveRequestsOptAttributes>, + ) { + let mut attributes = vec![ + crate::attributes::server::SERVER_ADDRESS.value(required_attributes.server_address.to_string().into()), + crate::attributes::server::SERVER_PORT.value(required_attributes.server_port), + ]; + + if let Some(value) = &optional_attributes { + if let Some(http_request_method) = &value.http_request_method { + attributes.push(crate::attributes::http::HTTP_REQUEST_METHOD.value(http_request_method)); + } + if let Some(url_scheme) = &value.url_scheme { + attributes.push(crate::attributes::url::URL_SCHEME.value(url_scheme.to_string().into())); + } + } + self.0.add(value, &attributes) } -} - -/// Number of active HTTP requests. -#[cfg(feature = "semconv_experimental")] -pub fn create_http_client_active_requests(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter - where opentelemetry::metrics::Meter: UpDownCounterProvider { - meter.create_up_down_counter("http.client.active_requests", "Number of active HTTP requests.", "{request}") -} +} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/metrics/mod.rs b/crates/weaver_forge/codegen_examples/expected_codegen/metrics/mod.rs index c8b7c989..336b4fe8 100644 --- a/crates/weaver_forge/codegen_examples/expected_codegen/metrics/mod.rs +++ b/crates/weaver_forge/codegen_examples/expected_codegen/metrics/mod.rs @@ -9,6 +9,8 @@ /// Metrics for the `http` namespace. pub mod http; +/// Metrics for the `system` namespace. +pub mod system; /// A trait implemented by histogram providers (e.g. `Meter`). pub trait HistogramProvider { @@ -64,4 +66,71 @@ impl UpDownCounterProvider for opentelemetry::metrics::Meter { .with_unit(opentelemetry::metrics::Unit::new(unit)) .init() } +} + +/// A trait implemented by counter providers (e.g. `Meter`). +pub trait CounterProvider { + /// Creates a new counter with the given name, description, and unit. + fn create_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Counter; +} + +/// This implementation specifies that a Meter is able to create u64 counters. +impl CounterProvider for opentelemetry::metrics::Meter { + /// Creates a new u64 counter with the given name, description, and unit. + fn create_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Counter { + self.u64_counter(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// This implementation specifies that a Meter is able to create f64 counters. +impl CounterProvider for opentelemetry::metrics::Meter { + /// Creates a new f64 counter with the given name, description, and unit. + fn create_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Counter { + self.f64_counter(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// A trait implemented by gauge providers (e.g. `Meter`). +pub trait GaugeProvider { + /// Creates a new gauge with the given name, description, and unit. + fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge; +} + +/// This implementation specifies that a Meter is able to create u64 gauges. +impl GaugeProvider for opentelemetry::metrics::Meter { + /// Creates a new u64 gauge with the given name, description, and unit. + fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge { + self.u64_gauge(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// This implementation specifies that a Meter is able to create i64 gauges. +impl GaugeProvider for opentelemetry::metrics::Meter { + /// Creates a new i64 gauge with the given name, description, and unit. + fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge { + self.i64_gauge(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// This implementation specifies that a Meter is able to create f64 gauges. +impl GaugeProvider for opentelemetry::metrics::Meter { + /// Creates a new f64 gauge with the given name, description, and unit. + fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge { + self.f64_gauge(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } } \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/metrics/system.rs b/crates/weaver_forge/codegen_examples/expected_codegen/metrics/system.rs new file mode 100644 index 00000000..f0e9f19f --- /dev/null +++ b/crates/weaver_forge/codegen_examples/expected_codegen/metrics/system.rs @@ -0,0 +1,190 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/metrics/metrics.rs.j2 + +use crate::metrics::{CounterProvider, GaugeProvider, HistogramProvider, UpDownCounterProvider}; + +/// Seconds each logical CPU spent on each mode +#[cfg(feature = "semconv_experimental")] +pub fn create_system_cpu_time(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Counter + where opentelemetry::metrics::Meter: CounterProvider { + meter.create_counter("system.cpu.time", "Seconds each logical CPU spent on each mode", "s") +} + +/// Metric: system.cpu.time +/// Brief: Seconds each logical CPU spent on each mode +/// Unit: s +#[derive(Debug)] +pub struct SystemCpuTime(opentelemetry::metrics::Counter); + + + + +#[derive(Debug, Clone, Default)] +pub struct SystemCpuTimeOptAttributes { + + /// The logical CPU number [0..n-1] + /// + /// Examples: + /// - 1 + pub system_cpu_logical_number: Option, + + /// The CPU state for this data point. A system's CPU SHOULD be characterized *either* by data points with no `state` labels, *or only* data points with `state` labels. + /// + /// Examples: + /// - idle + /// - interrupt + pub system_cpu_state: Option, +} + + +impl SystemCpuTime { + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: CounterProvider{ + Self(meter.create_counter("system.cpu.time", "Seconds each logical CPU spent on each mode", "s")) + } + + /// Adds an additional value to the counter. + pub fn add( + &self, + value: T, + + optional_attributes: Option<&SystemCpuTimeOptAttributes>, + ) { + let mut attributes = vec![ + ]; + + if let Some(value) = &optional_attributes { + #[cfg(feature = "semconv_experimental")] + if let Some(system_cpu_logical_number) = value.system_cpu_logical_number { + attributes.push(crate::attributes::system::SYSTEM_CPU_LOGICAL_NUMBER.value(system_cpu_logical_number)); + } + #[cfg(feature = "semconv_experimental")] + if let Some(system_cpu_state) = &value.system_cpu_state { + attributes.push(crate::attributes::system::SYSTEM_CPU_STATE.value(system_cpu_state)); + } + } + self.0.add(value, &attributes) + } +} + +/// Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs +#[cfg(feature = "semconv_experimental")] +pub fn create_system_cpu_utilization(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Gauge + where opentelemetry::metrics::Meter: GaugeProvider { + meter.create_gauge("system.cpu.utilization", "Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs", "1") +} + +/// Metric: system.cpu.utilization +/// Brief: Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs +/// Unit: 1 +#[derive(Debug)] +pub struct SystemCpuUtilization(opentelemetry::metrics::Gauge); + + + + +#[derive(Debug, Clone, Default)] +pub struct SystemCpuUtilizationOptAttributes { + + /// The logical CPU number [0..n-1] + /// + /// Examples: + /// - 1 + pub system_cpu_logical_number: Option, + + /// The CPU state for this data point. A system's CPU SHOULD be characterized *either* by data points with no `state` labels, *or only* data points with `state` labels. + /// + /// Examples: + /// - idle + /// - interrupt + pub system_cpu_state: Option, +} + + +impl SystemCpuUtilization { + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: GaugeProvider{ + Self(meter.create_gauge("system.cpu.utilization", "Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs", "1")) + } + + /// Records an additional value to the gauge. + pub fn record( + &self, + value: T, + + optional_attributes: Option<&SystemCpuUtilizationOptAttributes>, + ) { + let mut attributes = vec![ + ]; + + if let Some(value) = &optional_attributes { + #[cfg(feature = "semconv_experimental")] + if let Some(system_cpu_logical_number) = value.system_cpu_logical_number { + attributes.push(crate::attributes::system::SYSTEM_CPU_LOGICAL_NUMBER.value(system_cpu_logical_number)); + } + #[cfg(feature = "semconv_experimental")] + if let Some(system_cpu_state) = &value.system_cpu_state { + attributes.push(crate::attributes::system::SYSTEM_CPU_STATE.value(system_cpu_state)); + } + } + self.0.record(value, &attributes) + } +} + +/// Reports memory in use by state. +#[cfg(feature = "semconv_experimental")] +pub fn create_system_memory_usage(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter + where opentelemetry::metrics::Meter: UpDownCounterProvider { + meter.create_up_down_counter("system.memory.usage", "Reports memory in use by state.", "By") +} + +/// Metric: system.memory.usage +/// Brief: Reports memory in use by state. +/// Unit: By +#[derive(Debug)] +pub struct SystemMemoryUsage(opentelemetry::metrics::UpDownCounter); + + + + +#[derive(Debug, Clone, Default)] +pub struct SystemMemoryUsageOptAttributes { + + /// The memory state + /// + /// Examples: + /// - free + /// - cached + pub system_memory_state: Option, +} + + +impl SystemMemoryUsage { + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: UpDownCounterProvider{ + Self(meter.create_up_down_counter("system.memory.usage", "Reports memory in use by state.", "By")) + } + + /// Adds an additional value to the up-down-counter. + pub fn add( + &self, + value: T, + + optional_attributes: Option<&SystemMemoryUsageOptAttributes>, + ) { + let mut attributes = vec![ + ]; + + if let Some(value) = &optional_attributes { + #[cfg(feature = "semconv_experimental")] + if let Some(system_memory_state) = &value.system_memory_state { + attributes.push(crate::attributes::system::SYSTEM_MEMORY_STATE.value(system_memory_state)); + } + } + self.0.add(value, &attributes) + } +} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/README.md b/crates/weaver_forge/codegen_examples/templates/registry/rust/README.md index e5f4ef77..f64d622f 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/README.md +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/README.md @@ -3,18 +3,112 @@ # 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); +use opentelemetry::KeyValue; +use opentelemetry::metrics::{Histogram, MeterProvider}; +use opentelemetry_sdk::{Resource, runtime}; +use opentelemetry_sdk::metrics::{PeriodicReader, SdkMeterProvider}; + +use semconv::attributes; +use semconv::attributes::http::{HTTP_REQUEST_METHOD, HttpRequestMethod}; +use semconv::attributes::system::SystemCpuState; +use semconv::metrics::http::{create_http_client_request_duration, HttpClientActiveRequests, HttpClientActiveRequestsReqAttributes, HttpServerRequestDurationOptAttributes, HttpServerRequestDurationReqAttributes}; +use semconv::metrics::http::HttpServerRequestDuration; +use semconv::metrics::system::{SystemCpuTime, SystemCpuTimeOptAttributes, SystemCpuUtilization, SystemCpuUtilizationOptAttributes}; + +/// Main +#[tokio::main] +async fn main() -> Result<(), Box> { + let meter_provider = init_meter_provider(); + + // SemConv attributes are typed, so the compiler will catch type errors + // Experimental attributes are not visible if the `semconv_experimental` feature is not enabled + println!("{:?}", attributes::client::CLIENT_ADDRESS.value("145.34.23.56".into())); + println!("{:?}", attributes::client::CLIENT_ADDRESS.key()); + println!("{:?}", attributes::client::CLIENT_PORT.value(8080)); + println!("{:?}", attributes::client::CLIENT_PORT.key()); + + println!("{}", HttpRequestMethod::Connect); + + let meter = meter_provider.meter("mylibname"); + + // Create a u64 http.client.request.duration metric + let http_client_request_duration: Histogram = create_http_client_request_duration(&meter); + http_client_request_duration.record(100, &[ + HTTP_REQUEST_METHOD.value(&HttpRequestMethod::Connect), + // here nothing guarantees that all the required attributes are provided + ]); + + let http_client_request_duration: Histogram = create_http_client_request_duration(&meter); + dbg!(http_client_request_duration); + + // Create a u64 http.server.request.duration metric (as defined in the OpenTelemetry HTTP + // semantic conventions) + let http_request_duration = HttpServerRequestDuration::::new(&meter); + + // Records a new data point and provide the required and some optional attributes + http_request_duration.record(100, &HttpServerRequestDurationReqAttributes { + http_request_method: HttpRequestMethod::Connect, + url_scheme: "http".to_owned(), + }, Some(&HttpServerRequestDurationOptAttributes { + http_response_status_code: Some(200), + ..Default::default() + })); + + // Create a f64 http.server.request.duration metric (as defined in the OpenTelemetry HTTP + // semantic conventions) + let http_client_active_requests = HttpClientActiveRequests::::new(&meter); + + // Adds a new data point and provide the required attributes. Optional attributes are not + // provided in this example. + http_client_active_requests.add(10.0, &HttpClientActiveRequestsReqAttributes { + server_address: "10.0.0.1".to_owned(), + server_port: 8080, + }, None); + + // Create a f64 system.cpu.time metric (as defined in the OpenTelemetry System semantic + // conventions) + let system_cpu_time = SystemCpuTime::::new(&meter); + + // Adds a new data point and provide some optional attributes. + // Note: In the method signature, there is no required attribute. + system_cpu_time.add(10.0, Some(&SystemCpuTimeOptAttributes { + system_cpu_logical_number: Some(0), + system_cpu_state: Some(SystemCpuState::Idle) + })); + // Adds a new data point with a custom CPU state. + system_cpu_time.add(20.0, Some(&SystemCpuTimeOptAttributes { + system_cpu_logical_number: Some(0), + system_cpu_state: Some(SystemCpuState::_Custom("custom".to_owned())) + })); + + // Create a i64 system.cpu.utilization metric (as defined in the OpenTelemetry System semantic + // conventions) + let system_cpu_utilization = SystemCpuUtilization::::new(&meter); + + // Adds a new data point with no optional attributes. + system_cpu_utilization.record(-5, None); + // Adds a new data point with some optional attributes. + system_cpu_utilization.record(10, Some(&SystemCpuUtilizationOptAttributes { + system_cpu_logical_number: Some(0), + system_cpu_state: Some(SystemCpuState::Idle) + })); + + meter_provider.shutdown()?; + Ok(()) +} + +fn init_meter_provider() -> SdkMeterProvider { + let exporter = opentelemetry_stdout::MetricsExporterBuilder::default() + .with_encoder(|writer, data| + Ok(serde_json::to_writer_pretty(writer, &data).unwrap())) + .build(); + let reader = PeriodicReader::builder(exporter, runtime::Tokio).build(); + SdkMeterProvider::builder() + .with_reader(reader) + .with_resource(Resource::new(vec![KeyValue::new( + "service.name", + "metrics-basic-example", + )])) + .build() } ``` \ No newline at end of file From 5d8bf55cb6d8563ddaf1dcacd4ec61fbfea68143 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Fri, 3 May 2024 16:56:58 -0700 Subject: [PATCH 24/39] feat(forge): Update documentation --- .../templates/registry/rust/README.md | 267 ++++++++++++++++++ 1 file changed, 267 insertions(+) diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/README.md b/crates/weaver_forge/codegen_examples/templates/registry/rust/README.md index f64d622f..5ee01b69 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/README.md +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/README.md @@ -41,6 +41,7 @@ async fn main() -> Result<(), Box> { let http_client_request_duration: Histogram = create_http_client_request_duration(&meter); dbg!(http_client_request_duration); + // ==== A TYPE-SAFE HISTOGRAM API ==== // Create a u64 http.server.request.duration metric (as defined in the OpenTelemetry HTTP // semantic conventions) let http_request_duration = HttpServerRequestDuration::::new(&meter); @@ -54,6 +55,7 @@ async fn main() -> Result<(), Box> { ..Default::default() })); + // ==== A TYPE-SAFE UP-DOWN-COUNTER API ==== // Create a f64 http.server.request.duration metric (as defined in the OpenTelemetry HTTP // semantic conventions) let http_client_active_requests = HttpClientActiveRequests::::new(&meter); @@ -65,6 +67,7 @@ async fn main() -> Result<(), Box> { server_port: 8080, }, None); + // ==== A TYPE-SAFE COUNTER API ==== // Create a f64 system.cpu.time metric (as defined in the OpenTelemetry System semantic // conventions) let system_cpu_time = SystemCpuTime::::new(&meter); @@ -81,6 +84,7 @@ async fn main() -> Result<(), Box> { system_cpu_state: Some(SystemCpuState::_Custom("custom".to_owned())) })); + // ==== A TYPE-SAFE GAUGE API ==== // Create a i64 system.cpu.utilization metric (as defined in the OpenTelemetry System semantic // conventions) let system_cpu_utilization = SystemCpuUtilization::::new(&meter); @@ -111,4 +115,267 @@ fn init_meter_provider() -> SdkMeterProvider { )])) .build() } +``` + +The execution of this program will generate the following output: + +``` +KeyValue { key: Static("client.address"), value: String(Static("145.34.23.56")) } +Static("client.address") +KeyValue { key: Static("client.port"), value: I64(8080) } +Static("client.port") +CONNECT +[src/main.rs:39:5] http_client_request_duration = Histogram +{ + "resourceMetrics": { + "resource": { + "attributes": [ + { + "key": "service.name", + "value": { + "stringValue": "metrics-basic-example" + } + } + ] + }, + "scopeMetrics": [ + { + "scope": { + "name": "mylibname" + }, + "metrics": [ + { + "name": "http.client.request.duration", + "description": "Duration of HTTP client requests.", + "unit": "s", + "histogram": { + "dataPoints": [ + { + "attributes": { + "http.request.method": { + "stringValue": "CONNECT" + } + }, + "startTimeUnixNano": 1714780164856054000, + "timeUnixNano": 1714780164856202000, + "startTime": "2024-05-03 23:49:24.856", + "time": "2024-05-03 23:49:24.856", + "count": 1, + "explicitBounds": [ + 0.0, + 5.0, + 10.0, + 25.0, + 50.0, + 75.0, + 100.0, + 250.0, + 500.0, + 750.0, + 1000.0, + 2500.0, + 5000.0, + 7500.0, + 10000.0 + ], + "bucketCounts": [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "min": 100, + "max": 100, + "sum": 100, + "exemplars": [], + "flags": 0 + } + ], + "aggregationTemporality": "Cumulative" + } + }, + { + "name": "http.server.request.duration", + "description": "Duration of HTTP server requests.", + "unit": "s", + "histogram": { + "dataPoints": [ + { + "attributes": { + "http.request.method": { + "stringValue": "CONNECT" + }, + "http.response.status_code": { + "intValue": 200 + }, + "url.scheme": { + "stringValue": "http" + } + }, + "startTimeUnixNano": 1714780164856111000, + "timeUnixNano": 1714780164856204000, + "startTime": "2024-05-03 23:49:24.856", + "time": "2024-05-03 23:49:24.856", + "count": 1, + "explicitBounds": [ + 0.0, + 5.0, + 10.0, + 25.0, + 50.0, + 75.0, + 100.0, + 250.0, + 500.0, + 750.0, + 1000.0, + 2500.0, + 5000.0, + 7500.0, + 10000.0 + ], + "bucketCounts": [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "min": 100, + "max": 100, + "sum": 100, + "exemplars": [], + "flags": 0 + } + ], + "aggregationTemporality": "Cumulative" + } + }, + { + "name": "http.client.active_requests", + "description": "Number of active HTTP requests.", + "unit": "{request}", + "sum": { + "dataPoints": [ + { + "attributes": { + "server.address": { + "stringValue": "10.0.0.1" + }, + "server.port": { + "intValue": 8080 + } + }, + "startTime": "2024-05-03 23:49:24.856", + "time": "2024-05-03 23:49:24.856", + "startTimeUnixNano": 1714780164856139000, + "timeUnixNano": 1714780164856219000, + "value": 10.0 + } + ], + "aggregationTemporality": "Cumulative", + "isMonotonic": false + } + }, + { + "name": "system.cpu.time", + "description": "Seconds each logical CPU spent on each mode", + "unit": "s", + "sum": { + "dataPoints": [ + { + "attributes": { + "system.cpu.logical_number": { + "intValue": 0 + }, + "system.cpu.state": { + "stringValue": "idle" + } + }, + "startTime": "2024-05-03 23:49:24.856", + "time": "2024-05-03 23:49:24.856", + "startTimeUnixNano": 1714780164856152000, + "timeUnixNano": 1714780164856220000, + "value": 10.0 + }, + { + "attributes": { + "system.cpu.logical_number": { + "intValue": 0 + }, + "system.cpu.state": { + "stringValue": "custom" + } + }, + "startTime": "2024-05-03 23:49:24.856", + "time": "2024-05-03 23:49:24.856", + "startTimeUnixNano": 1714780164856152000, + "timeUnixNano": 1714780164856220000, + "value": 20.0 + } + ], + "aggregationTemporality": "Cumulative", + "isMonotonic": true + } + }, + { + "name": "system.cpu.utilization", + "description": "Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs", + "unit": "1", + "gauge": { + "dataPoints": [ + { + "attributes": { + "system.cpu.logical_number": { + "intValue": 0 + }, + "system.cpu.state": { + "stringValue": "idle" + } + }, + "startTime": null, + "time": "2024-05-03 23:49:24.856", + "startTimeUnixNano": null, + "timeUnixNano": 1714780164856176000, + "value": 10 + }, + { + "attributes": {}, + "startTime": null, + "time": "2024-05-03 23:49:24.856", + "startTimeUnixNano": null, + "timeUnixNano": 1714780164856171000, + "value": -5 + } + ] + } + } + ] + } + ] + } +} ``` \ No newline at end of file From 064e8447df5cf1b293c31d20aaef55882da61c56 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Fri, 3 May 2024 17:01:18 -0700 Subject: [PATCH 25/39] feat(forge): Fix Clippy lint issues --- Cargo.lock | 16 ++++++------- crates/weaver_forge/src/extensions/code.rs | 7 +++--- crates/weaver_forge/src/extensions/otel.rs | 28 +++++++++++----------- 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c1839b2d..2a6d9120 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -130,9 +130,9 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" @@ -349,9 +349,9 @@ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "clru" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8191fa7302e03607ff0e237d4246cc043ff5b3cb9409d995172ba3bea16b807" +checksum = "cbd0f76e066e64fdc5631e3bb46381254deab9ef1158292f27c8c57e3bf3fe59" [[package]] name = "colorchoice" @@ -2188,9 +2188,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -2777,9 +2777,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "self_cell" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bf37232d3bb9a2c4e641ca2a11d83b5062066f88df7fed36c28772046d65ba" +checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a" [[package]] name = "semver" diff --git a/crates/weaver_forge/src/extensions/code.rs b/crates/weaver_forge/src/extensions/code.rs index 6a03a945..8fd90181 100644 --- a/crates/weaver_forge/src/extensions/code.rs +++ b/crates/weaver_forge/src/extensions/code.rs @@ -67,9 +67,10 @@ This also covers UDP network interactions where one side initiates the interacti /// 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."#; - assert_eq!(comment_with_prefix(&Value::from(brief), "/// "), expected_brief); - - + assert_eq!( + comment_with_prefix(&Value::from(brief), "/// "), + expected_brief + ); } #[test] diff --git a/crates/weaver_forge/src/extensions/otel.rs b/crates/weaver_forge/src/extensions/otel.rs index 51a2cc53..7305f0a9 100644 --- a/crates/weaver_forge/src/extensions/otel.rs +++ b/crates/weaver_forge/src/extensions/otel.rs @@ -468,14 +468,14 @@ mod tests { tags: None, value: None, }, - Attribute { + Attribute { name: "rec.b".into(), r#type: AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::String), brief: "".into(), examples: None, tag: None, requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Recommended), - sampling_relevant: None, + sampling_relevant: None, note: "".into(), stability: None, deprecated: None, @@ -569,7 +569,7 @@ mod tests { Attribute { name: "req.a".into(), r#type: AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::String), - brief: "".into(), + brief: "".into(), examples: None, tag: None, requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Required), @@ -634,48 +634,48 @@ mod tests { "Expected item @ {idx} to have name {expected}, found {names:?}" ); } - } - + } + #[test] fn test_required_and_optional_filters() { let attrs = vec![ Attribute { - name: "attr1".to_string(), + name: "attr1".to_owned(), r#type: AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::String), - brief: "".to_string(), + brief: "".to_owned(), examples: None, tag: None, requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Required), sampling_relevant: None, - note: "".to_string(), + note: "".to_owned(), stability: None, deprecated: None, tags: None, value: None, }, Attribute { - name: "attr2".to_string(), + name: "attr2".to_owned(), r#type: AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::Int), - brief: "".to_string(), + brief: "".to_owned(), examples: None, tag: None, requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Recommended), sampling_relevant: None, - note: "".to_string(), + note: "".to_owned(), stability: None, deprecated: None, tags: None, value: None, }, Attribute { - name: "attr3".to_string(), + name: "attr3".to_owned(), r#type: AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::String), - brief: "".to_string(), + brief: "".to_owned(), examples: None, tag: None, requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Required), sampling_relevant: None, - note: "".to_string(), + note: "".to_owned(), stability: None, deprecated: None, tags: None, From 3f2e1883a89eefe2734e9114f216a39819492f29 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Fri, 3 May 2024 20:14:27 -0700 Subject: [PATCH 26/39] chore(forge): Exclude generated file from code coverage --- .github/codecov.yaml | 3 ++- .github/workflows/ci.yml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/codecov.yaml b/.github/codecov.yaml index f39c5bbe..b7264fe0 100644 --- a/.github/codecov.yaml +++ b/.github/codecov.yaml @@ -13,4 +13,5 @@ coverage: ignore: - "crates/xtask" # Part of the build system - - "src" # CLI (not tested yet) \ No newline at end of file + - "src" # CLI (not tested yet) + - "crates/weaver_forge/codegen_examples/expected_codegen" # Generated code \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4085ccc1..436d16b7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -175,7 +175,7 @@ jobs: - name: Install cargo-tarpaulin run: cargo install cargo-tarpaulin - name: Gather coverage - run: cargo tarpaulin --workspace --output-dir coverage --out lcov -e xtask -e weaver + run: cargo tarpaulin --workspace --output-dir coverage --out lcov -e xtask -e weaver --exclude-files 'crates/weaver_forge/codegen_examples/expected_codegen/*' - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v4.0.1 with: From 7ec190d17c42ce2fe9cce1ddbf4e01bf439af313 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Sat, 4 May 2024 11:23:17 -0700 Subject: [PATCH 27/39] chore(forge): Test infra for code gen [WIP] --- Cargo.lock | 90 +++ Cargo.toml | 1 + crates/weaver_forge/Cargo.toml | 5 + crates/weaver_forge/build.rs | 26 + .../mini_registry/metrics/system-metrics.yaml | 4 +- .../mini_registry/registry/system.yaml | 10 +- .../registry/rust/attributes/attributes.rs.j2 | 2 +- .../registry/rust/attributes/mod.rs.j2 | 2 +- .../registry/rust/metrics/counter.j2 | 8 +- .../templates/registry/rust/metrics/gauge.j2 | 8 +- .../registry/rust/metrics/histogram.j2 | 8 +- .../registry/rust/metrics/metrics.rs.j2 | 4 +- .../templates/registry/rust/metrics/mod.rs.j2 | 2 +- .../registry/rust/metrics/updowncounter.j2 | 8 +- crates/weaver_forge/tests/README.md | 381 +++++++++++ .../weaver_forge/tests/attributes/client.rs | 27 + crates/weaver_forge/tests/attributes/error.rs | 75 +++ .../tests/attributes/exception.rs | 47 ++ crates/weaver_forge/tests/attributes/http.rs | 220 ++++++ crates/weaver_forge/tests/attributes/mod.rs | 76 +++ .../weaver_forge/tests/attributes/network.rs | 628 ++++++++++++++++++ .../weaver_forge/tests/attributes/server.rs | 29 + .../weaver_forge/tests/attributes/system.rs | 139 ++++ crates/weaver_forge/tests/attributes/url.rs | 127 ++++ crates/weaver_forge/tests/codegen.rs | 95 +++ crates/weaver_forge/tests/lib.rs | 10 + crates/weaver_forge/tests/metrics/http.rs | 486 ++++++++++++++ crates/weaver_forge/tests/metrics/mod.rs | 136 ++++ crates/weaver_forge/tests/metrics/system.rs | 181 +++++ 29 files changed, 2804 insertions(+), 31 deletions(-) create mode 100644 crates/weaver_forge/build.rs create mode 100644 crates/weaver_forge/tests/README.md create mode 100644 crates/weaver_forge/tests/attributes/client.rs create mode 100644 crates/weaver_forge/tests/attributes/error.rs create mode 100644 crates/weaver_forge/tests/attributes/exception.rs create mode 100644 crates/weaver_forge/tests/attributes/http.rs create mode 100644 crates/weaver_forge/tests/attributes/mod.rs create mode 100644 crates/weaver_forge/tests/attributes/network.rs create mode 100644 crates/weaver_forge/tests/attributes/server.rs create mode 100644 crates/weaver_forge/tests/attributes/system.rs create mode 100644 crates/weaver_forge/tests/attributes/url.rs create mode 100644 crates/weaver_forge/tests/codegen.rs create mode 100644 crates/weaver_forge/tests/lib.rs create mode 100644 crates/weaver_forge/tests/metrics/http.rs create mode 100644 crates/weaver_forge/tests/metrics/mod.rs create mode 100644 crates/weaver_forge/tests/metrics/system.rs diff --git a/Cargo.lock b/Cargo.lock index 2a6d9120..0374880f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -128,6 +128,17 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "async-trait" +version = "0.1.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.3.0" @@ -675,12 +686,34 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "futures-sink" version = "0.3.30" @@ -701,6 +734,7 @@ checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", @@ -2229,6 +2263,59 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "opentelemetry" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900d57987be3f2aeb70d385fff9b27fb74c5723cc9a52d904d4f9c807a0667bf" +dependencies = [ + "futures-core", + "futures-sink", + "js-sys", + "once_cell", + "pin-project-lite", + "thiserror", + "urlencoding", +] + +[[package]] +name = "opentelemetry-stdout" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bdf28b381f23afcd150afc0b38a4183dd321fc96320c1554752b6b761648f78" +dependencies = [ + "async-trait", + "chrono", + "futures-util", + "opentelemetry", + "opentelemetry_sdk", + "ordered-float", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "opentelemetry_sdk" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e90c7113be649e31e9a0f8b5ee24ed7a16923b322c3c5ab6367469c049d6b7e" +dependencies = [ + "async-trait", + "crossbeam-channel", + "futures-channel", + "futures-executor", + "futures-util", + "glob", + "once_cell", + "opentelemetry", + "ordered-float", + "percent-encoding", + "rand 0.8.5", + "serde_json", + "thiserror", +] + [[package]] name = "option-ext" version = "0.2.0" @@ -3577,6 +3664,9 @@ dependencies = [ "jaq-parse", "jaq-std", "minijinja", + "opentelemetry", + "opentelemetry-stdout", + "opentelemetry_sdk", "rayon", "regex", "serde", diff --git a/Cargo.toml b/Cargo.toml index e1fa0848..044757a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ categories = ["command-line-utilities"] license = "Apache-2.0" readme = "README.md" publish = false +resolver = "2" # Workspace definition ======================================================== [workspace] diff --git a/crates/weaver_forge/Cargo.toml b/crates/weaver_forge/Cargo.toml index 89cd3d76..20605ba6 100644 --- a/crates/weaver_forge/Cargo.toml +++ b/crates/weaver_forge/Cargo.toml @@ -36,3 +36,8 @@ serde_json.workspace = true rayon.workspace = true walkdir.workspace = true +[dev-dependencies] +opentelemetry = { version = "0.22.0", features = ["trace", "metrics", "logs", "otel_unstable"] } +opentelemetry_sdk = { version = "0.22.1", features = ["trace", "metrics", "logs"] } +opentelemetry-stdout = { version = "0.3.0", features = ["trace", "metrics", "logs"] } + diff --git a/crates/weaver_forge/build.rs b/crates/weaver_forge/build.rs new file mode 100644 index 00000000..1b223315 --- /dev/null +++ b/crates/weaver_forge/build.rs @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: Apache-2.0 + +//! + +use std::env; + +fn main() { + env::vars().for_each(|(key, value)| { + println!("cargo:warning={}: {}", key, value); + }); + env::args().for_each(|arg| { + println!("cargo:warning=ARGS->{}", arg); + }); + env::args_os().for_each(|arg| { + println!("cargo:warning=AGS_OS->{:?}", arg); + }); + _ = env::current_dir().ok().map(|path| { + println!("cargo:warning=Current dir: {:?}", path); + }); + _ = env::current_exe().ok().map(|path| { + println!("cargo:warning=EXE->{}", path.display()); + }); + + let out_dir = env::var("OUT_DIR").unwrap(); + println!("cargo:warning={}", out_dir); +} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/mini_registry/metrics/system-metrics.yaml b/crates/weaver_forge/codegen_examples/mini_registry/metrics/system-metrics.yaml index 0afa0b2b..12073142 100644 --- a/crates/weaver_forge/codegen_examples/mini_registry/metrics/system-metrics.yaml +++ b/crates/weaver_forge/codegen_examples/mini_registry/metrics/system-metrics.yaml @@ -15,7 +15,7 @@ groups: - id: metric.system.cpu.utilization type: metric metric_name: system.cpu.utilization - stability: experimental + stability: stable brief: "Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs" instrument: gauge unit: "1" @@ -27,7 +27,7 @@ groups: - id: metric.system.memory.usage type: metric metric_name: system.memory.usage - stability: experimental + stability: stable brief: "Reports memory in use by state." note: | The sum over all `system.memory.state` values SHOULD equal the total memory diff --git a/crates/weaver_forge/codegen_examples/mini_registry/registry/system.yaml b/crates/weaver_forge/codegen_examples/mini_registry/registry/system.yaml index 6637b716..1f6bc175 100644 --- a/crates/weaver_forge/codegen_examples/mini_registry/registry/system.yaml +++ b/crates/weaver_forge/codegen_examples/mini_registry/registry/system.yaml @@ -11,16 +11,12 @@ groups: members: - id: user value: 'user' - stability: experimental - id: system value: 'system' - stability: experimental - id: nice value: 'nice' - stability: experimental - id: idle value: 'idle' - stability: experimental - id: iowait value: 'iowait' stability: experimental @@ -31,11 +27,11 @@ groups: value: 'steal' stability: experimental brief: "The state of the CPU" - stability: experimental + stability: stable examples: ["idle", "interrupt"] - id: logical_number type: int - stability: experimental + stability: stable brief: "The logical CPU number [0..n-1]" examples: [1] # sytem.memory.* attribute group @@ -64,6 +60,6 @@ groups: - id: cached value: 'cached' stability: experimental - stability: experimental + stability: stable brief: "The memory state" examples: ["free", "cached"] \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 index 806addfb..e7e19d26 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 @@ -13,7 +13,7 @@ //! Notes: {{ ctx.note | comment_with_prefix("//! ") }} {%- endif %} -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/attributes/attributes.rs.j2 +//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER {%- for attribute in ctx.attributes | attribute_sort %} {{ attribute_macros.comments(attribute, "///") }} diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/mod.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/mod.rs.j2 index 7a1d419e..a269e52b 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/mod.rs.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/mod.rs.j2 @@ -6,7 +6,7 @@ */ //! OpenTelemetry Semantic Convention Attributes -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/attributes/mod.rs.j2 +//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER use opentelemetry::{Key, KeyValue, StringValue}; diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/counter.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/counter.j2 index d541789a..beb24e57 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/counter.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/counter.j2 @@ -6,8 +6,8 @@ #[cfg(feature = "semconv_experimental")] {%- endif %} pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Counter - where opentelemetry::metrics::Meter: CounterProvider { - meter.create_counter("{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") + where opentelemetry::metrics::Meter: crate::metrics::CounterProvider { + crate::metrics::CounterProvider::create_counter(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") } /// Metric: {{ metric.metric_name }} @@ -50,8 +50,8 @@ pub struct {{ metric.metric_name | pascal_case }}OptAttributes { impl {{ metric.metric_name | pascal_case }} { pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: CounterProvider{ - Self(meter.create_counter("{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) + where opentelemetry::metrics::Meter: crate::metrics::CounterProvider{ + Self(crate::metrics::CounterProvider::create_counter(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) } /// Adds an additional value to the counter. diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/gauge.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/gauge.j2 index 833b48bc..f7cc057f 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/gauge.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/gauge.j2 @@ -6,8 +6,8 @@ #[cfg(feature = "semconv_experimental")] {%- endif %} pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Gauge - where opentelemetry::metrics::Meter: GaugeProvider { - meter.create_gauge("{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") + where opentelemetry::metrics::Meter: crate::metrics::GaugeProvider { + crate::metrics::GaugeProvider::create_gauge(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") } /// Metric: {{ metric.metric_name }} @@ -50,8 +50,8 @@ pub struct {{ metric.metric_name | pascal_case }}OptAttributes { impl {{ metric.metric_name | pascal_case }} { pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: GaugeProvider{ - Self(meter.create_gauge("{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) + where opentelemetry::metrics::Meter: crate::metrics::GaugeProvider{ + Self(crate::metrics::GaugeProvider::create_gauge(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) } /// Records an additional value to the gauge. diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 index 69991810..e09fc5cb 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 @@ -6,8 +6,8 @@ #[cfg(feature = "semconv_experimental")] {%- endif %} pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram - where opentelemetry::metrics::Meter: HistogramProvider { - meter.create_histogram("{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") + where opentelemetry::metrics::Meter: crate::metrics::HistogramProvider { + crate::metrics::HistogramProvider::create_histogram(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") } /// Metric: {{ metric.metric_name }} @@ -50,8 +50,8 @@ pub struct {{ metric.metric_name | pascal_case }}OptAttributes { impl {{ metric.metric_name | pascal_case }} { pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: HistogramProvider{ - Self(meter.create_histogram("{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) + where opentelemetry::metrics::Meter: crate::metrics::HistogramProvider{ + Self(crate::metrics::HistogramProvider::create_histogram(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) } /// Adds an additional value to the distribution. diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 index 70241b89..1ad2c471 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 @@ -6,9 +6,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/metrics/metrics.rs.j2 - -use crate::metrics::{CounterProvider, GaugeProvider, HistogramProvider, UpDownCounterProvider}; +//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER {%- for metric in ctx.groups %} {% include "metrics/" ~ metric.instrument ~ ".j2" %} diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/mod.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/mod.rs.j2 index c7bf41ef..eec7f03f 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/mod.rs.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/mod.rs.j2 @@ -6,7 +6,7 @@ */ //! OpenTelemetry Semantic Convention Metrics -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/metrics/mod.rs.j2 +//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER {% for group in ctx %} /// Metrics for the `{{ group.id | metric_namespace }}` namespace. diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/updowncounter.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/updowncounter.j2 index 062b307d..23ec9e4e 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/updowncounter.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/updowncounter.j2 @@ -6,8 +6,8 @@ #[cfg(feature = "semconv_experimental")] {%- endif %} pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter - where opentelemetry::metrics::Meter: UpDownCounterProvider { - meter.create_up_down_counter("{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") + where opentelemetry::metrics::Meter: crate::metrics::UpDownCounterProvider { + crate::metrics::UpDownCounterProvider::create_up_down_counter(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") } /// Metric: {{ metric.metric_name }} @@ -50,8 +50,8 @@ pub struct {{ metric.metric_name | pascal_case }}OptAttributes { impl {{ metric.metric_name | pascal_case }} { pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: UpDownCounterProvider{ - Self(meter.create_up_down_counter("{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) + where opentelemetry::metrics::Meter: crate::metrics::UpDownCounterProvider{ + Self(crate::metrics::UpDownCounterProvider::create_up_down_counter(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) } /// Adds an additional value to the up-down-counter. diff --git a/crates/weaver_forge/tests/README.md b/crates/weaver_forge/tests/README.md new file mode 100644 index 00000000..5ee01b69 --- /dev/null +++ b/crates/weaver_forge/tests/README.md @@ -0,0 +1,381 @@ +# Semantic Conventions for Rust + +# Usage + +```rust +use opentelemetry::KeyValue; +use opentelemetry::metrics::{Histogram, MeterProvider}; +use opentelemetry_sdk::{Resource, runtime}; +use opentelemetry_sdk::metrics::{PeriodicReader, SdkMeterProvider}; + +use semconv::attributes; +use semconv::attributes::http::{HTTP_REQUEST_METHOD, HttpRequestMethod}; +use semconv::attributes::system::SystemCpuState; +use semconv::metrics::http::{create_http_client_request_duration, HttpClientActiveRequests, HttpClientActiveRequestsReqAttributes, HttpServerRequestDurationOptAttributes, HttpServerRequestDurationReqAttributes}; +use semconv::metrics::http::HttpServerRequestDuration; +use semconv::metrics::system::{SystemCpuTime, SystemCpuTimeOptAttributes, SystemCpuUtilization, SystemCpuUtilizationOptAttributes}; + +/// Main +#[tokio::main] +async fn main() -> Result<(), Box> { + let meter_provider = init_meter_provider(); + + // SemConv attributes are typed, so the compiler will catch type errors + // Experimental attributes are not visible if the `semconv_experimental` feature is not enabled + println!("{:?}", attributes::client::CLIENT_ADDRESS.value("145.34.23.56".into())); + println!("{:?}", attributes::client::CLIENT_ADDRESS.key()); + println!("{:?}", attributes::client::CLIENT_PORT.value(8080)); + println!("{:?}", attributes::client::CLIENT_PORT.key()); + + println!("{}", HttpRequestMethod::Connect); + + let meter = meter_provider.meter("mylibname"); + + // Create a u64 http.client.request.duration metric + let http_client_request_duration: Histogram = create_http_client_request_duration(&meter); + http_client_request_duration.record(100, &[ + HTTP_REQUEST_METHOD.value(&HttpRequestMethod::Connect), + // here nothing guarantees that all the required attributes are provided + ]); + + let http_client_request_duration: Histogram = create_http_client_request_duration(&meter); + dbg!(http_client_request_duration); + + // ==== A TYPE-SAFE HISTOGRAM API ==== + // Create a u64 http.server.request.duration metric (as defined in the OpenTelemetry HTTP + // semantic conventions) + let http_request_duration = HttpServerRequestDuration::::new(&meter); + + // Records a new data point and provide the required and some optional attributes + http_request_duration.record(100, &HttpServerRequestDurationReqAttributes { + http_request_method: HttpRequestMethod::Connect, + url_scheme: "http".to_owned(), + }, Some(&HttpServerRequestDurationOptAttributes { + http_response_status_code: Some(200), + ..Default::default() + })); + + // ==== A TYPE-SAFE UP-DOWN-COUNTER API ==== + // Create a f64 http.server.request.duration metric (as defined in the OpenTelemetry HTTP + // semantic conventions) + let http_client_active_requests = HttpClientActiveRequests::::new(&meter); + + // Adds a new data point and provide the required attributes. Optional attributes are not + // provided in this example. + http_client_active_requests.add(10.0, &HttpClientActiveRequestsReqAttributes { + server_address: "10.0.0.1".to_owned(), + server_port: 8080, + }, None); + + // ==== A TYPE-SAFE COUNTER API ==== + // Create a f64 system.cpu.time metric (as defined in the OpenTelemetry System semantic + // conventions) + let system_cpu_time = SystemCpuTime::::new(&meter); + + // Adds a new data point and provide some optional attributes. + // Note: In the method signature, there is no required attribute. + system_cpu_time.add(10.0, Some(&SystemCpuTimeOptAttributes { + system_cpu_logical_number: Some(0), + system_cpu_state: Some(SystemCpuState::Idle) + })); + // Adds a new data point with a custom CPU state. + system_cpu_time.add(20.0, Some(&SystemCpuTimeOptAttributes { + system_cpu_logical_number: Some(0), + system_cpu_state: Some(SystemCpuState::_Custom("custom".to_owned())) + })); + + // ==== A TYPE-SAFE GAUGE API ==== + // Create a i64 system.cpu.utilization metric (as defined in the OpenTelemetry System semantic + // conventions) + let system_cpu_utilization = SystemCpuUtilization::::new(&meter); + + // Adds a new data point with no optional attributes. + system_cpu_utilization.record(-5, None); + // Adds a new data point with some optional attributes. + system_cpu_utilization.record(10, Some(&SystemCpuUtilizationOptAttributes { + system_cpu_logical_number: Some(0), + system_cpu_state: Some(SystemCpuState::Idle) + })); + + meter_provider.shutdown()?; + Ok(()) +} + +fn init_meter_provider() -> SdkMeterProvider { + let exporter = opentelemetry_stdout::MetricsExporterBuilder::default() + .with_encoder(|writer, data| + Ok(serde_json::to_writer_pretty(writer, &data).unwrap())) + .build(); + let reader = PeriodicReader::builder(exporter, runtime::Tokio).build(); + SdkMeterProvider::builder() + .with_reader(reader) + .with_resource(Resource::new(vec![KeyValue::new( + "service.name", + "metrics-basic-example", + )])) + .build() +} +``` + +The execution of this program will generate the following output: + +``` +KeyValue { key: Static("client.address"), value: String(Static("145.34.23.56")) } +Static("client.address") +KeyValue { key: Static("client.port"), value: I64(8080) } +Static("client.port") +CONNECT +[src/main.rs:39:5] http_client_request_duration = Histogram +{ + "resourceMetrics": { + "resource": { + "attributes": [ + { + "key": "service.name", + "value": { + "stringValue": "metrics-basic-example" + } + } + ] + }, + "scopeMetrics": [ + { + "scope": { + "name": "mylibname" + }, + "metrics": [ + { + "name": "http.client.request.duration", + "description": "Duration of HTTP client requests.", + "unit": "s", + "histogram": { + "dataPoints": [ + { + "attributes": { + "http.request.method": { + "stringValue": "CONNECT" + } + }, + "startTimeUnixNano": 1714780164856054000, + "timeUnixNano": 1714780164856202000, + "startTime": "2024-05-03 23:49:24.856", + "time": "2024-05-03 23:49:24.856", + "count": 1, + "explicitBounds": [ + 0.0, + 5.0, + 10.0, + 25.0, + 50.0, + 75.0, + 100.0, + 250.0, + 500.0, + 750.0, + 1000.0, + 2500.0, + 5000.0, + 7500.0, + 10000.0 + ], + "bucketCounts": [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "min": 100, + "max": 100, + "sum": 100, + "exemplars": [], + "flags": 0 + } + ], + "aggregationTemporality": "Cumulative" + } + }, + { + "name": "http.server.request.duration", + "description": "Duration of HTTP server requests.", + "unit": "s", + "histogram": { + "dataPoints": [ + { + "attributes": { + "http.request.method": { + "stringValue": "CONNECT" + }, + "http.response.status_code": { + "intValue": 200 + }, + "url.scheme": { + "stringValue": "http" + } + }, + "startTimeUnixNano": 1714780164856111000, + "timeUnixNano": 1714780164856204000, + "startTime": "2024-05-03 23:49:24.856", + "time": "2024-05-03 23:49:24.856", + "count": 1, + "explicitBounds": [ + 0.0, + 5.0, + 10.0, + 25.0, + 50.0, + 75.0, + 100.0, + 250.0, + 500.0, + 750.0, + 1000.0, + 2500.0, + 5000.0, + 7500.0, + 10000.0 + ], + "bucketCounts": [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "min": 100, + "max": 100, + "sum": 100, + "exemplars": [], + "flags": 0 + } + ], + "aggregationTemporality": "Cumulative" + } + }, + { + "name": "http.client.active_requests", + "description": "Number of active HTTP requests.", + "unit": "{request}", + "sum": { + "dataPoints": [ + { + "attributes": { + "server.address": { + "stringValue": "10.0.0.1" + }, + "server.port": { + "intValue": 8080 + } + }, + "startTime": "2024-05-03 23:49:24.856", + "time": "2024-05-03 23:49:24.856", + "startTimeUnixNano": 1714780164856139000, + "timeUnixNano": 1714780164856219000, + "value": 10.0 + } + ], + "aggregationTemporality": "Cumulative", + "isMonotonic": false + } + }, + { + "name": "system.cpu.time", + "description": "Seconds each logical CPU spent on each mode", + "unit": "s", + "sum": { + "dataPoints": [ + { + "attributes": { + "system.cpu.logical_number": { + "intValue": 0 + }, + "system.cpu.state": { + "stringValue": "idle" + } + }, + "startTime": "2024-05-03 23:49:24.856", + "time": "2024-05-03 23:49:24.856", + "startTimeUnixNano": 1714780164856152000, + "timeUnixNano": 1714780164856220000, + "value": 10.0 + }, + { + "attributes": { + "system.cpu.logical_number": { + "intValue": 0 + }, + "system.cpu.state": { + "stringValue": "custom" + } + }, + "startTime": "2024-05-03 23:49:24.856", + "time": "2024-05-03 23:49:24.856", + "startTimeUnixNano": 1714780164856152000, + "timeUnixNano": 1714780164856220000, + "value": 20.0 + } + ], + "aggregationTemporality": "Cumulative", + "isMonotonic": true + } + }, + { + "name": "system.cpu.utilization", + "description": "Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs", + "unit": "1", + "gauge": { + "dataPoints": [ + { + "attributes": { + "system.cpu.logical_number": { + "intValue": 0 + }, + "system.cpu.state": { + "stringValue": "idle" + } + }, + "startTime": null, + "time": "2024-05-03 23:49:24.856", + "startTimeUnixNano": null, + "timeUnixNano": 1714780164856176000, + "value": 10 + }, + { + "attributes": {}, + "startTime": null, + "time": "2024-05-03 23:49:24.856", + "startTimeUnixNano": null, + "timeUnixNano": 1714780164856171000, + "value": -5 + } + ] + } + } + ] + } + ] + } +} +``` \ No newline at end of file diff --git a/crates/weaver_forge/tests/attributes/client.rs b/crates/weaver_forge/tests/attributes/client.rs new file mode 100644 index 00000000..e509e4e9 --- /dev/null +++ b/crates/weaver_forge/tests/attributes/client.rs @@ -0,0 +1,27 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! 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 FILE HAS BEEN GENERATED BY WEAVER + +/// 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. +/// +/// Examples: +/// - client.example.com +/// - 10.1.2.80 +/// - /tmp/my.sock +pub const CLIENT_ADDRESS: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("client.address"); + +/// Client port number. +/// +/// 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. +/// +/// Examples: +/// - 65123 +pub const CLIENT_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("client.port"); \ No newline at end of file diff --git a/crates/weaver_forge/tests/attributes/error.rs b/crates/weaver_forge/tests/attributes/error.rs new file mode 100644 index 00000000..4fd81648 --- /dev/null +++ b/crates/weaver_forge/tests/attributes/error.rs @@ -0,0 +1,75 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! This document defines the shared attributes used to report an error. +//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER + +/// Describes a class of error the operation ended with. +/// +/// Notes: +/// The `error.type` SHOULD be predictable, and SHOULD have low cardinality. +/// +/// When `error.type` is set to a type (e.g., an exception type), its +/// canonical class name identifying the type within the artifact SHOULD be used. +/// +/// Instrumentations SHOULD document the list of errors they report. +/// +/// The cardinality of `error.type` within one instrumentation library SHOULD be low. +/// Telemetry consumers that aggregate data from multiple instrumentation libraries and applications +/// should be prepared for `error.type` to have high cardinality at query time when no +/// additional filters are applied. +/// +/// If the operation has completed successfully, instrumentations SHOULD NOT set `error.type`. +/// +/// If a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes), +/// it's RECOMMENDED to: +/// +/// * Use a domain-specific attribute +/// * Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. +/// +/// Examples: +/// - timeout +/// - java.net.UnknownHostException +/// - server_certificate_invalid +/// - 500 +pub const ERROR_TYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("error.type"); + +/// Describes a class of error the operation ended with. +#[derive(Debug, Clone)] +#[non_exhaustive] +pub enum ErrorType { /// A fallback error value to be used when the instrumentation doesn't define a custom value. + Other, + /// This variant allows defining a custom entry in the enum. + _Custom(String), +} + +impl ErrorType { + /// Returns the string representation of the [`ErrorType`]. + pub fn as_str(&self) -> &str { + match self { + ErrorType::Other => "_OTHER", + ErrorType::_Custom(v) => v.as_str(), + // 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 ErrorType { + /// Formats the value using the given formatter. + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &ErrorType) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} \ No newline at end of file diff --git a/crates/weaver_forge/tests/attributes/exception.rs b/crates/weaver_forge/tests/attributes/exception.rs new file mode 100644 index 00000000..e7c54bb6 --- /dev/null +++ b/crates/weaver_forge/tests/attributes/exception.rs @@ -0,0 +1,47 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! This document defines the shared attributes used to report a single exception associated with a span or log. +//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER + +/// SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span. +/// +/// Notes: +/// An exception is considered to have escaped (or left) the scope of a span, +/// if that span is ended while the exception is still logically "in flight". +/// This may be actually "in flight" in some languages (e.g. if the exception +/// is passed to a Context manager's `__exit__` method in Python) but will +/// usually be caught at the point of recording the exception in most languages. +/// +/// It is usually not possible to determine at the point where an exception is thrown +/// whether it will escape the scope of a span. +/// However, it is trivial to know that an exception +/// will escape, if one checks for an active exception just before ending the span, +/// as done in the [example for recording span exceptions](#recording-an-exception). +/// +/// It follows that an exception may still escape the scope of the span +/// 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: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("exception.escaped"); + +/// The exception message. +/// +/// Examples: +/// - Division by zero +/// - Can't convert 'int' object to str implicitly +pub const EXCEPTION_MESSAGE: crate::attributes::AttributeKey = crate::attributes::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. +/// +/// Example: Exception in thread "main" java.lang.RuntimeException: Test exception\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n at com.example.GenerateTrace.main(GenerateTrace.java:5) +pub const EXCEPTION_STACKTRACE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("exception.stacktrace"); + +/// 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. +/// +/// Examples: +/// - java.net.ConnectException +/// - OSError +pub const EXCEPTION_TYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("exception.type"); \ No newline at end of file diff --git a/crates/weaver_forge/tests/attributes/http.rs b/crates/weaver_forge/tests/attributes/http.rs new file mode 100644 index 00000000..c68fb9fe --- /dev/null +++ b/crates/weaver_forge/tests/attributes/http.rs @@ -0,0 +1,220 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! This document defines semantic convention attributes in the HTTP namespace. +//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER + +/// State of the HTTP connection in the HTTP connection pool. +/// +/// Examples: +/// - active +/// - idle +#[cfg(feature = "semconv_experimental")] +pub const HTTP_CONNECTION_STATE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.connection.state"); + +/// State of the HTTP connection in the HTTP connection pool. +#[derive(Debug, Clone)] +#[non_exhaustive] +pub enum HttpConnectionState { /// active state. + #[cfg(feature = "semconv_experimental")] + Active, /// idle state. + #[cfg(feature = "semconv_experimental")] + Idle, + /// This variant allows defining a custom entry in the enum. + _Custom(String), +} + +impl HttpConnectionState { + /// Returns the string representation of the [`HttpConnectionState`]. + pub fn as_str(&self) -> &str { + match self { + #[cfg(feature = "semconv_experimental")] + HttpConnectionState::Active => "active", + #[cfg(feature = "semconv_experimental")] + HttpConnectionState::Idle => "idle", + HttpConnectionState::_Custom(v) => v.as_str(), + // 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()) + } +} + +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &HttpConnectionState) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} + +/// 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. +/// +/// Example: 3495 +#[cfg(feature = "semconv_experimental")] +pub const HTTP_REQUEST_BODY_SIZE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.request.body.size"); + +/// HTTP request headers, `` being the normalized HTTP Header name (lowercase), the value being the header values. +/// +/// Notes: +/// 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. +/// +/// Examples: +/// - http.request.header.content-type=["application/json"] +/// - http.request.header.x-forwarded-for=["1.2.3.4", "1.2.3.5"] +pub const HTTP_REQUEST_HEADER: crate::attributes::AttributeKey> = crate::attributes::AttributeKey::new("http.request.header"); + +/// HTTP request method. +/// +/// Notes: +/// HTTP request method value SHOULD be "known" to the instrumentation. +/// By default, this convention defines "known" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods) +/// and the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html). +/// +/// If the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`. +/// +/// If the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override +/// the list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named +/// OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods +/// (this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults). +/// +/// 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. +/// +/// Examples: +/// - GET +/// - POST +/// - HEAD +pub const HTTP_REQUEST_METHOD: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.request.method"); + +/// HTTP request method. +#[derive(Debug, Clone)] +#[non_exhaustive] +pub enum HttpRequestMethod { /// CONNECT method. + Connect, /// DELETE method. + Delete, /// GET method. + Get, /// HEAD method. + Head, /// OPTIONS method. + Options, /// PATCH method. + Patch, /// POST method. + Post, /// PUT method. + Put, /// TRACE method. + Trace, /// Any HTTP method that the instrumentation has no prior knowledge of. + Other, + /// This variant allows defining a custom entry in the enum. + _Custom(String), +} + +impl HttpRequestMethod { + /// Returns the string representation of the [`HttpRequestMethod`]. + pub fn as_str(&self) -> &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", + HttpRequestMethod::_Custom(v) => v.as_str(), + // 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()) + } +} + +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &HttpRequestMethod) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} + +/// Original HTTP method sent by the client in the request line. +/// +/// Examples: +/// - GeT +/// - ACL +/// - foo +pub const HTTP_REQUEST_METHOD_ORIGINAL: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.request.method_original"); + +/// The ordinal number of request resending attempt (for any reason, including redirects). +/// +/// 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). +/// +/// Example: 3 +pub const HTTP_REQUEST_RESEND_COUNT: crate::attributes::AttributeKey = crate::attributes::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. +/// +/// Example: 1437 +#[cfg(feature = "semconv_experimental")] +pub const HTTP_REQUEST_SIZE: crate::attributes::AttributeKey = crate::attributes::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. +/// +/// Example: 3495 +#[cfg(feature = "semconv_experimental")] +pub const HTTP_RESPONSE_BODY_SIZE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.response.body.size"); + +/// HTTP response headers, `` being the normalized HTTP Header name (lowercase), the value being the header values. +/// +/// Notes: +/// 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. +/// +/// Examples: +/// - http.response.header.content-type=["application/json"] +/// - http.response.header.my-custom-header=["abc", "def"] +pub const HTTP_RESPONSE_HEADER: crate::attributes::AttributeKey> = crate::attributes::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. +/// +/// Example: 1437 +#[cfg(feature = "semconv_experimental")] +pub const HTTP_RESPONSE_SIZE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.response.size"); + +/// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). +/// +/// Examples: +/// - 200 +pub const HTTP_RESPONSE_STATUS_CODE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.response.status_code"); + +/// The matched route, that is, the path template in the format used by the respective server framework. +/// +/// 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. +/// +/// Examples: +/// - /users/:userID? +/// - {controller}/{action}/{id?} +pub const HTTP_ROUTE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.route"); \ No newline at end of file diff --git a/crates/weaver_forge/tests/attributes/mod.rs b/crates/weaver_forge/tests/attributes/mod.rs new file mode 100644 index 00000000..868be073 --- /dev/null +++ b/crates/weaver_forge/tests/attributes/mod.rs @@ -0,0 +1,76 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! OpenTelemetry Semantic Convention Attributes +//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER + +use opentelemetry::{Key, KeyValue, StringValue}; + + +/// Attributes for the `client` namespace. +pub mod client; +/// Attributes for the `error` namespace. +pub mod error; +/// Attributes for the `exception` namespace. +pub mod exception; +/// Attributes for the `http` namespace. +pub mod http; +/// Attributes for the `network` namespace. +pub mod network; +/// Attributes for the `server` namespace. +pub mod server; +/// Attributes for the `system` namespace. +pub mod system; +/// Attributes for the `url` namespace. +pub mod url; + +/// A typed attribute key. +pub struct AttributeKey { + key: Key, + phantom: std::marker::PhantomData +} + +impl AttributeKey { + /// Returns a new [`AttributeKey`] with the given key. + pub(crate) const fn new(key: &'static str) -> AttributeKey { + Self { + key: Key::from_static_str(key), + phantom: std::marker::PhantomData + } + } + + /// Returns the key of the attribute. + pub fn key(&self) -> &Key { + &self.key + } +} + +impl AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: StringValue) -> KeyValue { + KeyValue::new(self.key.clone(), v) + } +} + +impl AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: i64) -> KeyValue { + KeyValue::new(self.key.clone(), v) + } +} + +impl AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: f64) -> KeyValue { + KeyValue::new(self.key.clone(), v) + } +} + +impl AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: bool) -> KeyValue { + KeyValue::new(self.key.clone(), v) + } +} \ No newline at end of file diff --git a/crates/weaver_forge/tests/attributes/network.rs b/crates/weaver_forge/tests/attributes/network.rs new file mode 100644 index 00000000..b69454b8 --- /dev/null +++ b/crates/weaver_forge/tests/attributes/network.rs @@ -0,0 +1,628 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! These attributes may be used for any network related operation. +//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER + +/// Deprecated, use `server.address`. +/// +/// Examples: +/// - example.com +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `server.address`.")] +pub const NET_HOST_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.host.name"); + +/// Deprecated, use `server.port`. +/// +/// Examples: +/// - 8080 +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `server.port`.")] +pub const NET_HOST_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.host.port"); + +/// Deprecated, use `server.address` on client spans and `client.address` on server spans. +/// +/// Examples: +/// - example.com +#[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::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.peer.name"); + +/// Deprecated, use `server.port` on client spans and `client.port` on server spans. +/// +/// Examples: +/// - 8080 +#[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::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.peer.port"); + +/// Deprecated, use `network.protocol.name`. +/// +/// Examples: +/// - amqp +/// - http +/// - mqtt +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `network.protocol.name`.")] +pub const NET_PROTOCOL_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.protocol.name"); + +/// Deprecated, use `network.protocol.version`. +/// +/// Example: 3.1.1 +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `network.protocol.version`.")] +pub const NET_PROTOCOL_VERSION: crate::attributes::AttributeKey = crate::attributes::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::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.family"); + +/// Deprecated, use `network.transport` and `network.type`. +#[derive(Debug, Clone)] +#[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, + /// This variant allows defining a custom entry in the enum. + _Custom(String), +} + +impl NetSockFamily { + /// Returns the string representation of the [`NetSockFamily`]. + pub fn as_str(&self) -> &str { + match self { + #[cfg(feature = "semconv_experimental")] + NetSockFamily::Inet => "inet", + #[cfg(feature = "semconv_experimental")] + NetSockFamily::Inet6 => "inet6", + #[cfg(feature = "semconv_experimental")] + NetSockFamily::Unix => "unix", + NetSockFamily::_Custom(v) => v.as_str(), + // 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()) + } +} + +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &NetSockFamily) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} + +/// Deprecated, use `network.local.address`. +/// +/// Examples: +/// - /var/my.sock +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `network.local.address`.")] +pub const NET_SOCK_HOST_ADDR: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.host.addr"); + +/// Deprecated, use `network.local.port`. +/// +/// Examples: +/// - 8080 +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `network.local.port`.")] +pub const NET_SOCK_HOST_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.host.port"); + +/// Deprecated, use `network.peer.address`. +/// +/// Examples: +/// - 192.168.0.1 +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `network.peer.address`.")] +pub const NET_SOCK_PEER_ADDR: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.peer.addr"); + +/// Deprecated, no replacement at this time. +/// +/// Examples: +/// - /var/my.sock +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Removed.")] +pub const NET_SOCK_PEER_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.peer.name"); + +/// Deprecated, use `network.peer.port`. +/// +/// Examples: +/// - 65531 +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `network.peer.port`.")] +pub const NET_SOCK_PEER_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.peer.port"); + +/// Deprecated, use `network.transport`. +#[cfg(feature = "semconv_experimental")] +#[deprecated(note="Replaced by `network.transport`.")] +pub const NET_TRANSPORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.transport"); + +/// Deprecated, use `network.transport`. +#[derive(Debug, Clone)] +#[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, + /// This variant allows defining a custom entry in the enum. + _Custom(String), +} + +impl NetTransport { + /// Returns the string representation of the [`NetTransport`]. + pub fn as_str(&self) -> &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", + NetTransport::_Custom(v) => v.as_str(), + // 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()) + } +} + +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &NetTransport) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} + +/// The ISO 3166-1 alpha-2 2-character country code associated with the mobile carrier network. +/// +/// Example: DE +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_CARRIER_ICC: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.icc"); + +/// The mobile carrier country code. +/// +/// Example: 310 +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_CARRIER_MCC: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.mcc"); + +/// The mobile carrier network code. +/// +/// Example: 001 +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_CARRIER_MNC: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.mnc"); + +/// The name of the mobile carrier. +/// +/// Example: sprint +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_CARRIER_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.name"); + +/// This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection. +/// +/// Example: LTE +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_CONNECTION_SUBTYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.connection.subtype"); + +/// This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection. +#[derive(Debug, Clone)] +#[non_exhaustive] +pub enum NetworkConnectionSubtype { /// GPRS + #[cfg(feature = "semconv_experimental")] + Gprs, /// EDGE + #[cfg(feature = "semconv_experimental")] + Edge, /// UMTS + #[cfg(feature = "semconv_experimental")] + Umts, /// CDMA + #[cfg(feature = "semconv_experimental")] + Cdma, /// EVDO Rel. 0 + #[cfg(feature = "semconv_experimental")] + Evdo0, /// EVDO Rev. A + #[cfg(feature = "semconv_experimental")] + EvdoA, /// CDMA2000 1XRTT + #[cfg(feature = "semconv_experimental")] + Cdma20001Xrtt, /// HSDPA + #[cfg(feature = "semconv_experimental")] + Hsdpa, /// HSUPA + #[cfg(feature = "semconv_experimental")] + Hsupa, /// HSPA + #[cfg(feature = "semconv_experimental")] + Hspa, /// IDEN + #[cfg(feature = "semconv_experimental")] + Iden, /// EVDO Rev. B + #[cfg(feature = "semconv_experimental")] + EvdoB, /// LTE + #[cfg(feature = "semconv_experimental")] + Lte, /// EHRPD + #[cfg(feature = "semconv_experimental")] + Ehrpd, /// HSPAP + #[cfg(feature = "semconv_experimental")] + Hspap, /// GSM + #[cfg(feature = "semconv_experimental")] + Gsm, /// TD-SCDMA + #[cfg(feature = "semconv_experimental")] + TdScdma, /// IWLAN + #[cfg(feature = "semconv_experimental")] + Iwlan, /// 5G NR (New Radio) + #[cfg(feature = "semconv_experimental")] + Nr, /// 5G NRNSA (New Radio Non-Standalone) + #[cfg(feature = "semconv_experimental")] + Nrnsa, /// LTE CA + #[cfg(feature = "semconv_experimental")] + LteCa, + /// This variant allows defining a custom entry in the enum. + _Custom(String), +} + +impl NetworkConnectionSubtype { + /// Returns the string representation of the [`NetworkConnectionSubtype`]. + pub fn as_str(&self) -> &str { + match self { + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Gprs => "gprs", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Edge => "edge", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Umts => "umts", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Cdma => "cdma", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Evdo0 => "evdo_0", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::EvdoA => "evdo_a", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Cdma20001Xrtt => "cdma2000_1xrtt", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Hsdpa => "hsdpa", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Hsupa => "hsupa", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Hspa => "hspa", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Iden => "iden", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::EvdoB => "evdo_b", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Lte => "lte", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Ehrpd => "ehrpd", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Hspap => "hspap", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Gsm => "gsm", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::TdScdma => "td_scdma", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Iwlan => "iwlan", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Nr => "nr", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::Nrnsa => "nrnsa", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionSubtype::LteCa => "lte_ca", + NetworkConnectionSubtype::_Custom(v) => v.as_str(), + // 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 NetworkConnectionSubtype { + /// Formats the value using the given formatter. + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &NetworkConnectionSubtype) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} + +/// The internet connection type. +/// +/// Example: wifi +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_CONNECTION_TYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.connection.type"); + +/// The internet connection type. +#[derive(Debug, Clone)] +#[non_exhaustive] +pub enum NetworkConnectionType { + #[cfg(feature = "semconv_experimental")] + Wifi, + #[cfg(feature = "semconv_experimental")] + Wired, + #[cfg(feature = "semconv_experimental")] + Cell, + #[cfg(feature = "semconv_experimental")] + Unavailable, + #[cfg(feature = "semconv_experimental")] + Unknown, + /// This variant allows defining a custom entry in the enum. + _Custom(String), +} + +impl NetworkConnectionType { + /// Returns the string representation of the [`NetworkConnectionType`]. + pub fn as_str(&self) -> &str { + match self { + #[cfg(feature = "semconv_experimental")] + NetworkConnectionType::Wifi => "wifi", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionType::Wired => "wired", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionType::Cell => "cell", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionType::Unavailable => "unavailable", + #[cfg(feature = "semconv_experimental")] + NetworkConnectionType::Unknown => "unknown", + NetworkConnectionType::_Custom(v) => v.as_str(), + // 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 NetworkConnectionType { + /// Formats the value using the given formatter. + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &NetworkConnectionType) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} + +/// The network IO operation direction. +/// +/// Examples: +/// - transmit +#[cfg(feature = "semconv_experimental")] +pub const NETWORK_IO_DIRECTION: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.io.direction"); + +/// The network IO operation direction. +#[derive(Debug, Clone)] +#[non_exhaustive] +pub enum NetworkIoDirection { + #[cfg(feature = "semconv_experimental")] + Transmit, + #[cfg(feature = "semconv_experimental")] + Receive, + /// This variant allows defining a custom entry in the enum. + _Custom(String), +} + +impl NetworkIoDirection { + /// Returns the string representation of the [`NetworkIoDirection`]. + pub fn as_str(&self) -> &str { + match self { + #[cfg(feature = "semconv_experimental")] + NetworkIoDirection::Transmit => "transmit", + #[cfg(feature = "semconv_experimental")] + NetworkIoDirection::Receive => "receive", + NetworkIoDirection::_Custom(v) => v.as_str(), + // 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 NetworkIoDirection { + /// Formats the value using the given formatter. + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &NetworkIoDirection) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} + +/// Local address of the network connection - IP address or Unix domain socket name. +/// +/// Examples: +/// - 10.1.2.80 +/// - /tmp/my.sock +pub const NETWORK_LOCAL_ADDRESS: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.local.address"); + +/// Local port number of the network connection. +/// +/// Examples: +/// - 65123 +pub const NETWORK_LOCAL_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.local.port"); + +/// Peer address of the network connection - IP address or Unix domain socket name. +/// +/// Examples: +/// - 10.1.2.80 +/// - /tmp/my.sock +pub const NETWORK_PEER_ADDRESS: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.peer.address"); + +/// Peer port number of the network connection. +/// +/// Examples: +/// - 65123 +pub const NETWORK_PEER_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.peer.port"); + +/// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. +/// +/// Notes: +/// The value SHOULD be normalized to lowercase. +/// +/// Examples: +/// - amqp +/// - http +/// - mqtt +pub const NETWORK_PROTOCOL_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.protocol.name"); + +/// The actual version of the protocol used for network communication. +/// +/// Notes: +/// If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, this attribute SHOULD NOT be set. +/// +/// Examples: +/// - 1.1 +/// - 2 +pub const NETWORK_PROTOCOL_VERSION: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.protocol.version"); + +/// [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). +/// +/// Notes: +/// The value SHOULD be normalized to lowercase. +/// +/// Consider always setting the transport when setting a port number, since +/// a port number is ambiguous without knowing the transport. For example +/// different processes could be listening on TCP port 12345 and UDP port 12345. +/// +/// Examples: +/// - tcp +/// - udp +pub const NETWORK_TRANSPORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.transport"); + +/// [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). +#[derive(Debug, Clone)] +#[non_exhaustive] +pub enum NetworkTransport { /// TCP + Tcp, /// UDP + Udp, /// Named or anonymous pipe. + Pipe, /// Unix domain socket + Unix, + /// This variant allows defining a custom entry in the enum. + _Custom(String), +} + +impl NetworkTransport { + /// Returns the string representation of the [`NetworkTransport`]. + pub fn as_str(&self) -> &str { + match self { + NetworkTransport::Tcp => "tcp", + NetworkTransport::Udp => "udp", + NetworkTransport::Pipe => "pipe", + NetworkTransport::Unix => "unix", + NetworkTransport::_Custom(v) => v.as_str(), + // 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 NetworkTransport { + /// Formats the value using the given formatter. + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &NetworkTransport) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} + +/// [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. +/// +/// Notes: +/// The value SHOULD be normalized to lowercase. +/// +/// Examples: +/// - ipv4 +/// - ipv6 +pub const NETWORK_TYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.type"); + +/// [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. +#[derive(Debug, Clone)] +#[non_exhaustive] +pub enum NetworkType { /// IPv4 + Ipv4, /// IPv6 + Ipv6, + /// This variant allows defining a custom entry in the enum. + _Custom(String), +} + +impl NetworkType { + /// Returns the string representation of the [`NetworkType`]. + pub fn as_str(&self) -> &str { + match self { + NetworkType::Ipv4 => "ipv4", + NetworkType::Ipv6 => "ipv6", + NetworkType::_Custom(v) => v.as_str(), + // 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 NetworkType { + /// Formats the value using the given formatter. + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &NetworkType) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} \ No newline at end of file diff --git a/crates/weaver_forge/tests/attributes/server.rs b/crates/weaver_forge/tests/attributes/server.rs new file mode 100644 index 00000000..f5b790e3 --- /dev/null +++ b/crates/weaver_forge/tests/attributes/server.rs @@ -0,0 +1,29 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! These attributes may be used to describe the server 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 FILE HAS BEEN GENERATED BY WEAVER + +/// Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. +/// +/// Notes: +/// When observed from the client side, and when communicating through an intermediary, `server.address` SHOULD represent the server address behind any intermediaries, for example proxies, if it's available. +/// +/// Examples: +/// - example.com +/// - 10.1.2.80 +/// - /tmp/my.sock +pub const SERVER_ADDRESS: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("server.address"); + +/// Server port number. +/// +/// Notes: +/// When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent the server port behind any intermediaries, for example proxies, if it's available. +/// +/// Examples: +/// - 80 +/// - 8080 +/// - 443 +pub const SERVER_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("server.port"); \ No newline at end of file diff --git a/crates/weaver_forge/tests/attributes/system.rs b/crates/weaver_forge/tests/attributes/system.rs new file mode 100644 index 00000000..c8587be1 --- /dev/null +++ b/crates/weaver_forge/tests/attributes/system.rs @@ -0,0 +1,139 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Describes System CPU attributes +//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER + +/// The logical CPU number [0..n-1] +/// +/// Examples: +/// - 1 +pub const SYSTEM_CPU_LOGICAL_NUMBER: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("system.cpu.logical_number"); + +/// The state of the CPU +/// +/// Examples: +/// - idle +/// - interrupt +pub const SYSTEM_CPU_STATE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("system.cpu.state"); + +/// The state of the CPU +#[derive(Debug, Clone)] +#[non_exhaustive] +pub enum SystemCpuState { + User, + System, + Nice, + Idle, + #[cfg(feature = "semconv_experimental")] + Iowait, + #[cfg(feature = "semconv_experimental")] + Interrupt, + #[cfg(feature = "semconv_experimental")] + Steal, + /// This variant allows defining a custom entry in the enum. + _Custom(String), +} + +impl SystemCpuState { + /// Returns the string representation of the [`SystemCpuState`]. + pub fn as_str(&self) -> &str { + match self { + SystemCpuState::User => "user", + SystemCpuState::System => "system", + SystemCpuState::Nice => "nice", + SystemCpuState::Idle => "idle", + #[cfg(feature = "semconv_experimental")] + SystemCpuState::Iowait => "iowait", + #[cfg(feature = "semconv_experimental")] + SystemCpuState::Interrupt => "interrupt", + #[cfg(feature = "semconv_experimental")] + SystemCpuState::Steal => "steal", + SystemCpuState::_Custom(v) => v.as_str(), + // 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 SystemCpuState { + /// Formats the value using the given formatter. + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &SystemCpuState) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} + +/// The memory state +/// +/// Examples: +/// - free +/// - cached +pub const SYSTEM_MEMORY_STATE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("system.memory.state"); + +/// The memory state +#[derive(Debug, Clone)] +#[non_exhaustive] +pub enum SystemMemoryState { + #[cfg(feature = "semconv_experimental")] + Used, + #[cfg(feature = "semconv_experimental")] + Free, + #[cfg(feature = "semconv_experimental")] + Shared, + #[cfg(feature = "semconv_experimental")] + Buffers, + #[cfg(feature = "semconv_experimental")] + Cached, + /// This variant allows defining a custom entry in the enum. + _Custom(String), +} + +impl SystemMemoryState { + /// Returns the string representation of the [`SystemMemoryState`]. + pub fn as_str(&self) -> &str { + match self { + #[cfg(feature = "semconv_experimental")] + SystemMemoryState::Used => "used", + #[cfg(feature = "semconv_experimental")] + SystemMemoryState::Free => "free", + #[cfg(feature = "semconv_experimental")] + SystemMemoryState::Shared => "shared", + #[cfg(feature = "semconv_experimental")] + SystemMemoryState::Buffers => "buffers", + #[cfg(feature = "semconv_experimental")] + SystemMemoryState::Cached => "cached", + SystemMemoryState::_Custom(v) => v.as_str(), + // 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 SystemMemoryState { + /// Formats the value using the given formatter. + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +impl crate::attributes::AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &SystemMemoryState) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} \ No newline at end of file diff --git a/crates/weaver_forge/tests/attributes/url.rs b/crates/weaver_forge/tests/attributes/url.rs new file mode 100644 index 00000000..82ab6cdc --- /dev/null +++ b/crates/weaver_forge/tests/attributes/url.rs @@ -0,0 +1,127 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Attributes describing URL. +//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER + +/// Domain extracted from the `url.full`, such as "opentelemetry.io". +/// +/// Notes: +/// In some cases a URL may refer to an IP and/or port directly, without a domain name. In this case, the IP address would go to the domain field. If the URL contains a [literal IPv6 address](https://www.rfc-editor.org/rfc/rfc2732#section-2) enclosed by `[` and `]`, the `[` and `]` characters should also be captured in the domain field. +/// +/// Examples: +/// - www.foo.bar +/// - opentelemetry.io +/// - 3.12.167.2 +/// - [1080:0:0:0:8:800:200C:417A] +#[cfg(feature = "semconv_experimental")] +pub const URL_DOMAIN: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.domain"); + +/// The file extension extracted from the `url.full`, excluding the leading dot. +/// +/// Notes: +/// The file extension is only set if it exists, as not every url has a file extension. When the file name has multiple extensions `example.tar.gz`, only the last one should be captured `gz`, not `tar.gz`. +/// +/// Examples: +/// - png +/// - gz +#[cfg(feature = "semconv_experimental")] +pub const URL_EXTENSION: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.extension"); + +/// The [URI fragment](https://www.rfc-editor.org/rfc/rfc3986#section-3.5) component +/// +/// Examples: +/// - SemConv +pub const URL_FRAGMENT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.fragment"); + +/// Absolute URL describing a network resource according to [RFC3986](https://www.rfc-editor.org/rfc/rfc3986) +/// +/// Notes: +/// For network calls, URL usually has `scheme://host[:port][path][?query][#fragment]` format, where the fragment is not transmitted over HTTP, but if it is known, it SHOULD be included nevertheless. +/// `url.full` MUST NOT contain credentials passed via URL in form of `https://username:password@www.example.com/`. In such case username and password SHOULD be redacted and attribute's value SHOULD be `https://REDACTED:REDACTED@www.example.com/`. +/// `url.full` SHOULD capture the absolute URL when it is available (or can be reconstructed). Sensitive content provided in `url.full` SHOULD be scrubbed when instrumentations can identify it. +/// +/// Examples: +/// - https://www.foo.bar/search?q=OpenTelemetry#SemConv +/// - //localhost +pub const URL_FULL: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.full"); + +/// Unmodified original URL as seen in the event source. +/// +/// Notes: +/// In network monitoring, the observed URL may be a full URL, whereas in access logs, the URL is often just represented as a path. This field is meant to represent the URL as it was observed, complete or not. +/// `url.original` might contain credentials passed via URL in form of `https://username:password@www.example.com/`. In such case password and username SHOULD NOT be redacted and attribute's value SHOULD remain the same. +/// +/// Examples: +/// - https://www.foo.bar/search?q=OpenTelemetry#SemConv +/// - search?q=OpenTelemetry +#[cfg(feature = "semconv_experimental")] +pub const URL_ORIGINAL: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.original"); + +/// The [URI path](https://www.rfc-editor.org/rfc/rfc3986#section-3.3) component +/// +/// Notes: +/// Sensitive content provided in `url.path` SHOULD be scrubbed when instrumentations can identify it. +/// +/// Examples: +/// - /search +pub const URL_PATH: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.path"); + +/// Port extracted from the `url.full` +/// +/// Examples: +/// - 443 +#[cfg(feature = "semconv_experimental")] +pub const URL_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.port"); + +/// The [URI query](https://www.rfc-editor.org/rfc/rfc3986#section-3.4) component +/// +/// Notes: +/// Sensitive content provided in `url.query` SHOULD be scrubbed when instrumentations can identify it. +/// +/// Examples: +/// - q=OpenTelemetry +pub const URL_QUERY: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.query"); + +/// The highest registered url domain, stripped of the subdomain. +/// +/// Notes: +/// This value can be determined precisely with the [public suffix list](http://publicsuffix.org). For example, the registered domain for `foo.example.com` is `example.com`. Trying to approximate this by simply taking the last two labels will not work well for TLDs such as `co.uk`. +/// +/// Examples: +/// - example.com +/// - foo.co.uk +#[cfg(feature = "semconv_experimental")] +pub const URL_REGISTERED_DOMAIN: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.registered_domain"); + +/// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. +/// +/// Examples: +/// - https +/// - ftp +/// - telnet +pub const URL_SCHEME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.scheme"); + +/// The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. +/// +/// Notes: +/// The subdomain portion of `www.east.mydomain.co.uk` is `east`. If the domain has multiple levels of subdomain, such as `sub2.sub1.example.com`, the subdomain field should contain `sub2.sub1`, with no trailing period. +/// +/// Examples: +/// - east +/// - sub2.sub1 +#[cfg(feature = "semconv_experimental")] +pub const URL_SUBDOMAIN: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.subdomain"); + +/// The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is `com`. +/// +/// Notes: +/// This value can be determined precisely with the [public suffix list](http://publicsuffix.org). +/// +/// Examples: +/// - com +/// - co.uk +#[cfg(feature = "semconv_experimental")] +pub const URL_TOP_LEVEL_DOMAIN: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.top_level_domain"); \ No newline at end of file diff --git a/crates/weaver_forge/tests/codegen.rs b/crates/weaver_forge/tests/codegen.rs new file mode 100644 index 00000000..4f4646b0 --- /dev/null +++ b/crates/weaver_forge/tests/codegen.rs @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: Apache-2.0 + +//! Tests for the codegen module + +use opentelemetry::global; +use opentelemetry::metrics::Histogram; + +use attributes::http::{HTTP_REQUEST_METHOD, HttpRequestMethod}; +use attributes::system::SystemCpuState; +use metrics::http::{create_http_client_request_duration, HttpClientActiveRequests, HttpClientActiveRequestsReqAttributes, HttpServerRequestDurationOptAttributes, HttpServerRequestDurationReqAttributes}; +use metrics::http::HttpServerRequestDuration; +use metrics::system::{SystemCpuTime, SystemCpuTimeOptAttributes, SystemCpuUtilization, SystemCpuUtilizationOptAttributes}; + +pub mod attributes; +pub mod metrics; + +#[test] +fn test_semconv_rust_codegen() { + // SemConv attributes are typed, so the compiler will catch type errors + // Experimental attributes are not visible if the `semconv_experimental` feature is not enabled + println!("{:?}", attributes::client::CLIENT_ADDRESS.value("145.34.23.56".into())); + println!("{:?}", attributes::client::CLIENT_ADDRESS.key()); + println!("{:?}", attributes::client::CLIENT_PORT.value(8080)); + println!("{:?}", attributes::client::CLIENT_PORT.key()); + + println!("{}", HttpRequestMethod::Connect); + + let meter = global::meter("mylibname"); + + // Create a u64 http.client.request.duration metric + let http_client_request_duration: Histogram = create_http_client_request_duration(&meter); + http_client_request_duration.record(100, &[ + HTTP_REQUEST_METHOD.value(&HttpRequestMethod::Connect), + // here nothing guarantees that all the required attributes are provided + ]); + + let http_client_request_duration: Histogram = create_http_client_request_duration(&meter); + dbg!(http_client_request_duration); + + // ==== A TYPE-SAFE HISTOGRAM API ==== + // Create a u64 http.server.request.duration metric (as defined in the OpenTelemetry HTTP + // semantic conventions) + let http_request_duration = HttpServerRequestDuration::::new(&meter); + + // Records a new data point and provide the required and some optional attributes + http_request_duration.record(100, &HttpServerRequestDurationReqAttributes { + http_request_method: HttpRequestMethod::Connect, + url_scheme: "http".to_owned(), + }, Some(&HttpServerRequestDurationOptAttributes { + http_response_status_code: Some(200), + ..Default::default() + })); + + // ==== A TYPE-SAFE UP-DOWN-COUNTER API ==== + // Create a f64 http.server.request.duration metric (as defined in the OpenTelemetry HTTP + // semantic conventions) + let http_client_active_requests = HttpClientActiveRequests::::new(&meter); + + // Adds a new data point and provide the required attributes. Optional attributes are not + // provided in this example. + http_client_active_requests.add(10.0, &HttpClientActiveRequestsReqAttributes { + server_address: "10.0.0.1".to_owned(), + server_port: 8080, + }, None); + + // ==== A TYPE-SAFE COUNTER API ==== + // Create a f64 system.cpu.time metric (as defined in the OpenTelemetry System semantic + // conventions) + let system_cpu_time = SystemCpuTime::::new(&meter); + + // Adds a new data point and provide some optional attributes. + // Note: In the method signature, there is no required attribute. + system_cpu_time.add(10.0, Some(&SystemCpuTimeOptAttributes { + system_cpu_logical_number: Some(0), + system_cpu_state: Some(SystemCpuState::Idle) + })); + // Adds a new data point with a custom CPU state. + system_cpu_time.add(20.0, Some(&SystemCpuTimeOptAttributes { + system_cpu_logical_number: Some(0), + system_cpu_state: Some(SystemCpuState::_Custom("custom".to_owned())) + })); + + // ==== A TYPE-SAFE GAUGE API ==== + // Create a i64 system.cpu.utilization metric (as defined in the OpenTelemetry System semantic + // conventions) + let system_cpu_utilization = SystemCpuUtilization::::new(&meter); + + // Adds a new data point with no optional attributes. + system_cpu_utilization.record(-5, None); + // Adds a new data point with some optional attributes. + system_cpu_utilization.record(10, Some(&SystemCpuUtilizationOptAttributes { + system_cpu_logical_number: Some(0), + system_cpu_state: Some(SystemCpuState::Idle) + })); +} \ No newline at end of file diff --git a/crates/weaver_forge/tests/lib.rs b/crates/weaver_forge/tests/lib.rs new file mode 100644 index 00000000..ae1281bf --- /dev/null +++ b/crates/weaver_forge/tests/lib.rs @@ -0,0 +1,10 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! OpenTelemetry Semantic Convention Attributes +//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 + +pub mod attributes; +pub mod metrics; diff --git a/crates/weaver_forge/tests/metrics/http.rs b/crates/weaver_forge/tests/metrics/http.rs new file mode 100644 index 00000000..47d02c8d --- /dev/null +++ b/crates/weaver_forge/tests/metrics/http.rs @@ -0,0 +1,486 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER + +/// Duration of HTTP server requests. +pub fn create_http_server_request_duration(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram + where opentelemetry::metrics::Meter: crate::metrics::HistogramProvider { + crate::metrics::HistogramProvider::create_histogram(meter, "http.server.request.duration", "Duration of HTTP server requests.", "s") +} + +/// Metric: http.server.request.duration +/// Brief: Duration of HTTP server requests. +/// Unit: s +#[derive(Debug)] +pub struct HttpServerRequestDuration(opentelemetry::metrics::Histogram); + + +/// Attributes for the `http.server.request.duration` metric. +#[derive(Debug, Clone)] +pub struct HttpServerRequestDurationReqAttributes { + + /// HTTP request method. + /// + /// Notes: + /// HTTP request method value SHOULD be "known" to the instrumentation. + /// By default, this convention defines "known" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods) + /// and the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html). + /// + /// If the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`. + /// + /// If the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override + /// the list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named + /// OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods + /// (this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults). + /// + /// 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. + /// + /// Examples: + /// - GET + /// - POST + /// - HEAD + pub http_request_method: crate::attributes::http::HttpRequestMethod, + + /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. + /// + /// Notes: + /// The scheme of the original client request, if known (e.g. from [Forwarded#proto](https://developer.mozilla.org/docs/Web/HTTP/Headers/Forwarded#proto), [X-Forwarded-Proto](https://developer.mozilla.org/docs/Web/HTTP/Headers/X-Forwarded-Proto), or a similar header). Otherwise, the scheme of the immediate peer request. + /// + /// Examples: + /// - http + /// - https + pub url_scheme: String, +} + + + +#[derive(Debug, Clone, Default)] +pub struct HttpServerRequestDurationOptAttributes { + + /// Describes a class of error the operation ended with. + /// + /// Notes: + /// If the request fails with an error before response status code was sent or received, + /// `error.type` SHOULD be set to exception type (its fully-qualified class name, if applicable) + /// or a component-specific low cardinality error identifier. + /// + /// If response status code was sent or received and status indicates an error according to [HTTP span status definition](/docs/http/http-spans.md), + /// `error.type` SHOULD be set to the status code number (represented as a string), an exception type (if thrown) or a component-specific error identifier. + /// + /// The `error.type` value SHOULD be predictable and SHOULD have low cardinality. + /// Instrumentations SHOULD document the list of errors they report. + /// + /// The cardinality of `error.type` within one instrumentation library SHOULD be low, but + /// telemetry consumers that aggregate data from multiple instrumentation libraries and applications + /// should be prepared for `error.type` to have high cardinality at query time, when no + /// additional filters are applied. + /// + /// If the request has completed successfully, instrumentations SHOULD NOT set `error.type`. + /// + /// Examples: + /// - timeout + /// - java.net.UnknownHostException + /// - server_certificate_invalid + /// - 500 + pub error_type: Option, + + /// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). + /// + /// Examples: + /// - 200 + pub http_response_status_code: Option, + + /// The matched route, that is, the path template in the format used by the respective server framework. + /// + /// 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. + /// + /// Examples: + /// - /users/:userID? + /// - {controller}/{action}/{id?} + pub http_route: Option, + + /// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. + /// + /// Notes: + /// The value SHOULD be normalized to lowercase. + /// + /// Examples: + /// - http + /// - spdy + pub network_protocol_name: Option, + + /// The actual version of the protocol used for network communication. + /// + /// Notes: + /// If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, this attribute SHOULD NOT be set. + /// + /// Examples: + /// - 1.0 + /// - 1.1 + /// - 2 + /// - 3 + pub network_protocol_version: Option, + + /// Name of the local HTTP server that received the request. + /// + /// Notes: + /// See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). + /// > **Warning** + /// > Since this attribute is based on HTTP headers, opting in to it may allow an attacker + /// > to trigger cardinality limits, degrading the usefulness of the metric. + /// + /// Examples: + /// - example.com + /// - 10.1.2.80 + /// - /tmp/my.sock + pub server_address: Option, + + /// Port of the local HTTP server that received the request. + /// + /// Notes: + /// See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). + /// > **Warning** + /// > Since this attribute is based on HTTP headers, opting in to it may allow an attacker + /// > to trigger cardinality limits, degrading the usefulness of the metric. + /// + /// Examples: + /// - 80 + /// - 8080 + /// - 443 + pub server_port: Option, +} + + +impl HttpServerRequestDuration { + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: crate::metrics::HistogramProvider{ + Self(crate::metrics::HistogramProvider::create_histogram(meter, "http.server.request.duration", "Duration of HTTP server requests.", "s")) + } + + /// Adds an additional value to the distribution. + pub fn record( + &self, + value: T, + required_attributes: &HttpServerRequestDurationReqAttributes, + optional_attributes: Option<&HttpServerRequestDurationOptAttributes>, + ) { + let mut attributes = vec![ + crate::attributes::http::HTTP_REQUEST_METHOD.value(&required_attributes.http_request_method), + crate::attributes::url::URL_SCHEME.value(required_attributes.url_scheme.to_string().into()), + ]; + + if let Some(value) = &optional_attributes { + if let Some(error_type) = &value.error_type { + attributes.push(crate::attributes::error::ERROR_TYPE.value(error_type)); + } + if let Some(http_response_status_code) = value.http_response_status_code { + attributes.push(crate::attributes::http::HTTP_RESPONSE_STATUS_CODE.value(http_response_status_code)); + } + if let Some(http_route) = &value.http_route { + attributes.push(crate::attributes::http::HTTP_ROUTE.value(http_route.to_string().into())); + } + if let Some(network_protocol_name) = &value.network_protocol_name { + attributes.push(crate::attributes::network::NETWORK_PROTOCOL_NAME.value(network_protocol_name.to_string().into())); + } + if let Some(network_protocol_version) = &value.network_protocol_version { + attributes.push(crate::attributes::network::NETWORK_PROTOCOL_VERSION.value(network_protocol_version.to_string().into())); + } + if let Some(server_address) = &value.server_address { + attributes.push(crate::attributes::server::SERVER_ADDRESS.value(server_address.to_string().into())); + } + if let Some(server_port) = value.server_port { + attributes.push(crate::attributes::server::SERVER_PORT.value(server_port)); + } + } + self.0.record(value, &attributes) + } +} + +/// Duration of HTTP client requests. +pub fn create_http_client_request_duration(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram + where opentelemetry::metrics::Meter: crate::metrics::HistogramProvider { + crate::metrics::HistogramProvider::create_histogram(meter, "http.client.request.duration", "Duration of HTTP client requests.", "s") +} + +/// Metric: http.client.request.duration +/// Brief: Duration of HTTP client requests. +/// Unit: s +#[derive(Debug)] +pub struct HttpClientRequestDuration(opentelemetry::metrics::Histogram); + + +/// Attributes for the `http.client.request.duration` metric. +#[derive(Debug, Clone)] +pub struct HttpClientRequestDurationReqAttributes { + + /// HTTP request method. + /// + /// Notes: + /// HTTP request method value SHOULD be "known" to the instrumentation. + /// By default, this convention defines "known" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods) + /// and the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html). + /// + /// If the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`. + /// + /// If the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override + /// the list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named + /// OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods + /// (this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults). + /// + /// 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. + /// + /// Examples: + /// - GET + /// - POST + /// - HEAD + pub http_request_method: crate::attributes::http::HttpRequestMethod, + + /// Host identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. + /// + /// Notes: + /// If an HTTP client request is explicitly made to an IP address, e.g. `http://x.x.x.x:8080`, then `server.address` SHOULD be the IP address `x.x.x.x`. A DNS lookup SHOULD NOT be used. + /// + /// Examples: + /// - example.com + /// - 10.1.2.80 + /// - /tmp/my.sock + pub server_address: String, + + /// Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. + /// + /// Notes: + /// When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent the server port behind any intermediaries, for example proxies, if it's available. + /// + /// Examples: + /// - 80 + /// - 8080 + /// - 443 + pub server_port: i64, +} + + + +#[derive(Debug, Clone, Default)] +pub struct HttpClientRequestDurationOptAttributes { + + /// Describes a class of error the operation ended with. + /// + /// Notes: + /// If the request fails with an error before response status code was sent or received, + /// `error.type` SHOULD be set to exception type (its fully-qualified class name, if applicable) + /// or a component-specific low cardinality error identifier. + /// + /// If response status code was sent or received and status indicates an error according to [HTTP span status definition](/docs/http/http-spans.md), + /// `error.type` SHOULD be set to the status code number (represented as a string), an exception type (if thrown) or a component-specific error identifier. + /// + /// The `error.type` value SHOULD be predictable and SHOULD have low cardinality. + /// Instrumentations SHOULD document the list of errors they report. + /// + /// The cardinality of `error.type` within one instrumentation library SHOULD be low, but + /// telemetry consumers that aggregate data from multiple instrumentation libraries and applications + /// should be prepared for `error.type` to have high cardinality at query time, when no + /// additional filters are applied. + /// + /// If the request has completed successfully, instrumentations SHOULD NOT set `error.type`. + /// + /// Examples: + /// - timeout + /// - java.net.UnknownHostException + /// - server_certificate_invalid + /// - 500 + pub error_type: Option, + + /// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). + /// + /// Examples: + /// - 200 + pub http_response_status_code: Option, + + /// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. + /// + /// Notes: + /// The value SHOULD be normalized to lowercase. + /// + /// Examples: + /// - http + /// - spdy + pub network_protocol_name: Option, + + /// The actual version of the protocol used for network communication. + /// + /// Notes: + /// If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, this attribute SHOULD NOT be set. + /// + /// Examples: + /// - 1.0 + /// - 1.1 + /// - 2 + /// - 3 + pub network_protocol_version: Option, + + /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. + /// + /// Examples: + /// - http + /// - https + pub url_scheme: Option, +} + + +impl HttpClientRequestDuration { + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: crate::metrics::HistogramProvider{ + Self(crate::metrics::HistogramProvider::create_histogram(meter, "http.client.request.duration", "Duration of HTTP client requests.", "s")) + } + + /// Adds an additional value to the distribution. + pub fn record( + &self, + value: T, + required_attributes: &HttpClientRequestDurationReqAttributes, + optional_attributes: Option<&HttpClientRequestDurationOptAttributes>, + ) { + let mut attributes = vec![ + crate::attributes::http::HTTP_REQUEST_METHOD.value(&required_attributes.http_request_method), + crate::attributes::server::SERVER_ADDRESS.value(required_attributes.server_address.to_string().into()), + crate::attributes::server::SERVER_PORT.value(required_attributes.server_port), + ]; + + if let Some(value) = &optional_attributes { + if let Some(error_type) = &value.error_type { + attributes.push(crate::attributes::error::ERROR_TYPE.value(error_type)); + } + if let Some(http_response_status_code) = value.http_response_status_code { + attributes.push(crate::attributes::http::HTTP_RESPONSE_STATUS_CODE.value(http_response_status_code)); + } + if let Some(network_protocol_name) = &value.network_protocol_name { + attributes.push(crate::attributes::network::NETWORK_PROTOCOL_NAME.value(network_protocol_name.to_string().into())); + } + if let Some(network_protocol_version) = &value.network_protocol_version { + attributes.push(crate::attributes::network::NETWORK_PROTOCOL_VERSION.value(network_protocol_version.to_string().into())); + } + if let Some(url_scheme) = &value.url_scheme { + attributes.push(crate::attributes::url::URL_SCHEME.value(url_scheme.to_string().into())); + } + } + self.0.record(value, &attributes) + } +} + +/// Number of active HTTP requests. +#[cfg(feature = "semconv_experimental")] +pub fn create_http_client_active_requests(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter + where opentelemetry::metrics::Meter: crate::metrics::UpDownCounterProvider { + crate::metrics::UpDownCounterProvider::create_up_down_counter(meter, "http.client.active_requests", "Number of active HTTP requests.", "{request}") +} + +/// Metric: http.client.active_requests +/// Brief: Number of active HTTP requests. +/// Unit: {request} +#[derive(Debug)] +pub struct HttpClientActiveRequests(opentelemetry::metrics::UpDownCounter); + + +/// Attributes for the `http.client.active_requests` metric. +#[derive(Debug, Clone)] +pub struct HttpClientActiveRequestsReqAttributes { + + /// Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. + /// + /// Notes: + /// When observed from the client side, and when communicating through an intermediary, `server.address` SHOULD represent the server address behind any intermediaries, for example proxies, if it's available. + /// + /// Examples: + /// - example.com + /// - 10.1.2.80 + /// - /tmp/my.sock + pub server_address: String, + + /// Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. + /// + /// Notes: + /// When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent the server port behind any intermediaries, for example proxies, if it's available. + /// + /// Examples: + /// - 80 + /// - 8080 + /// - 443 + pub server_port: i64, +} + + + +#[derive(Debug, Clone, Default)] +pub struct HttpClientActiveRequestsOptAttributes { + + /// HTTP request method. + /// + /// Notes: + /// HTTP request method value SHOULD be "known" to the instrumentation. + /// By default, this convention defines "known" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods) + /// and the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html). + /// + /// If the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`. + /// + /// If the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override + /// the list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named + /// OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods + /// (this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults). + /// + /// 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. + /// + /// Examples: + /// - GET + /// - POST + /// - HEAD + pub http_request_method: Option, + + /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. + /// + /// Examples: + /// - http + /// - https + pub url_scheme: Option, +} + + +impl HttpClientActiveRequests { + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: crate::metrics::UpDownCounterProvider{ + Self(crate::metrics::UpDownCounterProvider::create_up_down_counter(meter, "http.client.active_requests", "Number of active HTTP requests.", "{request}")) + } + + /// Adds an additional value to the up-down-counter. + pub fn add( + &self, + value: T, + required_attributes: &HttpClientActiveRequestsReqAttributes, + optional_attributes: Option<&HttpClientActiveRequestsOptAttributes>, + ) { + let mut attributes = vec![ + crate::attributes::server::SERVER_ADDRESS.value(required_attributes.server_address.to_string().into()), + crate::attributes::server::SERVER_PORT.value(required_attributes.server_port), + ]; + + if let Some(value) = &optional_attributes { + if let Some(http_request_method) = &value.http_request_method { + attributes.push(crate::attributes::http::HTTP_REQUEST_METHOD.value(http_request_method)); + } + if let Some(url_scheme) = &value.url_scheme { + attributes.push(crate::attributes::url::URL_SCHEME.value(url_scheme.to_string().into())); + } + } + self.0.add(value, &attributes) + } +} \ No newline at end of file diff --git a/crates/weaver_forge/tests/metrics/mod.rs b/crates/weaver_forge/tests/metrics/mod.rs new file mode 100644 index 00000000..4da6cbcd --- /dev/null +++ b/crates/weaver_forge/tests/metrics/mod.rs @@ -0,0 +1,136 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! OpenTelemetry Semantic Convention Metrics +//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER + + +/// Metrics for the `http` namespace. +pub mod http; +/// Metrics for the `system` namespace. +pub mod system; + +/// A trait implemented by histogram providers (e.g. `Meter`). +pub trait HistogramProvider { + /// Creates a new histogram with the given name, description, and unit. + fn create_histogram(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Histogram; +} + +/// This implementation specifies that a Meter is able to create u64 histograms. +impl HistogramProvider for opentelemetry::metrics::Meter { + /// Creates a new u64 histogram with the given name, description, and unit. + fn create_histogram(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Histogram { + self.u64_histogram(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// This implementation specifies that a Meter is able to create u64 histograms. +impl HistogramProvider for opentelemetry::metrics::Meter { + /// Creates a new f64 histogram with the given name, description, and unit. + fn create_histogram(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Histogram { + self.f64_histogram(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// A trait implemented by up-down-counter providers (e.g. `Meter`). +pub trait UpDownCounterProvider { + /// Creates a new up-down-counter with the given name, description, and unit. + fn create_up_down_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::UpDownCounter; +} + +/// This implementation specifies that a Meter is able to create i64 up-down-counters. +impl UpDownCounterProvider for opentelemetry::metrics::Meter { + /// Creates a new i64 up-down-counter with the given name, description, and unit. + fn create_up_down_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::UpDownCounter { + self.i64_up_down_counter(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// This implementation specifies that a Meter is able to create f64 up-down-counters. +impl UpDownCounterProvider for opentelemetry::metrics::Meter { + /// Creates a new f64 up-down-counter with the given name, description, and unit. + fn create_up_down_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::UpDownCounter { + self.f64_up_down_counter(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// A trait implemented by counter providers (e.g. `Meter`). +pub trait CounterProvider { + /// Creates a new counter with the given name, description, and unit. + fn create_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Counter; +} + +/// This implementation specifies that a Meter is able to create u64 counters. +impl CounterProvider for opentelemetry::metrics::Meter { + /// Creates a new u64 counter with the given name, description, and unit. + fn create_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Counter { + self.u64_counter(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// This implementation specifies that a Meter is able to create f64 counters. +impl CounterProvider for opentelemetry::metrics::Meter { + /// Creates a new f64 counter with the given name, description, and unit. + fn create_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Counter { + self.f64_counter(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// A trait implemented by gauge providers (e.g. `Meter`). +pub trait GaugeProvider { + /// Creates a new gauge with the given name, description, and unit. + fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge; +} + +/// This implementation specifies that a Meter is able to create u64 gauges. +impl GaugeProvider for opentelemetry::metrics::Meter { + /// Creates a new u64 gauge with the given name, description, and unit. + fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge { + self.u64_gauge(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// This implementation specifies that a Meter is able to create i64 gauges. +impl GaugeProvider for opentelemetry::metrics::Meter { + /// Creates a new i64 gauge with the given name, description, and unit. + fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge { + self.i64_gauge(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// This implementation specifies that a Meter is able to create f64 gauges. +impl GaugeProvider for opentelemetry::metrics::Meter { + /// Creates a new f64 gauge with the given name, description, and unit. + fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge { + self.f64_gauge(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} \ No newline at end of file diff --git a/crates/weaver_forge/tests/metrics/system.rs b/crates/weaver_forge/tests/metrics/system.rs new file mode 100644 index 00000000..e2750731 --- /dev/null +++ b/crates/weaver_forge/tests/metrics/system.rs @@ -0,0 +1,181 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER + +/// Seconds each logical CPU spent on each mode +#[cfg(feature = "semconv_experimental")] +pub fn create_system_cpu_time(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Counter + where opentelemetry::metrics::Meter: crate::metrics::CounterProvider { + crate::metrics::CounterProvider::create_counter(meter, "system.cpu.time", "Seconds each logical CPU spent on each mode", "s") +} + +/// Metric: system.cpu.time +/// Brief: Seconds each logical CPU spent on each mode +/// Unit: s +#[derive(Debug)] +pub struct SystemCpuTime(opentelemetry::metrics::Counter); + + + + +#[derive(Debug, Clone, Default)] +pub struct SystemCpuTimeOptAttributes { + + /// The logical CPU number [0..n-1] + /// + /// Examples: + /// - 1 + pub system_cpu_logical_number: Option, + + /// The CPU state for this data point. A system's CPU SHOULD be characterized *either* by data points with no `state` labels, *or only* data points with `state` labels. + /// + /// Examples: + /// - idle + /// - interrupt + pub system_cpu_state: Option, +} + + +impl SystemCpuTime { + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: crate::metrics::CounterProvider{ + Self(crate::metrics::CounterProvider::create_counter(meter, "system.cpu.time", "Seconds each logical CPU spent on each mode", "s")) + } + + /// Adds an additional value to the counter. + pub fn add( + &self, + value: T, + + optional_attributes: Option<&SystemCpuTimeOptAttributes>, + ) { + let mut attributes = vec![ + ]; + + if let Some(value) = &optional_attributes { + if let Some(system_cpu_logical_number) = value.system_cpu_logical_number { + attributes.push(crate::attributes::system::SYSTEM_CPU_LOGICAL_NUMBER.value(system_cpu_logical_number)); + } + if let Some(system_cpu_state) = &value.system_cpu_state { + attributes.push(crate::attributes::system::SYSTEM_CPU_STATE.value(system_cpu_state)); + } + } + self.0.add(value, &attributes) + } +} + +/// Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs +pub fn create_system_cpu_utilization(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Gauge + where opentelemetry::metrics::Meter: crate::metrics::GaugeProvider { + crate::metrics::GaugeProvider::create_gauge(meter, "system.cpu.utilization", "Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs", "1") +} + +/// Metric: system.cpu.utilization +/// Brief: Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs +/// Unit: 1 +#[derive(Debug)] +pub struct SystemCpuUtilization(opentelemetry::metrics::Gauge); + + + + +#[derive(Debug, Clone, Default)] +pub struct SystemCpuUtilizationOptAttributes { + + /// The logical CPU number [0..n-1] + /// + /// Examples: + /// - 1 + pub system_cpu_logical_number: Option, + + /// The CPU state for this data point. A system's CPU SHOULD be characterized *either* by data points with no `state` labels, *or only* data points with `state` labels. + /// + /// Examples: + /// - idle + /// - interrupt + pub system_cpu_state: Option, +} + + +impl SystemCpuUtilization { + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: crate::metrics::GaugeProvider{ + Self(crate::metrics::GaugeProvider::create_gauge(meter, "system.cpu.utilization", "Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs", "1")) + } + + /// Records an additional value to the gauge. + pub fn record( + &self, + value: T, + + optional_attributes: Option<&SystemCpuUtilizationOptAttributes>, + ) { + let mut attributes = vec![ + ]; + + if let Some(value) = &optional_attributes { + if let Some(system_cpu_logical_number) = value.system_cpu_logical_number { + attributes.push(crate::attributes::system::SYSTEM_CPU_LOGICAL_NUMBER.value(system_cpu_logical_number)); + } + if let Some(system_cpu_state) = &value.system_cpu_state { + attributes.push(crate::attributes::system::SYSTEM_CPU_STATE.value(system_cpu_state)); + } + } + self.0.record(value, &attributes) + } +} + +/// Reports memory in use by state. +pub fn create_system_memory_usage(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter + where opentelemetry::metrics::Meter: crate::metrics::UpDownCounterProvider { + crate::metrics::UpDownCounterProvider::create_up_down_counter(meter, "system.memory.usage", "Reports memory in use by state.", "By") +} + +/// Metric: system.memory.usage +/// Brief: Reports memory in use by state. +/// Unit: By +#[derive(Debug)] +pub struct SystemMemoryUsage(opentelemetry::metrics::UpDownCounter); + + + + +#[derive(Debug, Clone, Default)] +pub struct SystemMemoryUsageOptAttributes { + + /// The memory state + /// + /// Examples: + /// - free + /// - cached + pub system_memory_state: Option, +} + + +impl SystemMemoryUsage { + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: crate::metrics::UpDownCounterProvider{ + Self(crate::metrics::UpDownCounterProvider::create_up_down_counter(meter, "system.memory.usage", "Reports memory in use by state.", "By")) + } + + /// Adds an additional value to the up-down-counter. + pub fn add( + &self, + value: T, + + optional_attributes: Option<&SystemMemoryUsageOptAttributes>, + ) { + let mut attributes = vec![ + ]; + + if let Some(value) = &optional_attributes { + if let Some(system_memory_state) = &value.system_memory_state { + attributes.push(crate::attributes::system::SYSTEM_MEMORY_STATE.value(system_memory_state)); + } + } + self.0.add(value, &attributes) + } +} \ No newline at end of file From da441c31176bf5f0567d0178d7ef291c7c18f922 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Sun, 5 May 2024 10:04:35 -0700 Subject: [PATCH 28/39] chore(forge): Remove build.rs --- crates/weaver_forge/build.rs | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 crates/weaver_forge/build.rs diff --git a/crates/weaver_forge/build.rs b/crates/weaver_forge/build.rs deleted file mode 100644 index 1b223315..00000000 --- a/crates/weaver_forge/build.rs +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -//! - -use std::env; - -fn main() { - env::vars().for_each(|(key, value)| { - println!("cargo:warning={}: {}", key, value); - }); - env::args().for_each(|arg| { - println!("cargo:warning=ARGS->{}", arg); - }); - env::args_os().for_each(|arg| { - println!("cargo:warning=AGS_OS->{:?}", arg); - }); - _ = env::current_dir().ok().map(|path| { - println!("cargo:warning=Current dir: {:?}", path); - }); - _ = env::current_exe().ok().map(|path| { - println!("cargo:warning=EXE->{}", path.display()); - }); - - let out_dir = env::var("OUT_DIR").unwrap(); - println!("cargo:warning={}", out_dir); -} \ No newline at end of file From c006d177321a668fc9534574f103549c47867469 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Mon, 6 May 2024 10:42:26 -0700 Subject: [PATCH 29/39] chore(forge): Move to not_required filter --- .../codegen_examples/templates/registry/rust/README.md | 10 +++++----- .../templates/registry/rust/attribute_macros.j2 | 6 +++--- .../templates/registry/rust/metrics/counter.j2 | 10 +++++----- .../templates/registry/rust/metrics/gauge.j2 | 10 +++++----- .../templates/registry/rust/metrics/histogram.j2 | 10 +++++----- .../templates/registry/rust/metrics/updowncounter.j2 | 10 +++++----- crates/weaver_forge/tests/README.md | 10 +++++----- 7 files changed, 33 insertions(+), 33 deletions(-) diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/README.md b/crates/weaver_forge/codegen_examples/templates/registry/rust/README.md index 5ee01b69..c4ce1f7f 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/README.md +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/README.md @@ -46,7 +46,7 @@ async fn main() -> Result<(), Box> { // semantic conventions) let http_request_duration = HttpServerRequestDuration::::new(&meter); - // Records a new data point and provide the required and some optional attributes + // Records a new data point and provide the required and some not required attributes http_request_duration.record(100, &HttpServerRequestDurationReqAttributes { http_request_method: HttpRequestMethod::Connect, url_scheme: "http".to_owned(), @@ -60,7 +60,7 @@ async fn main() -> Result<(), Box> { // semantic conventions) let http_client_active_requests = HttpClientActiveRequests::::new(&meter); - // Adds a new data point and provide the required attributes. Optional attributes are not + // Adds a new data point and provide the required attributes. Not required attributes are not // provided in this example. http_client_active_requests.add(10.0, &HttpClientActiveRequestsReqAttributes { server_address: "10.0.0.1".to_owned(), @@ -72,7 +72,7 @@ async fn main() -> Result<(), Box> { // conventions) let system_cpu_time = SystemCpuTime::::new(&meter); - // Adds a new data point and provide some optional attributes. + // Adds a new data point and provide some not required attributes. // Note: In the method signature, there is no required attribute. system_cpu_time.add(10.0, Some(&SystemCpuTimeOptAttributes { system_cpu_logical_number: Some(0), @@ -89,9 +89,9 @@ async fn main() -> Result<(), Box> { // conventions) let system_cpu_utilization = SystemCpuUtilization::::new(&meter); - // Adds a new data point with no optional attributes. + // Adds a new data point with no not required attributes. system_cpu_utilization.record(-5, None); - // Adds a new data point with some optional attributes. + // Adds a new data point with some not required attributes. system_cpu_utilization.record(10, Some(&SystemCpuUtilizationOptAttributes { system_cpu_logical_number: Some(0), system_cpu_state: Some(SystemCpuState::Idle) diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/attribute_macros.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/attribute_macros.j2 index c71281e6..d132ec32 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/attribute_macros.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/attribute_macros.j2 @@ -21,7 +21,7 @@ {%- endif %} {%- endmacro %} -{%- macro attributes_to_key_values(required_attributes, optional_attributes) -%} +{%- macro attributes_to_key_values(required_attributes, not_required_attributes) -%} let mut attributes = vec![ {%- for attribute in required_attributes | attribute_sort %} {%- if attribute is experimental %} @@ -37,8 +37,8 @@ {%- endfor %} ]; - if let Some(value) = &optional_attributes { - {%- for attribute in optional_attributes | attribute_sort %} + if let Some(value) = ¬_required_attributes { + {%- for attribute in not_required_attributes | attribute_sort %} {%- if attribute is experimental %} #[cfg(feature = "semconv_experimental")] {%- endif %} diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/counter.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/counter.j2 index beb24e57..7ab88889 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/counter.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/counter.j2 @@ -17,7 +17,7 @@ pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::me pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::Counter); {%- set required_attributes = metric.attributes | required %} -{%- set optional_attributes = metric.attributes | optional %} +{%- set not_required_attributes = metric.attributes | not_required %} {% if required_attributes %} /// Attributes for the `{{ metric.metric_name }}` metric. @@ -34,10 +34,10 @@ pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { } {% endif %} -{% if optional_attributes %} +{% if not_required_attributes %} #[derive(Debug, Clone, Default)] pub struct {{ metric.metric_name | pascal_case }}OptAttributes { - {%- for attribute in optional_attributes | attribute_sort %} + {%- for attribute in not_required_attributes | attribute_sort %} {{ attribute_macros.comments(attribute, " ///") }} {%- if attribute.type.members is defined %} pub {{ attribute.name | snake_case }}: Option, @@ -59,9 +59,9 @@ impl {{ metric.metric_name | pascal_case }} { &self, value: T, {% if required_attributes %}required_attributes: &{{ metric.metric_name | pascal_case }}ReqAttributes,{% endif %} - {% if optional_attributes %}optional_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} + {% if not_required_attributes %}not_required_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} ) { - {{ attribute_macros.attributes_to_key_values(required_attributes, optional_attributes) }} + {{ attribute_macros.attributes_to_key_values(required_attributes, not_required_attributes) }} self.0.add(value, &attributes) } } \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/gauge.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/gauge.j2 index f7cc057f..a2730662 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/gauge.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/gauge.j2 @@ -17,7 +17,7 @@ pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::me pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::Gauge); {%- set required_attributes = metric.attributes | required %} -{%- set optional_attributes = metric.attributes | optional %} +{%- set not_required_attributes = metric.attributes | not_required %} {% if required_attributes %} /// Attributes for the `{{ metric.metric_name }}` metric. @@ -34,10 +34,10 @@ pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { } {% endif %} -{% if optional_attributes %} +{% if not_required_attributes %} #[derive(Debug, Clone, Default)] pub struct {{ metric.metric_name | pascal_case }}OptAttributes { - {%- for attribute in optional_attributes | attribute_sort %} + {%- for attribute in not_required_attributes | attribute_sort %} {{ attribute_macros.comments(attribute, " ///") }} {%- if attribute.type.members is defined %} pub {{ attribute.name | snake_case }}: Option, @@ -59,9 +59,9 @@ impl {{ metric.metric_name | pascal_case }} { &self, value: T, {% if required_attributes %}required_attributes: &{{ metric.metric_name | pascal_case }}ReqAttributes,{% endif %} - {% if optional_attributes %}optional_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} + {% if not_required_attributes %}not_required_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} ) { - {{ attribute_macros.attributes_to_key_values(required_attributes, optional_attributes) }} + {{ attribute_macros.attributes_to_key_values(required_attributes, not_required_attributes) }} self.0.record(value, &attributes) } } \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 index e09fc5cb..fd662ae5 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 @@ -17,7 +17,7 @@ pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::me pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::Histogram); {%- set required_attributes = metric.attributes | required %} -{%- set optional_attributes = metric.attributes | optional %} +{%- set not_required_attributes = metric.attributes | not_required %} {% if required_attributes %} /// Attributes for the `{{ metric.metric_name }}` metric. @@ -34,10 +34,10 @@ pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { } {% endif %} -{% if optional_attributes %} +{% if not_required_attributes %} #[derive(Debug, Clone, Default)] pub struct {{ metric.metric_name | pascal_case }}OptAttributes { - {%- for attribute in optional_attributes | attribute_sort %} + {%- for attribute in not_required_attributes | attribute_sort %} {{ attribute_macros.comments(attribute, " ///") }} {%- if attribute.type.members is defined %} pub {{ attribute.name | snake_case }}: Option, @@ -59,9 +59,9 @@ impl {{ metric.metric_name | pascal_case }} { &self, value: T, {% if required_attributes %}required_attributes: &{{ metric.metric_name | pascal_case }}ReqAttributes,{% endif %} - {% if optional_attributes %}optional_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} + {% if not_required_attributes %}not_required_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} ) { - {{ attribute_macros.attributes_to_key_values(required_attributes, optional_attributes) }} + {{ attribute_macros.attributes_to_key_values(required_attributes, not_required_attributes) }} self.0.record(value, &attributes) } } \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/updowncounter.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/updowncounter.j2 index 23ec9e4e..d046e1f5 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/updowncounter.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/updowncounter.j2 @@ -17,7 +17,7 @@ pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::me pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::UpDownCounter); {%- set required_attributes = metric.attributes | required %} -{%- set optional_attributes = metric.attributes | optional %} +{%- set not_required_attributes = metric.attributes | not_required %} {% if required_attributes %} /// Attributes for the `{{ metric.metric_name }}` metric. @@ -34,10 +34,10 @@ pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { } {% endif %} -{% if optional_attributes %} +{% if not_required_attributes %} #[derive(Debug, Clone, Default)] pub struct {{ metric.metric_name | pascal_case }}OptAttributes { - {%- for attribute in optional_attributes | attribute_sort %} + {%- for attribute in not_required_attributes | attribute_sort %} {{ attribute_macros.comments(attribute, " ///") }} {%- if attribute.type.members is defined %} pub {{ attribute.name | snake_case }}: Option, @@ -59,9 +59,9 @@ impl {{ metric.metric_name | pascal_case }} { &self, value: T, {% if required_attributes %}required_attributes: &{{ metric.metric_name | pascal_case }}ReqAttributes,{% endif %} - {% if optional_attributes %}optional_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} + {% if not_required_attributes %}not_required_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} ) { - {{ attribute_macros.attributes_to_key_values(required_attributes, optional_attributes) }} + {{ attribute_macros.attributes_to_key_values(required_attributes, not_required_attributes) }} self.0.add(value, &attributes) } } \ No newline at end of file diff --git a/crates/weaver_forge/tests/README.md b/crates/weaver_forge/tests/README.md index 5ee01b69..c4ce1f7f 100644 --- a/crates/weaver_forge/tests/README.md +++ b/crates/weaver_forge/tests/README.md @@ -46,7 +46,7 @@ async fn main() -> Result<(), Box> { // semantic conventions) let http_request_duration = HttpServerRequestDuration::::new(&meter); - // Records a new data point and provide the required and some optional attributes + // Records a new data point and provide the required and some not required attributes http_request_duration.record(100, &HttpServerRequestDurationReqAttributes { http_request_method: HttpRequestMethod::Connect, url_scheme: "http".to_owned(), @@ -60,7 +60,7 @@ async fn main() -> Result<(), Box> { // semantic conventions) let http_client_active_requests = HttpClientActiveRequests::::new(&meter); - // Adds a new data point and provide the required attributes. Optional attributes are not + // Adds a new data point and provide the required attributes. Not required attributes are not // provided in this example. http_client_active_requests.add(10.0, &HttpClientActiveRequestsReqAttributes { server_address: "10.0.0.1".to_owned(), @@ -72,7 +72,7 @@ async fn main() -> Result<(), Box> { // conventions) let system_cpu_time = SystemCpuTime::::new(&meter); - // Adds a new data point and provide some optional attributes. + // Adds a new data point and provide some not required attributes. // Note: In the method signature, there is no required attribute. system_cpu_time.add(10.0, Some(&SystemCpuTimeOptAttributes { system_cpu_logical_number: Some(0), @@ -89,9 +89,9 @@ async fn main() -> Result<(), Box> { // conventions) let system_cpu_utilization = SystemCpuUtilization::::new(&meter); - // Adds a new data point with no optional attributes. + // Adds a new data point with no not required attributes. system_cpu_utilization.record(-5, None); - // Adds a new data point with some optional attributes. + // Adds a new data point with some not required attributes. system_cpu_utilization.record(10, Some(&SystemCpuUtilizationOptAttributes { system_cpu_logical_number: Some(0), system_cpu_state: Some(SystemCpuState::Idle) From 97ee4a3eb17aedcd8d0a973601bd1ec2e0227b95 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Mon, 6 May 2024 11:25:35 -0700 Subject: [PATCH 30/39] chore(forge): Improve error messages --- .../rust/metrics/{ => instruments}/counter.j2 | 0 .../rust/metrics/{ => instruments}/gauge.j2 | 0 .../metrics/{ => instruments}/histogram.j2 | 0 .../{ => instruments}/updowncounter.j2 | 0 .../registry/rust/metrics/metrics.rs.j2 | 2 +- crates/weaver_forge/src/debug.rs | 28 ++++++++++++++++--- crates/weaver_forge/tests/metrics/http.rs | 12 ++++---- crates/weaver_forge/tests/metrics/system.rs | 12 ++++---- 8 files changed, 37 insertions(+), 17 deletions(-) rename crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/{ => instruments}/counter.j2 (100%) rename crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/{ => instruments}/gauge.j2 (100%) rename crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/{ => instruments}/histogram.j2 (100%) rename crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/{ => instruments}/updowncounter.j2 (100%) diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/counter.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/counter.j2 similarity index 100% rename from crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/counter.j2 rename to crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/counter.j2 diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/gauge.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/gauge.j2 similarity index 100% rename from crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/gauge.j2 rename to crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/gauge.j2 diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/histogram.j2 similarity index 100% rename from crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/histogram.j2 rename to crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/histogram.j2 diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/updowncounter.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/updowncounter.j2 similarity index 100% rename from crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/updowncounter.j2 rename to crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/updowncounter.j2 diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 index 1ad2c471..0b23820a 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 @@ -9,5 +9,5 @@ //! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER {%- for metric in ctx.groups %} -{% include "metrics/" ~ metric.instrument ~ ".j2" %} +{% include "metrics/instruments/" ~ metric.instrument ~ ".j2" %} {%- endfor %} \ No newline at end of file diff --git a/crates/weaver_forge/src/debug.rs b/crates/weaver_forge/src/debug.rs index ae3fc590..989251b8 100644 --- a/crates/weaver_forge/src/debug.rs +++ b/crates/weaver_forge/src/debug.rs @@ -2,14 +2,34 @@ //! Utility functions to help with debugging. -use crate::error::Error; +use std::error::Error; use crate::error::Error::{CompoundError, TemplateEvaluationFailed}; use indexmap::IndexMap; use weaver_common::Logger; -/// Return a nice summary of the error. +/// Return a nice summary of the error including the chain of causes. +/// Only the last error in the chain is displayed with a full stack trace. pub(crate) fn error_summary(error: minijinja::Error) -> String { - format!("{:#}", error) + let mut errors = Vec::new(); + let mut curr_error: &dyn Error = &error; + + errors.push(curr_error); + + while let Some(e) = curr_error.source() { + errors.push(e); + curr_error = e; + } + + let mut error_msg = String::new(); + for (i, e) in errors.iter().enumerate() { + if i == errors.len() - 1 { + // Display the last error with all the referenced variables + error_msg.push_str(&format!("{:#}\n", e)); + } else { + error_msg.push_str(&format!("{}\nCaused by:\n", e)); + } + } + error_msg } /// Print deduplicated errors. @@ -26,7 +46,7 @@ pub(crate) fn error_summary(error: minijinja::Error) -> String { /// /// * `logger` - The logger to use for logging. /// * `error` - The error to print. -pub fn print_dedup_errors(logger: impl Logger + Sync + Clone, error: Error) { +pub fn print_dedup_errors(logger: impl Logger + Sync + Clone, error: crate::error::Error) { struct DedupError { pub error: String, pub occurrences: usize, diff --git a/crates/weaver_forge/tests/metrics/http.rs b/crates/weaver_forge/tests/metrics/http.rs index 47d02c8d..8f4c1c10 100644 --- a/crates/weaver_forge/tests/metrics/http.rs +++ b/crates/weaver_forge/tests/metrics/http.rs @@ -169,14 +169,14 @@ impl HttpServerRequestDuration { &self, value: T, required_attributes: &HttpServerRequestDurationReqAttributes, - optional_attributes: Option<&HttpServerRequestDurationOptAttributes>, + not_required_attributes: Option<&HttpServerRequestDurationOptAttributes>, ) { let mut attributes = vec![ crate::attributes::http::HTTP_REQUEST_METHOD.value(&required_attributes.http_request_method), crate::attributes::url::URL_SCHEME.value(required_attributes.url_scheme.to_string().into()), ]; - if let Some(value) = &optional_attributes { + if let Some(value) = ¬_required_attributes { if let Some(error_type) = &value.error_type { attributes.push(crate::attributes::error::ERROR_TYPE.value(error_type)); } @@ -347,7 +347,7 @@ impl HttpClientRequestDuration { &self, value: T, required_attributes: &HttpClientRequestDurationReqAttributes, - optional_attributes: Option<&HttpClientRequestDurationOptAttributes>, + not_required_attributes: Option<&HttpClientRequestDurationOptAttributes>, ) { let mut attributes = vec![ crate::attributes::http::HTTP_REQUEST_METHOD.value(&required_attributes.http_request_method), @@ -355,7 +355,7 @@ impl HttpClientRequestDuration { crate::attributes::server::SERVER_PORT.value(required_attributes.server_port), ]; - if let Some(value) = &optional_attributes { + if let Some(value) = ¬_required_attributes { if let Some(error_type) = &value.error_type { attributes.push(crate::attributes::error::ERROR_TYPE.value(error_type)); } @@ -466,14 +466,14 @@ impl HttpClientActiveRequests { &self, value: T, required_attributes: &HttpClientActiveRequestsReqAttributes, - optional_attributes: Option<&HttpClientActiveRequestsOptAttributes>, + not_required_attributes: Option<&HttpClientActiveRequestsOptAttributes>, ) { let mut attributes = vec![ crate::attributes::server::SERVER_ADDRESS.value(required_attributes.server_address.to_string().into()), crate::attributes::server::SERVER_PORT.value(required_attributes.server_port), ]; - if let Some(value) = &optional_attributes { + if let Some(value) = ¬_required_attributes { if let Some(http_request_method) = &value.http_request_method { attributes.push(crate::attributes::http::HTTP_REQUEST_METHOD.value(http_request_method)); } diff --git a/crates/weaver_forge/tests/metrics/system.rs b/crates/weaver_forge/tests/metrics/system.rs index e2750731..fe89695a 100644 --- a/crates/weaver_forge/tests/metrics/system.rs +++ b/crates/weaver_forge/tests/metrics/system.rs @@ -50,12 +50,12 @@ impl SystemCpuTime { &self, value: T, - optional_attributes: Option<&SystemCpuTimeOptAttributes>, + not_required_attributes: Option<&SystemCpuTimeOptAttributes>, ) { let mut attributes = vec![ ]; - if let Some(value) = &optional_attributes { + if let Some(value) = ¬_required_attributes { if let Some(system_cpu_logical_number) = value.system_cpu_logical_number { attributes.push(crate::attributes::system::SYSTEM_CPU_LOGICAL_NUMBER.value(system_cpu_logical_number)); } @@ -111,12 +111,12 @@ impl SystemCpuUtilization { &self, value: T, - optional_attributes: Option<&SystemCpuUtilizationOptAttributes>, + not_required_attributes: Option<&SystemCpuUtilizationOptAttributes>, ) { let mut attributes = vec![ ]; - if let Some(value) = &optional_attributes { + if let Some(value) = ¬_required_attributes { if let Some(system_cpu_logical_number) = value.system_cpu_logical_number { attributes.push(crate::attributes::system::SYSTEM_CPU_LOGICAL_NUMBER.value(system_cpu_logical_number)); } @@ -166,12 +166,12 @@ impl SystemMemoryUsage { &self, value: T, - optional_attributes: Option<&SystemMemoryUsageOptAttributes>, + not_required_attributes: Option<&SystemMemoryUsageOptAttributes>, ) { let mut attributes = vec![ ]; - if let Some(value) = &optional_attributes { + if let Some(value) = ¬_required_attributes { if let Some(system_memory_state) = &value.system_memory_state { attributes.push(crate::attributes::system::SYSTEM_MEMORY_STATE.value(system_memory_state)); } From 9045e057743640237eb96289f58833aa715a2175 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Mon, 6 May 2024 17:11:06 -0700 Subject: [PATCH 31/39] chore(forge): Create code generation test infrastructure --- Cargo.lock | 15 + crates/weaver_codegen_test/Cargo.toml | 29 ++ crates/weaver_codegen_test/README.md | 227 +++++++++++ .../allowed-external-types.toml | 6 + crates/weaver_codegen_test/build.rs | 108 +++++ .../semconv_registry/http-common.yaml | 87 ++++ .../semconv_registry/metrics/http.yaml | 62 +++ .../metrics/system-metrics.yaml | 38 ++ .../semconv_registry/registry/client.yaml | 28 ++ .../registry/deprecated/network.yaml | 121 ++++++ .../semconv_registry/registry/error.yaml | 40 ++ .../semconv_registry/registry/exception.yaml | 54 +++ .../semconv_registry/registry/http.yaml | 174 ++++++++ .../semconv_registry/registry/network.yaml | 235 +++++++++++ .../semconv_registry/registry/server.yaml | 28 ++ .../semconv_registry/registry/system.yaml | 65 +++ .../semconv_registry/registry/url.yaml | 116 ++++++ crates/weaver_codegen_test/src/main.rs | 7 + .../templates/registry/rust/README.md | 382 ++++++++++++++++++ .../registry/rust/attribute_macros.j2 | 60 +++ .../registry/rust/attributes/attributes.rs.j2 | 83 ++++ .../registry/rust/attributes/mod.rs.j2 | 65 +++ .../templates/registry/rust/lib.rs | 13 + .../rust/metrics/instruments/counter.j2 | 69 ++++ .../rust/metrics/instruments/gauge.j2 | 69 ++++ .../rust/metrics/instruments/histogram.j2 | 69 ++++ .../rust/metrics/instruments/updowncounter.j2 | 70 ++++ .../registry/rust/metrics/metrics.rs.j2 | 13 + .../templates/registry/rust/metrics/mod.rs.j2 | 137 +++++++ .../templates/registry/rust/weaver.yaml | 156 +++++++ crates/weaver_codegen_test/tests/codegen.rs | 140 +++++++ crates/weaver_common/src/in_memory.rs | 129 ++++++ crates/weaver_common/src/lib.rs | 1 + 33 files changed, 2896 insertions(+) create mode 100644 crates/weaver_codegen_test/Cargo.toml create mode 100644 crates/weaver_codegen_test/README.md create mode 100644 crates/weaver_codegen_test/allowed-external-types.toml create mode 100644 crates/weaver_codegen_test/build.rs create mode 100644 crates/weaver_codegen_test/semconv_registry/http-common.yaml create mode 100644 crates/weaver_codegen_test/semconv_registry/metrics/http.yaml create mode 100644 crates/weaver_codegen_test/semconv_registry/metrics/system-metrics.yaml create mode 100644 crates/weaver_codegen_test/semconv_registry/registry/client.yaml create mode 100644 crates/weaver_codegen_test/semconv_registry/registry/deprecated/network.yaml create mode 100644 crates/weaver_codegen_test/semconv_registry/registry/error.yaml create mode 100644 crates/weaver_codegen_test/semconv_registry/registry/exception.yaml create mode 100644 crates/weaver_codegen_test/semconv_registry/registry/http.yaml create mode 100644 crates/weaver_codegen_test/semconv_registry/registry/network.yaml create mode 100644 crates/weaver_codegen_test/semconv_registry/registry/server.yaml create mode 100644 crates/weaver_codegen_test/semconv_registry/registry/system.yaml create mode 100644 crates/weaver_codegen_test/semconv_registry/registry/url.yaml create mode 100644 crates/weaver_codegen_test/src/main.rs create mode 100644 crates/weaver_codegen_test/templates/registry/rust/README.md create mode 100644 crates/weaver_codegen_test/templates/registry/rust/attribute_macros.j2 create mode 100644 crates/weaver_codegen_test/templates/registry/rust/attributes/attributes.rs.j2 create mode 100644 crates/weaver_codegen_test/templates/registry/rust/attributes/mod.rs.j2 create mode 100644 crates/weaver_codegen_test/templates/registry/rust/lib.rs create mode 100644 crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/counter.j2 create mode 100644 crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/gauge.j2 create mode 100644 crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/histogram.j2 create mode 100644 crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/updowncounter.j2 create mode 100644 crates/weaver_codegen_test/templates/registry/rust/metrics/metrics.rs.j2 create mode 100644 crates/weaver_codegen_test/templates/registry/rust/metrics/mod.rs.j2 create mode 100644 crates/weaver_codegen_test/templates/registry/rust/weaver.yaml create mode 100644 crates/weaver_codegen_test/tests/codegen.rs create mode 100644 crates/weaver_common/src/in_memory.rs diff --git a/Cargo.lock b/Cargo.lock index 3ee731c0..7ab3c66d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3634,6 +3634,21 @@ dependencies = [ "weaver_common", ] +[[package]] +name = "weaver_codegen_test" +version = "0.1.0" +dependencies = [ + "opentelemetry", + "opentelemetry-stdout", + "opentelemetry_sdk", + "walkdir", + "weaver_cache", + "weaver_common", + "weaver_forge", + "weaver_resolver", + "weaver_semconv", +] + [[package]] name = "weaver_common" version = "0.1.0" diff --git a/crates/weaver_codegen_test/Cargo.toml b/crates/weaver_codegen_test/Cargo.toml new file mode 100644 index 00000000..753832ff --- /dev/null +++ b/crates/weaver_codegen_test/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "weaver_codegen_test" +version = "0.1.0" +authors.workspace = true +repository.workspace = true +license.workspace = true +publish.workspace = true +edition.workspace = true +rust-version.workspace = true + +[lints] +workspace = true + +[build-dependencies] +weaver_common = { path = "../weaver_common" } +weaver_cache = { path = "../weaver_cache" } +weaver_forge = { path = "../weaver_forge" } +weaver_resolver = { path = "../weaver_resolver" } +weaver_semconv = { path = "../weaver_semconv" } +walkdir.workspace = true + +[dependencies] +opentelemetry = { version = "0.22.0", features = ["trace", "metrics", "logs", "otel_unstable"] } +opentelemetry_sdk = { version = "0.22.1", features = ["trace", "metrics", "logs"] } +opentelemetry-stdout = { version = "0.3.0", features = ["trace", "metrics", "logs"] } + +[dev-dependencies] +walkdir.workspace = true + diff --git a/crates/weaver_codegen_test/README.md b/crates/weaver_codegen_test/README.md new file mode 100644 index 00000000..f27ef8e6 --- /dev/null +++ b/crates/weaver_codegen_test/README.md @@ -0,0 +1,227 @@ +# Weaver Forge - Template Engine + +- [Introduction](#introduction) +- [Template Directory Structure and Naming Conventions](#template-directory-structure-and-naming-conventions) +- [Configuration File - `weaver.yaml`](#configuration-file---weaveryaml) +- [Jinja Filters](#jinja-filters) +- [Jinja Functions](#jinja-functions) +- [Jinja Tests](#jinja-tests) + +## Introduction + +OTel Weaver is capable of generating documentation or code from a semantic +convention registry or a telemetry schema (phase 2). To do this, +OTel Weaver uses a template engine compatible with the Jinja2 syntax (see the +[MiniJinja](https://github.com/mitsuhiko/minijinja) project for more details). +A set of filters, functions, tests, and naming conventions have been added to +the classic Jinja logic to make the task easier for template authors. + +The following diagram illustrates the documentation and code generation pipeline +using the OTel Weaver tool: + +![Weaver Forge](images/artifact-generation-pipeline.svg) + +## Template Directory Structure and Naming Conventions + +By default, the OTel Weaver tool expects to find a templates directory in the +current directory. + +```plaintext +templates/ + registry/ + go/ <-- Templates to generate the semantic conventions in Go + ... + html/ <-- Templates to generate the semantic conventions in HTML + ... + markdown/ <-- Templates to generate the semantic conventions in markdown + ... + rust/ <-- Templates to generate the semantic conventions in Rust + ... + go/ <-- Templates to generate the semantic conventions in Go + ... + schema/ + sdk-go/ <-- Templates to generate a Go Client SDK derived from the telemetry schema + ... + sdk-rust/ <-- Templates to generate a Rust Client SDK derived from the telemetry schema + ... +``` + +The command `weaver generate registry markdown` will generate the markdown +files based on the templates located in the `templates/registry/markdown`. + +When the name of a file (excluding the extension) matches a recognized pattern +(e.g., attribute_group, groups, ...), OTel Weaver extracts the objects from the +registry and passes them to the template at the time of its evaluation. +Depending on the nature of the pattern, the template is evaluated as many times +as there are objects that match or only once if the pattern corresponds to a +set of objects. By default, the name of the file that will be generated from +the template will be that of the template, but it is possible within the +template to dynamically redefine the name of the produced file. + +For example, the following snippet redefine the name of the file that will be +produced from the template: + +```jinja +{%- set file_name = group.id | file_name -%} +{{- template.set_file_name("span/" ~ file_name ~ ".md") -}} +``` + +This mechanism allows the template to dynamically generate the name of the file +to be produced and to organize the generated files in a directory structure of +its choice. + +## Configuration File - `weaver.yaml` + +The configuration file `weaver.yaml` is optional. It allows configuring the +following options: + +```yaml +# Configuration of the type mapping. This is useful to generate code in a +# specific language. This is optional. +# Example: {{ attribute.type | type_mapping }} will be evaluated as int64 +# if the semconv attribute type is int. +#type_mapping: +# int: int64 +# double: double +# boolean: bool +# string: string +# "int[]": "[]int64" +# "double[]": "[]double" +# "boolean[]": "[]bool" +# "string[]": "[]string" +# ... + +# Configuration of the template engine (optional) +#template_syntax: +# block_start: "{%" +# block_end: "%}" +# variable_start: "{{" +# variable_end: "}}" +# comment_start: "{#" +# comment_end: "#}" + +# Please uncomment the following section to specify a list of acronyms that +# will be interpreted by the acronym filter. This is optional. +# acronyms: ["iOS", "HTTP", "API", "SDK", "CLI", "URL", "JSON", "XML", "HTML"] + +# Please uncomment the following templates to override the default template +# mapping. Each template mapping specifies a jaq filter (compatible with jq) +# to apply to every file matching the pattern. The application_mode specifies +# how the template should be applied. The application_mode can be `each` or +# `single`. The `each` mode will evaluate the template for each object selected +# by the jaq filter. The `single` mode will evaluate the template once with all +# the objects selected by the jq filter. +# +# Note: jaq is a Rust reimplementation of jq. Most of the jq filters are +# supported. For more information, see https://github.com/01mf02/jaq +# +# templates: +# - pattern: "**/registry.md" +# filter: "." +# application_mode: single +# - pattern: "**/attribute_group.md" +# filter: ".groups[] | select(.type == \"attribute_group\")" +# application_mode: each +# - pattern: "**/attribute_groups.md" +# filter: ".groups[] | select(.type == \"attribute_group\")" +# application_mode: single +# - pattern: "**/event.md" +# filter: ".groups[] | select(.type == \"event\")" +# application_mode: each +# - pattern: "**/events.md" +# filter: ".groups[] | select(.type == \"event\")" +# application_mode: single +# - pattern: "**/group.md" +# filter: ".groups[] | select(.type == \"group\")" +# application_mode: each +# - pattern: "**/groups.md" +# filter: ".groups[] | select(.type == \"group\")" +# application_mode: single +# - pattern: "**/metric.md" +# filter: ".groups[] | select(.type == \"metric\")" +# application_mode: each +# - pattern: "**/metrics.md" +# filter: ".groups[] | select(.type == \"metric\")" +# application_mode: single +# - pattern: "**/metric_group.md" +# filter: ".groups[] | select(.type == \"metric_group\")" +# application_mode: each +# - pattern: "**/metric_groups.md" +# filter: ".groups[] | select(.type == \"metric_group\")" +# application_mode: single +# - pattern: "**/resource.md" +# filter: ".groups[] | select(.type == \"resource\")" +# application_mode: each +# - pattern: "**/resources.md" +# filter: ".groups[] | select(.type == \"resource\")" +# application_mode: single +# - pattern: "**/scope.md" +# filter: ".groups[] | select(.type == \"scope\")" +# application_mode: each +# - pattern: "**/scopes.md" +# filter: ".groups[] | select(.type == \"scope\")" +# application_mode: single +# - pattern: "**/span.md" +# filter: ".groups[] | select(.type == \"span\")" +# application_mode: each +# - pattern: "**/spans.md" +# filter: ".groups[] | select(.type == \"span\")" +# application_mode: single +``` + +## Jinja Filters + +All the filters available in the MiniJinja template engine are available (see +this online [documentation](https://docs.rs/minijinja/latest/minijinja/filters/index.html)). + +In addition, OTel Weaver provides a set of custom filters to facilitate the +generation of documentation and code. + +The following filters are available: +- `lower_case`: Converts a string to lowercase. +- `upper_case`: Converts a string to UPPERCASE. +- `title_case`: Converts a string to TitleCase. +- `pascal_case`: Converts a string to PascalCase. +- `camel_case`: Converts a string to camelCase. +- `snake_case`: Converts a string to snake_case. +- `screaming_snake_case`: Converts a string to SCREAMING_SNAKE_CASE. +- `kebab_case`: Converts a string to kebab-case. +- `screaming_kebab_case`: Converts a string to SCREAMING-KEBAB-CASE. +- `acronym`: Replaces acronyms in the input string with the full name defined in the `acronyms` section of the `weaver.yaml` configuration file. +- `split_ids`: Splits a string by '.' creating a list of nested ids. +- `type_mapping`: Converts a semantic convention type to a target type (see weaver.yaml section `type_mapping`). +- `comment_with_prefix(prefix)`: Outputs a multiline comment with the given prefix. +- `flatten`: Converts a List of Lists into a single list with all elements. +e.g. \[\[a,b\],\[c\]\] => \[a,b,c\] +- `attribute_sort`: Sorts a list of `Attribute`s by requirement level, then name. +- `metric_namespace`: Converts registry.{namespace}.{other}.{components} to {namespace}. +- `attribute_registry_file`: Converts registry.{namespace}.{other}.{components} to attributes-registry/{namespace}.md (kebab-case namespace). +- `attribute_registry_title`: Converts registry.{namespace}.{other}.{components} to {Namespace} (title case the namespace). +- `attribute_registry_namespace`: Converts metric.{namespace}.{other}.{components} to {namespace}. +- `attribute_namespace`: Converts {namespace}.{attribute_id} to {namespace}. +- `required`: Filters a list of `Attribute`s to include only the required attributes. The "conditionally_required" attributes are not returned by this filter. +- `not_required`: Filters a list of `Attribute`s to only include non-required attributes. The "conditionally_required" attributes are returned by this filter. + +> Please open an issue if you have any suggestions for new filters. They are easy to implement. + +## Jinja Functions + +All the functions available in the MiniJinja template engine are available (see +this online [documentation](https://docs.rs/minijinja/latest/minijinja/functions/index.html)). + +Right now, OTel Weaver does not provide any custom functions but feel free to +open an issue if you have any suggestions. They are easy to implement. + +## Jinja Tests + +All the tests available in the MiniJinja template engine are available (see +this online [documentation](https://docs.rs/minijinja/latest/minijinja/tests/index.html)). + +In addition, OTel Weaver provides a set of custom tests to facilitate the +generation of assets. + +- `stable`: Tests if an `Attribute` is stable. +- `experimental`: Tests if an `Attribute` is experimental. +- `deprecated`: Tests if an `Attribute` is deprecated. + +> Please open an issue if you have any suggestions for new tests. They are easy to implement. \ No newline at end of file diff --git a/crates/weaver_codegen_test/allowed-external-types.toml b/crates/weaver_codegen_test/allowed-external-types.toml new file mode 100644 index 00000000..f186b677 --- /dev/null +++ b/crates/weaver_codegen_test/allowed-external-types.toml @@ -0,0 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 +# This is used with cargo-check-external-types to reduce the surface area of downstream crates from +# the public API. Ideally this can have a few exceptions as possible. +allowed_external_types = [ +] \ No newline at end of file diff --git a/crates/weaver_codegen_test/build.rs b/crates/weaver_codegen_test/build.rs new file mode 100644 index 00000000..9e45980f --- /dev/null +++ b/crates/weaver_codegen_test/build.rs @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: Apache-2.0 + +//! Generate code for the Semantic Conventions Rust API based on +//! the templates in `templates/registry/rust` and the mini +//! semantic conventions registry in `semconv_registry`. + +use std::path::{Path, PathBuf}; +use std::process::exit; +use weaver_cache::Cache; +use weaver_common::{in_memory, Logger}; +use weaver_common::in_memory::LogMessage; +use weaver_forge::{GeneratorConfig, TemplateEngine}; +use weaver_forge::registry::TemplateRegistry; +use weaver_resolver::SchemaResolver; +use weaver_semconv::path::RegistryPath; +use weaver_semconv::registry::SemConvRegistry; + +fn main() { + println!("cargo:rerun-if-changed=templates/registry/rust"); + println!("cargo:rerun-if-changed=semconv_registry"); + println!("cargo:rerun-if-changed=build.rs"); + + let target_dir = std::env::var("OUT_DIR").unwrap(); + + let logger = in_memory::Logger::new(0); + let cache = Cache::try_new().unwrap_or_else(|e| { + process_error(&logger, e) + }); + let registry_path = RegistryPath::Local { + path_pattern: "./semconv_registry/".into(), + }; + + let semconv_specs = SchemaResolver::load_semconv_specs(®istry_path, &cache).unwrap_or_else(|e| { + process_error(&logger, e) + }); + + let registry_id = "test"; + let mut registry = SemConvRegistry::from_semconv_specs(registry_id, semconv_specs); + let schema = SchemaResolver::resolve_semantic_convention_registry(&mut registry) + .unwrap_or_else(|e| { + process_error(&logger, e) + }); + let config = GeneratorConfig::new("./templates/".into()); + + let engine = TemplateEngine::try_new("registry/rust", config) + .unwrap_or_else(|e| { + process_error(&logger, e) + }); + + let template_registry = TemplateRegistry::try_from_resolved_registry( + schema + .registry(registry_id) + .expect("Failed to get the registry from the resolved schema"), + schema.catalog(), + ) + .unwrap_or_else(|e| { + process_error(&logger, e) + }); + + let output: PathBuf = target_dir.into(); + engine + .generate(logger.clone(), &template_registry, output.as_path()) + .unwrap_or_else(|e| { + process_error(&logger, e) + }); + + print_logs(&logger); + + alter_generated_files(output.as_path()); +} + +/// Alter all the generated files to replace //! comments with standard // comments +fn alter_generated_files(path: &Path) { + let walker = walkdir::WalkDir::new(path); + for entry in walker { + let entry = entry.unwrap(); + let path = entry.path(); + if path.is_file() { + let file_content = std::fs::read_to_string(path).unwrap(); + if file_content.contains("DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER") { + println!("cargo:warning=Altering `{}`", path.display()); + let new_file = file_content.replace("//!", "//"); + // remove line starting with pub mod + let new_file = new_file.lines().filter(|line| !line.starts_with("pub mod")).collect::>().join("\n"); + std::fs::write(path, new_file).unwrap(); + } else { + println!("cargo:warning=Skipping `{}`", path.display()); + } + } + } +} + +fn print_logs(logger: &in_memory::Logger) { + for log_message in logger.messages() { + match &log_message { + LogMessage::Warn(msg) => println!("cargo:warning={}", msg), + LogMessage::Error(err) => println!("cargo:warning=Error: {}", err), + _ => { /* Ignore */ } + } + } +} + +fn process_error(logger: &in_memory::Logger, error: impl std::fmt::Display) -> ! { + logger.error(&error.to_string()); + print_logs(logger); + #[allow(clippy::exit)] // Expected behavior + exit(1) +} \ No newline at end of file diff --git a/crates/weaver_codegen_test/semconv_registry/http-common.yaml b/crates/weaver_codegen_test/semconv_registry/http-common.yaml new file mode 100644 index 00000000..f175215f --- /dev/null +++ b/crates/weaver_codegen_test/semconv_registry/http-common.yaml @@ -0,0 +1,87 @@ +groups: + - id: attributes.http.common + type: attribute_group + brief: "Describes HTTP attributes." + attributes: + - ref: http.request.method + requirement_level: required + - ref: http.response.status_code + requirement_level: + conditionally_required: If and only if one was received/sent. + - ref: error.type + requirement_level: + conditionally_required: If request has ended with an error. + examples: ['timeout', 'java.net.UnknownHostException', 'server_certificate_invalid', '500'] + note: | + If the request fails with an error before response status code was sent or received, + `error.type` SHOULD be set to exception type (its fully-qualified class name, if applicable) + or a component-specific low cardinality error identifier. + + If response status code was sent or received and status indicates an error according to [HTTP span status definition](/docs/http/http-spans.md), + `error.type` SHOULD be set to the status code number (represented as a string), an exception type (if thrown) or a component-specific error identifier. + + The `error.type` value SHOULD be predictable and SHOULD have low cardinality. + Instrumentations SHOULD document the list of errors they report. + + The cardinality of `error.type` within one instrumentation library SHOULD be low, but + telemetry consumers that aggregate data from multiple instrumentation libraries and applications + should be prepared for `error.type` to have high cardinality at query time, when no + additional filters are applied. + + If the request has completed successfully, instrumentations SHOULD NOT set `error.type`. + - ref: network.protocol.name + examples: ['http', 'spdy'] + requirement_level: + conditionally_required: If not `http` and `network.protocol.version` is set. + - ref: network.protocol.version + examples: ['1.0', '1.1', '2', '3'] + + - id: attributes.http.client + type: attribute_group + brief: 'HTTP Client attributes' + extends: attributes.http.common + attributes: + - ref: server.address + requirement_level: required + brief: > + Host identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. + note: > + If an HTTP client request is explicitly made to an IP address, e.g. `http://x.x.x.x:8080`, then + `server.address` SHOULD be the IP address `x.x.x.x`. A DNS lookup SHOULD NOT be used. + - ref: server.port + requirement_level: required + brief: > + Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. + - ref: url.scheme + requirement_level: opt_in + examples: ["http", "https"] + + - id: attributes.http.server + type: attribute_group + brief: 'HTTP Server attributes' + extends: attributes.http.common + attributes: + - ref: http.route + requirement_level: + conditionally_required: If and only if it's available + - ref: server.address + brief: > + Name of the local HTTP server that received the request. + note: > + See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). + - ref: server.port + brief: > + Port of the local HTTP server that received the request. + note: > + See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). + requirement_level: + conditionally_required: If `server.address` is set. + - ref: url.scheme + requirement_level: required + examples: ["http", "https"] + note: > + The scheme of the original client request, if known + (e.g. from [Forwarded#proto](https://developer.mozilla.org/docs/Web/HTTP/Headers/Forwarded#proto), + [X-Forwarded-Proto](https://developer.mozilla.org/docs/Web/HTTP/Headers/X-Forwarded-Proto), + or a similar header). + Otherwise, the scheme of the immediate peer request. \ No newline at end of file diff --git a/crates/weaver_codegen_test/semconv_registry/metrics/http.yaml b/crates/weaver_codegen_test/semconv_registry/metrics/http.yaml new file mode 100644 index 00000000..9d24d884 --- /dev/null +++ b/crates/weaver_codegen_test/semconv_registry/metrics/http.yaml @@ -0,0 +1,62 @@ +groups: + - id: metric_attributes.http.server + type: attribute_group + brief: 'HTTP server attributes' + extends: attributes.http.server + attributes: + - ref: server.address + requirement_level: opt_in + note: | + See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). + > **Warning** + > Since this attribute is based on HTTP headers, opting in to it may allow an attacker + > to trigger cardinality limits, degrading the usefulness of the metric. + - ref: server.port + requirement_level: opt_in + note: | + See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). + > **Warning** + > Since this attribute is based on HTTP headers, opting in to it may allow an attacker + > to trigger cardinality limits, degrading the usefulness of the metric. + - id: metric_attributes.http.client + type: attribute_group + brief: 'HTTP client attributes' + extends: attributes.http.client + + - id: metric.http.server.request.duration + type: metric + metric_name: http.server.request.duration + brief: "Duration of HTTP server requests." + instrument: histogram + unit: "s" + stability: stable + extends: metric_attributes.http.server + + - id: metric.http.client.request.duration + type: metric + metric_name: http.client.request.duration + brief: "Duration of HTTP client requests." + instrument: histogram + unit: "s" + stability: stable + extends: metric_attributes.http.client + + - id: metric.http.client.active_requests + type: metric + metric_name: http.client.active_requests + stability: experimental + brief: "Number of active HTTP requests." + instrument: updowncounter + unit: "{request}" + attributes: + - ref: http.request.method + requirement_level: recommended + - ref: server.address + requirement_level: required + - ref: server.port + requirement_level: required + brief: > + Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. + - ref: url.scheme + requirement_level: opt_in + examples: ["http", "https"] \ No newline at end of file diff --git a/crates/weaver_codegen_test/semconv_registry/metrics/system-metrics.yaml b/crates/weaver_codegen_test/semconv_registry/metrics/system-metrics.yaml new file mode 100644 index 00000000..12073142 --- /dev/null +++ b/crates/weaver_codegen_test/semconv_registry/metrics/system-metrics.yaml @@ -0,0 +1,38 @@ +groups: + # system.cpu.* metrics + - id: metric.system.cpu.time + type: metric + metric_name: system.cpu.time + stability: experimental + brief: "Seconds each logical CPU spent on each mode" + instrument: counter + unit: "s" + attributes: + - ref: system.cpu.state + brief: "The CPU state for this data point. A system's CPU SHOULD be characterized *either* by data points with no `state` labels, *or only* data points with `state` labels." + - ref: system.cpu.logical_number + + - id: metric.system.cpu.utilization + type: metric + metric_name: system.cpu.utilization + stability: stable + brief: "Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs" + instrument: gauge + unit: "1" + attributes: + - ref: system.cpu.state + brief: "The CPU state for this data point. A system's CPU SHOULD be characterized *either* by data points with no `state` labels, *or only* data points with `state` labels." + - ref: system.cpu.logical_number + + - id: metric.system.memory.usage + type: metric + metric_name: system.memory.usage + stability: stable + brief: "Reports memory in use by state." + note: | + The sum over all `system.memory.state` values SHOULD equal the total memory + available on the system, that is `system.memory.limit`. + instrument: updowncounter + unit: "By" + attributes: + - ref: system.memory.state \ No newline at end of file diff --git a/crates/weaver_codegen_test/semconv_registry/registry/client.yaml b/crates/weaver_codegen_test/semconv_registry/registry/client.yaml new file mode 100644 index 00000000..3b17ed8b --- /dev/null +++ b/crates/weaver_codegen_test/semconv_registry/registry/client.yaml @@ -0,0 +1,28 @@ +groups: + - id: registry.client + prefix: client + type: attribute_group + brief: > + 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. + attributes: + - id: address + stability: stable + type: string + brief: "Client address - domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name." + note: > + 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. + examples: ['client.example.com', '10.1.2.80', '/tmp/my.sock'] + - id: port + stability: stable + type: int + brief: Client port number. + examples: [65123] + note: > + 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. diff --git a/crates/weaver_codegen_test/semconv_registry/registry/deprecated/network.yaml b/crates/weaver_codegen_test/semconv_registry/registry/deprecated/network.yaml new file mode 100644 index 00000000..66144671 --- /dev/null +++ b/crates/weaver_codegen_test/semconv_registry/registry/deprecated/network.yaml @@ -0,0 +1,121 @@ +groups: + - id: registry.network.deprecated + prefix: net + type: attribute_group + brief: > + These attributes may be used for any network related operation. + attributes: + - id: sock.peer.name + type: string + deprecated: "Removed." + stability: experimental + brief: Deprecated, no replacement at this time. + examples: ['/var/my.sock'] + - id: sock.peer.addr + type: string + deprecated: "Replaced by `network.peer.address`." + stability: experimental + brief: Deprecated, use `network.peer.address`. + examples: ['192.168.0.1'] + - id: sock.peer.port + type: int + deprecated: "Replaced by `network.peer.port`." + stability: experimental + examples: [65531] + brief: Deprecated, use `network.peer.port`. + - id: peer.name + type: string + deprecated: "Replaced by `server.address` on client spans and `client.address` on server spans." + stability: experimental + brief: Deprecated, use `server.address` on client spans and `client.address` on server spans. + examples: ['example.com'] + - id: peer.port + type: int + deprecated: "Replaced by `server.port` on client spans and `client.port` on server spans." + stability: experimental + brief: Deprecated, use `server.port` on client spans and `client.port` on server spans. + examples: [8080] + - id: host.name + type: string + deprecated: "Replaced by `server.address`." + stability: experimental + brief: Deprecated, use `server.address`. + examples: ['example.com'] + - id: host.port + type: int + deprecated: "Replaced by `server.port`." + stability: experimental + brief: Deprecated, use `server.port`. + examples: [8080] + - id: sock.host.addr + type: string + deprecated: "Replaced by `network.local.address`." + stability: experimental + brief: Deprecated, use `network.local.address`. + examples: ['/var/my.sock'] + - id: sock.host.port + type: int + deprecated: "Replaced by `network.local.port`." + stability: experimental + brief: Deprecated, use `network.local.port`. + examples: [8080] + - id: transport + type: + allow_custom_values: true + members: + - id: ip_tcp + value: "ip_tcp" + stability: experimental + - id: ip_udp + value: "ip_udp" + stability: experimental + - id: pipe + value: "pipe" + brief: 'Named or anonymous pipe.' + stability: experimental + - id: inproc + value: "inproc" + brief: 'In-process communication.' + stability: experimental + note: > + 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. + - id: other + value: "other" + stability: experimental + brief: 'Something else (non IP-based).' + deprecated: "Replaced by `network.transport`." + stability: experimental + brief: Deprecated, use `network.transport`. + - id: protocol.name + type: string + deprecated: "Replaced by `network.protocol.name`." + stability: experimental + brief: Deprecated, use `network.protocol.name`. + examples: ['amqp', 'http', 'mqtt'] + - id: protocol.version + type: string + deprecated: "Replaced by `network.protocol.version`." + stability: experimental + brief: Deprecated, use `network.protocol.version`. + examples: '3.1.1' + - id: sock.family + type: + allow_custom_values: true + members: + - id: inet + value: 'inet' + brief: "IPv4 address" + stability: experimental + - id: inet6 + value: 'inet6' + brief: "IPv6 address" + stability: experimental + - id: unix + value: 'unix' + brief: "Unix domain socket path" + stability: experimental + deprecated: "Split to `network.transport` and `network.type`." + stability: experimental + brief: Deprecated, use `network.transport` and `network.type`. diff --git a/crates/weaver_codegen_test/semconv_registry/registry/error.yaml b/crates/weaver_codegen_test/semconv_registry/registry/error.yaml new file mode 100644 index 00000000..621022f6 --- /dev/null +++ b/crates/weaver_codegen_test/semconv_registry/registry/error.yaml @@ -0,0 +1,40 @@ +groups: + - id: registry.error + type: attribute_group + prefix: error + brief: > + This document defines the shared attributes used to report an error. + attributes: + - id: type + stability: stable + brief: > + Describes a class of error the operation ended with. + type: + allow_custom_values: true + members: + - id: other + value: "_OTHER" + stability: stable + brief: > + A fallback error value to be used when the instrumentation doesn't define a custom value. + examples: ['timeout', 'java.net.UnknownHostException', 'server_certificate_invalid', '500'] + note: | + The `error.type` SHOULD be predictable, and SHOULD have low cardinality. + + When `error.type` is set to a type (e.g., an exception type), its + canonical class name identifying the type within the artifact SHOULD be used. + + Instrumentations SHOULD document the list of errors they report. + + The cardinality of `error.type` within one instrumentation library SHOULD be low. + Telemetry consumers that aggregate data from multiple instrumentation libraries and applications + should be prepared for `error.type` to have high cardinality at query time when no + additional filters are applied. + + If the operation has completed successfully, instrumentations SHOULD NOT set `error.type`. + + If a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes), + it's RECOMMENDED to: + + * Use a domain-specific attribute + * Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. \ No newline at end of file diff --git a/crates/weaver_codegen_test/semconv_registry/registry/exception.yaml b/crates/weaver_codegen_test/semconv_registry/registry/exception.yaml new file mode 100644 index 00000000..7e1b0118 --- /dev/null +++ b/crates/weaver_codegen_test/semconv_registry/registry/exception.yaml @@ -0,0 +1,54 @@ +groups: + - id: registry.exception + type: attribute_group + prefix: exception + brief: > + This document defines the shared attributes used to + report a single exception associated with a span or log. + attributes: + - id: type + type: string + stability: stable + brief: > + 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. + examples: ["java.net.ConnectException", "OSError"] + - id: message + type: string + stability: stable + brief: The exception message. + examples: ["Division by zero", "Can't convert 'int' object to str implicitly"] + - id: stacktrace + type: string + stability: stable + brief: > + 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. + examples: 'Exception in thread "main" java.lang.RuntimeException: Test exception\n + at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n + at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n + at com.example.GenerateTrace.main(GenerateTrace.java:5)' + - id: escaped + type: boolean + stability: stable + brief: > + SHOULD be set to true if the exception event is recorded at a point where + it is known that the exception is escaping the scope of the span. + note: |- + An exception is considered to have escaped (or left) the scope of a span, + if that span is ended while the exception is still logically "in flight". + This may be actually "in flight" in some languages (e.g. if the exception + is passed to a Context manager's `__exit__` method in Python) but will + usually be caught at the point of recording the exception in most languages. + + It is usually not possible to determine at the point where an exception is thrown + whether it will escape the scope of a span. + However, it is trivial to know that an exception + will escape, if one checks for an active exception just before ending the span, + as done in the [example for recording span exceptions](#recording-an-exception). + + It follows that an exception may still escape the scope of the span + 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. diff --git a/crates/weaver_codegen_test/semconv_registry/registry/http.yaml b/crates/weaver_codegen_test/semconv_registry/registry/http.yaml new file mode 100644 index 00000000..e013704a --- /dev/null +++ b/crates/weaver_codegen_test/semconv_registry/registry/http.yaml @@ -0,0 +1,174 @@ +groups: + - id: registry.http + prefix: http + type: attribute_group + brief: 'This document defines semantic convention attributes in the HTTP namespace.' + attributes: + - id: request.body.size + type: int + brief: > + 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. + examples: 3495 + stability: experimental # this should not be marked stable with other HTTP attributes + - id: request.header + stability: stable + type: template[string[]] + brief: > + HTTP request headers, `` being the normalized HTTP Header name (lowercase), the value being the header values. + note: > + 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. + examples: ['http.request.header.content-type=["application/json"]', 'http.request.header.x-forwarded-for=["1.2.3.4", "1.2.3.5"]'] + - id: request.method + stability: stable + type: + allow_custom_values: true + members: + - id: connect + value: "CONNECT" + brief: 'CONNECT method.' + stability: stable + - id: delete + value: "DELETE" + brief: 'DELETE method.' + stability: stable + - id: get + value: "GET" + brief: 'GET method.' + stability: stable + - id: head + value: "HEAD" + brief: 'HEAD method.' + stability: stable + - id: options + value: "OPTIONS" + brief: 'OPTIONS method.' + stability: stable + - id: patch + value: "PATCH" + brief: 'PATCH method.' + stability: stable + - id: post + value: "POST" + brief: 'POST method.' + stability: stable + - id: put + value: "PUT" + brief: 'PUT method.' + stability: stable + - id: trace + value: "TRACE" + brief: 'TRACE method.' + stability: stable + - id: other + value: "_OTHER" + brief: 'Any HTTP method that the instrumentation has no prior knowledge of.' + stability: stable + brief: 'HTTP request method.' + examples: ["GET", "POST", "HEAD"] + note: | + HTTP request method value SHOULD be "known" to the instrumentation. + By default, this convention defines "known" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods) + and the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html). + + If the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`. + + If the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override + the list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named + OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods + (this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults). + + 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. + - id: request.method_original + stability: stable + type: string + brief: Original HTTP method sent by the client in the request line. + examples: ["GeT", "ACL", "foo"] + - id: request.resend_count + stability: stable + type: int + brief: > + The ordinal number of request resending attempt (for any reason, including redirects). + note: > + 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). + examples: 3 + - id: request.size + type: int + brief: > + 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. + examples: 1437 + stability: experimental + - id: response.body.size + type: int + brief: > + 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. + examples: 3495 + stability: experimental # this should not be marked stable with other HTTP attributes + - id: response.header + stability: stable + type: template[string[]] + brief: > + HTTP response headers, `` being the normalized HTTP Header name (lowercase), the value being the header values. + note: > + 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. + examples: ['http.response.header.content-type=["application/json"]', 'http.response.header.my-custom-header=["abc", "def"]'] + - id: response.size + type: int + brief: > + 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. + examples: 1437 + stability: experimental + - id: response.status_code + stability: stable + type: int + brief: '[HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6).' + examples: [200] + - id: route + stability: stable + type: string + brief: > + The matched route, that is, the path template in the format used by the respective server framework. + examples: ['/users/:userID?', '{controller}/{action}/{id?}'] + note: > + 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. + - id: connection.state + type: + allow_custom_values: true + members: + - id: active + value: "active" + brief: 'active state.' + stability: experimental + - id: idle + value: "idle" + brief: 'idle state.' + stability: experimental + brief: State of the HTTP connection in the HTTP connection pool. + stability: experimental + examples: ["active", "idle"] diff --git a/crates/weaver_codegen_test/semconv_registry/registry/network.yaml b/crates/weaver_codegen_test/semconv_registry/registry/network.yaml new file mode 100644 index 00000000..591a0188 --- /dev/null +++ b/crates/weaver_codegen_test/semconv_registry/registry/network.yaml @@ -0,0 +1,235 @@ +groups: + - id: registry.network + prefix: network + type: attribute_group + brief: > + These attributes may be used for any network related operation. + attributes: + - id: carrier.icc + type: string + stability: experimental + brief: "The ISO 3166-1 alpha-2 2-character country code associated with the mobile carrier network." + examples: "DE" + - id: carrier.mcc + type: string + stability: experimental + brief: "The mobile carrier country code." + examples: "310" + - id: carrier.mnc + type: string + stability: experimental + brief: "The mobile carrier network code." + examples: "001" + - id: carrier.name + type: string + stability: experimental + brief: "The name of the mobile carrier." + examples: "sprint" + - id: connection.subtype + type: + allow_custom_values: true + members: + - id: gprs + brief: GPRS + value: "gprs" + stability: experimental + - id: edge + brief: EDGE + value: "edge" + stability: experimental + - id: umts + brief: UMTS + value: "umts" + stability: experimental + - id: cdma + brief: CDMA + value: "cdma" + stability: experimental + - id: evdo_0 + brief: EVDO Rel. 0 + value: "evdo_0" + stability: experimental + - id: evdo_a + brief: "EVDO Rev. A" + value: "evdo_a" + stability: experimental + - id: cdma2000_1xrtt + brief: CDMA2000 1XRTT + value: "cdma2000_1xrtt" + stability: experimental + - id: hsdpa + brief: HSDPA + value: "hsdpa" + stability: experimental + - id: hsupa + brief: HSUPA + value: "hsupa" + stability: experimental + - id: hspa + brief: HSPA + value: "hspa" + stability: experimental + - id: iden + brief: IDEN + value: "iden" + stability: experimental + - id: evdo_b + brief: "EVDO Rev. B" + value: "evdo_b" + stability: experimental + - id: lte + brief: LTE + value: "lte" + stability: experimental + - id: ehrpd + brief: EHRPD + value: "ehrpd" + stability: experimental + - id: hspap + brief: HSPAP + value: "hspap" + stability: experimental + - id: gsm + brief: GSM + value: "gsm" + stability: experimental + - id: td_scdma + brief: TD-SCDMA + value: "td_scdma" + stability: experimental + - id: iwlan + brief: IWLAN + value: "iwlan" + stability: experimental + - id: nr + brief: "5G NR (New Radio)" + value: "nr" + stability: experimental + - id: nrnsa + brief: "5G NRNSA (New Radio Non-Standalone)" + value: "nrnsa" + stability: experimental + - id: lte_ca + brief: LTE CA + value: "lte_ca" + stability: experimental + stability: experimental + brief: 'This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection.' + examples: 'LTE' + - id: connection.type + type: + allow_custom_values: true + members: + - id: wifi + value: "wifi" + stability: experimental + - id: wired + value: "wired" + stability: experimental + - id: cell + value: "cell" + stability: experimental + - id: unavailable + value: "unavailable" + stability: experimental + - id: unknown + value: "unknown" + stability: experimental + stability: experimental + brief: 'The internet connection type.' + examples: 'wifi' + - id: local.address + stability: stable + type: string + brief: Local address of the network connection - IP address or Unix domain socket name. + examples: ['10.1.2.80', '/tmp/my.sock'] + - id: local.port + stability: stable + type: int + brief: Local port number of the network connection. + examples: [65123] + - id: peer.address + stability: stable + type: string + brief: Peer address of the network connection - IP address or Unix domain socket name. + examples: ['10.1.2.80', '/tmp/my.sock'] + - id: peer.port + stability: stable + type: int + brief: Peer port number of the network connection. + examples: [65123] + - id: protocol.name + stability: stable + type: string + brief: '[OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent.' + note: The value SHOULD be normalized to lowercase. + examples: ['amqp', 'http', 'mqtt'] + - id: protocol.version + stability: stable + type: string + brief: The actual version of the protocol used for network communication. + examples: ['1.1', '2'] + note: > + If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), + this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, + this attribute SHOULD NOT be set. + - id: transport + stability: stable + type: + allow_custom_values: true + members: + - id: tcp + value: 'tcp' + brief: "TCP" + stability: stable + - id: udp + value: 'udp' + brief: "UDP" + stability: stable + - id: pipe + value: "pipe" + brief: 'Named or anonymous pipe.' + stability: stable + - id: unix + value: 'unix' + brief: "Unix domain socket" + stability: stable + brief: > + [OSI transport layer](https://osi-model.com/transport-layer/) or + [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). + note: | + The value SHOULD be normalized to lowercase. + + Consider always setting the transport when setting a port number, since + a port number is ambiguous without knowing the transport. For example + different processes could be listening on TCP port 12345 and UDP port 12345. + examples: ['tcp', 'udp'] + - id: type + stability: stable + type: + allow_custom_values: true + members: + - id: ipv4 + value: 'ipv4' + brief: "IPv4" + stability: stable + - id: ipv6 + value: 'ipv6' + brief: "IPv6" + stability: stable + brief: '[OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent.' + note: The value SHOULD be normalized to lowercase. + examples: ['ipv4', 'ipv6'] + - id: io.direction + type: + allow_custom_values: false + members: + - id: transmit + value: 'transmit' + stability: experimental + - id: receive + value: 'receive' + stability: experimental + stability: experimental + brief: "The network IO operation direction." + examples: ["transmit"] \ No newline at end of file diff --git a/crates/weaver_codegen_test/semconv_registry/registry/server.yaml b/crates/weaver_codegen_test/semconv_registry/registry/server.yaml new file mode 100644 index 00000000..0afe3fab --- /dev/null +++ b/crates/weaver_codegen_test/semconv_registry/registry/server.yaml @@ -0,0 +1,28 @@ +groups: + - id: registry.server + prefix: server + type: attribute_group + brief: > + These attributes may be used to describe the server 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. + attributes: + - id: address + stability: stable + type: string + brief: "Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name." + note: > + When observed from the client side, and when communicating through an intermediary, `server.address` SHOULD represent + the server address behind any intermediaries, for example proxies, if it's available. + examples: ['example.com', '10.1.2.80', '/tmp/my.sock'] + - id: port + stability: stable + type: int + brief: Server port number. + note: > + When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent + the server port behind any intermediaries, for example proxies, if it's available. + examples: [80, 8080, 443] \ No newline at end of file diff --git a/crates/weaver_codegen_test/semconv_registry/registry/system.yaml b/crates/weaver_codegen_test/semconv_registry/registry/system.yaml new file mode 100644 index 00000000..1f6bc175 --- /dev/null +++ b/crates/weaver_codegen_test/semconv_registry/registry/system.yaml @@ -0,0 +1,65 @@ +groups: + # system.cpu.* attribute group + - id: registry.system.cpu + prefix: system.cpu + type: attribute_group + brief: "Describes System CPU attributes" + attributes: + - id: state + type: + allow_custom_values: true + members: + - id: user + value: 'user' + - id: system + value: 'system' + - id: nice + value: 'nice' + - id: idle + value: 'idle' + - id: iowait + value: 'iowait' + stability: experimental + - id: interrupt + value: 'interrupt' + stability: experimental + - id: steal + value: 'steal' + stability: experimental + brief: "The state of the CPU" + stability: stable + examples: ["idle", "interrupt"] + - id: logical_number + type: int + stability: stable + brief: "The logical CPU number [0..n-1]" + examples: [1] + # sytem.memory.* attribute group + - id: registry.system.memory + prefix: system.memory + type: attribute_group + brief: "Describes System Memory attributes" + attributes: + - id: state + type: + allow_custom_values: true + members: + - id: used + value: 'used' + stability: experimental + - id: free + value: 'free' + stability: experimental + - id: shared + value: 'shared' + stability: experimental + deprecated: 'Removed, report shared memory usage with `metric.system.memory.shared` metric' + - id: buffers + value: 'buffers' + stability: experimental + - id: cached + value: 'cached' + stability: experimental + stability: stable + brief: "The memory state" + examples: ["free", "cached"] \ No newline at end of file diff --git a/crates/weaver_codegen_test/semconv_registry/registry/url.yaml b/crates/weaver_codegen_test/semconv_registry/registry/url.yaml new file mode 100644 index 00000000..7c132dae --- /dev/null +++ b/crates/weaver_codegen_test/semconv_registry/registry/url.yaml @@ -0,0 +1,116 @@ +groups: + - id: registry.url + brief: Attributes describing URL. + type: attribute_group + prefix: url + attributes: + - id: domain + type: string + stability: experimental + brief: > + Domain extracted from the `url.full`, such as "opentelemetry.io". + note: > + In some cases a URL may refer to an IP and/or port directly, + without a domain name. In this case, the IP address would go to the domain field. + If the URL contains a [literal IPv6 address](https://www.rfc-editor.org/rfc/rfc2732#section-2) + enclosed by `[` and `]`, the `[` and `]` characters should also be captured in the domain field. + examples: ["www.foo.bar", "opentelemetry.io", "3.12.167.2", "[1080:0:0:0:8:800:200C:417A]"] + - id: extension + type: string + stability: experimental + brief: > + The file extension extracted from the `url.full`, excluding the leading dot. + note: > + The file extension is only set if it exists, as not every url has a file extension. + When the file name has multiple extensions `example.tar.gz`, only the last one should be captured `gz`, not `tar.gz`. + examples: [ "png", "gz" ] + - id: fragment + stability: stable + type: string + brief: > + The [URI fragment](https://www.rfc-editor.org/rfc/rfc3986#section-3.5) component + examples: ["SemConv"] + - id: full + stability: stable + type: string + brief: Absolute URL describing a network resource according to [RFC3986](https://www.rfc-editor.org/rfc/rfc3986) + note: > + For network calls, URL usually has `scheme://host[:port][path][?query][#fragment]` format, where the fragment + is not transmitted over HTTP, but if it is known, it SHOULD be included nevertheless. + + `url.full` MUST NOT contain credentials passed via URL in form of `https://username:password@www.example.com/`. + In such case username and password SHOULD be redacted and attribute's value SHOULD be `https://REDACTED:REDACTED@www.example.com/`. + + `url.full` SHOULD capture the absolute URL when it is available (or can be reconstructed). + Sensitive content provided in `url.full` SHOULD be scrubbed when instrumentations can identify it. + examples: ['https://www.foo.bar/search?q=OpenTelemetry#SemConv', '//localhost'] + - id: original + type: string + stability: experimental + brief: > + Unmodified original URL as seen in the event source. + note: > + In network monitoring, the observed URL may be a full URL, whereas in access logs, the URL is often + just represented as a path. This field is meant to represent the URL as it was observed, complete or not. + + `url.original` might contain credentials passed via URL in form of `https://username:password@www.example.com/`. + In such case password and username SHOULD NOT be redacted and attribute's value SHOULD remain the same. + examples: ["https://www.foo.bar/search?q=OpenTelemetry#SemConv", "search?q=OpenTelemetry"] + - id: path + stability: stable + type: string + brief: > + The [URI path](https://www.rfc-editor.org/rfc/rfc3986#section-3.3) component + examples: ["/search"] + note: > + Sensitive content provided in `url.path` SHOULD be scrubbed when instrumentations can identify it. + - id: port + type: int + stability: experimental + brief: > + Port extracted from the `url.full` + examples: [443] + - id: query + stability: stable + type: string + brief: > + The [URI query](https://www.rfc-editor.org/rfc/rfc3986#section-3.4) component + examples: ["q=OpenTelemetry"] + note: > + Sensitive content provided in `url.query` SHOULD be scrubbed when instrumentations can identify it. + - id: registered_domain + type: string + stability: experimental + brief: > + The highest registered url domain, stripped of the subdomain. + examples: ["example.com", "foo.co.uk"] + note: > + This value can be determined precisely with the [public suffix list](http://publicsuffix.org). + For example, the registered domain for `foo.example.com` is `example.com`. + Trying to approximate this by simply taking the last two labels will not work well for TLDs such as `co.uk`. + - id: scheme + stability: stable + type: string + brief: > + The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. + examples: ["https", "ftp", "telnet"] + - id: subdomain + type: string + stability: experimental + brief: > + The subdomain portion of a fully qualified domain name includes all of the names except the host name + under the registered_domain. In a partially qualified domain, or if the qualification level of the + full name cannot be determined, subdomain contains all of the names below the registered domain. + examples: ["east", "sub2.sub1"] + note: > + The subdomain portion of `www.east.mydomain.co.uk` is `east`. If the domain has multiple levels of subdomain, + such as `sub2.sub1.example.com`, the subdomain field should contain `sub2.sub1`, with no trailing period. + - id: top_level_domain + type: string + stability: experimental + brief: > + The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. + For example, the top level domain for example.com is `com`. + examples: ["com", "co.uk"] + note: > + This value can be determined precisely with the [public suffix list](http://publicsuffix.org). \ No newline at end of file diff --git a/crates/weaver_codegen_test/src/main.rs b/crates/weaver_codegen_test/src/main.rs new file mode 100644 index 00000000..cad261b6 --- /dev/null +++ b/crates/weaver_codegen_test/src/main.rs @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: Apache-2.0 + +//! + +fn main() { + println!("Hello, world!"); +} \ No newline at end of file diff --git a/crates/weaver_codegen_test/templates/registry/rust/README.md b/crates/weaver_codegen_test/templates/registry/rust/README.md new file mode 100644 index 00000000..5a12148c --- /dev/null +++ b/crates/weaver_codegen_test/templates/registry/rust/README.md @@ -0,0 +1,382 @@ +[comment]: # DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER +# Semantic Conventions for Rust + +# Usage + +```rust +use opentelemetry::KeyValue; +use opentelemetry::metrics::{Histogram, MeterProvider}; +use opentelemetry_sdk::{Resource, runtime}; +use opentelemetry_sdk::metrics::{PeriodicReader, SdkMeterProvider}; + +use semconv::attributes; +use semconv::attributes::http::{HTTP_REQUEST_METHOD, HttpRequestMethod}; +use semconv::attributes::system::SystemCpuState; +use semconv::metrics::http::{create_http_client_request_duration, HttpClientActiveRequests, HttpClientActiveRequestsReqAttributes, HttpServerRequestDurationOptAttributes, HttpServerRequestDurationReqAttributes}; +use semconv::metrics::http::HttpServerRequestDuration; +use semconv::metrics::system::{SystemCpuTime, SystemCpuTimeOptAttributes, SystemCpuUtilization, SystemCpuUtilizationOptAttributes}; + +/// Main +#[tokio::main] +async fn main() -> Result<(), Box> { + let meter_provider = init_meter_provider(); + + // SemConv attributes are typed, so the compiler will catch type errors + // Experimental attributes are not visible if the `semconv_experimental` feature is not enabled + println!("{:?}", attributes::client::CLIENT_ADDRESS.value("145.34.23.56".into())); + println!("{:?}", attributes::client::CLIENT_ADDRESS.key()); + println!("{:?}", attributes::client::CLIENT_PORT.value(8080)); + println!("{:?}", attributes::client::CLIENT_PORT.key()); + + println!("{}", HttpRequestMethod::Connect); + + let meter = meter_provider.meter("mylibname"); + + // Create a u64 http.client.request.duration metric + let http_client_request_duration: Histogram = create_http_client_request_duration(&meter); + http_client_request_duration.record(100, &[ + HTTP_REQUEST_METHOD.value(&HttpRequestMethod::Connect), + // here nothing guarantees that all the required attributes are provided + ]); + + let http_client_request_duration: Histogram = create_http_client_request_duration(&meter); + dbg!(http_client_request_duration); + + // ==== A TYPE-SAFE HISTOGRAM API ==== + // Create a u64 http.server.request.duration metric (as defined in the OpenTelemetry HTTP + // semantic conventions) + let http_request_duration = HttpServerRequestDuration::::new(&meter); + + // Records a new data point and provide the required and some not required attributes + http_request_duration.record(100, &HttpServerRequestDurationReqAttributes { + http_request_method: HttpRequestMethod::Connect, + url_scheme: "http".to_owned(), + }, Some(&HttpServerRequestDurationOptAttributes { + http_response_status_code: Some(200), + ..Default::default() + })); + + // ==== A TYPE-SAFE UP-DOWN-COUNTER API ==== + // Create a f64 http.server.request.duration metric (as defined in the OpenTelemetry HTTP + // semantic conventions) + let http_client_active_requests = HttpClientActiveRequests::::new(&meter); + + // Adds a new data point and provide the required attributes. Not required attributes are not + // provided in this example. + http_client_active_requests.add(10.0, &HttpClientActiveRequestsReqAttributes { + server_address: "10.0.0.1".to_owned(), + server_port: 8080, + }, None); + + // ==== A TYPE-SAFE COUNTER API ==== + // Create a f64 system.cpu.time metric (as defined in the OpenTelemetry System semantic + // conventions) + let system_cpu_time = SystemCpuTime::::new(&meter); + + // Adds a new data point and provide some not required attributes. + // Note: In the method signature, there is no required attribute. + system_cpu_time.add(10.0, Some(&SystemCpuTimeOptAttributes { + system_cpu_logical_number: Some(0), + system_cpu_state: Some(SystemCpuState::Idle) + })); + // Adds a new data point with a custom CPU state. + system_cpu_time.add(20.0, Some(&SystemCpuTimeOptAttributes { + system_cpu_logical_number: Some(0), + system_cpu_state: Some(SystemCpuState::_Custom("custom".to_owned())) + })); + + // ==== A TYPE-SAFE GAUGE API ==== + // Create a i64 system.cpu.utilization metric (as defined in the OpenTelemetry System semantic + // conventions) + let system_cpu_utilization = SystemCpuUtilization::::new(&meter); + + // Adds a new data point with no not required attributes. + system_cpu_utilization.record(-5, None); + // Adds a new data point with some not required attributes. + system_cpu_utilization.record(10, Some(&SystemCpuUtilizationOptAttributes { + system_cpu_logical_number: Some(0), + system_cpu_state: Some(SystemCpuState::Idle) + })); + + meter_provider.shutdown()?; + Ok(()) +} + +fn init_meter_provider() -> SdkMeterProvider { + let exporter = opentelemetry_stdout::MetricsExporterBuilder::default() + .with_encoder(|writer, data| + Ok(serde_json::to_writer_pretty(writer, &data).unwrap())) + .build(); + let reader = PeriodicReader::builder(exporter, runtime::Tokio).build(); + SdkMeterProvider::builder() + .with_reader(reader) + .with_resource(Resource::new(vec![KeyValue::new( + "service.name", + "metrics-basic-example", + )])) + .build() +} +``` + +The execution of this program will generate the following output: + +``` +KeyValue { key: Static("client.address"), value: String(Static("145.34.23.56")) } +Static("client.address") +KeyValue { key: Static("client.port"), value: I64(8080) } +Static("client.port") +CONNECT +[src/main.rs:39:5] http_client_request_duration = Histogram +{ + "resourceMetrics": { + "resource": { + "attributes": [ + { + "key": "service.name", + "value": { + "stringValue": "metrics-basic-example" + } + } + ] + }, + "scopeMetrics": [ + { + "scope": { + "name": "mylibname" + }, + "metrics": [ + { + "name": "http.client.request.duration", + "description": "Duration of HTTP client requests.", + "unit": "s", + "histogram": { + "dataPoints": [ + { + "attributes": { + "http.request.method": { + "stringValue": "CONNECT" + } + }, + "startTimeUnixNano": 1714780164856054000, + "timeUnixNano": 1714780164856202000, + "startTime": "2024-05-03 23:49:24.856", + "time": "2024-05-03 23:49:24.856", + "count": 1, + "explicitBounds": [ + 0.0, + 5.0, + 10.0, + 25.0, + 50.0, + 75.0, + 100.0, + 250.0, + 500.0, + 750.0, + 1000.0, + 2500.0, + 5000.0, + 7500.0, + 10000.0 + ], + "bucketCounts": [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "min": 100, + "max": 100, + "sum": 100, + "exemplars": [], + "flags": 0 + } + ], + "aggregationTemporality": "Cumulative" + } + }, + { + "name": "http.server.request.duration", + "description": "Duration of HTTP server requests.", + "unit": "s", + "histogram": { + "dataPoints": [ + { + "attributes": { + "http.request.method": { + "stringValue": "CONNECT" + }, + "http.response.status_code": { + "intValue": 200 + }, + "url.scheme": { + "stringValue": "http" + } + }, + "startTimeUnixNano": 1714780164856111000, + "timeUnixNano": 1714780164856204000, + "startTime": "2024-05-03 23:49:24.856", + "time": "2024-05-03 23:49:24.856", + "count": 1, + "explicitBounds": [ + 0.0, + 5.0, + 10.0, + 25.0, + 50.0, + 75.0, + 100.0, + 250.0, + 500.0, + 750.0, + 1000.0, + 2500.0, + 5000.0, + 7500.0, + 10000.0 + ], + "bucketCounts": [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "min": 100, + "max": 100, + "sum": 100, + "exemplars": [], + "flags": 0 + } + ], + "aggregationTemporality": "Cumulative" + } + }, + { + "name": "http.client.active_requests", + "description": "Number of active HTTP requests.", + "unit": "{request}", + "sum": { + "dataPoints": [ + { + "attributes": { + "server.address": { + "stringValue": "10.0.0.1" + }, + "server.port": { + "intValue": 8080 + } + }, + "startTime": "2024-05-03 23:49:24.856", + "time": "2024-05-03 23:49:24.856", + "startTimeUnixNano": 1714780164856139000, + "timeUnixNano": 1714780164856219000, + "value": 10.0 + } + ], + "aggregationTemporality": "Cumulative", + "isMonotonic": false + } + }, + { + "name": "system.cpu.time", + "description": "Seconds each logical CPU spent on each mode", + "unit": "s", + "sum": { + "dataPoints": [ + { + "attributes": { + "system.cpu.logical_number": { + "intValue": 0 + }, + "system.cpu.state": { + "stringValue": "idle" + } + }, + "startTime": "2024-05-03 23:49:24.856", + "time": "2024-05-03 23:49:24.856", + "startTimeUnixNano": 1714780164856152000, + "timeUnixNano": 1714780164856220000, + "value": 10.0 + }, + { + "attributes": { + "system.cpu.logical_number": { + "intValue": 0 + }, + "system.cpu.state": { + "stringValue": "custom" + } + }, + "startTime": "2024-05-03 23:49:24.856", + "time": "2024-05-03 23:49:24.856", + "startTimeUnixNano": 1714780164856152000, + "timeUnixNano": 1714780164856220000, + "value": 20.0 + } + ], + "aggregationTemporality": "Cumulative", + "isMonotonic": true + } + }, + { + "name": "system.cpu.utilization", + "description": "Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs", + "unit": "1", + "gauge": { + "dataPoints": [ + { + "attributes": { + "system.cpu.logical_number": { + "intValue": 0 + }, + "system.cpu.state": { + "stringValue": "idle" + } + }, + "startTime": null, + "time": "2024-05-03 23:49:24.856", + "startTimeUnixNano": null, + "timeUnixNano": 1714780164856176000, + "value": 10 + }, + { + "attributes": {}, + "startTime": null, + "time": "2024-05-03 23:49:24.856", + "startTimeUnixNano": null, + "timeUnixNano": 1714780164856171000, + "value": -5 + } + ] + } + } + ] + } + ] + } +} +``` \ No newline at end of file diff --git a/crates/weaver_codegen_test/templates/registry/rust/attribute_macros.j2 b/crates/weaver_codegen_test/templates/registry/rust/attribute_macros.j2 new file mode 100644 index 00000000..d132ec32 --- /dev/null +++ b/crates/weaver_codegen_test/templates/registry/rust/attribute_macros.j2 @@ -0,0 +1,60 @@ +{%- macro comments(attribute, prefix) -%} +{%- if attribute.brief %} +{{ attribute.brief | comment_with_prefix(prefix ~ " ") }} +{%- endif %} +{%- if attribute.note %} +{{ prefix }} +{{ prefix }} Notes: +{{ attribute.note | comment_with_prefix(prefix ~ " ") }} +{%- endif %} +{%- if attribute.examples %} +{%- if attribute.examples is sequence %} +{{ prefix }} +{{ prefix }} Examples: +{%- for example in attribute.examples %} +{{ example | comment_with_prefix(prefix ~ " - ") }} +{%- endfor %} +{%- else %} +{{ prefix }} +{{ prefix }} Example: {{ attribute.examples | trim }} +{%- endif %} +{%- endif %} +{%- endmacro %} + +{%- macro attributes_to_key_values(required_attributes, not_required_attributes) -%} + let mut attributes = vec![ + {%- for attribute in required_attributes | attribute_sort %} + {%- if attribute is experimental %} + #[cfg(feature = "semconv_experimental")] + {%- endif %} + {%- if attribute.type.members is defined %} + crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(&required_attributes.{{ attribute.name | snake_case }}), + {%- elif attribute.type == "string" %} + crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(required_attributes.{{ attribute.name | snake_case }}.to_string().into()), + {%- else %} + crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(required_attributes.{{ attribute.name | snake_case }}), + {%- endif %} + {%- endfor %} + ]; + + if let Some(value) = ¬_required_attributes { + {%- for attribute in not_required_attributes | attribute_sort %} + {%- if attribute is experimental %} + #[cfg(feature = "semconv_experimental")] + {%- endif %} + {%- if attribute.type.members is defined %} + if let Some({{ attribute.name | snake_case }}) = &value.{{ attribute.name | snake_case }} { + attributes.push(crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value({{ attribute.name | snake_case }})); + } + {%- elif attribute.type == "string" %} + if let Some({{ attribute.name | snake_case }}) = &value.{{ attribute.name | snake_case }} { + attributes.push(crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value({{ attribute.name | snake_case }}.to_string().into())); + } + {%- else %} + if let Some({{ attribute.name | snake_case }}) = value.{{ attribute.name | snake_case }} { + attributes.push(crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value({{ attribute.name | snake_case }})); + } + {%- endif %} + {%- endfor %} + } +{%- endmacro %} \ No newline at end of file diff --git a/crates/weaver_codegen_test/templates/registry/rust/attributes/attributes.rs.j2 b/crates/weaver_codegen_test/templates/registry/rust/attributes/attributes.rs.j2 new file mode 100644 index 00000000..94e70b52 --- /dev/null +++ b/crates/weaver_codegen_test/templates/registry/rust/attributes/attributes.rs.j2 @@ -0,0 +1,83 @@ +{%- set file_name = ctx.id | attribute_registry_namespace | snake_case -%} +{{- template.set_file_name("attributes/" ~ file_name ~ ".rs") -}} +{%- import 'attribute_macros.j2' as attribute_macros -%} + +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +{{ ctx.brief | comment_with_prefix("//! ") }} +{%- if ctx.note %} +//! +//! Notes: +{{ ctx.note | comment_with_prefix("//! ") }} +{%- endif %} +//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER + +{%- for attribute in ctx.attributes | attribute_sort %} +{{ attribute_macros.comments(attribute, "///") }} +{%- if attribute is experimental %} +#[cfg(feature = "semconv_experimental")] +{%- endif %} +{%- if attribute is deprecated %} +#[deprecated(note="{{ attribute.deprecated }}")] +{%- endif %} +{%- if attribute.type.allow_custom_values is defined %} +pub const {{ attribute.name | screaming_snake_case }}: crate::attributes::AttributeKey<{{ attribute.name | pascal_case }}> = crate::attributes::AttributeKey::new("{{ attribute.name }}"); +{%- elif attribute.type == "string" %} +pub const {{ attribute.name | screaming_snake_case }}: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("{{ attribute.name }}"); +{%- else %} +pub const {{ attribute.name | screaming_snake_case }}: crate::attributes::AttributeKey<{{ attribute.type | type_mapping }}> = crate::attributes::AttributeKey::new("{{ attribute.name }}"); +{%- endif %} +{%- if attribute.type.members is defined %} + +{% if attribute.brief %}{{ attribute.brief | comment_with_prefix("/// ") }}{%- endif %} +#[derive(Debug, Clone)] +#[non_exhaustive] +pub enum {{ attribute.name | pascal_case }} { +{%- for variant in attribute.type.members %} + {{ variant.brief | default("No brief") | comment_with_prefix(" /// ") }} + {%- if variant.note %}{{ variant.note | comment_with_prefix(" /// ") }}{% endif %} + {%- if variant is experimental %} + #[cfg(feature = "semconv_experimental")] {% endif %} + {{ variant.id | pascal_case }}, +{%- endfor %} + /// This variant allows defining a custom entry in the enum. + _Custom(String), +} + +impl {{ attribute.name | pascal_case }} { + /// Returns the string representation of the [`{{ attribute.name | pascal_case }}`]. + pub fn as_str(&self) -> &str { + match self { + {%- for variant in attribute.type.members %} + {%- if variant is experimental %} + #[cfg(feature = "semconv_experimental")] {% endif %} + {{ attribute.name | pascal_case }}::{{ variant.id | pascal_case }} => "{{ variant.value }}", + {%- endfor %} + {{ attribute.name | pascal_case }}::_Custom(v) => v.as_str(), + // 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 {{ attribute.name | pascal_case }} { + /// Formats the value using the given formatter. + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +impl crate::attributes::AttributeKey<{{ attribute.name | pascal_case }}> { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: &{{ attribute.name | pascal_case }}) -> opentelemetry::KeyValue { + opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) + } +} +{%- endif %} +{%- endfor %} \ No newline at end of file diff --git a/crates/weaver_codegen_test/templates/registry/rust/attributes/mod.rs.j2 b/crates/weaver_codegen_test/templates/registry/rust/attributes/mod.rs.j2 new file mode 100644 index 00000000..a269e52b --- /dev/null +++ b/crates/weaver_codegen_test/templates/registry/rust/attributes/mod.rs.j2 @@ -0,0 +1,65 @@ +{{- template.set_file_name("attributes/mod.rs") -}} + +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! OpenTelemetry Semantic Convention Attributes +//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER + +use opentelemetry::{Key, KeyValue, StringValue}; + +{% for group in ctx %} +/// Attributes for the `{{ group.id | attribute_registry_namespace }}` namespace. +pub mod {{ group.id | attribute_registry_namespace | snake_case }}; +{%- endfor %} + +/// A typed attribute key. +pub struct AttributeKey { + key: Key, + phantom: std::marker::PhantomData +} + +impl AttributeKey { + /// Returns a new [`AttributeKey`] with the given key. + pub(crate) const fn new(key: &'static str) -> AttributeKey { + Self { + key: Key::from_static_str(key), + phantom: std::marker::PhantomData + } + } + + /// Returns the key of the attribute. + pub fn key(&self) -> &Key { + &self.key + } +} + +impl AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: StringValue) -> KeyValue { + KeyValue::new(self.key.clone(), v) + } +} + +impl AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: i64) -> KeyValue { + KeyValue::new(self.key.clone(), v) + } +} + +impl AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: f64) -> KeyValue { + KeyValue::new(self.key.clone(), v) + } +} + +impl AttributeKey { + /// Returns a [`KeyValue`] pair for the given value. + pub fn value(&self, v: bool) -> KeyValue { + KeyValue::new(self.key.clone(), v) + } +} diff --git a/crates/weaver_codegen_test/templates/registry/rust/lib.rs b/crates/weaver_codegen_test/templates/registry/rust/lib.rs new file mode 100644 index 00000000..dad69ebf --- /dev/null +++ b/crates/weaver_codegen_test/templates/registry/rust/lib.rs @@ -0,0 +1,13 @@ +{{- template.set_file_name("lib.rs") -}} + +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! OpenTelemetry Semantic Convention Attributes. +//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER + +pub mod attributes; +pub mod metrics; + diff --git a/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/counter.j2 b/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/counter.j2 new file mode 100644 index 00000000..d5b23273 --- /dev/null +++ b/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/counter.j2 @@ -0,0 +1,69 @@ +{%- import 'attribute_macros.j2' as attribute_macros %} +{%- if metric.brief %} +{{ metric.brief | comment_with_prefix("/// ") }} +{%- endif %} +{%- if metric is experimental %} +#[cfg(feature = "semconv_experimental")] +{%- endif %} +pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Counter + where opentelemetry::metrics::Meter: crate::metrics::CounterProvider { + crate::metrics::CounterProvider::create_counter(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") +} + +/// Metric: {{ metric.metric_name }} +/// Brief: {{ metric.brief }} +/// Unit: {{ metric.unit }} +#[derive(Debug)] +pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::Counter); + +{%- set required_attributes = metric.attributes | required %} +{%- set not_required_attributes = metric.attributes | not_required %} + +{% if required_attributes %} +/// Required attributes for the `{{ metric.metric_name }}` metric. +#[derive(Debug, Clone)] +pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { + {%- for attribute in required_attributes | attribute_sort %} + {{ attribute_macros.comments(attribute, " ///") }} + {%- if attribute.type.members is defined %} + pub {{ attribute.name | snake_case }}: crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | pascal_case }}, + {%- else %} + pub {{ attribute.name | snake_case }}: {{ attribute.type | type_mapping }}, + {%- endif %} + {%- endfor %} +} +{% endif %} + +{% if not_required_attributes %} +/// Not required attributes for the `{{ metric.metric_name }}` metric. +#[derive(Debug, Clone, Default)] +pub struct {{ metric.metric_name | pascal_case }}OptAttributes { + {%- for attribute in not_required_attributes | attribute_sort %} + {{ attribute_macros.comments(attribute, " ///") }} + {%- if attribute.type.members is defined %} + pub {{ attribute.name | snake_case }}: Option, + {%- else %} + pub {{ attribute.name | snake_case }}: Option<{{ attribute.type | type_mapping }}>, + {%- endif %} + {%- endfor %} +} +{% endif %} + +impl {{ metric.metric_name | pascal_case }} { + /// Creates a new `{{ metric.metric_name }}` metric. + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: crate::metrics::CounterProvider{ + Self(crate::metrics::CounterProvider::create_counter(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) + } + + /// Adds an additional value to the counter. + pub fn add( + &self, + value: T, + {% if required_attributes %}required_attributes: &{{ metric.metric_name | pascal_case }}ReqAttributes,{% endif %} + {% if not_required_attributes %}not_required_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} + ) { + {{ attribute_macros.attributes_to_key_values(required_attributes, not_required_attributes) }} + self.0.add(value, &attributes) + } +} \ No newline at end of file diff --git a/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/gauge.j2 b/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/gauge.j2 new file mode 100644 index 00000000..063c440e --- /dev/null +++ b/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/gauge.j2 @@ -0,0 +1,69 @@ +{%- import 'attribute_macros.j2' as attribute_macros %} +{%- if metric.brief %} +{{ metric.brief | comment_with_prefix("/// ") }} +{%- endif %} +{%- if metric is experimental %} +#[cfg(feature = "semconv_experimental")] +{%- endif %} +pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Gauge + where opentelemetry::metrics::Meter: crate::metrics::GaugeProvider { + crate::metrics::GaugeProvider::create_gauge(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") +} + +/// Metric: {{ metric.metric_name }} +/// Brief: {{ metric.brief }} +/// Unit: {{ metric.unit }} +#[derive(Debug)] +pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::Gauge); + +{%- set required_attributes = metric.attributes | required %} +{%- set not_required_attributes = metric.attributes | not_required %} + +{% if required_attributes %} +/// Required attributes for the `{{ metric.metric_name }}` metric. +#[derive(Debug, Clone)] +pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { + {%- for attribute in required_attributes | attribute_sort %} + {{ attribute_macros.comments(attribute, " ///") }} + {%- if attribute.type.members is defined %} + pub {{ attribute.name | snake_case }}: crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | pascal_case }}, + {%- else %} + pub {{ attribute.name | snake_case }}: {{ attribute.type | type_mapping }}, + {%- endif %} + {%- endfor %} +} +{% endif %} + +{% if not_required_attributes %} +/// Not required attributes for the `{{ metric.metric_name }}` metric. +#[derive(Debug, Clone, Default)] +pub struct {{ metric.metric_name | pascal_case }}OptAttributes { + {%- for attribute in not_required_attributes | attribute_sort %} + {{ attribute_macros.comments(attribute, " ///") }} + {%- if attribute.type.members is defined %} + pub {{ attribute.name | snake_case }}: Option, + {%- else %} + pub {{ attribute.name | snake_case }}: Option<{{ attribute.type | type_mapping }}>, + {%- endif %} + {%- endfor %} +} +{% endif %} + +impl {{ metric.metric_name | pascal_case }} { + /// Creates a new `{{ metric.metric_name }}` metric. + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: crate::metrics::GaugeProvider{ + Self(crate::metrics::GaugeProvider::create_gauge(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) + } + + /// Records an additional value to the gauge. + pub fn record( + &self, + value: T, + {% if required_attributes %}required_attributes: &{{ metric.metric_name | pascal_case }}ReqAttributes,{% endif %} + {% if not_required_attributes %}not_required_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} + ) { + {{ attribute_macros.attributes_to_key_values(required_attributes, not_required_attributes) }} + self.0.record(value, &attributes) + } +} \ No newline at end of file diff --git a/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/histogram.j2 b/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/histogram.j2 new file mode 100644 index 00000000..ea700f01 --- /dev/null +++ b/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/histogram.j2 @@ -0,0 +1,69 @@ +{%- import 'attribute_macros.j2' as attribute_macros %} +{%- if metric.brief %} +{{ metric.brief | comment_with_prefix("/// ") }} +{%- endif %} +{%- if metric is experimental %} +#[cfg(feature = "semconv_experimental")] +{%- endif %} +pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram + where opentelemetry::metrics::Meter: crate::metrics::HistogramProvider { + crate::metrics::HistogramProvider::create_histogram(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") +} + +/// Metric: {{ metric.metric_name }} +/// Brief: {{ metric.brief }} +/// Unit: {{ metric.unit }} +#[derive(Debug)] +pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::Histogram); + +{%- set required_attributes = metric.attributes | required %} +{%- set not_required_attributes = metric.attributes | not_required %} + +{% if required_attributes %} +/// Required attributes for the `{{ metric.metric_name }}` metric. +#[derive(Debug, Clone)] +pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { + {%- for attribute in required_attributes | attribute_sort %} + {{ attribute_macros.comments(attribute, " ///") }} + {%- if attribute.type.members is defined %} + pub {{ attribute.name | snake_case }}: crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | pascal_case }}, + {%- else %} + pub {{ attribute.name | snake_case }}: {{ attribute.type | type_mapping }}, + {%- endif %} + {%- endfor %} +} +{% endif %} + +{% if not_required_attributes %} +/// Not required attributes for the `{{ metric.metric_name }}` metric. +#[derive(Debug, Clone, Default)] +pub struct {{ metric.metric_name | pascal_case }}OptAttributes { + {%- for attribute in not_required_attributes | attribute_sort %} + {{ attribute_macros.comments(attribute, " ///") }} + {%- if attribute.type.members is defined %} + pub {{ attribute.name | snake_case }}: Option, + {%- else %} + pub {{ attribute.name | snake_case }}: Option<{{ attribute.type | type_mapping }}>, + {%- endif %} + {%- endfor %} +} +{% endif %} + +impl {{ metric.metric_name | pascal_case }} { + /// Creates a new instance of the `{{ metric.metric_name }}` metric. + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: crate::metrics::HistogramProvider{ + Self(crate::metrics::HistogramProvider::create_histogram(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) + } + + /// Adds an additional value to the distribution. + pub fn record( + &self, + value: T, + {% if required_attributes %}required_attributes: &{{ metric.metric_name | pascal_case }}ReqAttributes,{% endif %} + {% if not_required_attributes %}not_required_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} + ) { + {{ attribute_macros.attributes_to_key_values(required_attributes, not_required_attributes) }} + self.0.record(value, &attributes) + } +} \ No newline at end of file diff --git a/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/updowncounter.j2 b/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/updowncounter.j2 new file mode 100644 index 00000000..bc827a46 --- /dev/null +++ b/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/updowncounter.j2 @@ -0,0 +1,70 @@ +{%- import 'attribute_macros.j2' as attribute_macros %} +{%- if metric.brief %} +{{ metric.brief | comment_with_prefix("/// ") }} +{%- endif %} +{%- if metric is experimental %} +#[cfg(feature = "semconv_experimental")] +{%- endif %} +pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter + where opentelemetry::metrics::Meter: crate::metrics::UpDownCounterProvider { + crate::metrics::UpDownCounterProvider::create_up_down_counter(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") +} + +/// Metric: {{ metric.metric_name }} +/// Brief: {{ metric.brief }} +/// Unit: {{ metric.unit }} +#[derive(Debug)] +pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::UpDownCounter); + +{%- set required_attributes = metric.attributes | required %} +{%- set not_required_attributes = metric.attributes | not_required %} + +{% if required_attributes %} +/// Required attributes for the `{{ metric.metric_name }}` metric. +/// Attributes for the `{{ metric.metric_name }}` metric. +#[derive(Debug, Clone)] +pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { + {%- for attribute in required_attributes | attribute_sort %} + {{ attribute_macros.comments(attribute, " ///") }} + {%- if attribute.type.members is defined %} + pub {{ attribute.name | snake_case }}: crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | pascal_case }}, + {%- else %} + pub {{ attribute.name | snake_case }}: {{ attribute.type | type_mapping }}, + {%- endif %} + {%- endfor %} +} +{% endif %} + +{% if not_required_attributes %} +/// Not required attributes for the `{{ metric.metric_name }}` metric. +#[derive(Debug, Clone, Default)] +pub struct {{ metric.metric_name | pascal_case }}OptAttributes { + {%- for attribute in not_required_attributes | attribute_sort %} + {{ attribute_macros.comments(attribute, " ///") }} + {%- if attribute.type.members is defined %} + pub {{ attribute.name | snake_case }}: Option, + {%- else %} + pub {{ attribute.name | snake_case }}: Option<{{ attribute.type | type_mapping }}>, + {%- endif %} + {%- endfor %} +} +{% endif %} + +impl {{ metric.metric_name | pascal_case }} { + /// Creates a new instance of the `{{ metric.metric_name }}` metric. + pub fn new(meter: &opentelemetry::metrics::Meter) -> Self + where opentelemetry::metrics::Meter: crate::metrics::UpDownCounterProvider{ + Self(crate::metrics::UpDownCounterProvider::create_up_down_counter(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) + } + + /// Adds an additional value to the up-down-counter. + pub fn add( + &self, + value: T, + {% if required_attributes %}required_attributes: &{{ metric.metric_name | pascal_case }}ReqAttributes,{% endif %} + {% if not_required_attributes %}not_required_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} + ) { + {{ attribute_macros.attributes_to_key_values(required_attributes, not_required_attributes) }} + self.0.add(value, &attributes) + } +} \ No newline at end of file diff --git a/crates/weaver_codegen_test/templates/registry/rust/metrics/metrics.rs.j2 b/crates/weaver_codegen_test/templates/registry/rust/metrics/metrics.rs.j2 new file mode 100644 index 00000000..0b23820a --- /dev/null +++ b/crates/weaver_codegen_test/templates/registry/rust/metrics/metrics.rs.j2 @@ -0,0 +1,13 @@ +{%- set file_name = ctx.prefix | snake_case -%} +{{- template.set_file_name("metrics/" ~ file_name ~ ".rs") -}} + +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER + +{%- for metric in ctx.groups %} +{% include "metrics/instruments/" ~ metric.instrument ~ ".j2" %} +{%- endfor %} \ No newline at end of file diff --git a/crates/weaver_codegen_test/templates/registry/rust/metrics/mod.rs.j2 b/crates/weaver_codegen_test/templates/registry/rust/metrics/mod.rs.j2 new file mode 100644 index 00000000..eec7f03f --- /dev/null +++ b/crates/weaver_codegen_test/templates/registry/rust/metrics/mod.rs.j2 @@ -0,0 +1,137 @@ +{{- template.set_file_name("metrics/mod.rs") -}} + +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +//! OpenTelemetry Semantic Convention Metrics +//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER + +{% for group in ctx %} +/// Metrics for the `{{ group.id | metric_namespace }}` namespace. +pub mod {{ group.id | metric_namespace | snake_case }}; +{%- endfor %} + +/// A trait implemented by histogram providers (e.g. `Meter`). +pub trait HistogramProvider { + /// Creates a new histogram with the given name, description, and unit. + fn create_histogram(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Histogram; +} + +/// This implementation specifies that a Meter is able to create u64 histograms. +impl HistogramProvider for opentelemetry::metrics::Meter { + /// Creates a new u64 histogram with the given name, description, and unit. + fn create_histogram(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Histogram { + self.u64_histogram(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// This implementation specifies that a Meter is able to create u64 histograms. +impl HistogramProvider for opentelemetry::metrics::Meter { + /// Creates a new f64 histogram with the given name, description, and unit. + fn create_histogram(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Histogram { + self.f64_histogram(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// A trait implemented by up-down-counter providers (e.g. `Meter`). +pub trait UpDownCounterProvider { + /// Creates a new up-down-counter with the given name, description, and unit. + fn create_up_down_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::UpDownCounter; +} + +/// This implementation specifies that a Meter is able to create i64 up-down-counters. +impl UpDownCounterProvider for opentelemetry::metrics::Meter { + /// Creates a new i64 up-down-counter with the given name, description, and unit. + fn create_up_down_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::UpDownCounter { + self.i64_up_down_counter(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// This implementation specifies that a Meter is able to create f64 up-down-counters. +impl UpDownCounterProvider for opentelemetry::metrics::Meter { + /// Creates a new f64 up-down-counter with the given name, description, and unit. + fn create_up_down_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::UpDownCounter { + self.f64_up_down_counter(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// A trait implemented by counter providers (e.g. `Meter`). +pub trait CounterProvider { + /// Creates a new counter with the given name, description, and unit. + fn create_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Counter; +} + +/// This implementation specifies that a Meter is able to create u64 counters. +impl CounterProvider for opentelemetry::metrics::Meter { + /// Creates a new u64 counter with the given name, description, and unit. + fn create_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Counter { + self.u64_counter(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// This implementation specifies that a Meter is able to create f64 counters. +impl CounterProvider for opentelemetry::metrics::Meter { + /// Creates a new f64 counter with the given name, description, and unit. + fn create_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Counter { + self.f64_counter(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// A trait implemented by gauge providers (e.g. `Meter`). +pub trait GaugeProvider { + /// Creates a new gauge with the given name, description, and unit. + fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge; +} + +/// This implementation specifies that a Meter is able to create u64 gauges. +impl GaugeProvider for opentelemetry::metrics::Meter { + /// Creates a new u64 gauge with the given name, description, and unit. + fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge { + self.u64_gauge(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// This implementation specifies that a Meter is able to create i64 gauges. +impl GaugeProvider for opentelemetry::metrics::Meter { + /// Creates a new i64 gauge with the given name, description, and unit. + fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge { + self.i64_gauge(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} + +/// This implementation specifies that a Meter is able to create f64 gauges. +impl GaugeProvider for opentelemetry::metrics::Meter { + /// Creates a new f64 gauge with the given name, description, and unit. + fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge { + self.f64_gauge(name) + .with_description(description) + .with_unit(opentelemetry::metrics::Unit::new(unit)) + .init() + } +} \ No newline at end of file diff --git a/crates/weaver_codegen_test/templates/registry/rust/weaver.yaml b/crates/weaver_codegen_test/templates/registry/rust/weaver.yaml new file mode 100644 index 00000000..eeb0fc6b --- /dev/null +++ b/crates/weaver_codegen_test/templates/registry/rust/weaver.yaml @@ -0,0 +1,156 @@ +type_mapping: + int: i64 + double: f64 + boolean: bool + string: String + string[]: Vec + template[string]: String # Not yet properly handled in codegen + template[string[]]: Vec # Not yet properly handled in codegen + +templates: + - pattern: README.md + filter: . + application_mode: single + - pattern: lib.rs + filter: . + application_mode: single + + # Templates for the `attribute_group` group type + - pattern: attributes/mod.rs.j2 + # The following JQ filter extracts the id, type, brief, and prefix of groups matching the following criteria: + # - groups with an id starting with the prefix `registry.` + # - groups of the type `attribute_group`. + # - groups are deduplicated by namespace. + # - groups are sorted by namespace. + filter: > + .groups + | map(select(.id | startswith("registry."))) + | map(select(.type == "attribute_group") + | { + id, + type, + brief, + prefix}) + | unique_by(.id | split(".") | .[1]) + | sort_by(.id | split(".") | .[1]) + application_mode: single + - pattern: attributes/attributes.rs.j2 + # The following JQ filter extracts the id, type, brief, prefix, and attributes of groups matching the following + # criteria: + # - groups with an id starting with the prefix `registry.` + # - groups of the type `attribute_group`. + # - groups are sorted by namespace. + filter: > + .groups + | map(select(.id | startswith("registry."))) + | map(select(.type == "attribute_group") + | { + id, + type, + brief, + prefix, + attributes}) + | group_by(.id | split(".") | .[1]) + | map({ + id: (map(select(.id | endswith(".deprecated") | not)) | first).id, + type: (map(select(.id | endswith(".deprecated") | not)) | first).type, + brief: (map(select(.id | endswith(".deprecated") | not)) | first).brief, + prefix: (map(select(.id | endswith(".deprecated") | not)) | first).prefix, + attributes: map(.attributes) | add + }) + | sort_by(.id | split(".") | .[1]) + application_mode: each + + # Templates for the `metric` group type + - pattern: metrics/mod.rs.j2 + # The following JQ filter extracts the id, type, brief, and prefix of groups matching the following criteria: + # - groups with an id starting with the prefix `metric.` + # - groups of the type `metric`. + # - groups are deduplicated by namespace. + # - groups are sorted by prefix. + filter: > + .groups + | map(select(.id | startswith("metric."))) + | map(select(.type == "metric") + | { + id, + type, + brief, + prefix}) + | unique_by(.id | split(".") | .[1]) + | sort_by(.id | split(".") | .[1]) + application_mode: single + - pattern: metrics/metrics.rs.j2 + # The following JQ filter extracts the id, type, brief, prefix, and attributes of groups matching the following + # criteria: + # - groups with an id starting with the prefix `metric.` + # - groups of the type `metric`. + # - groups are sorted by namespace. + filter: > + .groups + | map(select(.id | startswith("metric."))) + | group_by(.id | split(".") | .[1]) + | map({ + prefix: .[0].id | split(".") | .[1], + groups: . + }) + 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: +# - groups with an id starting with the prefix `registry.` +# - groups of the type `attribute_group`. +# - groups with a well-defined prefix. +# - groups with a non-empty list of attributes that are neither deprecated nor experimental. +# - groups are deduplicated by prefix. +# - groups are sorted by prefix. +# filter: > +# .groups +# | map(select(.id | startswith("registry."))) +# | map(select(.type == "attribute_group" and .prefix != null and .prefix != "") +# | { +# id, +# type, +# brief, +# prefix, +# attributes: (.attributes +# | map(select(.stability == "experimental" and .deprecated | not)))}) +# | map(select(.attributes | length > 0)) +# | map( +# { +# id, +# type, +# brief, +# prefix +# } +# ) +# | unique_by(.prefix) +# | sort_by(.prefix) + + +# The following JQ filter extracts the id, type, brief, prefix, and attributes of groups matching the following +# criteria: +# - groups with an id starting with the prefix `registry.` +# - groups of the type `attribute_group`. +# - groups with a well-defined prefix. +# - groups with a non-empty list of attributes that are neither deprecated nor experimental. +# - groups are sorted by prefix. +# filter: > +# .groups +# | map(select(.id | startswith("registry."))) +# | map(select(.type == "attribute_group" and .prefix != null and .prefix != "") +# | { +# id, +# type, +# brief, +# prefix, +# attributes: (.attributes | map(select(.stability == "experimental" and .deprecated | not)))}) +# | sort_by(.prefix // empty) \ No newline at end of file diff --git a/crates/weaver_codegen_test/tests/codegen.rs b/crates/weaver_codegen_test/tests/codegen.rs new file mode 100644 index 00000000..9021fe67 --- /dev/null +++ b/crates/weaver_codegen_test/tests/codegen.rs @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: Apache-2.0 + +//! Test code generation + +use opentelemetry::global; +use opentelemetry::metrics::Histogram; +use crate::attributes::client; +use crate::metrics::http::create_http_client_request_duration; +use crate::attributes::http::HTTP_REQUEST_METHOD; +use crate::metrics::http::HttpServerRequestDuration; +use crate::metrics::http::HttpServerRequestDurationReqAttributes; +use crate::metrics::http::HttpServerRequestDurationOptAttributes; +use crate::metrics::http::HttpClientActiveRequests; +use crate::metrics::http::HttpClientActiveRequestsReqAttributes; +use crate::metrics::system::SystemCpuTime; +use crate::metrics::system::SystemCpuTimeOptAttributes; +use crate::attributes::system::SystemCpuState; +use crate::metrics::system::SystemCpuUtilization; +use crate::metrics::system::SystemCpuUtilizationOptAttributes; + +pub mod attributes { + include!(concat!(env!("OUT_DIR"), "/attributes/mod.rs")); + pub mod client { + include!(concat!(env!("OUT_DIR"), "/attributes/client.rs")); + } + pub mod error { + include!(concat!(env!("OUT_DIR"), "/attributes/error.rs")); + } + pub mod exception { + include!(concat!(env!("OUT_DIR"), "/attributes/exception.rs")); + } + pub mod http { + include!(concat!(env!("OUT_DIR"), "/attributes/http.rs")); + } + pub mod network { + include!(concat!(env!("OUT_DIR"), "/attributes/network.rs")); + } + pub mod server { + include!(concat!(env!("OUT_DIR"), "/attributes/server.rs")); + } + pub mod system { + include!(concat!(env!("OUT_DIR"), "/attributes/system.rs")); + } + pub mod url { + include!(concat!(env!("OUT_DIR"), "/attributes/url.rs")); + } +} + +pub mod metrics { + include!(concat!(env!("OUT_DIR"), "/metrics/mod.rs")); + pub mod http { + include!(concat!(env!("OUT_DIR"), "/metrics/http.rs")); + } + pub mod system { + include!(concat!(env!("OUT_DIR"), "/metrics/system.rs")); + } +} + + use crate::attributes::http::HttpRequestMethod; + +#[test] +fn test_codegen() { + println!("{:?}", client::CLIENT_ADDRESS.value("145.34.23.56".into())); + println!("{:?}", client::CLIENT_ADDRESS.key()); + println!("{:?}", client::CLIENT_PORT.value(8080)); + println!("{:?}", client::CLIENT_PORT.key()); + + println!("{}", HttpRequestMethod::Connect); + + let meter = global::meter("mylibname"); + + // Create a u64 http.client.request.duration metric + let http_client_request_duration: Histogram = create_http_client_request_duration(&meter); + http_client_request_duration.record(100, &[ + HTTP_REQUEST_METHOD.value(&HttpRequestMethod::Connect), + // here nothing guarantees that all the required attributes are provided + ]); + + let http_client_request_duration: Histogram = create_http_client_request_duration(&meter); + dbg!(http_client_request_duration); + + // ==== A TYPE-SAFE HISTOGRAM API ==== + // Create a u64 http.server.request.duration metric (as defined in the OpenTelemetry HTTP + // semantic conventions) + let http_request_duration = HttpServerRequestDuration::::new(&meter); + + // Records a new data point and provide the required and some optional attributes + http_request_duration.record(100, &HttpServerRequestDurationReqAttributes { + http_request_method: HttpRequestMethod::Connect, + url_scheme: "http".to_owned(), + }, Some(&HttpServerRequestDurationOptAttributes { + http_response_status_code: Some(200), + ..Default::default() + })); + + // ==== A TYPE-SAFE UP-DOWN-COUNTER API ==== + // Create a f64 http.server.request.duration metric (as defined in the OpenTelemetry HTTP + // semantic conventions) + let http_client_active_requests = HttpClientActiveRequests::::new(&meter); + + // Adds a new data point and provide the required attributes. Optional attributes are not + // provided in this example. + http_client_active_requests.add(10.0, &HttpClientActiveRequestsReqAttributes { + server_address: "10.0.0.1".to_owned(), + server_port: 8080, + }, None); + + // ==== A TYPE-SAFE COUNTER API ==== + // Create a f64 system.cpu.time metric (as defined in the OpenTelemetry System semantic + // conventions) + let system_cpu_time = SystemCpuTime::::new(&meter); + + // Adds a new data point and provide some optional attributes. + // Note: In the method signature, there is no required attribute. + system_cpu_time.add(10.0, Some(&SystemCpuTimeOptAttributes { + system_cpu_logical_number: Some(0), + system_cpu_state: Some(SystemCpuState::Idle) + })); + // Adds a new data point with a custom CPU state. + system_cpu_time.add(20.0, Some(&SystemCpuTimeOptAttributes { + system_cpu_logical_number: Some(0), + system_cpu_state: Some(SystemCpuState::_Custom("custom".to_owned())) + })); + + // ==== A TYPE-SAFE GAUGE API ==== + // Create a i64 system.cpu.utilization metric (as defined in the OpenTelemetry System semantic + // conventions) + let system_cpu_utilization = SystemCpuUtilization::::new(&meter); + + // Adds a new data point with no optional attributes. + system_cpu_utilization.record(-5, None); + // Adds a new data point with some optional attributes. + system_cpu_utilization.record(10, Some(&SystemCpuUtilizationOptAttributes { + system_cpu_logical_number: Some(0), + system_cpu_state: Some(SystemCpuState::Idle) + })); + + // All the tests passed, remove the generated files + //remove_generated_files(); +} \ No newline at end of file diff --git a/crates/weaver_common/src/in_memory.rs b/crates/weaver_common/src/in_memory.rs new file mode 100644 index 00000000..1cf20a86 --- /dev/null +++ b/crates/weaver_common/src/in_memory.rs @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: Apache-2.0 + +//! In-memory logger implementation. +//! Can be used in tests and build.rs scripts. + +use std::sync::{Arc, Mutex}; + +/// An in-memory log message. +#[derive(Debug, Clone)] +pub enum LogMessage { + /// A trace message. + Trace(String), + /// An info message. + Info(String), + /// A warning message. + Warn(String), + /// An error message. + Error(String), + /// A success message. + Success(String), + /// A loading message. + Loading(String), + /// A log message. + Log(String), +} + +/// A logger that can be used in tests or build.rs scripts. +/// This logger is thread-safe and can be cloned. +#[derive(Default, Clone)] +pub struct Logger { + messages: Arc>>, + debug_level: u8, +} + +impl Logger { + /// Creates a new logger. + #[must_use] + pub fn new(debug_level: u8) -> Self { + Logger { + messages: Arc::new(Mutex::new(Vec::new())), + debug_level, + } + } + + /// Returns the number of warning messages logged. + #[must_use] + pub fn warn_count(&self) -> usize { + self.messages.lock().expect("Failed to lock messages") + .iter() + .filter(|m| matches!(m, LogMessage::Warn(_))) + .count() + } + + /// Returns the number of error messages logged. + #[must_use] + pub fn error_count(&self) -> usize { + self.messages.lock().expect("Failed to lock messages") + .iter() + .filter(|m| matches!(m, LogMessage::Error(_))) + .count() + } + + /// Returns the recorded log messages. + #[must_use] + pub fn messages(&self) -> Vec { + self.messages.lock().expect("Failed to lock messages").clone() + } +} + +impl crate::Logger for Logger { + /// Logs a trace message (only with debug enabled). + fn trace(&self, message: &str) { + if self.debug_level > 0 { + self.messages.lock().expect("Failed to lock messages") + .push(LogMessage::Trace(message.to_owned())); + } + } + + /// Logs an info message. + fn info(&self, message: &str) { + self.messages.lock().expect("Failed to lock messages") + .push(LogMessage::Info(message.to_owned())); + } + + /// Logs a warning message. + fn warn(&self, message: &str) { + self.messages.lock().expect("Failed to lock messages") + .push(LogMessage::Warn(message.to_owned())); + } + + /// Logs an error message. + fn error(&self, message: &str) { + self.messages.lock().expect("Failed to lock messages") + .push(LogMessage::Error(message.to_owned())); + } + + /// Logs a success message. + fn success(&self, message: &str) { + self.messages.lock().expect("Failed to lock messages") + .push(LogMessage::Success(message.to_owned())); + } + + /// Logs a newline. + fn newline(&self, _count: usize) {} + + /// Indents the logger. + fn indent(&self, _count: usize) {} + + /// Stops a loading message. + fn done(&self) {} + + /// Adds a style to the logger. + fn add_style(&self, _name: &str, _styles: Vec<&'static str>) -> &Self { self } + + /// Logs a loading message with a spinner. + fn loading(&self, message: &str) { + self.messages.lock().expect("Failed to lock messages") + .push(LogMessage::Loading(message.to_owned())); + } + + /// Forces the logger to not print a newline for the next message. + fn same(&self) -> &Self { self } + + /// Logs a message without icon. + fn log(&self, message: &str) { + self.messages.lock().expect("Failed to lock messages") + .push(LogMessage::Log(message.to_owned())); + } +} diff --git a/crates/weaver_common/src/lib.rs b/crates/weaver_common/src/lib.rs index 796c639f..1d4e2edf 100644 --- a/crates/weaver_common/src/lib.rs +++ b/crates/weaver_common/src/lib.rs @@ -5,6 +5,7 @@ pub mod diag; pub mod error; pub mod quiet; +pub mod in_memory; use std::sync::atomic::AtomicUsize; use std::sync::{Arc, Mutex}; From 423111b5bf1873027e69080c79d58daa2284c42b Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Mon, 6 May 2024 18:41:01 -0700 Subject: [PATCH 32/39] chore(forge): Create code generation test infrastructure --- crates/weaver_codegen_test/Cargo.toml | 1 + crates/weaver_codegen_test/build.rs | 92 ++++++++++++++++++--- crates/weaver_codegen_test/tests/codegen.rs | 43 +--------- 3 files changed, 85 insertions(+), 51 deletions(-) diff --git a/crates/weaver_codegen_test/Cargo.toml b/crates/weaver_codegen_test/Cargo.toml index 753832ff..5f30ac3c 100644 --- a/crates/weaver_codegen_test/Cargo.toml +++ b/crates/weaver_codegen_test/Cargo.toml @@ -23,6 +23,7 @@ walkdir.workspace = true opentelemetry = { version = "0.22.0", features = ["trace", "metrics", "logs", "otel_unstable"] } opentelemetry_sdk = { version = "0.22.1", features = ["trace", "metrics", "logs"] } opentelemetry-stdout = { version = "0.3.0", features = ["trace", "metrics", "logs"] } +walkdir.workspace = true [dev-dependencies] walkdir.workspace = true diff --git a/crates/weaver_codegen_test/build.rs b/crates/weaver_codegen_test/build.rs index 9e45980f..11cb0079 100644 --- a/crates/weaver_codegen_test/build.rs +++ b/crates/weaver_codegen_test/build.rs @@ -4,6 +4,8 @@ //! the templates in `templates/registry/rust` and the mini //! semantic conventions registry in `semconv_registry`. +use std::collections::HashMap; +use std::io::Write; use std::path::{Path, PathBuf}; use std::process::exit; use weaver_cache::Cache; @@ -69,25 +71,93 @@ fn main() { alter_generated_files(output.as_path()); } -/// Alter all the generated files to replace //! comments with standard // comments -fn alter_generated_files(path: &Path) { - let walker = walkdir::WalkDir::new(path); +fn alter_generated_files(root: &Path) { + let walker = walkdir::WalkDir::new(root); + let mut root_module = Module { + name: "".to_string(), + content: "".to_string(), + sub_modules: HashMap::new(), + }; + for entry in walker { let entry = entry.unwrap(); let path = entry.path(); - if path.is_file() { + // Only process files with the .rs extension that contain the generated comment + if path.is_file() && path.extension().map_or(false, |ext| ext == "rs") { let file_content = std::fs::read_to_string(path).unwrap(); if file_content.contains("DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER") { - println!("cargo:warning=Altering `{}`", path.display()); - let new_file = file_content.replace("//!", "//"); - // remove line starting with pub mod - let new_file = new_file.lines().filter(|line| !line.starts_with("pub mod")).collect::>().join("\n"); - std::fs::write(path, new_file).unwrap(); - } else { - println!("cargo:warning=Skipping `{}`", path.display()); + let relative_path = path.strip_prefix(root).expect("Failed to strip prefix"); + let file_name = path.file_stem().unwrap().to_str().unwrap(); + let parent_modules = relative_path.parent().map_or(vec![], |parent| { + let parent = parent.display().to_string(); + if parent == "" { + return vec![]; + } else { + parent.split('/').map(|s| s.to_string()).collect::>() + } + }); + + // Skip generated.rs + if file_name == "generated" { + continue; + } + + // Replace //! with // + let new_file_content = file_content.replace("//!", "//"); + // Remove line starting with pub mod + let new_file = new_file_content.lines().filter(|line| !line.starts_with("pub mod")).collect::>().join("\n"); + + add_modules(&mut root_module, parent_modules.clone(), file_name.to_string(), new_file); } } } + + let mut output = std::fs::File::create(root.join("generated.rs")).unwrap(); + output.write_all(root_module.generate().as_bytes()).unwrap(); + // println!("cargo:warning=Generated file: {}", root.join("generated.rs").display()); +} + +struct Module { + name: String, + content: String, + sub_modules: HashMap, +} + +impl Module { + pub fn generate(&self) -> String { + let mut content = String::new(); + + content.push_str(&self.content); + + for module in self.sub_modules.values() { + content.push_str(&format!("\npub mod {} {{\n", module.name)); + content.push_str(&module.generate()); + content.push_str("\n}\n"); + } + content + } +} + +fn add_modules(root_module: &mut Module, parent_modules: Vec, file_name: String, file_content: String) { + let mut current_module = root_module; + for module_name in parent_modules.iter() { + let module = current_module.sub_modules.entry(module_name.clone()).or_insert(Module { + name: module_name.clone(), + content: "".to_owned(), + sub_modules: HashMap::new(), + }); + current_module = module; + } + + if file_name == "mod" || file_name == "lib" { + current_module.content = file_content; + } else { + _ = current_module.sub_modules.insert(file_name.clone(), Module { + name: file_name.clone(), + content: file_content, + sub_modules: HashMap::new(), + }); + } } fn print_logs(logger: &in_memory::Logger) { diff --git a/crates/weaver_codegen_test/tests/codegen.rs b/crates/weaver_codegen_test/tests/codegen.rs index 9021fe67..7db96ceb 100644 --- a/crates/weaver_codegen_test/tests/codegen.rs +++ b/crates/weaver_codegen_test/tests/codegen.rs @@ -2,6 +2,8 @@ //! Test code generation +include!(concat!(env!("OUT_DIR"), "/generated.rs")); + use opentelemetry::global; use opentelemetry::metrics::Histogram; use crate::attributes::client; @@ -17,46 +19,7 @@ use crate::metrics::system::SystemCpuTimeOptAttributes; use crate::attributes::system::SystemCpuState; use crate::metrics::system::SystemCpuUtilization; use crate::metrics::system::SystemCpuUtilizationOptAttributes; - -pub mod attributes { - include!(concat!(env!("OUT_DIR"), "/attributes/mod.rs")); - pub mod client { - include!(concat!(env!("OUT_DIR"), "/attributes/client.rs")); - } - pub mod error { - include!(concat!(env!("OUT_DIR"), "/attributes/error.rs")); - } - pub mod exception { - include!(concat!(env!("OUT_DIR"), "/attributes/exception.rs")); - } - pub mod http { - include!(concat!(env!("OUT_DIR"), "/attributes/http.rs")); - } - pub mod network { - include!(concat!(env!("OUT_DIR"), "/attributes/network.rs")); - } - pub mod server { - include!(concat!(env!("OUT_DIR"), "/attributes/server.rs")); - } - pub mod system { - include!(concat!(env!("OUT_DIR"), "/attributes/system.rs")); - } - pub mod url { - include!(concat!(env!("OUT_DIR"), "/attributes/url.rs")); - } -} - -pub mod metrics { - include!(concat!(env!("OUT_DIR"), "/metrics/mod.rs")); - pub mod http { - include!(concat!(env!("OUT_DIR"), "/metrics/http.rs")); - } - pub mod system { - include!(concat!(env!("OUT_DIR"), "/metrics/system.rs")); - } -} - - use crate::attributes::http::HttpRequestMethod; +use crate::attributes::http::HttpRequestMethod; #[test] fn test_codegen() { From 1306e6a0fae430eec126ed73cf639157e40d52ce Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Mon, 6 May 2024 23:42:05 -0700 Subject: [PATCH 33/39] chore(forge): Create code generation test infrastructure --- Cargo.lock | 43 +- crates/weaver_codegen_test/Cargo.toml | 9 +- crates/weaver_codegen_test/README.md | 230 +------ crates/weaver_codegen_test/build.rs | 179 +++-- crates/weaver_codegen_test/src/lib.rs | 6 + crates/weaver_codegen_test/src/main.rs | 7 - .../templates/registry/rust/README.md | 382 ----------- .../registry/rust/attribute_macros.j2 | 4 +- .../registry/rust/attributes/attributes.rs.j2 | 2 + .../registry/rust/attributes/mod.rs.j2 | 6 + .../templates/registry/rust/lib.rs | 13 - .../rust/metrics/instruments/counter.j2 | 4 +- .../rust/metrics/instruments/gauge.j2 | 4 +- .../rust/metrics/instruments/histogram.j2 | 4 +- .../rust/metrics/instruments/updowncounter.j2 | 4 +- crates/weaver_codegen_test/tests/codegen.rs | 152 +++-- crates/weaver_common/src/in_memory.rs | 49 +- crates/weaver_common/src/lib.rs | 2 +- .../expected_codegen/README.md | 20 - .../expected_codegen/attributes/client.rs | 27 - .../expected_codegen/attributes/error.rs | 75 --- .../expected_codegen/attributes/exception.rs | 47 -- .../expected_codegen/attributes/http.rs | 220 ------ .../expected_codegen/attributes/mod.rs | 76 --- .../expected_codegen/attributes/network.rs | 628 ------------------ .../expected_codegen/attributes/server.rs | 29 - .../expected_codegen/attributes/system.rs | 150 ----- .../expected_codegen/attributes/url.rs | 127 ---- .../codegen_examples/expected_codegen/lib.rs | 10 - .../expected_codegen/metrics/http.rs | 488 -------------- .../expected_codegen/metrics/mod.rs | 136 ---- .../expected_codegen/metrics/system.rs | 190 ------ .../http-common.yaml | 0 .../metrics/http.yaml | 0 .../metrics/system-metrics.yaml | 0 .../registry/client.yaml | 0 .../registry/deprecated/network.yaml | 0 .../registry/error.yaml | 0 .../registry/exception.yaml | 0 .../registry/http.yaml | 0 .../registry/network.yaml | 0 .../registry/server.yaml | 0 .../registry/system.yaml | 0 .../registry/url.yaml | 0 .../registry/rust/attribute_macros.j2 | 4 +- .../registry/rust/attributes/attributes.rs.j2 | 4 +- .../registry/rust/attributes/mod.rs.j2 | 6 + .../rust/metrics/instruments/counter.j2 | 8 +- .../rust/metrics/instruments/gauge.j2 | 8 +- .../rust/metrics/instruments/histogram.j2 | 8 +- .../rust/metrics/instruments/updowncounter.j2 | 7 +- crates/weaver_forge/src/debug.rs | 2 +- crates/weaver_forge/src/extensions/otel.rs | 2 +- crates/weaver_forge/tests/README.md | 381 ----------- .../weaver_forge/tests/attributes/client.rs | 27 - crates/weaver_forge/tests/attributes/error.rs | 75 --- .../tests/attributes/exception.rs | 47 -- crates/weaver_forge/tests/attributes/http.rs | 220 ------ crates/weaver_forge/tests/attributes/mod.rs | 76 --- .../weaver_forge/tests/attributes/network.rs | 628 ------------------ .../weaver_forge/tests/attributes/server.rs | 29 - .../weaver_forge/tests/attributes/system.rs | 139 ---- crates/weaver_forge/tests/attributes/url.rs | 127 ---- crates/weaver_forge/tests/codegen.rs | 95 --- crates/weaver_forge/tests/lib.rs | 10 - crates/weaver_forge/tests/metrics/http.rs | 486 -------------- crates/weaver_forge/tests/metrics/mod.rs | 136 ---- crates/weaver_forge/tests/metrics/system.rs | 181 ----- docs/images/dependencies.svg | 84 +-- 69 files changed, 380 insertions(+), 5733 deletions(-) create mode 100644 crates/weaver_codegen_test/src/lib.rs delete mode 100644 crates/weaver_codegen_test/src/main.rs delete mode 100644 crates/weaver_codegen_test/templates/registry/rust/README.md delete mode 100644 crates/weaver_codegen_test/templates/registry/rust/lib.rs delete mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/README.md delete mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/attributes/client.rs delete mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/attributes/error.rs delete mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/attributes/exception.rs delete mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/attributes/http.rs delete mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/attributes/mod.rs delete mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/attributes/network.rs delete mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/attributes/server.rs delete mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/attributes/system.rs delete mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/attributes/url.rs delete mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/lib.rs delete mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/metrics/http.rs delete mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/metrics/mod.rs delete mode 100644 crates/weaver_forge/codegen_examples/expected_codegen/metrics/system.rs rename crates/weaver_forge/codegen_examples/{mini_registry => semconv_registry}/http-common.yaml (100%) rename crates/weaver_forge/codegen_examples/{mini_registry => semconv_registry}/metrics/http.yaml (100%) rename crates/weaver_forge/codegen_examples/{mini_registry => semconv_registry}/metrics/system-metrics.yaml (100%) rename crates/weaver_forge/codegen_examples/{mini_registry => semconv_registry}/registry/client.yaml (100%) rename crates/weaver_forge/codegen_examples/{mini_registry => semconv_registry}/registry/deprecated/network.yaml (100%) rename crates/weaver_forge/codegen_examples/{mini_registry => semconv_registry}/registry/error.yaml (100%) rename crates/weaver_forge/codegen_examples/{mini_registry => semconv_registry}/registry/exception.yaml (100%) rename crates/weaver_forge/codegen_examples/{mini_registry => semconv_registry}/registry/http.yaml (100%) rename crates/weaver_forge/codegen_examples/{mini_registry => semconv_registry}/registry/network.yaml (100%) rename crates/weaver_forge/codegen_examples/{mini_registry => semconv_registry}/registry/server.yaml (100%) rename crates/weaver_forge/codegen_examples/{mini_registry => semconv_registry}/registry/system.yaml (100%) rename crates/weaver_forge/codegen_examples/{mini_registry => semconv_registry}/registry/url.yaml (100%) delete mode 100644 crates/weaver_forge/tests/README.md delete mode 100644 crates/weaver_forge/tests/attributes/client.rs delete mode 100644 crates/weaver_forge/tests/attributes/error.rs delete mode 100644 crates/weaver_forge/tests/attributes/exception.rs delete mode 100644 crates/weaver_forge/tests/attributes/http.rs delete mode 100644 crates/weaver_forge/tests/attributes/mod.rs delete mode 100644 crates/weaver_forge/tests/attributes/network.rs delete mode 100644 crates/weaver_forge/tests/attributes/server.rs delete mode 100644 crates/weaver_forge/tests/attributes/system.rs delete mode 100644 crates/weaver_forge/tests/attributes/url.rs delete mode 100644 crates/weaver_forge/tests/codegen.rs delete mode 100644 crates/weaver_forge/tests/lib.rs delete mode 100644 crates/weaver_forge/tests/metrics/http.rs delete mode 100644 crates/weaver_forge/tests/metrics/mod.rs delete mode 100644 crates/weaver_forge/tests/metrics/system.rs diff --git a/Cargo.lock b/Cargo.lock index 7ab3c66d..265c0782 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -112,9 +112,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.82" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" +checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" [[package]] name = "arc-swap" @@ -2158,11 +2158,10 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" dependencies = [ - "autocfg", "num-integer", "num-traits", ] @@ -2486,9 +2485,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" dependencies = [ "unicode-ident", ] @@ -2823,9 +2822,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -2870,9 +2869,9 @@ checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a" [[package]] name = "semver" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" dependencies = [ "serde", ] @@ -3078,9 +3077,9 @@ checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" [[package]] name = "syn" -version = "2.0.60" +version = "2.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +checksum = "c993ed8ccba56ae856363b1845da7266a7cb78e1d146c8a32d54b45a8b831fc9" dependencies = [ "proc-macro2", "quote", @@ -3159,18 +3158,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.59" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" +checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.59" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" +checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" dependencies = [ "proc-macro2", "quote", @@ -3639,8 +3638,6 @@ name = "weaver_codegen_test" version = "0.1.0" dependencies = [ "opentelemetry", - "opentelemetry-stdout", - "opentelemetry_sdk", "walkdir", "weaver_cache", "weaver_common", @@ -3991,18 +3988,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.33" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "087eca3c1eaf8c47b94d02790dd086cd594b912d2043d4de4bfdd466b3befb7c" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.33" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f4b6c273f496d8fd4eaf18853e6b448760225dc030ff2c485a786859aea6393" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", diff --git a/crates/weaver_codegen_test/Cargo.toml b/crates/weaver_codegen_test/Cargo.toml index 5f30ac3c..15643f12 100644 --- a/crates/weaver_codegen_test/Cargo.toml +++ b/crates/weaver_codegen_test/Cargo.toml @@ -20,11 +20,4 @@ weaver_semconv = { path = "../weaver_semconv" } walkdir.workspace = true [dependencies] -opentelemetry = { version = "0.22.0", features = ["trace", "metrics", "logs", "otel_unstable"] } -opentelemetry_sdk = { version = "0.22.1", features = ["trace", "metrics", "logs"] } -opentelemetry-stdout = { version = "0.3.0", features = ["trace", "metrics", "logs"] } -walkdir.workspace = true - -[dev-dependencies] -walkdir.workspace = true - +opentelemetry = { version = "0.22.0", features = ["trace", "metrics", "logs", "otel_unstable"] } \ No newline at end of file diff --git a/crates/weaver_codegen_test/README.md b/crates/weaver_codegen_test/README.md index f27ef8e6..b67a0da7 100644 --- a/crates/weaver_codegen_test/README.md +++ b/crates/weaver_codegen_test/README.md @@ -1,227 +1,7 @@ -# Weaver Forge - Template Engine +# Weaver CodeGen Test -- [Introduction](#introduction) -- [Template Directory Structure and Naming Conventions](#template-directory-structure-and-naming-conventions) -- [Configuration File - `weaver.yaml`](#configuration-file---weaveryaml) -- [Jinja Filters](#jinja-filters) -- [Jinja Functions](#jinja-functions) -- [Jinja Tests](#jinja-tests) +This crate is used to test the generation of an unofficial Rust OpenTelemetry Client API derived from a semantic +convention registry. This crate is not intended to be published. It is used solely for testing and validation purposes. -## Introduction - -OTel Weaver is capable of generating documentation or code from a semantic -convention registry or a telemetry schema (phase 2). To do this, -OTel Weaver uses a template engine compatible with the Jinja2 syntax (see the -[MiniJinja](https://github.com/mitsuhiko/minijinja) project for more details). -A set of filters, functions, tests, and naming conventions have been added to -the classic Jinja logic to make the task easier for template authors. - -The following diagram illustrates the documentation and code generation pipeline -using the OTel Weaver tool: - -![Weaver Forge](images/artifact-generation-pipeline.svg) - -## Template Directory Structure and Naming Conventions - -By default, the OTel Weaver tool expects to find a templates directory in the -current directory. - -```plaintext -templates/ - registry/ - go/ <-- Templates to generate the semantic conventions in Go - ... - html/ <-- Templates to generate the semantic conventions in HTML - ... - markdown/ <-- Templates to generate the semantic conventions in markdown - ... - rust/ <-- Templates to generate the semantic conventions in Rust - ... - go/ <-- Templates to generate the semantic conventions in Go - ... - schema/ - sdk-go/ <-- Templates to generate a Go Client SDK derived from the telemetry schema - ... - sdk-rust/ <-- Templates to generate a Rust Client SDK derived from the telemetry schema - ... -``` - -The command `weaver generate registry markdown` will generate the markdown -files based on the templates located in the `templates/registry/markdown`. - -When the name of a file (excluding the extension) matches a recognized pattern -(e.g., attribute_group, groups, ...), OTel Weaver extracts the objects from the -registry and passes them to the template at the time of its evaluation. -Depending on the nature of the pattern, the template is evaluated as many times -as there are objects that match or only once if the pattern corresponds to a -set of objects. By default, the name of the file that will be generated from -the template will be that of the template, but it is possible within the -template to dynamically redefine the name of the produced file. - -For example, the following snippet redefine the name of the file that will be -produced from the template: - -```jinja -{%- set file_name = group.id | file_name -%} -{{- template.set_file_name("span/" ~ file_name ~ ".md") -}} -``` - -This mechanism allows the template to dynamically generate the name of the file -to be produced and to organize the generated files in a directory structure of -its choice. - -## Configuration File - `weaver.yaml` - -The configuration file `weaver.yaml` is optional. It allows configuring the -following options: - -```yaml -# Configuration of the type mapping. This is useful to generate code in a -# specific language. This is optional. -# Example: {{ attribute.type | type_mapping }} will be evaluated as int64 -# if the semconv attribute type is int. -#type_mapping: -# int: int64 -# double: double -# boolean: bool -# string: string -# "int[]": "[]int64" -# "double[]": "[]double" -# "boolean[]": "[]bool" -# "string[]": "[]string" -# ... - -# Configuration of the template engine (optional) -#template_syntax: -# block_start: "{%" -# block_end: "%}" -# variable_start: "{{" -# variable_end: "}}" -# comment_start: "{#" -# comment_end: "#}" - -# Please uncomment the following section to specify a list of acronyms that -# will be interpreted by the acronym filter. This is optional. -# acronyms: ["iOS", "HTTP", "API", "SDK", "CLI", "URL", "JSON", "XML", "HTML"] - -# Please uncomment the following templates to override the default template -# mapping. Each template mapping specifies a jaq filter (compatible with jq) -# to apply to every file matching the pattern. The application_mode specifies -# how the template should be applied. The application_mode can be `each` or -# `single`. The `each` mode will evaluate the template for each object selected -# by the jaq filter. The `single` mode will evaluate the template once with all -# the objects selected by the jq filter. -# -# Note: jaq is a Rust reimplementation of jq. Most of the jq filters are -# supported. For more information, see https://github.com/01mf02/jaq -# -# templates: -# - pattern: "**/registry.md" -# filter: "." -# application_mode: single -# - pattern: "**/attribute_group.md" -# filter: ".groups[] | select(.type == \"attribute_group\")" -# application_mode: each -# - pattern: "**/attribute_groups.md" -# filter: ".groups[] | select(.type == \"attribute_group\")" -# application_mode: single -# - pattern: "**/event.md" -# filter: ".groups[] | select(.type == \"event\")" -# application_mode: each -# - pattern: "**/events.md" -# filter: ".groups[] | select(.type == \"event\")" -# application_mode: single -# - pattern: "**/group.md" -# filter: ".groups[] | select(.type == \"group\")" -# application_mode: each -# - pattern: "**/groups.md" -# filter: ".groups[] | select(.type == \"group\")" -# application_mode: single -# - pattern: "**/metric.md" -# filter: ".groups[] | select(.type == \"metric\")" -# application_mode: each -# - pattern: "**/metrics.md" -# filter: ".groups[] | select(.type == \"metric\")" -# application_mode: single -# - pattern: "**/metric_group.md" -# filter: ".groups[] | select(.type == \"metric_group\")" -# application_mode: each -# - pattern: "**/metric_groups.md" -# filter: ".groups[] | select(.type == \"metric_group\")" -# application_mode: single -# - pattern: "**/resource.md" -# filter: ".groups[] | select(.type == \"resource\")" -# application_mode: each -# - pattern: "**/resources.md" -# filter: ".groups[] | select(.type == \"resource\")" -# application_mode: single -# - pattern: "**/scope.md" -# filter: ".groups[] | select(.type == \"scope\")" -# application_mode: each -# - pattern: "**/scopes.md" -# filter: ".groups[] | select(.type == \"scope\")" -# application_mode: single -# - pattern: "**/span.md" -# filter: ".groups[] | select(.type == \"span\")" -# application_mode: each -# - pattern: "**/spans.md" -# filter: ".groups[] | select(.type == \"span\")" -# application_mode: single -``` - -## Jinja Filters - -All the filters available in the MiniJinja template engine are available (see -this online [documentation](https://docs.rs/minijinja/latest/minijinja/filters/index.html)). - -In addition, OTel Weaver provides a set of custom filters to facilitate the -generation of documentation and code. - -The following filters are available: -- `lower_case`: Converts a string to lowercase. -- `upper_case`: Converts a string to UPPERCASE. -- `title_case`: Converts a string to TitleCase. -- `pascal_case`: Converts a string to PascalCase. -- `camel_case`: Converts a string to camelCase. -- `snake_case`: Converts a string to snake_case. -- `screaming_snake_case`: Converts a string to SCREAMING_SNAKE_CASE. -- `kebab_case`: Converts a string to kebab-case. -- `screaming_kebab_case`: Converts a string to SCREAMING-KEBAB-CASE. -- `acronym`: Replaces acronyms in the input string with the full name defined in the `acronyms` section of the `weaver.yaml` configuration file. -- `split_ids`: Splits a string by '.' creating a list of nested ids. -- `type_mapping`: Converts a semantic convention type to a target type (see weaver.yaml section `type_mapping`). -- `comment_with_prefix(prefix)`: Outputs a multiline comment with the given prefix. -- `flatten`: Converts a List of Lists into a single list with all elements. -e.g. \[\[a,b\],\[c\]\] => \[a,b,c\] -- `attribute_sort`: Sorts a list of `Attribute`s by requirement level, then name. -- `metric_namespace`: Converts registry.{namespace}.{other}.{components} to {namespace}. -- `attribute_registry_file`: Converts registry.{namespace}.{other}.{components} to attributes-registry/{namespace}.md (kebab-case namespace). -- `attribute_registry_title`: Converts registry.{namespace}.{other}.{components} to {Namespace} (title case the namespace). -- `attribute_registry_namespace`: Converts metric.{namespace}.{other}.{components} to {namespace}. -- `attribute_namespace`: Converts {namespace}.{attribute_id} to {namespace}. -- `required`: Filters a list of `Attribute`s to include only the required attributes. The "conditionally_required" attributes are not returned by this filter. -- `not_required`: Filters a list of `Attribute`s to only include non-required attributes. The "conditionally_required" attributes are returned by this filter. - -> Please open an issue if you have any suggestions for new filters. They are easy to implement. - -## Jinja Functions - -All the functions available in the MiniJinja template engine are available (see -this online [documentation](https://docs.rs/minijinja/latest/minijinja/functions/index.html)). - -Right now, OTel Weaver does not provide any custom functions but feel free to -open an issue if you have any suggestions. They are easy to implement. - -## Jinja Tests - -All the tests available in the MiniJinja template engine are available (see -this online [documentation](https://docs.rs/minijinja/latest/minijinja/tests/index.html)). - -In addition, OTel Weaver provides a set of custom tests to facilitate the -generation of assets. - -- `stable`: Tests if an `Attribute` is stable. -- `experimental`: Tests if an `Attribute` is experimental. -- `deprecated`: Tests if an `Attribute` is deprecated. - -> Please open an issue if you have any suggestions for new tests. They are easy to implement. \ No newline at end of file +The generated Rust API client exposes a type-safe API (i.e., one that cannot be misused) that adheres to the signal +specification defined in the semantic convention registry located in the semconv_registry directory. \ No newline at end of file diff --git a/crates/weaver_codegen_test/build.rs b/crates/weaver_codegen_test/build.rs index 11cb0079..888c97ae 100644 --- a/crates/weaver_codegen_test/build.rs +++ b/crates/weaver_codegen_test/build.rs @@ -1,120 +1,146 @@ // SPDX-License-Identifier: Apache-2.0 -//! Generate code for the Semantic Conventions Rust API based on -//! the templates in `templates/registry/rust` and the mini -//! semantic conventions registry in `semconv_registry`. +//! This `build.rs` generates code for the local semantic convention registry located in the +//! `semconv_registry` directory. The templates used for code generation are located in the +//! `templates/registry/rust` directory. The generated code is produced in the `OUT_DIR` directory +//! specified by Cargo. This generation step occurs before the standard build of the crate. The +//! generated code, along with the standard crate code, will be compiled together. use std::collections::HashMap; use std::io::Write; use std::path::{Path, PathBuf}; use std::process::exit; use weaver_cache::Cache; -use weaver_common::{in_memory, Logger}; use weaver_common::in_memory::LogMessage; -use weaver_forge::{GeneratorConfig, TemplateEngine}; +use weaver_common::{in_memory, Logger}; use weaver_forge::registry::TemplateRegistry; +use weaver_forge::{GeneratorConfig, TemplateEngine}; use weaver_resolver::SchemaResolver; use weaver_semconv::path::RegistryPath; use weaver_semconv::registry::SemConvRegistry; +const SEMCONV_REGISTRY_PATH: &str = "./semconv_registry/"; +const TEMPLATES_PATH: &str = "./templates/"; +const REGISTRY_ID: &str = "test"; +const TARGET: &str = "rust"; + fn main() { + // Tell Cargo when to rerun this build script println!("cargo:rerun-if-changed=templates/registry/rust"); println!("cargo:rerun-if-changed=semconv_registry"); println!("cargo:rerun-if-changed=build.rs"); - let target_dir = std::env::var("OUT_DIR").unwrap(); + // Get the output directory from Cargo + let target_dir = std::env::var("OUT_DIR").expect("Failed to get OUT_DIR from Cargo"); + // Create an in-memory logger as stdout and stderr are not "classically" available in build.rs. let logger = in_memory::Logger::new(0); - let cache = Cache::try_new().unwrap_or_else(|e| { - process_error(&logger, e) - }); + + // Load and resolve the semantic convention registry + let cache = Cache::try_new().unwrap_or_else(|e| process_error(&logger, e)); let registry_path = RegistryPath::Local { - path_pattern: "./semconv_registry/".into(), + path_pattern: SEMCONV_REGISTRY_PATH.into(), }; - - let semconv_specs = SchemaResolver::load_semconv_specs(®istry_path, &cache).unwrap_or_else(|e| { - process_error(&logger, e) - }); - - let registry_id = "test"; - let mut registry = SemConvRegistry::from_semconv_specs(registry_id, semconv_specs); + let semconv_specs = SchemaResolver::load_semconv_specs(®istry_path, &cache) + .unwrap_or_else(|e| process_error(&logger, e)); + let mut registry = SemConvRegistry::from_semconv_specs(REGISTRY_ID, semconv_specs); let schema = SchemaResolver::resolve_semantic_convention_registry(&mut registry) - .unwrap_or_else(|e| { - process_error(&logger, e) - }); - let config = GeneratorConfig::new("./templates/".into()); - - let engine = TemplateEngine::try_new("registry/rust", config) - .unwrap_or_else(|e| { - process_error(&logger, e) - }); + .unwrap_or_else(|e| process_error(&logger, e)); + let config = GeneratorConfig::new(TEMPLATES_PATH.into()); + let engine = TemplateEngine::try_new(&format!("registry/{}", TARGET), config) + .unwrap_or_else(|e| process_error(&logger, e)); let template_registry = TemplateRegistry::try_from_resolved_registry( schema - .registry(registry_id) + .registry(REGISTRY_ID) .expect("Failed to get the registry from the resolved schema"), schema.catalog(), ) - .unwrap_or_else(|e| { - process_error(&logger, e) - }); - - let output: PathBuf = target_dir.into(); + .unwrap_or_else(|e| process_error(&logger, e)); + let target_dir: PathBuf = target_dir.into(); engine - .generate(logger.clone(), &template_registry, output.as_path()) - .unwrap_or_else(|e| { - process_error(&logger, e) - }); + .generate(logger.clone(), &template_registry, target_dir.as_path()) + .unwrap_or_else(|e| process_error(&logger, e)); print_logs(&logger); - alter_generated_files(output.as_path()); + // For the purpose of the integration test located in `tests/codegen.rs`, we need to: + // - Combine all generated files to form a single file containing all the generated code + // organized in nested modules. + // - Replace `//!` with `//` + // - Remove `pub mod` lines + create_single_generated_rs_file(target_dir.as_path()); } -fn alter_generated_files(root: &Path) { - let walker = walkdir::WalkDir::new(root); +/// Create a single generated.rs file containing all the generated code organized in nested modules. +fn create_single_generated_rs_file(root: &Path) { let mut root_module = Module { - name: "".to_string(), - content: "".to_string(), + name: "".to_owned(), + content: "".to_owned(), sub_modules: HashMap::new(), }; - for entry in walker { - let entry = entry.unwrap(); + // Traverse the directory and add the content of each file to the root module + for entry in walkdir::WalkDir::new(root) { + let entry = entry.expect("Failed to read entry"); let path = entry.path(); + // Only process files with the .rs extension that contain the generated comment if path.is_file() && path.extension().map_or(false, |ext| ext == "rs") { - let file_content = std::fs::read_to_string(path).unwrap(); + let file_content = std::fs::read_to_string(path).expect("Failed to read file"); + + // Only process files that have been generated + // This test expects the comment `DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER` + // to be present in each generated file. if file_content.contains("DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER") { let relative_path = path.strip_prefix(root).expect("Failed to strip prefix"); - let file_name = path.file_stem().unwrap().to_str().unwrap(); + let file_name = path + .file_stem() + .expect("Failed to extract the file name") + .to_str() + .expect("Failed to convert to string"); let parent_modules = relative_path.parent().map_or(vec![], |parent| { let parent = parent.display().to_string(); - if parent == "" { - return vec![]; + if parent.is_empty() { + vec![] } else { - parent.split('/').map(|s| s.to_string()).collect::>() + parent.split('/').map(|s| s.to_owned()).collect::>() } }); // Skip generated.rs - if file_name == "generated" { + if file_name == "generated" { continue; } // Replace //! with // + // Nested modules doesn't support //! comments let new_file_content = file_content.replace("//!", "//"); - // Remove line starting with pub mod - let new_file = new_file_content.lines().filter(|line| !line.starts_with("pub mod")).collect::>().join("\n"); - add_modules(&mut root_module, parent_modules.clone(), file_name.to_string(), new_file); + // Remove lines starting with `pub mod` because we are going to nest the modules + // manually in the generated.rs file + let new_file = new_file_content + .lines() + .filter(|line| !line.starts_with("pub mod")) + .collect::>() + .join("\n"); + + add_modules( + &mut root_module, + parent_modules.clone(), + file_name.to_owned(), + new_file, + ); } } } - let mut output = std::fs::File::create(root.join("generated.rs")).unwrap(); - output.write_all(root_module.generate().as_bytes()).unwrap(); - // println!("cargo:warning=Generated file: {}", root.join("generated.rs").display()); + // Generate `generated.rs` from the hierarchy of modules + let mut output = + std::fs::File::create(root.join("generated.rs")).expect("Failed to create file"); + output + .write_all(root_module.generate().as_bytes()) + .expect("Failed to write to file"); } struct Module { @@ -124,6 +150,7 @@ struct Module { } impl Module { + /// Generate the content of the module and its sub-modules pub fn generate(&self) -> String { let mut content = String::new(); @@ -138,28 +165,41 @@ impl Module { } } -fn add_modules(root_module: &mut Module, parent_modules: Vec, file_name: String, file_content: String) { +/// Add the given module to the hierarchy of modules represented by the root module. +fn add_modules( + root_module: &mut Module, + parent_modules: Vec, + module_name: String, + module_content: String, +) { let mut current_module = root_module; for module_name in parent_modules.iter() { - let module = current_module.sub_modules.entry(module_name.clone()).or_insert(Module { - name: module_name.clone(), - content: "".to_owned(), - sub_modules: HashMap::new(), - }); + let module = current_module + .sub_modules + .entry(module_name.clone()) + .or_insert(Module { + name: module_name.clone(), + content: "".to_owned(), + sub_modules: HashMap::new(), + }); current_module = module; } - if file_name == "mod" || file_name == "lib" { - current_module.content = file_content; + if module_name == "mod" || module_name == "lib" { + current_module.content = module_content; } else { - _ = current_module.sub_modules.insert(file_name.clone(), Module { - name: file_name.clone(), - content: file_content, - sub_modules: HashMap::new(), - }); + _ = current_module.sub_modules.insert( + module_name.clone(), + Module { + name: module_name.clone(), + content: module_content, + sub_modules: HashMap::new(), + }, + ); } } +/// Print logs to stdout by following the Cargo's build script output format. fn print_logs(logger: &in_memory::Logger) { for log_message in logger.messages() { match &log_message { @@ -170,9 +210,10 @@ fn print_logs(logger: &in_memory::Logger) { } } +/// Process the error message and exit the build script with a non-zero exit code. fn process_error(logger: &in_memory::Logger, error: impl std::fmt::Display) -> ! { logger.error(&error.to_string()); print_logs(logger); #[allow(clippy::exit)] // Expected behavior exit(1) -} \ No newline at end of file +} diff --git a/crates/weaver_codegen_test/src/lib.rs b/crates/weaver_codegen_test/src/lib.rs new file mode 100644 index 00000000..8bb850f1 --- /dev/null +++ b/crates/weaver_codegen_test/src/lib.rs @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: Apache-2.0 + +//! This lib file is used to test the code generation of the `weaver_codegen_test` crate. +//! This file only exists to satisfy the `cargo` build process. The actual code generation +//! is done in the `build.rs` file. +//! See the integration test `tests/codegen.rs` for more information. diff --git a/crates/weaver_codegen_test/src/main.rs b/crates/weaver_codegen_test/src/main.rs deleted file mode 100644 index cad261b6..00000000 --- a/crates/weaver_codegen_test/src/main.rs +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -//! - -fn main() { - println!("Hello, world!"); -} \ No newline at end of file diff --git a/crates/weaver_codegen_test/templates/registry/rust/README.md b/crates/weaver_codegen_test/templates/registry/rust/README.md deleted file mode 100644 index 5a12148c..00000000 --- a/crates/weaver_codegen_test/templates/registry/rust/README.md +++ /dev/null @@ -1,382 +0,0 @@ -[comment]: # DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER -# Semantic Conventions for Rust - -# Usage - -```rust -use opentelemetry::KeyValue; -use opentelemetry::metrics::{Histogram, MeterProvider}; -use opentelemetry_sdk::{Resource, runtime}; -use opentelemetry_sdk::metrics::{PeriodicReader, SdkMeterProvider}; - -use semconv::attributes; -use semconv::attributes::http::{HTTP_REQUEST_METHOD, HttpRequestMethod}; -use semconv::attributes::system::SystemCpuState; -use semconv::metrics::http::{create_http_client_request_duration, HttpClientActiveRequests, HttpClientActiveRequestsReqAttributes, HttpServerRequestDurationOptAttributes, HttpServerRequestDurationReqAttributes}; -use semconv::metrics::http::HttpServerRequestDuration; -use semconv::metrics::system::{SystemCpuTime, SystemCpuTimeOptAttributes, SystemCpuUtilization, SystemCpuUtilizationOptAttributes}; - -/// Main -#[tokio::main] -async fn main() -> Result<(), Box> { - let meter_provider = init_meter_provider(); - - // SemConv attributes are typed, so the compiler will catch type errors - // Experimental attributes are not visible if the `semconv_experimental` feature is not enabled - println!("{:?}", attributes::client::CLIENT_ADDRESS.value("145.34.23.56".into())); - println!("{:?}", attributes::client::CLIENT_ADDRESS.key()); - println!("{:?}", attributes::client::CLIENT_PORT.value(8080)); - println!("{:?}", attributes::client::CLIENT_PORT.key()); - - println!("{}", HttpRequestMethod::Connect); - - let meter = meter_provider.meter("mylibname"); - - // Create a u64 http.client.request.duration metric - let http_client_request_duration: Histogram = create_http_client_request_duration(&meter); - http_client_request_duration.record(100, &[ - HTTP_REQUEST_METHOD.value(&HttpRequestMethod::Connect), - // here nothing guarantees that all the required attributes are provided - ]); - - let http_client_request_duration: Histogram = create_http_client_request_duration(&meter); - dbg!(http_client_request_duration); - - // ==== A TYPE-SAFE HISTOGRAM API ==== - // Create a u64 http.server.request.duration metric (as defined in the OpenTelemetry HTTP - // semantic conventions) - let http_request_duration = HttpServerRequestDuration::::new(&meter); - - // Records a new data point and provide the required and some not required attributes - http_request_duration.record(100, &HttpServerRequestDurationReqAttributes { - http_request_method: HttpRequestMethod::Connect, - url_scheme: "http".to_owned(), - }, Some(&HttpServerRequestDurationOptAttributes { - http_response_status_code: Some(200), - ..Default::default() - })); - - // ==== A TYPE-SAFE UP-DOWN-COUNTER API ==== - // Create a f64 http.server.request.duration metric (as defined in the OpenTelemetry HTTP - // semantic conventions) - let http_client_active_requests = HttpClientActiveRequests::::new(&meter); - - // Adds a new data point and provide the required attributes. Not required attributes are not - // provided in this example. - http_client_active_requests.add(10.0, &HttpClientActiveRequestsReqAttributes { - server_address: "10.0.0.1".to_owned(), - server_port: 8080, - }, None); - - // ==== A TYPE-SAFE COUNTER API ==== - // Create a f64 system.cpu.time metric (as defined in the OpenTelemetry System semantic - // conventions) - let system_cpu_time = SystemCpuTime::::new(&meter); - - // Adds a new data point and provide some not required attributes. - // Note: In the method signature, there is no required attribute. - system_cpu_time.add(10.0, Some(&SystemCpuTimeOptAttributes { - system_cpu_logical_number: Some(0), - system_cpu_state: Some(SystemCpuState::Idle) - })); - // Adds a new data point with a custom CPU state. - system_cpu_time.add(20.0, Some(&SystemCpuTimeOptAttributes { - system_cpu_logical_number: Some(0), - system_cpu_state: Some(SystemCpuState::_Custom("custom".to_owned())) - })); - - // ==== A TYPE-SAFE GAUGE API ==== - // Create a i64 system.cpu.utilization metric (as defined in the OpenTelemetry System semantic - // conventions) - let system_cpu_utilization = SystemCpuUtilization::::new(&meter); - - // Adds a new data point with no not required attributes. - system_cpu_utilization.record(-5, None); - // Adds a new data point with some not required attributes. - system_cpu_utilization.record(10, Some(&SystemCpuUtilizationOptAttributes { - system_cpu_logical_number: Some(0), - system_cpu_state: Some(SystemCpuState::Idle) - })); - - meter_provider.shutdown()?; - Ok(()) -} - -fn init_meter_provider() -> SdkMeterProvider { - let exporter = opentelemetry_stdout::MetricsExporterBuilder::default() - .with_encoder(|writer, data| - Ok(serde_json::to_writer_pretty(writer, &data).unwrap())) - .build(); - let reader = PeriodicReader::builder(exporter, runtime::Tokio).build(); - SdkMeterProvider::builder() - .with_reader(reader) - .with_resource(Resource::new(vec![KeyValue::new( - "service.name", - "metrics-basic-example", - )])) - .build() -} -``` - -The execution of this program will generate the following output: - -``` -KeyValue { key: Static("client.address"), value: String(Static("145.34.23.56")) } -Static("client.address") -KeyValue { key: Static("client.port"), value: I64(8080) } -Static("client.port") -CONNECT -[src/main.rs:39:5] http_client_request_duration = Histogram -{ - "resourceMetrics": { - "resource": { - "attributes": [ - { - "key": "service.name", - "value": { - "stringValue": "metrics-basic-example" - } - } - ] - }, - "scopeMetrics": [ - { - "scope": { - "name": "mylibname" - }, - "metrics": [ - { - "name": "http.client.request.duration", - "description": "Duration of HTTP client requests.", - "unit": "s", - "histogram": { - "dataPoints": [ - { - "attributes": { - "http.request.method": { - "stringValue": "CONNECT" - } - }, - "startTimeUnixNano": 1714780164856054000, - "timeUnixNano": 1714780164856202000, - "startTime": "2024-05-03 23:49:24.856", - "time": "2024-05-03 23:49:24.856", - "count": 1, - "explicitBounds": [ - 0.0, - 5.0, - 10.0, - 25.0, - 50.0, - 75.0, - 100.0, - 250.0, - 500.0, - 750.0, - 1000.0, - 2500.0, - 5000.0, - 7500.0, - 10000.0 - ], - "bucketCounts": [ - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ], - "min": 100, - "max": 100, - "sum": 100, - "exemplars": [], - "flags": 0 - } - ], - "aggregationTemporality": "Cumulative" - } - }, - { - "name": "http.server.request.duration", - "description": "Duration of HTTP server requests.", - "unit": "s", - "histogram": { - "dataPoints": [ - { - "attributes": { - "http.request.method": { - "stringValue": "CONNECT" - }, - "http.response.status_code": { - "intValue": 200 - }, - "url.scheme": { - "stringValue": "http" - } - }, - "startTimeUnixNano": 1714780164856111000, - "timeUnixNano": 1714780164856204000, - "startTime": "2024-05-03 23:49:24.856", - "time": "2024-05-03 23:49:24.856", - "count": 1, - "explicitBounds": [ - 0.0, - 5.0, - 10.0, - 25.0, - 50.0, - 75.0, - 100.0, - 250.0, - 500.0, - 750.0, - 1000.0, - 2500.0, - 5000.0, - 7500.0, - 10000.0 - ], - "bucketCounts": [ - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ], - "min": 100, - "max": 100, - "sum": 100, - "exemplars": [], - "flags": 0 - } - ], - "aggregationTemporality": "Cumulative" - } - }, - { - "name": "http.client.active_requests", - "description": "Number of active HTTP requests.", - "unit": "{request}", - "sum": { - "dataPoints": [ - { - "attributes": { - "server.address": { - "stringValue": "10.0.0.1" - }, - "server.port": { - "intValue": 8080 - } - }, - "startTime": "2024-05-03 23:49:24.856", - "time": "2024-05-03 23:49:24.856", - "startTimeUnixNano": 1714780164856139000, - "timeUnixNano": 1714780164856219000, - "value": 10.0 - } - ], - "aggregationTemporality": "Cumulative", - "isMonotonic": false - } - }, - { - "name": "system.cpu.time", - "description": "Seconds each logical CPU spent on each mode", - "unit": "s", - "sum": { - "dataPoints": [ - { - "attributes": { - "system.cpu.logical_number": { - "intValue": 0 - }, - "system.cpu.state": { - "stringValue": "idle" - } - }, - "startTime": "2024-05-03 23:49:24.856", - "time": "2024-05-03 23:49:24.856", - "startTimeUnixNano": 1714780164856152000, - "timeUnixNano": 1714780164856220000, - "value": 10.0 - }, - { - "attributes": { - "system.cpu.logical_number": { - "intValue": 0 - }, - "system.cpu.state": { - "stringValue": "custom" - } - }, - "startTime": "2024-05-03 23:49:24.856", - "time": "2024-05-03 23:49:24.856", - "startTimeUnixNano": 1714780164856152000, - "timeUnixNano": 1714780164856220000, - "value": 20.0 - } - ], - "aggregationTemporality": "Cumulative", - "isMonotonic": true - } - }, - { - "name": "system.cpu.utilization", - "description": "Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs", - "unit": "1", - "gauge": { - "dataPoints": [ - { - "attributes": { - "system.cpu.logical_number": { - "intValue": 0 - }, - "system.cpu.state": { - "stringValue": "idle" - } - }, - "startTime": null, - "time": "2024-05-03 23:49:24.856", - "startTimeUnixNano": null, - "timeUnixNano": 1714780164856176000, - "value": 10 - }, - { - "attributes": {}, - "startTime": null, - "time": "2024-05-03 23:49:24.856", - "startTimeUnixNano": null, - "timeUnixNano": 1714780164856171000, - "value": -5 - } - ] - } - } - ] - } - ] - } -} -``` \ No newline at end of file diff --git a/crates/weaver_codegen_test/templates/registry/rust/attribute_macros.j2 b/crates/weaver_codegen_test/templates/registry/rust/attribute_macros.j2 index d132ec32..447c6b74 100644 --- a/crates/weaver_codegen_test/templates/registry/rust/attribute_macros.j2 +++ b/crates/weaver_codegen_test/templates/registry/rust/attribute_macros.j2 @@ -30,7 +30,7 @@ {%- if attribute.type.members is defined %} crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(&required_attributes.{{ attribute.name | snake_case }}), {%- elif attribute.type == "string" %} - crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(required_attributes.{{ attribute.name | snake_case }}.to_string().into()), + crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(required_attributes.{{ attribute.name | snake_case }}.to_owned().into()), {%- else %} crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(required_attributes.{{ attribute.name | snake_case }}), {%- endif %} @@ -48,7 +48,7 @@ } {%- elif attribute.type == "string" %} if let Some({{ attribute.name | snake_case }}) = &value.{{ attribute.name | snake_case }} { - attributes.push(crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value({{ attribute.name | snake_case }}.to_string().into())); + attributes.push(crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value({{ attribute.name | snake_case }}.to_owned().into())); } {%- else %} if let Some({{ attribute.name | snake_case }}) = value.{{ attribute.name | snake_case }} { diff --git a/crates/weaver_codegen_test/templates/registry/rust/attributes/attributes.rs.j2 b/crates/weaver_codegen_test/templates/registry/rust/attributes/attributes.rs.j2 index 94e70b52..b14e3465 100644 --- a/crates/weaver_codegen_test/templates/registry/rust/attributes/attributes.rs.j2 +++ b/crates/weaver_codegen_test/templates/registry/rust/attributes/attributes.rs.j2 @@ -49,6 +49,7 @@ pub enum {{ attribute.name | pascal_case }} { impl {{ attribute.name | pascal_case }} { /// Returns the string representation of the [`{{ attribute.name | pascal_case }}`]. + #[must_use] pub fn as_str(&self) -> &str { match self { {%- for variant in attribute.type.members %} @@ -75,6 +76,7 @@ impl core::fmt::Display for {{ attribute.name | pascal_case }} { impl crate::attributes::AttributeKey<{{ attribute.name | pascal_case }}> { /// Returns a [`KeyValue`] pair for the given value. + #[must_use] pub fn value(&self, v: &{{ attribute.name | pascal_case }}) -> opentelemetry::KeyValue { opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) } diff --git a/crates/weaver_codegen_test/templates/registry/rust/attributes/mod.rs.j2 b/crates/weaver_codegen_test/templates/registry/rust/attributes/mod.rs.j2 index a269e52b..064c9ff7 100644 --- a/crates/weaver_codegen_test/templates/registry/rust/attributes/mod.rs.j2 +++ b/crates/weaver_codegen_test/templates/registry/rust/attributes/mod.rs.j2 @@ -23,6 +23,7 @@ pub struct AttributeKey { impl AttributeKey { /// Returns a new [`AttributeKey`] with the given key. + #[must_use] pub(crate) const fn new(key: &'static str) -> AttributeKey { Self { key: Key::from_static_str(key), @@ -31,6 +32,7 @@ impl AttributeKey { } /// Returns the key of the attribute. + #[must_use] pub fn key(&self) -> &Key { &self.key } @@ -38,6 +40,7 @@ impl AttributeKey { impl AttributeKey { /// Returns a [`KeyValue`] pair for the given value. + #[must_use] pub fn value(&self, v: StringValue) -> KeyValue { KeyValue::new(self.key.clone(), v) } @@ -45,6 +48,7 @@ impl AttributeKey { impl AttributeKey { /// Returns a [`KeyValue`] pair for the given value. + #[must_use] pub fn value(&self, v: i64) -> KeyValue { KeyValue::new(self.key.clone(), v) } @@ -52,6 +56,7 @@ impl AttributeKey { impl AttributeKey { /// Returns a [`KeyValue`] pair for the given value. + #[must_use] pub fn value(&self, v: f64) -> KeyValue { KeyValue::new(self.key.clone(), v) } @@ -59,6 +64,7 @@ impl AttributeKey { impl AttributeKey { /// Returns a [`KeyValue`] pair for the given value. + #[must_use] pub fn value(&self, v: bool) -> KeyValue { KeyValue::new(self.key.clone(), v) } diff --git a/crates/weaver_codegen_test/templates/registry/rust/lib.rs b/crates/weaver_codegen_test/templates/registry/rust/lib.rs deleted file mode 100644 index dad69ebf..00000000 --- a/crates/weaver_codegen_test/templates/registry/rust/lib.rs +++ /dev/null @@ -1,13 +0,0 @@ -{{- template.set_file_name("lib.rs") -}} - -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! OpenTelemetry Semantic Convention Attributes. -//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER - -pub mod attributes; -pub mod metrics; - diff --git a/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/counter.j2 b/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/counter.j2 index d5b23273..8a32cc75 100644 --- a/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/counter.j2 +++ b/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/counter.j2 @@ -5,6 +5,7 @@ {%- if metric is experimental %} #[cfg(feature = "semconv_experimental")] {%- endif %} +#[must_use] pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Counter where opentelemetry::metrics::Meter: crate::metrics::CounterProvider { crate::metrics::CounterProvider::create_counter(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") @@ -51,6 +52,7 @@ pub struct {{ metric.metric_name | pascal_case }}OptAttributes { impl {{ metric.metric_name | pascal_case }} { /// Creates a new `{{ metric.metric_name }}` metric. + #[must_use] pub fn new(meter: &opentelemetry::metrics::Meter) -> Self where opentelemetry::metrics::Meter: crate::metrics::CounterProvider{ Self(crate::metrics::CounterProvider::create_counter(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) @@ -64,6 +66,6 @@ impl {{ metric.metric_name | pascal_case }} { {% if not_required_attributes %}not_required_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} ) { {{ attribute_macros.attributes_to_key_values(required_attributes, not_required_attributes) }} - self.0.add(value, &attributes) + self.0.add(value, &attributes); } } \ No newline at end of file diff --git a/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/gauge.j2 b/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/gauge.j2 index 063c440e..930cbc6f 100644 --- a/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/gauge.j2 +++ b/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/gauge.j2 @@ -5,6 +5,7 @@ {%- if metric is experimental %} #[cfg(feature = "semconv_experimental")] {%- endif %} +#[must_use] pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Gauge where opentelemetry::metrics::Meter: crate::metrics::GaugeProvider { crate::metrics::GaugeProvider::create_gauge(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") @@ -51,6 +52,7 @@ pub struct {{ metric.metric_name | pascal_case }}OptAttributes { impl {{ metric.metric_name | pascal_case }} { /// Creates a new `{{ metric.metric_name }}` metric. + #[must_use] pub fn new(meter: &opentelemetry::metrics::Meter) -> Self where opentelemetry::metrics::Meter: crate::metrics::GaugeProvider{ Self(crate::metrics::GaugeProvider::create_gauge(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) @@ -64,6 +66,6 @@ impl {{ metric.metric_name | pascal_case }} { {% if not_required_attributes %}not_required_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} ) { {{ attribute_macros.attributes_to_key_values(required_attributes, not_required_attributes) }} - self.0.record(value, &attributes) + self.0.record(value, &attributes); } } \ No newline at end of file diff --git a/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/histogram.j2 b/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/histogram.j2 index ea700f01..ffe08a10 100644 --- a/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/histogram.j2 +++ b/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/histogram.j2 @@ -5,6 +5,7 @@ {%- if metric is experimental %} #[cfg(feature = "semconv_experimental")] {%- endif %} +#[must_use] pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram where opentelemetry::metrics::Meter: crate::metrics::HistogramProvider { crate::metrics::HistogramProvider::create_histogram(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") @@ -51,6 +52,7 @@ pub struct {{ metric.metric_name | pascal_case }}OptAttributes { impl {{ metric.metric_name | pascal_case }} { /// Creates a new instance of the `{{ metric.metric_name }}` metric. + #[must_use] pub fn new(meter: &opentelemetry::metrics::Meter) -> Self where opentelemetry::metrics::Meter: crate::metrics::HistogramProvider{ Self(crate::metrics::HistogramProvider::create_histogram(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) @@ -64,6 +66,6 @@ impl {{ metric.metric_name | pascal_case }} { {% if not_required_attributes %}not_required_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} ) { {{ attribute_macros.attributes_to_key_values(required_attributes, not_required_attributes) }} - self.0.record(value, &attributes) + self.0.record(value, &attributes); } } \ No newline at end of file diff --git a/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/updowncounter.j2 b/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/updowncounter.j2 index bc827a46..3276cb6f 100644 --- a/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/updowncounter.j2 +++ b/crates/weaver_codegen_test/templates/registry/rust/metrics/instruments/updowncounter.j2 @@ -5,6 +5,7 @@ {%- if metric is experimental %} #[cfg(feature = "semconv_experimental")] {%- endif %} +#[must_use] pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter where opentelemetry::metrics::Meter: crate::metrics::UpDownCounterProvider { crate::metrics::UpDownCounterProvider::create_up_down_counter(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") @@ -52,6 +53,7 @@ pub struct {{ metric.metric_name | pascal_case }}OptAttributes { impl {{ metric.metric_name | pascal_case }} { /// Creates a new instance of the `{{ metric.metric_name }}` metric. + #[must_use] pub fn new(meter: &opentelemetry::metrics::Meter) -> Self where opentelemetry::metrics::Meter: crate::metrics::UpDownCounterProvider{ Self(crate::metrics::UpDownCounterProvider::create_up_down_counter(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) @@ -65,6 +67,6 @@ impl {{ metric.metric_name | pascal_case }} { {% if not_required_attributes %}not_required_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} ) { {{ attribute_macros.attributes_to_key_values(required_attributes, not_required_attributes) }} - self.0.add(value, &attributes) + self.0.add(value, &attributes); } } \ No newline at end of file diff --git a/crates/weaver_codegen_test/tests/codegen.rs b/crates/weaver_codegen_test/tests/codegen.rs index 7db96ceb..daa62be2 100644 --- a/crates/weaver_codegen_test/tests/codegen.rs +++ b/crates/weaver_codegen_test/tests/codegen.rs @@ -1,103 +1,143 @@ // SPDX-License-Identifier: Apache-2.0 -//! Test code generation +//! This integration test aims to validate the code generation from a semantic convention registry. +//! By using an integration test, we confirm that the interface of the generated code is public. We +//! also verify that the entirety of the generated code is compilable and exposes the expected +//! constants, structs, enums, and functions. +// Include the generated code include!(concat!(env!("OUT_DIR"), "/generated.rs")); -use opentelemetry::global; -use opentelemetry::metrics::Histogram; use crate::attributes::client; -use crate::metrics::http::create_http_client_request_duration; +use crate::attributes::http::HttpRequestMethod; use crate::attributes::http::HTTP_REQUEST_METHOD; -use crate::metrics::http::HttpServerRequestDuration; -use crate::metrics::http::HttpServerRequestDurationReqAttributes; -use crate::metrics::http::HttpServerRequestDurationOptAttributes; +use crate::attributes::system::SystemCpuState; +use crate::metrics::http::create_http_client_request_duration; use crate::metrics::http::HttpClientActiveRequests; use crate::metrics::http::HttpClientActiveRequestsReqAttributes; +use crate::metrics::http::HttpServerRequestDuration; +use crate::metrics::http::HttpServerRequestDurationOptAttributes; +use crate::metrics::http::HttpServerRequestDurationReqAttributes; use crate::metrics::system::SystemCpuTime; use crate::metrics::system::SystemCpuTimeOptAttributes; -use crate::attributes::system::SystemCpuState; use crate::metrics::system::SystemCpuUtilization; use crate::metrics::system::SystemCpuUtilizationOptAttributes; -use crate::attributes::http::HttpRequestMethod; +use opentelemetry::metrics::Histogram; +use opentelemetry::{global, KeyValue}; #[test] fn test_codegen() { - println!("{:?}", client::CLIENT_ADDRESS.value("145.34.23.56".into())); - println!("{:?}", client::CLIENT_ADDRESS.key()); - println!("{:?}", client::CLIENT_PORT.value(8080)); - println!("{:?}", client::CLIENT_PORT.key()); - - println!("{}", HttpRequestMethod::Connect); - - let meter = global::meter("mylibname"); - - // Create a u64 http.client.request.duration metric + // Test the constants generated for the attributes + // In the generated API the attributes are typed, so the compiler will catch type errors + assert_eq!(client::CLIENT_ADDRESS.key().as_str(), "client.address"); + assert_eq!( + client::CLIENT_ADDRESS.value("145.34.23.56".into()), + KeyValue::new("client.address", "145.34.23.56") + ); + assert_eq!(client::CLIENT_PORT.key().as_str(), "client.port"); + assert_eq!( + client::CLIENT_PORT.value(8080), + KeyValue::new("client.port", 8080) + ); + + // Enum values are also generated + assert_eq!(HttpRequestMethod::Connect.as_str(), "CONNECT"); + assert_eq!(HttpRequestMethod::Delete.as_str(), "DELETE"); + assert_eq!( + HttpRequestMethod::_Custom("UNKNOWN_METHOD".to_owned()).as_str(), + "UNKNOWN_METHOD" + ); + + // Create an OpenTelemetry meter + let meter = global::meter("my_meter"); + + // Create a u64 http.client.request.duration metric and record a data point. + // This is the low-level API, where: + // - the required attributes are not enforced by the compiler. + // - the attributes provided are not checked for correctness by the compiler (i.e. the + // attributes specified in the original semantic convention let http_client_request_duration: Histogram = create_http_client_request_duration(&meter); - http_client_request_duration.record(100, &[ - HTTP_REQUEST_METHOD.value(&HttpRequestMethod::Connect), - // here nothing guarantees that all the required attributes are provided - ]); + http_client_request_duration.record( + 100, + &[HTTP_REQUEST_METHOD.value(&HttpRequestMethod::Connect)], + ); + // Create a f64 http.client.request.duration metric and record a data point. let http_client_request_duration: Histogram = create_http_client_request_duration(&meter); - dbg!(http_client_request_duration); + http_client_request_duration.record( + 100.0, + &[HTTP_REQUEST_METHOD.value(&HttpRequestMethod::Connect)], + ); // ==== A TYPE-SAFE HISTOGRAM API ==== // Create a u64 http.server.request.duration metric (as defined in the OpenTelemetry HTTP - // semantic conventions) + // semantic conventions). + // The API is type-safe, so the compiler will catch type errors. The required attributes are + // enforced by the compiler. All the attributes provided are checked for correctness by the + // compiler in relation to the original semantic convention. let http_request_duration = HttpServerRequestDuration::::new(&meter); - // Records a new data point and provide the required and some optional attributes - http_request_duration.record(100, &HttpServerRequestDurationReqAttributes { - http_request_method: HttpRequestMethod::Connect, - url_scheme: "http".to_owned(), - }, Some(&HttpServerRequestDurationOptAttributes { - http_response_status_code: Some(200), - ..Default::default() - })); + http_request_duration.record( + 100, + &HttpServerRequestDurationReqAttributes { + http_request_method: HttpRequestMethod::Connect, + url_scheme: "http".to_owned(), + }, + Some(&HttpServerRequestDurationOptAttributes { + http_response_status_code: Some(200), + ..Default::default() + }), + ); // ==== A TYPE-SAFE UP-DOWN-COUNTER API ==== // Create a f64 http.server.request.duration metric (as defined in the OpenTelemetry HTTP // semantic conventions) let http_client_active_requests = HttpClientActiveRequests::::new(&meter); - // Adds a new data point and provide the required attributes. Optional attributes are not // provided in this example. - http_client_active_requests.add(10.0, &HttpClientActiveRequestsReqAttributes { - server_address: "10.0.0.1".to_owned(), - server_port: 8080, - }, None); + http_client_active_requests.add( + 10.0, + &HttpClientActiveRequestsReqAttributes { + server_address: "10.0.0.1".to_owned(), + server_port: 8080, + }, + None, + ); // ==== A TYPE-SAFE COUNTER API ==== // Create a f64 system.cpu.time metric (as defined in the OpenTelemetry System semantic // conventions) let system_cpu_time = SystemCpuTime::::new(&meter); - // Adds a new data point and provide some optional attributes. // Note: In the method signature, there is no required attribute. - system_cpu_time.add(10.0, Some(&SystemCpuTimeOptAttributes { - system_cpu_logical_number: Some(0), - system_cpu_state: Some(SystemCpuState::Idle) - })); + system_cpu_time.add( + 10.0, + Some(&SystemCpuTimeOptAttributes { + system_cpu_logical_number: Some(0), + system_cpu_state: Some(SystemCpuState::Idle), + }), + ); // Adds a new data point with a custom CPU state. - system_cpu_time.add(20.0, Some(&SystemCpuTimeOptAttributes { - system_cpu_logical_number: Some(0), - system_cpu_state: Some(SystemCpuState::_Custom("custom".to_owned())) - })); + system_cpu_time.add( + 20.0, + Some(&SystemCpuTimeOptAttributes { + system_cpu_logical_number: Some(0), + system_cpu_state: Some(SystemCpuState::_Custom("custom".to_owned())), + }), + ); // ==== A TYPE-SAFE GAUGE API ==== // Create a i64 system.cpu.utilization metric (as defined in the OpenTelemetry System semantic // conventions) let system_cpu_utilization = SystemCpuUtilization::::new(&meter); - // Adds a new data point with no optional attributes. system_cpu_utilization.record(-5, None); // Adds a new data point with some optional attributes. - system_cpu_utilization.record(10, Some(&SystemCpuUtilizationOptAttributes { - system_cpu_logical_number: Some(0), - system_cpu_state: Some(SystemCpuState::Idle) - })); - - // All the tests passed, remove the generated files - //remove_generated_files(); -} \ No newline at end of file + system_cpu_utilization.record( + 10, + Some(&SystemCpuUtilizationOptAttributes { + system_cpu_logical_number: Some(0), + system_cpu_state: Some(SystemCpuState::Idle), + }), + ); +} diff --git a/crates/weaver_common/src/in_memory.rs b/crates/weaver_common/src/in_memory.rs index 1cf20a86..19d8a6c7 100644 --- a/crates/weaver_common/src/in_memory.rs +++ b/crates/weaver_common/src/in_memory.rs @@ -45,7 +45,9 @@ impl Logger { /// Returns the number of warning messages logged. #[must_use] pub fn warn_count(&self) -> usize { - self.messages.lock().expect("Failed to lock messages") + self.messages + .lock() + .expect("Failed to lock messages") .iter() .filter(|m| matches!(m, LogMessage::Warn(_))) .count() @@ -54,7 +56,9 @@ impl Logger { /// Returns the number of error messages logged. #[must_use] pub fn error_count(&self) -> usize { - self.messages.lock().expect("Failed to lock messages") + self.messages + .lock() + .expect("Failed to lock messages") .iter() .filter(|m| matches!(m, LogMessage::Error(_))) .count() @@ -63,7 +67,10 @@ impl Logger { /// Returns the recorded log messages. #[must_use] pub fn messages(&self) -> Vec { - self.messages.lock().expect("Failed to lock messages").clone() + self.messages + .lock() + .expect("Failed to lock messages") + .clone() } } @@ -71,32 +78,42 @@ impl crate::Logger for Logger { /// Logs a trace message (only with debug enabled). fn trace(&self, message: &str) { if self.debug_level > 0 { - self.messages.lock().expect("Failed to lock messages") + self.messages + .lock() + .expect("Failed to lock messages") .push(LogMessage::Trace(message.to_owned())); } } /// Logs an info message. fn info(&self, message: &str) { - self.messages.lock().expect("Failed to lock messages") + self.messages + .lock() + .expect("Failed to lock messages") .push(LogMessage::Info(message.to_owned())); } /// Logs a warning message. fn warn(&self, message: &str) { - self.messages.lock().expect("Failed to lock messages") + self.messages + .lock() + .expect("Failed to lock messages") .push(LogMessage::Warn(message.to_owned())); } /// Logs an error message. fn error(&self, message: &str) { - self.messages.lock().expect("Failed to lock messages") + self.messages + .lock() + .expect("Failed to lock messages") .push(LogMessage::Error(message.to_owned())); } /// Logs a success message. fn success(&self, message: &str) { - self.messages.lock().expect("Failed to lock messages") + self.messages + .lock() + .expect("Failed to lock messages") .push(LogMessage::Success(message.to_owned())); } @@ -110,20 +127,28 @@ impl crate::Logger for Logger { fn done(&self) {} /// Adds a style to the logger. - fn add_style(&self, _name: &str, _styles: Vec<&'static str>) -> &Self { self } + fn add_style(&self, _name: &str, _styles: Vec<&'static str>) -> &Self { + self + } /// Logs a loading message with a spinner. fn loading(&self, message: &str) { - self.messages.lock().expect("Failed to lock messages") + self.messages + .lock() + .expect("Failed to lock messages") .push(LogMessage::Loading(message.to_owned())); } /// Forces the logger to not print a newline for the next message. - fn same(&self) -> &Self { self } + fn same(&self) -> &Self { + self + } /// Logs a message without icon. fn log(&self, message: &str) { - self.messages.lock().expect("Failed to lock messages") + self.messages + .lock() + .expect("Failed to lock messages") .push(LogMessage::Log(message.to_owned())); } } diff --git a/crates/weaver_common/src/lib.rs b/crates/weaver_common/src/lib.rs index 1d4e2edf..1f6c1581 100644 --- a/crates/weaver_common/src/lib.rs +++ b/crates/weaver_common/src/lib.rs @@ -4,8 +4,8 @@ pub mod diag; pub mod error; -pub mod quiet; pub mod in_memory; +pub mod quiet; use std::sync::atomic::AtomicUsize; use std::sync::{Arc, Mutex}; diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/README.md b/crates/weaver_forge/codegen_examples/expected_codegen/README.md deleted file mode 100644 index e5f4ef77..00000000 --- a/crates/weaver_forge/codegen_examples/expected_codegen/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# 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/attributes/client.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/client.rs deleted file mode 100644 index 4c69c8ac..00000000 --- a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/client.rs +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! 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/attributes/attributes.rs.j2 - -/// 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. -/// -/// Examples: -/// - client.example.com -/// - 10.1.2.80 -/// - /tmp/my.sock -pub const CLIENT_ADDRESS: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("client.address"); - -/// Client port number. -/// -/// 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. -/// -/// Examples: -/// - 65123 -pub const CLIENT_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("client.port"); \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/error.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/error.rs deleted file mode 100644 index 1091cc6e..00000000 --- a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/error.rs +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! This document defines the shared attributes used to report an error. -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/attributes/attributes.rs.j2 - -/// Describes a class of error the operation ended with. -/// -/// Notes: -/// The `error.type` SHOULD be predictable, and SHOULD have low cardinality. -/// -/// When `error.type` is set to a type (e.g., an exception type), its -/// canonical class name identifying the type within the artifact SHOULD be used. -/// -/// Instrumentations SHOULD document the list of errors they report. -/// -/// The cardinality of `error.type` within one instrumentation library SHOULD be low. -/// Telemetry consumers that aggregate data from multiple instrumentation libraries and applications -/// should be prepared for `error.type` to have high cardinality at query time when no -/// additional filters are applied. -/// -/// If the operation has completed successfully, instrumentations SHOULD NOT set `error.type`. -/// -/// If a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes), -/// it's RECOMMENDED to: -/// -/// * Use a domain-specific attribute -/// * Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. -/// -/// Examples: -/// - timeout -/// - java.net.UnknownHostException -/// - server_certificate_invalid -/// - 500 -pub const ERROR_TYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("error.type"); - -/// Describes a class of error the operation ended with. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum ErrorType { /// A fallback error value to be used when the instrumentation doesn't define a custom value. - Other, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl ErrorType { - /// Returns the string representation of the [`ErrorType`]. - pub fn as_str(&self) -> &str { - match self { - ErrorType::Other => "_OTHER", - ErrorType::_Custom(v) => v.as_str(), - // 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 ErrorType { - /// Formats the value using the given formatter. - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &ErrorType) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/exception.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/exception.rs deleted file mode 100644 index 2d13b70b..00000000 --- a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/exception.rs +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! 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/attributes/attributes.rs.j2 - -/// SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span. -/// -/// Notes: -/// An exception is considered to have escaped (or left) the scope of a span, -/// if that span is ended while the exception is still logically "in flight". -/// This may be actually "in flight" in some languages (e.g. if the exception -/// is passed to a Context manager's `__exit__` method in Python) but will -/// usually be caught at the point of recording the exception in most languages. -/// -/// It is usually not possible to determine at the point where an exception is thrown -/// whether it will escape the scope of a span. -/// However, it is trivial to know that an exception -/// will escape, if one checks for an active exception just before ending the span, -/// as done in the [example for recording span exceptions](#recording-an-exception). -/// -/// It follows that an exception may still escape the scope of the span -/// 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: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("exception.escaped"); - -/// The exception message. -/// -/// Examples: -/// - Division by zero -/// - Can't convert 'int' object to str implicitly -pub const EXCEPTION_MESSAGE: crate::attributes::AttributeKey = crate::attributes::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. -/// -/// Example: Exception in thread "main" java.lang.RuntimeException: Test exception\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n at com.example.GenerateTrace.main(GenerateTrace.java:5) -pub const EXCEPTION_STACKTRACE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("exception.stacktrace"); - -/// 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. -/// -/// Examples: -/// - java.net.ConnectException -/// - OSError -pub const EXCEPTION_TYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("exception.type"); \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/http.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/http.rs deleted file mode 100644 index bab1a220..00000000 --- a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/http.rs +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! This document defines semantic convention attributes in the HTTP namespace. -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/attributes/attributes.rs.j2 - -/// State of the HTTP connection in the HTTP connection pool. -/// -/// Examples: -/// - active -/// - idle -#[cfg(feature = "semconv_experimental")] -pub const HTTP_CONNECTION_STATE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.connection.state"); - -/// State of the HTTP connection in the HTTP connection pool. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum HttpConnectionState { /// active state. - #[cfg(feature = "semconv_experimental")] - Active, /// idle state. - #[cfg(feature = "semconv_experimental")] - Idle, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl HttpConnectionState { - /// Returns the string representation of the [`HttpConnectionState`]. - pub fn as_str(&self) -> &str { - match self { - #[cfg(feature = "semconv_experimental")] - HttpConnectionState::Active => "active", - #[cfg(feature = "semconv_experimental")] - HttpConnectionState::Idle => "idle", - HttpConnectionState::_Custom(v) => v.as_str(), - // 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()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &HttpConnectionState) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} - -/// 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. -/// -/// Example: 3495 -#[cfg(feature = "semconv_experimental")] -pub const HTTP_REQUEST_BODY_SIZE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.request.body.size"); - -/// HTTP request headers, `` being the normalized HTTP Header name (lowercase), the value being the header values. -/// -/// Notes: -/// 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. -/// -/// Examples: -/// - http.request.header.content-type=["application/json"] -/// - http.request.header.x-forwarded-for=["1.2.3.4", "1.2.3.5"] -pub const HTTP_REQUEST_HEADER: crate::attributes::AttributeKey> = crate::attributes::AttributeKey::new("http.request.header"); - -/// HTTP request method. -/// -/// Notes: -/// HTTP request method value SHOULD be "known" to the instrumentation. -/// By default, this convention defines "known" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods) -/// and the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html). -/// -/// If the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`. -/// -/// If the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override -/// the list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named -/// OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods -/// (this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults). -/// -/// 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. -/// -/// Examples: -/// - GET -/// - POST -/// - HEAD -pub const HTTP_REQUEST_METHOD: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.request.method"); - -/// HTTP request method. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum HttpRequestMethod { /// CONNECT method. - Connect, /// DELETE method. - Delete, /// GET method. - Get, /// HEAD method. - Head, /// OPTIONS method. - Options, /// PATCH method. - Patch, /// POST method. - Post, /// PUT method. - Put, /// TRACE method. - Trace, /// Any HTTP method that the instrumentation has no prior knowledge of. - Other, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl HttpRequestMethod { - /// Returns the string representation of the [`HttpRequestMethod`]. - pub fn as_str(&self) -> &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", - HttpRequestMethod::_Custom(v) => v.as_str(), - // 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()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &HttpRequestMethod) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} - -/// Original HTTP method sent by the client in the request line. -/// -/// Examples: -/// - GeT -/// - ACL -/// - foo -pub const HTTP_REQUEST_METHOD_ORIGINAL: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.request.method_original"); - -/// The ordinal number of request resending attempt (for any reason, including redirects). -/// -/// 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). -/// -/// Example: 3 -pub const HTTP_REQUEST_RESEND_COUNT: crate::attributes::AttributeKey = crate::attributes::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. -/// -/// Example: 1437 -#[cfg(feature = "semconv_experimental")] -pub const HTTP_REQUEST_SIZE: crate::attributes::AttributeKey = crate::attributes::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. -/// -/// Example: 3495 -#[cfg(feature = "semconv_experimental")] -pub const HTTP_RESPONSE_BODY_SIZE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.response.body.size"); - -/// HTTP response headers, `` being the normalized HTTP Header name (lowercase), the value being the header values. -/// -/// Notes: -/// 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. -/// -/// Examples: -/// - http.response.header.content-type=["application/json"] -/// - http.response.header.my-custom-header=["abc", "def"] -pub const HTTP_RESPONSE_HEADER: crate::attributes::AttributeKey> = crate::attributes::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. -/// -/// Example: 1437 -#[cfg(feature = "semconv_experimental")] -pub const HTTP_RESPONSE_SIZE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.response.size"); - -/// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). -/// -/// Examples: -/// - 200 -pub const HTTP_RESPONSE_STATUS_CODE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.response.status_code"); - -/// The matched route, that is, the path template in the format used by the respective server framework. -/// -/// 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. -/// -/// Examples: -/// - /users/:userID? -/// - {controller}/{action}/{id?} -pub const HTTP_ROUTE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.route"); \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/mod.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/mod.rs deleted file mode 100644 index 26e301b8..00000000 --- a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/mod.rs +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! OpenTelemetry Semantic Convention Attributes -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/attributes/mod.rs.j2 - -use opentelemetry::{Key, KeyValue, StringValue}; - - -/// Attributes for the `client` namespace. -pub mod client; -/// Attributes for the `error` namespace. -pub mod error; -/// Attributes for the `exception` namespace. -pub mod exception; -/// Attributes for the `http` namespace. -pub mod http; -/// Attributes for the `network` namespace. -pub mod network; -/// Attributes for the `server` namespace. -pub mod server; -/// Attributes for the `system` namespace. -pub mod system; -/// Attributes for the `url` namespace. -pub mod url; - -/// A typed attribute key. -pub struct AttributeKey { - key: Key, - phantom: std::marker::PhantomData -} - -impl AttributeKey { - /// Returns a new [`AttributeKey`] with the given key. - pub(crate) const fn new(key: &'static str) -> AttributeKey { - Self { - key: Key::from_static_str(key), - phantom: std::marker::PhantomData - } - } - - /// Returns the key of the attribute. - pub fn key(&self) -> &Key { - &self.key - } -} - -impl AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: StringValue) -> KeyValue { - KeyValue::new(self.key.clone(), v) - } -} - -impl AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: i64) -> KeyValue { - KeyValue::new(self.key.clone(), v) - } -} - -impl AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: f64) -> KeyValue { - KeyValue::new(self.key.clone(), v) - } -} - -impl AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: bool) -> KeyValue { - KeyValue::new(self.key.clone(), v) - } -} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/network.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/network.rs deleted file mode 100644 index 10e6a8a2..00000000 --- a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/network.rs +++ /dev/null @@ -1,628 +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/attributes/attributes.rs.j2 - -/// Deprecated, use `server.address`. -/// -/// Examples: -/// - example.com -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `server.address`.")] -pub const NET_HOST_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.host.name"); - -/// Deprecated, use `server.port`. -/// -/// Examples: -/// - 8080 -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `server.port`.")] -pub const NET_HOST_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.host.port"); - -/// Deprecated, use `server.address` on client spans and `client.address` on server spans. -/// -/// Examples: -/// - example.com -#[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::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.peer.name"); - -/// Deprecated, use `server.port` on client spans and `client.port` on server spans. -/// -/// Examples: -/// - 8080 -#[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::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.peer.port"); - -/// Deprecated, use `network.protocol.name`. -/// -/// Examples: -/// - amqp -/// - http -/// - mqtt -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `network.protocol.name`.")] -pub const NET_PROTOCOL_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.protocol.name"); - -/// Deprecated, use `network.protocol.version`. -/// -/// Example: 3.1.1 -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `network.protocol.version`.")] -pub const NET_PROTOCOL_VERSION: crate::attributes::AttributeKey = crate::attributes::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::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.family"); - -/// Deprecated, use `network.transport` and `network.type`. -#[derive(Debug, Clone)] -#[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, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl NetSockFamily { - /// Returns the string representation of the [`NetSockFamily`]. - pub fn as_str(&self) -> &str { - match self { - #[cfg(feature = "semconv_experimental")] - NetSockFamily::Inet => "inet", - #[cfg(feature = "semconv_experimental")] - NetSockFamily::Inet6 => "inet6", - #[cfg(feature = "semconv_experimental")] - NetSockFamily::Unix => "unix", - NetSockFamily::_Custom(v) => v.as_str(), - // 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()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &NetSockFamily) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} - -/// Deprecated, use `network.local.address`. -/// -/// Examples: -/// - /var/my.sock -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `network.local.address`.")] -pub const NET_SOCK_HOST_ADDR: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.host.addr"); - -/// Deprecated, use `network.local.port`. -/// -/// Examples: -/// - 8080 -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `network.local.port`.")] -pub const NET_SOCK_HOST_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.host.port"); - -/// Deprecated, use `network.peer.address`. -/// -/// Examples: -/// - 192.168.0.1 -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `network.peer.address`.")] -pub const NET_SOCK_PEER_ADDR: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.peer.addr"); - -/// Deprecated, no replacement at this time. -/// -/// Examples: -/// - /var/my.sock -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Removed.")] -pub const NET_SOCK_PEER_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.peer.name"); - -/// Deprecated, use `network.peer.port`. -/// -/// Examples: -/// - 65531 -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `network.peer.port`.")] -pub const NET_SOCK_PEER_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.peer.port"); - -/// Deprecated, use `network.transport`. -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `network.transport`.")] -pub const NET_TRANSPORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.transport"); - -/// Deprecated, use `network.transport`. -#[derive(Debug, Clone)] -#[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, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl NetTransport { - /// Returns the string representation of the [`NetTransport`]. - pub fn as_str(&self) -> &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", - NetTransport::_Custom(v) => v.as_str(), - // 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()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &NetTransport) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} - -/// The ISO 3166-1 alpha-2 2-character country code associated with the mobile carrier network. -/// -/// Example: DE -#[cfg(feature = "semconv_experimental")] -pub const NETWORK_CARRIER_ICC: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.icc"); - -/// The mobile carrier country code. -/// -/// Example: 310 -#[cfg(feature = "semconv_experimental")] -pub const NETWORK_CARRIER_MCC: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.mcc"); - -/// The mobile carrier network code. -/// -/// Example: 001 -#[cfg(feature = "semconv_experimental")] -pub const NETWORK_CARRIER_MNC: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.mnc"); - -/// The name of the mobile carrier. -/// -/// Example: sprint -#[cfg(feature = "semconv_experimental")] -pub const NETWORK_CARRIER_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.name"); - -/// This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection. -/// -/// Example: LTE -#[cfg(feature = "semconv_experimental")] -pub const NETWORK_CONNECTION_SUBTYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.connection.subtype"); - -/// This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum NetworkConnectionSubtype { /// GPRS - #[cfg(feature = "semconv_experimental")] - Gprs, /// EDGE - #[cfg(feature = "semconv_experimental")] - Edge, /// UMTS - #[cfg(feature = "semconv_experimental")] - Umts, /// CDMA - #[cfg(feature = "semconv_experimental")] - Cdma, /// EVDO Rel. 0 - #[cfg(feature = "semconv_experimental")] - Evdo0, /// EVDO Rev. A - #[cfg(feature = "semconv_experimental")] - EvdoA, /// CDMA2000 1XRTT - #[cfg(feature = "semconv_experimental")] - Cdma20001Xrtt, /// HSDPA - #[cfg(feature = "semconv_experimental")] - Hsdpa, /// HSUPA - #[cfg(feature = "semconv_experimental")] - Hsupa, /// HSPA - #[cfg(feature = "semconv_experimental")] - Hspa, /// IDEN - #[cfg(feature = "semconv_experimental")] - Iden, /// EVDO Rev. B - #[cfg(feature = "semconv_experimental")] - EvdoB, /// LTE - #[cfg(feature = "semconv_experimental")] - Lte, /// EHRPD - #[cfg(feature = "semconv_experimental")] - Ehrpd, /// HSPAP - #[cfg(feature = "semconv_experimental")] - Hspap, /// GSM - #[cfg(feature = "semconv_experimental")] - Gsm, /// TD-SCDMA - #[cfg(feature = "semconv_experimental")] - TdScdma, /// IWLAN - #[cfg(feature = "semconv_experimental")] - Iwlan, /// 5G NR (New Radio) - #[cfg(feature = "semconv_experimental")] - Nr, /// 5G NRNSA (New Radio Non-Standalone) - #[cfg(feature = "semconv_experimental")] - Nrnsa, /// LTE CA - #[cfg(feature = "semconv_experimental")] - LteCa, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl NetworkConnectionSubtype { - /// Returns the string representation of the [`NetworkConnectionSubtype`]. - pub fn as_str(&self) -> &str { - match self { - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Gprs => "gprs", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Edge => "edge", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Umts => "umts", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Cdma => "cdma", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Evdo0 => "evdo_0", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::EvdoA => "evdo_a", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Cdma20001Xrtt => "cdma2000_1xrtt", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Hsdpa => "hsdpa", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Hsupa => "hsupa", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Hspa => "hspa", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Iden => "iden", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::EvdoB => "evdo_b", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Lte => "lte", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Ehrpd => "ehrpd", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Hspap => "hspap", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Gsm => "gsm", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::TdScdma => "td_scdma", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Iwlan => "iwlan", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Nr => "nr", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Nrnsa => "nrnsa", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::LteCa => "lte_ca", - NetworkConnectionSubtype::_Custom(v) => v.as_str(), - // 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 NetworkConnectionSubtype { - /// Formats the value using the given formatter. - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &NetworkConnectionSubtype) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} - -/// The internet connection type. -/// -/// Example: wifi -#[cfg(feature = "semconv_experimental")] -pub const NETWORK_CONNECTION_TYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.connection.type"); - -/// The internet connection type. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum NetworkConnectionType { - #[cfg(feature = "semconv_experimental")] - Wifi, - #[cfg(feature = "semconv_experimental")] - Wired, - #[cfg(feature = "semconv_experimental")] - Cell, - #[cfg(feature = "semconv_experimental")] - Unavailable, - #[cfg(feature = "semconv_experimental")] - Unknown, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl NetworkConnectionType { - /// Returns the string representation of the [`NetworkConnectionType`]. - pub fn as_str(&self) -> &str { - match self { - #[cfg(feature = "semconv_experimental")] - NetworkConnectionType::Wifi => "wifi", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionType::Wired => "wired", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionType::Cell => "cell", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionType::Unavailable => "unavailable", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionType::Unknown => "unknown", - NetworkConnectionType::_Custom(v) => v.as_str(), - // 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 NetworkConnectionType { - /// Formats the value using the given formatter. - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &NetworkConnectionType) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} - -/// The network IO operation direction. -/// -/// Examples: -/// - transmit -#[cfg(feature = "semconv_experimental")] -pub const NETWORK_IO_DIRECTION: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.io.direction"); - -/// The network IO operation direction. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum NetworkIoDirection { - #[cfg(feature = "semconv_experimental")] - Transmit, - #[cfg(feature = "semconv_experimental")] - Receive, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl NetworkIoDirection { - /// Returns the string representation of the [`NetworkIoDirection`]. - pub fn as_str(&self) -> &str { - match self { - #[cfg(feature = "semconv_experimental")] - NetworkIoDirection::Transmit => "transmit", - #[cfg(feature = "semconv_experimental")] - NetworkIoDirection::Receive => "receive", - NetworkIoDirection::_Custom(v) => v.as_str(), - // 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 NetworkIoDirection { - /// Formats the value using the given formatter. - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &NetworkIoDirection) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} - -/// Local address of the network connection - IP address or Unix domain socket name. -/// -/// Examples: -/// - 10.1.2.80 -/// - /tmp/my.sock -pub const NETWORK_LOCAL_ADDRESS: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.local.address"); - -/// Local port number of the network connection. -/// -/// Examples: -/// - 65123 -pub const NETWORK_LOCAL_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.local.port"); - -/// Peer address of the network connection - IP address or Unix domain socket name. -/// -/// Examples: -/// - 10.1.2.80 -/// - /tmp/my.sock -pub const NETWORK_PEER_ADDRESS: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.peer.address"); - -/// Peer port number of the network connection. -/// -/// Examples: -/// - 65123 -pub const NETWORK_PEER_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.peer.port"); - -/// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. -/// -/// Notes: -/// The value SHOULD be normalized to lowercase. -/// -/// Examples: -/// - amqp -/// - http -/// - mqtt -pub const NETWORK_PROTOCOL_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.protocol.name"); - -/// The actual version of the protocol used for network communication. -/// -/// Notes: -/// If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, this attribute SHOULD NOT be set. -/// -/// Examples: -/// - 1.1 -/// - 2 -pub const NETWORK_PROTOCOL_VERSION: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.protocol.version"); - -/// [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). -/// -/// Notes: -/// The value SHOULD be normalized to lowercase. -/// -/// Consider always setting the transport when setting a port number, since -/// a port number is ambiguous without knowing the transport. For example -/// different processes could be listening on TCP port 12345 and UDP port 12345. -/// -/// Examples: -/// - tcp -/// - udp -pub const NETWORK_TRANSPORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.transport"); - -/// [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum NetworkTransport { /// TCP - Tcp, /// UDP - Udp, /// Named or anonymous pipe. - Pipe, /// Unix domain socket - Unix, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl NetworkTransport { - /// Returns the string representation of the [`NetworkTransport`]. - pub fn as_str(&self) -> &str { - match self { - NetworkTransport::Tcp => "tcp", - NetworkTransport::Udp => "udp", - NetworkTransport::Pipe => "pipe", - NetworkTransport::Unix => "unix", - NetworkTransport::_Custom(v) => v.as_str(), - // 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 NetworkTransport { - /// Formats the value using the given formatter. - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &NetworkTransport) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} - -/// [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. -/// -/// Notes: -/// The value SHOULD be normalized to lowercase. -/// -/// Examples: -/// - ipv4 -/// - ipv6 -pub const NETWORK_TYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.type"); - -/// [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum NetworkType { /// IPv4 - Ipv4, /// IPv6 - Ipv6, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl NetworkType { - /// Returns the string representation of the [`NetworkType`]. - pub fn as_str(&self) -> &str { - match self { - NetworkType::Ipv4 => "ipv4", - NetworkType::Ipv6 => "ipv6", - NetworkType::_Custom(v) => v.as_str(), - // 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 NetworkType { - /// Formats the value using the given formatter. - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &NetworkType) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/server.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/server.rs deleted file mode 100644 index 9b894160..00000000 --- a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/server.rs +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! These attributes may be used to describe the server 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/attributes/attributes.rs.j2 - -/// Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. -/// -/// Notes: -/// When observed from the client side, and when communicating through an intermediary, `server.address` SHOULD represent the server address behind any intermediaries, for example proxies, if it's available. -/// -/// Examples: -/// - example.com -/// - 10.1.2.80 -/// - /tmp/my.sock -pub const SERVER_ADDRESS: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("server.address"); - -/// Server port number. -/// -/// Notes: -/// When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent the server port behind any intermediaries, for example proxies, if it's available. -/// -/// Examples: -/// - 80 -/// - 8080 -/// - 443 -pub const SERVER_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("server.port"); \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/system.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/system.rs deleted file mode 100644 index 77838d2a..00000000 --- a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/system.rs +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! Describes System CPU attributes -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/attributes/attributes.rs.j2 - -/// The logical CPU number [0..n-1] -/// -/// Examples: -/// - 1 -#[cfg(feature = "semconv_experimental")] -pub const SYSTEM_CPU_LOGICAL_NUMBER: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("system.cpu.logical_number"); - -/// The state of the CPU -/// -/// Examples: -/// - idle -/// - interrupt -#[cfg(feature = "semconv_experimental")] -pub const SYSTEM_CPU_STATE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("system.cpu.state"); - -/// The state of the CPU -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum SystemCpuState { - #[cfg(feature = "semconv_experimental")] - User, - #[cfg(feature = "semconv_experimental")] - System, - #[cfg(feature = "semconv_experimental")] - Nice, - #[cfg(feature = "semconv_experimental")] - Idle, - #[cfg(feature = "semconv_experimental")] - Iowait, - #[cfg(feature = "semconv_experimental")] - Interrupt, - #[cfg(feature = "semconv_experimental")] - Steal, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl SystemCpuState { - /// Returns the string representation of the [`SystemCpuState`]. - pub fn as_str(&self) -> &str { - match self { - #[cfg(feature = "semconv_experimental")] - SystemCpuState::User => "user", - #[cfg(feature = "semconv_experimental")] - SystemCpuState::System => "system", - #[cfg(feature = "semconv_experimental")] - SystemCpuState::Nice => "nice", - #[cfg(feature = "semconv_experimental")] - SystemCpuState::Idle => "idle", - #[cfg(feature = "semconv_experimental")] - SystemCpuState::Iowait => "iowait", - #[cfg(feature = "semconv_experimental")] - SystemCpuState::Interrupt => "interrupt", - #[cfg(feature = "semconv_experimental")] - SystemCpuState::Steal => "steal", - SystemCpuState::_Custom(v) => v.as_str(), - // 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 SystemCpuState { - /// Formats the value using the given formatter. - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &SystemCpuState) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} - -/// The memory state -/// -/// Examples: -/// - free -/// - cached -#[cfg(feature = "semconv_experimental")] -pub const SYSTEM_MEMORY_STATE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("system.memory.state"); - -/// The memory state -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum SystemMemoryState { - #[cfg(feature = "semconv_experimental")] - Used, - #[cfg(feature = "semconv_experimental")] - Free, - #[cfg(feature = "semconv_experimental")] - Shared, - #[cfg(feature = "semconv_experimental")] - Buffers, - #[cfg(feature = "semconv_experimental")] - Cached, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl SystemMemoryState { - /// Returns the string representation of the [`SystemMemoryState`]. - pub fn as_str(&self) -> &str { - match self { - #[cfg(feature = "semconv_experimental")] - SystemMemoryState::Used => "used", - #[cfg(feature = "semconv_experimental")] - SystemMemoryState::Free => "free", - #[cfg(feature = "semconv_experimental")] - SystemMemoryState::Shared => "shared", - #[cfg(feature = "semconv_experimental")] - SystemMemoryState::Buffers => "buffers", - #[cfg(feature = "semconv_experimental")] - SystemMemoryState::Cached => "cached", - SystemMemoryState::_Custom(v) => v.as_str(), - // 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 SystemMemoryState { - /// Formats the value using the given formatter. - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &SystemMemoryState) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/url.rs b/crates/weaver_forge/codegen_examples/expected_codegen/attributes/url.rs deleted file mode 100644 index ac5f9d1b..00000000 --- a/crates/weaver_forge/codegen_examples/expected_codegen/attributes/url.rs +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! Attributes describing URL. -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/attributes/attributes.rs.j2 - -/// Domain extracted from the `url.full`, such as "opentelemetry.io". -/// -/// Notes: -/// In some cases a URL may refer to an IP and/or port directly, without a domain name. In this case, the IP address would go to the domain field. If the URL contains a [literal IPv6 address](https://www.rfc-editor.org/rfc/rfc2732#section-2) enclosed by `[` and `]`, the `[` and `]` characters should also be captured in the domain field. -/// -/// Examples: -/// - www.foo.bar -/// - opentelemetry.io -/// - 3.12.167.2 -/// - [1080:0:0:0:8:800:200C:417A] -#[cfg(feature = "semconv_experimental")] -pub const URL_DOMAIN: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.domain"); - -/// The file extension extracted from the `url.full`, excluding the leading dot. -/// -/// Notes: -/// The file extension is only set if it exists, as not every url has a file extension. When the file name has multiple extensions `example.tar.gz`, only the last one should be captured `gz`, not `tar.gz`. -/// -/// Examples: -/// - png -/// - gz -#[cfg(feature = "semconv_experimental")] -pub const URL_EXTENSION: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.extension"); - -/// The [URI fragment](https://www.rfc-editor.org/rfc/rfc3986#section-3.5) component -/// -/// Examples: -/// - SemConv -pub const URL_FRAGMENT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.fragment"); - -/// Absolute URL describing a network resource according to [RFC3986](https://www.rfc-editor.org/rfc/rfc3986) -/// -/// Notes: -/// For network calls, URL usually has `scheme://host[:port][path][?query][#fragment]` format, where the fragment is not transmitted over HTTP, but if it is known, it SHOULD be included nevertheless. -/// `url.full` MUST NOT contain credentials passed via URL in form of `https://username:password@www.example.com/`. In such case username and password SHOULD be redacted and attribute's value SHOULD be `https://REDACTED:REDACTED@www.example.com/`. -/// `url.full` SHOULD capture the absolute URL when it is available (or can be reconstructed). Sensitive content provided in `url.full` SHOULD be scrubbed when instrumentations can identify it. -/// -/// Examples: -/// - https://www.foo.bar/search?q=OpenTelemetry#SemConv -/// - //localhost -pub const URL_FULL: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.full"); - -/// Unmodified original URL as seen in the event source. -/// -/// Notes: -/// In network monitoring, the observed URL may be a full URL, whereas in access logs, the URL is often just represented as a path. This field is meant to represent the URL as it was observed, complete or not. -/// `url.original` might contain credentials passed via URL in form of `https://username:password@www.example.com/`. In such case password and username SHOULD NOT be redacted and attribute's value SHOULD remain the same. -/// -/// Examples: -/// - https://www.foo.bar/search?q=OpenTelemetry#SemConv -/// - search?q=OpenTelemetry -#[cfg(feature = "semconv_experimental")] -pub const URL_ORIGINAL: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.original"); - -/// The [URI path](https://www.rfc-editor.org/rfc/rfc3986#section-3.3) component -/// -/// Notes: -/// Sensitive content provided in `url.path` SHOULD be scrubbed when instrumentations can identify it. -/// -/// Examples: -/// - /search -pub const URL_PATH: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.path"); - -/// Port extracted from the `url.full` -/// -/// Examples: -/// - 443 -#[cfg(feature = "semconv_experimental")] -pub const URL_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.port"); - -/// The [URI query](https://www.rfc-editor.org/rfc/rfc3986#section-3.4) component -/// -/// Notes: -/// Sensitive content provided in `url.query` SHOULD be scrubbed when instrumentations can identify it. -/// -/// Examples: -/// - q=OpenTelemetry -pub const URL_QUERY: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.query"); - -/// The highest registered url domain, stripped of the subdomain. -/// -/// Notes: -/// This value can be determined precisely with the [public suffix list](http://publicsuffix.org). For example, the registered domain for `foo.example.com` is `example.com`. Trying to approximate this by simply taking the last two labels will not work well for TLDs such as `co.uk`. -/// -/// Examples: -/// - example.com -/// - foo.co.uk -#[cfg(feature = "semconv_experimental")] -pub const URL_REGISTERED_DOMAIN: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.registered_domain"); - -/// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. -/// -/// Examples: -/// - https -/// - ftp -/// - telnet -pub const URL_SCHEME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.scheme"); - -/// The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. -/// -/// Notes: -/// The subdomain portion of `www.east.mydomain.co.uk` is `east`. If the domain has multiple levels of subdomain, such as `sub2.sub1.example.com`, the subdomain field should contain `sub2.sub1`, with no trailing period. -/// -/// Examples: -/// - east -/// - sub2.sub1 -#[cfg(feature = "semconv_experimental")] -pub const URL_SUBDOMAIN: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.subdomain"); - -/// The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is `com`. -/// -/// Notes: -/// This value can be determined precisely with the [public suffix list](http://publicsuffix.org). -/// -/// Examples: -/// - com -/// - co.uk -#[cfg(feature = "semconv_experimental")] -pub const URL_TOP_LEVEL_DOMAIN: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.top_level_domain"); \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/lib.rs b/crates/weaver_forge/codegen_examples/expected_codegen/lib.rs deleted file mode 100644 index ae1281bf..00000000 --- a/crates/weaver_forge/codegen_examples/expected_codegen/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! OpenTelemetry Semantic Convention Attributes -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 - -pub mod attributes; -pub mod metrics; diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/metrics/http.rs b/crates/weaver_forge/codegen_examples/expected_codegen/metrics/http.rs deleted file mode 100644 index 016c30cb..00000000 --- a/crates/weaver_forge/codegen_examples/expected_codegen/metrics/http.rs +++ /dev/null @@ -1,488 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/metrics/metrics.rs.j2 - -use crate::metrics::{CounterProvider, GaugeProvider, HistogramProvider, UpDownCounterProvider}; - -/// Duration of HTTP server requests. -pub fn create_http_server_request_duration(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram - where opentelemetry::metrics::Meter: HistogramProvider { - meter.create_histogram("http.server.request.duration", "Duration of HTTP server requests.", "s") -} - -/// Metric: http.server.request.duration -/// Brief: Duration of HTTP server requests. -/// Unit: s -#[derive(Debug)] -pub struct HttpServerRequestDuration(opentelemetry::metrics::Histogram); - - -/// Attributes for the `http.server.request.duration` metric. -#[derive(Debug, Clone)] -pub struct HttpServerRequestDurationReqAttributes { - - /// HTTP request method. - /// - /// Notes: - /// HTTP request method value SHOULD be "known" to the instrumentation. - /// By default, this convention defines "known" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods) - /// and the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html). - /// - /// If the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`. - /// - /// If the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override - /// the list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named - /// OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods - /// (this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults). - /// - /// 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. - /// - /// Examples: - /// - GET - /// - POST - /// - HEAD - pub http_request_method: crate::attributes::http::HttpRequestMethod, - - /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. - /// - /// Notes: - /// The scheme of the original client request, if known (e.g. from [Forwarded#proto](https://developer.mozilla.org/docs/Web/HTTP/Headers/Forwarded#proto), [X-Forwarded-Proto](https://developer.mozilla.org/docs/Web/HTTP/Headers/X-Forwarded-Proto), or a similar header). Otherwise, the scheme of the immediate peer request. - /// - /// Examples: - /// - http - /// - https - pub url_scheme: String, -} - - - -#[derive(Debug, Clone, Default)] -pub struct HttpServerRequestDurationOptAttributes { - - /// Describes a class of error the operation ended with. - /// - /// Notes: - /// If the request fails with an error before response status code was sent or received, - /// `error.type` SHOULD be set to exception type (its fully-qualified class name, if applicable) - /// or a component-specific low cardinality error identifier. - /// - /// If response status code was sent or received and status indicates an error according to [HTTP span status definition](/docs/http/http-spans.md), - /// `error.type` SHOULD be set to the status code number (represented as a string), an exception type (if thrown) or a component-specific error identifier. - /// - /// The `error.type` value SHOULD be predictable and SHOULD have low cardinality. - /// Instrumentations SHOULD document the list of errors they report. - /// - /// The cardinality of `error.type` within one instrumentation library SHOULD be low, but - /// telemetry consumers that aggregate data from multiple instrumentation libraries and applications - /// should be prepared for `error.type` to have high cardinality at query time, when no - /// additional filters are applied. - /// - /// If the request has completed successfully, instrumentations SHOULD NOT set `error.type`. - /// - /// Examples: - /// - timeout - /// - java.net.UnknownHostException - /// - server_certificate_invalid - /// - 500 - pub error_type: Option, - - /// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). - /// - /// Examples: - /// - 200 - pub http_response_status_code: Option, - - /// The matched route, that is, the path template in the format used by the respective server framework. - /// - /// 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. - /// - /// Examples: - /// - /users/:userID? - /// - {controller}/{action}/{id?} - pub http_route: Option, - - /// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. - /// - /// Notes: - /// The value SHOULD be normalized to lowercase. - /// - /// Examples: - /// - http - /// - spdy - pub network_protocol_name: Option, - - /// The actual version of the protocol used for network communication. - /// - /// Notes: - /// If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, this attribute SHOULD NOT be set. - /// - /// Examples: - /// - 1.0 - /// - 1.1 - /// - 2 - /// - 3 - pub network_protocol_version: Option, - - /// Name of the local HTTP server that received the request. - /// - /// Notes: - /// See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). - /// > **Warning** - /// > Since this attribute is based on HTTP headers, opting in to it may allow an attacker - /// > to trigger cardinality limits, degrading the usefulness of the metric. - /// - /// Examples: - /// - example.com - /// - 10.1.2.80 - /// - /tmp/my.sock - pub server_address: Option, - - /// Port of the local HTTP server that received the request. - /// - /// Notes: - /// See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). - /// > **Warning** - /// > Since this attribute is based on HTTP headers, opting in to it may allow an attacker - /// > to trigger cardinality limits, degrading the usefulness of the metric. - /// - /// Examples: - /// - 80 - /// - 8080 - /// - 443 - pub server_port: Option, -} - - -impl HttpServerRequestDuration { - pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: HistogramProvider{ - Self(meter.create_histogram("http.server.request.duration", "Duration of HTTP server requests.", "s")) - } - - /// Adds an additional value to the distribution. - pub fn record( - &self, - value: T, - required_attributes: &HttpServerRequestDurationReqAttributes, - optional_attributes: Option<&HttpServerRequestDurationOptAttributes>, - ) { - let mut attributes = vec![ - crate::attributes::http::HTTP_REQUEST_METHOD.value(&required_attributes.http_request_method), - crate::attributes::url::URL_SCHEME.value(required_attributes.url_scheme.to_string().into()), - ]; - - if let Some(value) = &optional_attributes { - if let Some(error_type) = &value.error_type { - attributes.push(crate::attributes::error::ERROR_TYPE.value(error_type)); - } - if let Some(http_response_status_code) = value.http_response_status_code { - attributes.push(crate::attributes::http::HTTP_RESPONSE_STATUS_CODE.value(http_response_status_code)); - } - if let Some(http_route) = &value.http_route { - attributes.push(crate::attributes::http::HTTP_ROUTE.value(http_route.to_string().into())); - } - if let Some(network_protocol_name) = &value.network_protocol_name { - attributes.push(crate::attributes::network::NETWORK_PROTOCOL_NAME.value(network_protocol_name.to_string().into())); - } - if let Some(network_protocol_version) = &value.network_protocol_version { - attributes.push(crate::attributes::network::NETWORK_PROTOCOL_VERSION.value(network_protocol_version.to_string().into())); - } - if let Some(server_address) = &value.server_address { - attributes.push(crate::attributes::server::SERVER_ADDRESS.value(server_address.to_string().into())); - } - if let Some(server_port) = value.server_port { - attributes.push(crate::attributes::server::SERVER_PORT.value(server_port)); - } - } - self.0.record(value, &attributes) - } -} - -/// Duration of HTTP client requests. -pub fn create_http_client_request_duration(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram - where opentelemetry::metrics::Meter: HistogramProvider { - meter.create_histogram("http.client.request.duration", "Duration of HTTP client requests.", "s") -} - -/// Metric: http.client.request.duration -/// Brief: Duration of HTTP client requests. -/// Unit: s -#[derive(Debug)] -pub struct HttpClientRequestDuration(opentelemetry::metrics::Histogram); - - -/// Attributes for the `http.client.request.duration` metric. -#[derive(Debug, Clone)] -pub struct HttpClientRequestDurationReqAttributes { - - /// HTTP request method. - /// - /// Notes: - /// HTTP request method value SHOULD be "known" to the instrumentation. - /// By default, this convention defines "known" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods) - /// and the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html). - /// - /// If the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`. - /// - /// If the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override - /// the list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named - /// OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods - /// (this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults). - /// - /// 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. - /// - /// Examples: - /// - GET - /// - POST - /// - HEAD - pub http_request_method: crate::attributes::http::HttpRequestMethod, - - /// Host identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. - /// - /// Notes: - /// If an HTTP client request is explicitly made to an IP address, e.g. `http://x.x.x.x:8080`, then `server.address` SHOULD be the IP address `x.x.x.x`. A DNS lookup SHOULD NOT be used. - /// - /// Examples: - /// - example.com - /// - 10.1.2.80 - /// - /tmp/my.sock - pub server_address: String, - - /// Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. - /// - /// Notes: - /// When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent the server port behind any intermediaries, for example proxies, if it's available. - /// - /// Examples: - /// - 80 - /// - 8080 - /// - 443 - pub server_port: i64, -} - - - -#[derive(Debug, Clone, Default)] -pub struct HttpClientRequestDurationOptAttributes { - - /// Describes a class of error the operation ended with. - /// - /// Notes: - /// If the request fails with an error before response status code was sent or received, - /// `error.type` SHOULD be set to exception type (its fully-qualified class name, if applicable) - /// or a component-specific low cardinality error identifier. - /// - /// If response status code was sent or received and status indicates an error according to [HTTP span status definition](/docs/http/http-spans.md), - /// `error.type` SHOULD be set to the status code number (represented as a string), an exception type (if thrown) or a component-specific error identifier. - /// - /// The `error.type` value SHOULD be predictable and SHOULD have low cardinality. - /// Instrumentations SHOULD document the list of errors they report. - /// - /// The cardinality of `error.type` within one instrumentation library SHOULD be low, but - /// telemetry consumers that aggregate data from multiple instrumentation libraries and applications - /// should be prepared for `error.type` to have high cardinality at query time, when no - /// additional filters are applied. - /// - /// If the request has completed successfully, instrumentations SHOULD NOT set `error.type`. - /// - /// Examples: - /// - timeout - /// - java.net.UnknownHostException - /// - server_certificate_invalid - /// - 500 - pub error_type: Option, - - /// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). - /// - /// Examples: - /// - 200 - pub http_response_status_code: Option, - - /// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. - /// - /// Notes: - /// The value SHOULD be normalized to lowercase. - /// - /// Examples: - /// - http - /// - spdy - pub network_protocol_name: Option, - - /// The actual version of the protocol used for network communication. - /// - /// Notes: - /// If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, this attribute SHOULD NOT be set. - /// - /// Examples: - /// - 1.0 - /// - 1.1 - /// - 2 - /// - 3 - pub network_protocol_version: Option, - - /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. - /// - /// Examples: - /// - http - /// - https - pub url_scheme: Option, -} - - -impl HttpClientRequestDuration { - pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: HistogramProvider{ - Self(meter.create_histogram("http.client.request.duration", "Duration of HTTP client requests.", "s")) - } - - /// Adds an additional value to the distribution. - pub fn record( - &self, - value: T, - required_attributes: &HttpClientRequestDurationReqAttributes, - optional_attributes: Option<&HttpClientRequestDurationOptAttributes>, - ) { - let mut attributes = vec![ - crate::attributes::http::HTTP_REQUEST_METHOD.value(&required_attributes.http_request_method), - crate::attributes::server::SERVER_ADDRESS.value(required_attributes.server_address.to_string().into()), - crate::attributes::server::SERVER_PORT.value(required_attributes.server_port), - ]; - - if let Some(value) = &optional_attributes { - if let Some(error_type) = &value.error_type { - attributes.push(crate::attributes::error::ERROR_TYPE.value(error_type)); - } - if let Some(http_response_status_code) = value.http_response_status_code { - attributes.push(crate::attributes::http::HTTP_RESPONSE_STATUS_CODE.value(http_response_status_code)); - } - if let Some(network_protocol_name) = &value.network_protocol_name { - attributes.push(crate::attributes::network::NETWORK_PROTOCOL_NAME.value(network_protocol_name.to_string().into())); - } - if let Some(network_protocol_version) = &value.network_protocol_version { - attributes.push(crate::attributes::network::NETWORK_PROTOCOL_VERSION.value(network_protocol_version.to_string().into())); - } - if let Some(url_scheme) = &value.url_scheme { - attributes.push(crate::attributes::url::URL_SCHEME.value(url_scheme.to_string().into())); - } - } - self.0.record(value, &attributes) - } -} - -/// Number of active HTTP requests. -#[cfg(feature = "semconv_experimental")] -pub fn create_http_client_active_requests(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter - where opentelemetry::metrics::Meter: UpDownCounterProvider { - meter.create_up_down_counter("http.client.active_requests", "Number of active HTTP requests.", "{request}") -} - -/// Metric: http.client.active_requests -/// Brief: Number of active HTTP requests. -/// Unit: {request} -#[derive(Debug)] -pub struct HttpClientActiveRequests(opentelemetry::metrics::UpDownCounter); - - -/// Attributes for the `http.client.active_requests` metric. -#[derive(Debug, Clone)] -pub struct HttpClientActiveRequestsReqAttributes { - - /// Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. - /// - /// Notes: - /// When observed from the client side, and when communicating through an intermediary, `server.address` SHOULD represent the server address behind any intermediaries, for example proxies, if it's available. - /// - /// Examples: - /// - example.com - /// - 10.1.2.80 - /// - /tmp/my.sock - pub server_address: String, - - /// Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. - /// - /// Notes: - /// When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent the server port behind any intermediaries, for example proxies, if it's available. - /// - /// Examples: - /// - 80 - /// - 8080 - /// - 443 - pub server_port: i64, -} - - - -#[derive(Debug, Clone, Default)] -pub struct HttpClientActiveRequestsOptAttributes { - - /// HTTP request method. - /// - /// Notes: - /// HTTP request method value SHOULD be "known" to the instrumentation. - /// By default, this convention defines "known" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods) - /// and the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html). - /// - /// If the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`. - /// - /// If the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override - /// the list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named - /// OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods - /// (this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults). - /// - /// 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. - /// - /// Examples: - /// - GET - /// - POST - /// - HEAD - pub http_request_method: Option, - - /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. - /// - /// Examples: - /// - http - /// - https - pub url_scheme: Option, -} - - -impl HttpClientActiveRequests { - pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: UpDownCounterProvider{ - Self(meter.create_up_down_counter("http.client.active_requests", "Number of active HTTP requests.", "{request}")) - } - - /// Adds an additional value to the up-down-counter. - pub fn add( - &self, - value: T, - required_attributes: &HttpClientActiveRequestsReqAttributes, - optional_attributes: Option<&HttpClientActiveRequestsOptAttributes>, - ) { - let mut attributes = vec![ - crate::attributes::server::SERVER_ADDRESS.value(required_attributes.server_address.to_string().into()), - crate::attributes::server::SERVER_PORT.value(required_attributes.server_port), - ]; - - if let Some(value) = &optional_attributes { - if let Some(http_request_method) = &value.http_request_method { - attributes.push(crate::attributes::http::HTTP_REQUEST_METHOD.value(http_request_method)); - } - if let Some(url_scheme) = &value.url_scheme { - attributes.push(crate::attributes::url::URL_SCHEME.value(url_scheme.to_string().into())); - } - } - self.0.add(value, &attributes) - } -} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/metrics/mod.rs b/crates/weaver_forge/codegen_examples/expected_codegen/metrics/mod.rs deleted file mode 100644 index 336b4fe8..00000000 --- a/crates/weaver_forge/codegen_examples/expected_codegen/metrics/mod.rs +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! OpenTelemetry Semantic Convention Metrics -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/metrics/mod.rs.j2 - - -/// Metrics for the `http` namespace. -pub mod http; -/// Metrics for the `system` namespace. -pub mod system; - -/// A trait implemented by histogram providers (e.g. `Meter`). -pub trait HistogramProvider { - /// Creates a new histogram with the given name, description, and unit. - fn create_histogram(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Histogram; -} - -/// This implementation specifies that a Meter is able to create u64 histograms. -impl HistogramProvider for opentelemetry::metrics::Meter { - /// Creates a new u64 histogram with the given name, description, and unit. - fn create_histogram(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Histogram { - self.u64_histogram(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// This implementation specifies that a Meter is able to create u64 histograms. -impl HistogramProvider for opentelemetry::metrics::Meter { - /// Creates a new f64 histogram with the given name, description, and unit. - fn create_histogram(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Histogram { - self.f64_histogram(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// A trait implemented by up-down-counter providers (e.g. `Meter`). -pub trait UpDownCounterProvider { - /// Creates a new up-down-counter with the given name, description, and unit. - fn create_up_down_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::UpDownCounter; -} - -/// This implementation specifies that a Meter is able to create i64 up-down-counters. -impl UpDownCounterProvider for opentelemetry::metrics::Meter { - /// Creates a new i64 up-down-counter with the given name, description, and unit. - fn create_up_down_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::UpDownCounter { - self.i64_up_down_counter(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// This implementation specifies that a Meter is able to create f64 up-down-counters. -impl UpDownCounterProvider for opentelemetry::metrics::Meter { - /// Creates a new f64 up-down-counter with the given name, description, and unit. - fn create_up_down_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::UpDownCounter { - self.f64_up_down_counter(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// A trait implemented by counter providers (e.g. `Meter`). -pub trait CounterProvider { - /// Creates a new counter with the given name, description, and unit. - fn create_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Counter; -} - -/// This implementation specifies that a Meter is able to create u64 counters. -impl CounterProvider for opentelemetry::metrics::Meter { - /// Creates a new u64 counter with the given name, description, and unit. - fn create_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Counter { - self.u64_counter(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// This implementation specifies that a Meter is able to create f64 counters. -impl CounterProvider for opentelemetry::metrics::Meter { - /// Creates a new f64 counter with the given name, description, and unit. - fn create_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Counter { - self.f64_counter(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// A trait implemented by gauge providers (e.g. `Meter`). -pub trait GaugeProvider { - /// Creates a new gauge with the given name, description, and unit. - fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge; -} - -/// This implementation specifies that a Meter is able to create u64 gauges. -impl GaugeProvider for opentelemetry::metrics::Meter { - /// Creates a new u64 gauge with the given name, description, and unit. - fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge { - self.u64_gauge(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// This implementation specifies that a Meter is able to create i64 gauges. -impl GaugeProvider for opentelemetry::metrics::Meter { - /// Creates a new i64 gauge with the given name, description, and unit. - fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge { - self.i64_gauge(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// This implementation specifies that a Meter is able to create f64 gauges. -impl GaugeProvider for opentelemetry::metrics::Meter { - /// Creates a new f64 gauge with the given name, description, and unit. - fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge { - self.f64_gauge(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/expected_codegen/metrics/system.rs b/crates/weaver_forge/codegen_examples/expected_codegen/metrics/system.rs deleted file mode 100644 index f0e9f19f..00000000 --- a/crates/weaver_forge/codegen_examples/expected_codegen/metrics/system.rs +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/metrics/metrics.rs.j2 - -use crate::metrics::{CounterProvider, GaugeProvider, HistogramProvider, UpDownCounterProvider}; - -/// Seconds each logical CPU spent on each mode -#[cfg(feature = "semconv_experimental")] -pub fn create_system_cpu_time(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Counter - where opentelemetry::metrics::Meter: CounterProvider { - meter.create_counter("system.cpu.time", "Seconds each logical CPU spent on each mode", "s") -} - -/// Metric: system.cpu.time -/// Brief: Seconds each logical CPU spent on each mode -/// Unit: s -#[derive(Debug)] -pub struct SystemCpuTime(opentelemetry::metrics::Counter); - - - - -#[derive(Debug, Clone, Default)] -pub struct SystemCpuTimeOptAttributes { - - /// The logical CPU number [0..n-1] - /// - /// Examples: - /// - 1 - pub system_cpu_logical_number: Option, - - /// The CPU state for this data point. A system's CPU SHOULD be characterized *either* by data points with no `state` labels, *or only* data points with `state` labels. - /// - /// Examples: - /// - idle - /// - interrupt - pub system_cpu_state: Option, -} - - -impl SystemCpuTime { - pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: CounterProvider{ - Self(meter.create_counter("system.cpu.time", "Seconds each logical CPU spent on each mode", "s")) - } - - /// Adds an additional value to the counter. - pub fn add( - &self, - value: T, - - optional_attributes: Option<&SystemCpuTimeOptAttributes>, - ) { - let mut attributes = vec![ - ]; - - if let Some(value) = &optional_attributes { - #[cfg(feature = "semconv_experimental")] - if let Some(system_cpu_logical_number) = value.system_cpu_logical_number { - attributes.push(crate::attributes::system::SYSTEM_CPU_LOGICAL_NUMBER.value(system_cpu_logical_number)); - } - #[cfg(feature = "semconv_experimental")] - if let Some(system_cpu_state) = &value.system_cpu_state { - attributes.push(crate::attributes::system::SYSTEM_CPU_STATE.value(system_cpu_state)); - } - } - self.0.add(value, &attributes) - } -} - -/// Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs -#[cfg(feature = "semconv_experimental")] -pub fn create_system_cpu_utilization(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Gauge - where opentelemetry::metrics::Meter: GaugeProvider { - meter.create_gauge("system.cpu.utilization", "Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs", "1") -} - -/// Metric: system.cpu.utilization -/// Brief: Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs -/// Unit: 1 -#[derive(Debug)] -pub struct SystemCpuUtilization(opentelemetry::metrics::Gauge); - - - - -#[derive(Debug, Clone, Default)] -pub struct SystemCpuUtilizationOptAttributes { - - /// The logical CPU number [0..n-1] - /// - /// Examples: - /// - 1 - pub system_cpu_logical_number: Option, - - /// The CPU state for this data point. A system's CPU SHOULD be characterized *either* by data points with no `state` labels, *or only* data points with `state` labels. - /// - /// Examples: - /// - idle - /// - interrupt - pub system_cpu_state: Option, -} - - -impl SystemCpuUtilization { - pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: GaugeProvider{ - Self(meter.create_gauge("system.cpu.utilization", "Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs", "1")) - } - - /// Records an additional value to the gauge. - pub fn record( - &self, - value: T, - - optional_attributes: Option<&SystemCpuUtilizationOptAttributes>, - ) { - let mut attributes = vec![ - ]; - - if let Some(value) = &optional_attributes { - #[cfg(feature = "semconv_experimental")] - if let Some(system_cpu_logical_number) = value.system_cpu_logical_number { - attributes.push(crate::attributes::system::SYSTEM_CPU_LOGICAL_NUMBER.value(system_cpu_logical_number)); - } - #[cfg(feature = "semconv_experimental")] - if let Some(system_cpu_state) = &value.system_cpu_state { - attributes.push(crate::attributes::system::SYSTEM_CPU_STATE.value(system_cpu_state)); - } - } - self.0.record(value, &attributes) - } -} - -/// Reports memory in use by state. -#[cfg(feature = "semconv_experimental")] -pub fn create_system_memory_usage(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter - where opentelemetry::metrics::Meter: UpDownCounterProvider { - meter.create_up_down_counter("system.memory.usage", "Reports memory in use by state.", "By") -} - -/// Metric: system.memory.usage -/// Brief: Reports memory in use by state. -/// Unit: By -#[derive(Debug)] -pub struct SystemMemoryUsage(opentelemetry::metrics::UpDownCounter); - - - - -#[derive(Debug, Clone, Default)] -pub struct SystemMemoryUsageOptAttributes { - - /// The memory state - /// - /// Examples: - /// - free - /// - cached - pub system_memory_state: Option, -} - - -impl SystemMemoryUsage { - pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: UpDownCounterProvider{ - Self(meter.create_up_down_counter("system.memory.usage", "Reports memory in use by state.", "By")) - } - - /// Adds an additional value to the up-down-counter. - pub fn add( - &self, - value: T, - - optional_attributes: Option<&SystemMemoryUsageOptAttributes>, - ) { - let mut attributes = vec![ - ]; - - if let Some(value) = &optional_attributes { - #[cfg(feature = "semconv_experimental")] - if let Some(system_memory_state) = &value.system_memory_state { - attributes.push(crate::attributes::system::SYSTEM_MEMORY_STATE.value(system_memory_state)); - } - } - self.0.add(value, &attributes) - } -} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/mini_registry/http-common.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/http-common.yaml similarity index 100% rename from crates/weaver_forge/codegen_examples/mini_registry/http-common.yaml rename to crates/weaver_forge/codegen_examples/semconv_registry/http-common.yaml diff --git a/crates/weaver_forge/codegen_examples/mini_registry/metrics/http.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/metrics/http.yaml similarity index 100% rename from crates/weaver_forge/codegen_examples/mini_registry/metrics/http.yaml rename to crates/weaver_forge/codegen_examples/semconv_registry/metrics/http.yaml diff --git a/crates/weaver_forge/codegen_examples/mini_registry/metrics/system-metrics.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/metrics/system-metrics.yaml similarity index 100% rename from crates/weaver_forge/codegen_examples/mini_registry/metrics/system-metrics.yaml rename to crates/weaver_forge/codegen_examples/semconv_registry/metrics/system-metrics.yaml diff --git a/crates/weaver_forge/codegen_examples/mini_registry/registry/client.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/registry/client.yaml similarity index 100% rename from crates/weaver_forge/codegen_examples/mini_registry/registry/client.yaml rename to crates/weaver_forge/codegen_examples/semconv_registry/registry/client.yaml diff --git a/crates/weaver_forge/codegen_examples/mini_registry/registry/deprecated/network.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/registry/deprecated/network.yaml similarity index 100% rename from crates/weaver_forge/codegen_examples/mini_registry/registry/deprecated/network.yaml rename to crates/weaver_forge/codegen_examples/semconv_registry/registry/deprecated/network.yaml diff --git a/crates/weaver_forge/codegen_examples/mini_registry/registry/error.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/registry/error.yaml similarity index 100% rename from crates/weaver_forge/codegen_examples/mini_registry/registry/error.yaml rename to crates/weaver_forge/codegen_examples/semconv_registry/registry/error.yaml diff --git a/crates/weaver_forge/codegen_examples/mini_registry/registry/exception.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/registry/exception.yaml similarity index 100% rename from crates/weaver_forge/codegen_examples/mini_registry/registry/exception.yaml rename to crates/weaver_forge/codegen_examples/semconv_registry/registry/exception.yaml diff --git a/crates/weaver_forge/codegen_examples/mini_registry/registry/http.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/registry/http.yaml similarity index 100% rename from crates/weaver_forge/codegen_examples/mini_registry/registry/http.yaml rename to crates/weaver_forge/codegen_examples/semconv_registry/registry/http.yaml diff --git a/crates/weaver_forge/codegen_examples/mini_registry/registry/network.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/registry/network.yaml similarity index 100% rename from crates/weaver_forge/codegen_examples/mini_registry/registry/network.yaml rename to crates/weaver_forge/codegen_examples/semconv_registry/registry/network.yaml diff --git a/crates/weaver_forge/codegen_examples/mini_registry/registry/server.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/registry/server.yaml similarity index 100% rename from crates/weaver_forge/codegen_examples/mini_registry/registry/server.yaml rename to crates/weaver_forge/codegen_examples/semconv_registry/registry/server.yaml diff --git a/crates/weaver_forge/codegen_examples/mini_registry/registry/system.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/registry/system.yaml similarity index 100% rename from crates/weaver_forge/codegen_examples/mini_registry/registry/system.yaml rename to crates/weaver_forge/codegen_examples/semconv_registry/registry/system.yaml diff --git a/crates/weaver_forge/codegen_examples/mini_registry/registry/url.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/registry/url.yaml similarity index 100% rename from crates/weaver_forge/codegen_examples/mini_registry/registry/url.yaml rename to crates/weaver_forge/codegen_examples/semconv_registry/registry/url.yaml diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/attribute_macros.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/attribute_macros.j2 index d132ec32..447c6b74 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/attribute_macros.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/attribute_macros.j2 @@ -30,7 +30,7 @@ {%- if attribute.type.members is defined %} crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(&required_attributes.{{ attribute.name | snake_case }}), {%- elif attribute.type == "string" %} - crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(required_attributes.{{ attribute.name | snake_case }}.to_string().into()), + crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(required_attributes.{{ attribute.name | snake_case }}.to_owned().into()), {%- else %} crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(required_attributes.{{ attribute.name | snake_case }}), {%- endif %} @@ -48,7 +48,7 @@ } {%- elif attribute.type == "string" %} if let Some({{ attribute.name | snake_case }}) = &value.{{ attribute.name | snake_case }} { - attributes.push(crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value({{ attribute.name | snake_case }}.to_string().into())); + attributes.push(crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value({{ attribute.name | snake_case }}.to_owned().into())); } {%- else %} if let Some({{ attribute.name | snake_case }}) = value.{{ attribute.name | snake_case }} { diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 index e7e19d26..b14e3465 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 @@ -37,7 +37,7 @@ pub const {{ attribute.name | screaming_snake_case }}: crate::attributes::Attrib #[non_exhaustive] pub enum {{ attribute.name | pascal_case }} { {%- for variant in attribute.type.members %} - {%- if variant.brief %}{{ variant.brief | comment_with_prefix(" /// ") }}{% endif %} + {{ variant.brief | default("No brief") | comment_with_prefix(" /// ") }} {%- if variant.note %}{{ variant.note | comment_with_prefix(" /// ") }}{% endif %} {%- if variant is experimental %} #[cfg(feature = "semconv_experimental")] {% endif %} @@ -49,6 +49,7 @@ pub enum {{ attribute.name | pascal_case }} { impl {{ attribute.name | pascal_case }} { /// Returns the string representation of the [`{{ attribute.name | pascal_case }}`]. + #[must_use] pub fn as_str(&self) -> &str { match self { {%- for variant in attribute.type.members %} @@ -75,6 +76,7 @@ impl core::fmt::Display for {{ attribute.name | pascal_case }} { impl crate::attributes::AttributeKey<{{ attribute.name | pascal_case }}> { /// Returns a [`KeyValue`] pair for the given value. + #[must_use] pub fn value(&self, v: &{{ attribute.name | pascal_case }}) -> opentelemetry::KeyValue { opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) } diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/mod.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/mod.rs.j2 index a269e52b..064c9ff7 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/mod.rs.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/mod.rs.j2 @@ -23,6 +23,7 @@ pub struct AttributeKey { impl AttributeKey { /// Returns a new [`AttributeKey`] with the given key. + #[must_use] pub(crate) const fn new(key: &'static str) -> AttributeKey { Self { key: Key::from_static_str(key), @@ -31,6 +32,7 @@ impl AttributeKey { } /// Returns the key of the attribute. + #[must_use] pub fn key(&self) -> &Key { &self.key } @@ -38,6 +40,7 @@ impl AttributeKey { impl AttributeKey { /// Returns a [`KeyValue`] pair for the given value. + #[must_use] pub fn value(&self, v: StringValue) -> KeyValue { KeyValue::new(self.key.clone(), v) } @@ -45,6 +48,7 @@ impl AttributeKey { impl AttributeKey { /// Returns a [`KeyValue`] pair for the given value. + #[must_use] pub fn value(&self, v: i64) -> KeyValue { KeyValue::new(self.key.clone(), v) } @@ -52,6 +56,7 @@ impl AttributeKey { impl AttributeKey { /// Returns a [`KeyValue`] pair for the given value. + #[must_use] pub fn value(&self, v: f64) -> KeyValue { KeyValue::new(self.key.clone(), v) } @@ -59,6 +64,7 @@ impl AttributeKey { impl AttributeKey { /// Returns a [`KeyValue`] pair for the given value. + #[must_use] pub fn value(&self, v: bool) -> KeyValue { KeyValue::new(self.key.clone(), v) } diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/counter.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/counter.j2 index 7ab88889..8a32cc75 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/counter.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/counter.j2 @@ -5,6 +5,7 @@ {%- if metric is experimental %} #[cfg(feature = "semconv_experimental")] {%- endif %} +#[must_use] pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Counter where opentelemetry::metrics::Meter: crate::metrics::CounterProvider { crate::metrics::CounterProvider::create_counter(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") @@ -20,7 +21,7 @@ pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::Cou {%- set not_required_attributes = metric.attributes | not_required %} {% if required_attributes %} -/// Attributes for the `{{ metric.metric_name }}` metric. +/// Required attributes for the `{{ metric.metric_name }}` metric. #[derive(Debug, Clone)] pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { {%- for attribute in required_attributes | attribute_sort %} @@ -35,6 +36,7 @@ pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { {% endif %} {% if not_required_attributes %} +/// Not required attributes for the `{{ metric.metric_name }}` metric. #[derive(Debug, Clone, Default)] pub struct {{ metric.metric_name | pascal_case }}OptAttributes { {%- for attribute in not_required_attributes | attribute_sort %} @@ -49,6 +51,8 @@ pub struct {{ metric.metric_name | pascal_case }}OptAttributes { {% endif %} impl {{ metric.metric_name | pascal_case }} { + /// Creates a new `{{ metric.metric_name }}` metric. + #[must_use] pub fn new(meter: &opentelemetry::metrics::Meter) -> Self where opentelemetry::metrics::Meter: crate::metrics::CounterProvider{ Self(crate::metrics::CounterProvider::create_counter(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) @@ -62,6 +66,6 @@ impl {{ metric.metric_name | pascal_case }} { {% if not_required_attributes %}not_required_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} ) { {{ attribute_macros.attributes_to_key_values(required_attributes, not_required_attributes) }} - self.0.add(value, &attributes) + self.0.add(value, &attributes); } } \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/gauge.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/gauge.j2 index a2730662..930cbc6f 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/gauge.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/gauge.j2 @@ -5,6 +5,7 @@ {%- if metric is experimental %} #[cfg(feature = "semconv_experimental")] {%- endif %} +#[must_use] pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Gauge where opentelemetry::metrics::Meter: crate::metrics::GaugeProvider { crate::metrics::GaugeProvider::create_gauge(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") @@ -20,7 +21,7 @@ pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::Gau {%- set not_required_attributes = metric.attributes | not_required %} {% if required_attributes %} -/// Attributes for the `{{ metric.metric_name }}` metric. +/// Required attributes for the `{{ metric.metric_name }}` metric. #[derive(Debug, Clone)] pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { {%- for attribute in required_attributes | attribute_sort %} @@ -35,6 +36,7 @@ pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { {% endif %} {% if not_required_attributes %} +/// Not required attributes for the `{{ metric.metric_name }}` metric. #[derive(Debug, Clone, Default)] pub struct {{ metric.metric_name | pascal_case }}OptAttributes { {%- for attribute in not_required_attributes | attribute_sort %} @@ -49,6 +51,8 @@ pub struct {{ metric.metric_name | pascal_case }}OptAttributes { {% endif %} impl {{ metric.metric_name | pascal_case }} { + /// Creates a new `{{ metric.metric_name }}` metric. + #[must_use] pub fn new(meter: &opentelemetry::metrics::Meter) -> Self where opentelemetry::metrics::Meter: crate::metrics::GaugeProvider{ Self(crate::metrics::GaugeProvider::create_gauge(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) @@ -62,6 +66,6 @@ impl {{ metric.metric_name | pascal_case }} { {% if not_required_attributes %}not_required_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} ) { {{ attribute_macros.attributes_to_key_values(required_attributes, not_required_attributes) }} - self.0.record(value, &attributes) + self.0.record(value, &attributes); } } \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/histogram.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/histogram.j2 index fd662ae5..ffe08a10 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/histogram.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/histogram.j2 @@ -5,6 +5,7 @@ {%- if metric is experimental %} #[cfg(feature = "semconv_experimental")] {%- endif %} +#[must_use] pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram where opentelemetry::metrics::Meter: crate::metrics::HistogramProvider { crate::metrics::HistogramProvider::create_histogram(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") @@ -20,7 +21,7 @@ pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::His {%- set not_required_attributes = metric.attributes | not_required %} {% if required_attributes %} -/// Attributes for the `{{ metric.metric_name }}` metric. +/// Required attributes for the `{{ metric.metric_name }}` metric. #[derive(Debug, Clone)] pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { {%- for attribute in required_attributes | attribute_sort %} @@ -35,6 +36,7 @@ pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { {% endif %} {% if not_required_attributes %} +/// Not required attributes for the `{{ metric.metric_name }}` metric. #[derive(Debug, Clone, Default)] pub struct {{ metric.metric_name | pascal_case }}OptAttributes { {%- for attribute in not_required_attributes | attribute_sort %} @@ -49,6 +51,8 @@ pub struct {{ metric.metric_name | pascal_case }}OptAttributes { {% endif %} impl {{ metric.metric_name | pascal_case }} { + /// Creates a new instance of the `{{ metric.metric_name }}` metric. + #[must_use] pub fn new(meter: &opentelemetry::metrics::Meter) -> Self where opentelemetry::metrics::Meter: crate::metrics::HistogramProvider{ Self(crate::metrics::HistogramProvider::create_histogram(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) @@ -62,6 +66,6 @@ impl {{ metric.metric_name | pascal_case }} { {% if not_required_attributes %}not_required_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} ) { {{ attribute_macros.attributes_to_key_values(required_attributes, not_required_attributes) }} - self.0.record(value, &attributes) + self.0.record(value, &attributes); } } \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/updowncounter.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/updowncounter.j2 index d046e1f5..3276cb6f 100644 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/updowncounter.j2 +++ b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/updowncounter.j2 @@ -5,6 +5,7 @@ {%- if metric is experimental %} #[cfg(feature = "semconv_experimental")] {%- endif %} +#[must_use] pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter where opentelemetry::metrics::Meter: crate::metrics::UpDownCounterProvider { crate::metrics::UpDownCounterProvider::create_up_down_counter(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") @@ -20,6 +21,7 @@ pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::UpD {%- set not_required_attributes = metric.attributes | not_required %} {% if required_attributes %} +/// Required attributes for the `{{ metric.metric_name }}` metric. /// Attributes for the `{{ metric.metric_name }}` metric. #[derive(Debug, Clone)] pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { @@ -35,6 +37,7 @@ pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { {% endif %} {% if not_required_attributes %} +/// Not required attributes for the `{{ metric.metric_name }}` metric. #[derive(Debug, Clone, Default)] pub struct {{ metric.metric_name | pascal_case }}OptAttributes { {%- for attribute in not_required_attributes | attribute_sort %} @@ -49,6 +52,8 @@ pub struct {{ metric.metric_name | pascal_case }}OptAttributes { {% endif %} impl {{ metric.metric_name | pascal_case }} { + /// Creates a new instance of the `{{ metric.metric_name }}` metric. + #[must_use] pub fn new(meter: &opentelemetry::metrics::Meter) -> Self where opentelemetry::metrics::Meter: crate::metrics::UpDownCounterProvider{ Self(crate::metrics::UpDownCounterProvider::create_up_down_counter(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) @@ -62,6 +67,6 @@ impl {{ metric.metric_name | pascal_case }} { {% if not_required_attributes %}not_required_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} ) { {{ attribute_macros.attributes_to_key_values(required_attributes, not_required_attributes) }} - self.0.add(value, &attributes) + self.0.add(value, &attributes); } } \ No newline at end of file diff --git a/crates/weaver_forge/src/debug.rs b/crates/weaver_forge/src/debug.rs index 989251b8..0941b145 100644 --- a/crates/weaver_forge/src/debug.rs +++ b/crates/weaver_forge/src/debug.rs @@ -2,9 +2,9 @@ //! Utility functions to help with debugging. -use std::error::Error; use crate::error::Error::{CompoundError, TemplateEvaluationFailed}; use indexmap::IndexMap; +use std::error::Error; use weaver_common::Logger; /// Return a nice summary of the error including the chain of causes. diff --git a/crates/weaver_forge/src/extensions/otel.rs b/crates/weaver_forge/src/extensions/otel.rs index 8a5787cf..c27729f8 100644 --- a/crates/weaver_forge/src/extensions/otel.rs +++ b/crates/weaver_forge/src/extensions/otel.rs @@ -2,10 +2,10 @@ //! Set of filters, tests, and functions that are specific to the OpenTelemetry project. +use crate::config::CaseConvention; use itertools::Itertools; use minijinja::{ErrorKind, Value}; use serde::de::Error; -use crate::config::CaseConvention; /// Filters the input value to only include the required "object". /// A required object is one that has a field named "requirement_level" with the value "required". diff --git a/crates/weaver_forge/tests/README.md b/crates/weaver_forge/tests/README.md deleted file mode 100644 index c4ce1f7f..00000000 --- a/crates/weaver_forge/tests/README.md +++ /dev/null @@ -1,381 +0,0 @@ -# Semantic Conventions for Rust - -# Usage - -```rust -use opentelemetry::KeyValue; -use opentelemetry::metrics::{Histogram, MeterProvider}; -use opentelemetry_sdk::{Resource, runtime}; -use opentelemetry_sdk::metrics::{PeriodicReader, SdkMeterProvider}; - -use semconv::attributes; -use semconv::attributes::http::{HTTP_REQUEST_METHOD, HttpRequestMethod}; -use semconv::attributes::system::SystemCpuState; -use semconv::metrics::http::{create_http_client_request_duration, HttpClientActiveRequests, HttpClientActiveRequestsReqAttributes, HttpServerRequestDurationOptAttributes, HttpServerRequestDurationReqAttributes}; -use semconv::metrics::http::HttpServerRequestDuration; -use semconv::metrics::system::{SystemCpuTime, SystemCpuTimeOptAttributes, SystemCpuUtilization, SystemCpuUtilizationOptAttributes}; - -/// Main -#[tokio::main] -async fn main() -> Result<(), Box> { - let meter_provider = init_meter_provider(); - - // SemConv attributes are typed, so the compiler will catch type errors - // Experimental attributes are not visible if the `semconv_experimental` feature is not enabled - println!("{:?}", attributes::client::CLIENT_ADDRESS.value("145.34.23.56".into())); - println!("{:?}", attributes::client::CLIENT_ADDRESS.key()); - println!("{:?}", attributes::client::CLIENT_PORT.value(8080)); - println!("{:?}", attributes::client::CLIENT_PORT.key()); - - println!("{}", HttpRequestMethod::Connect); - - let meter = meter_provider.meter("mylibname"); - - // Create a u64 http.client.request.duration metric - let http_client_request_duration: Histogram = create_http_client_request_duration(&meter); - http_client_request_duration.record(100, &[ - HTTP_REQUEST_METHOD.value(&HttpRequestMethod::Connect), - // here nothing guarantees that all the required attributes are provided - ]); - - let http_client_request_duration: Histogram = create_http_client_request_duration(&meter); - dbg!(http_client_request_duration); - - // ==== A TYPE-SAFE HISTOGRAM API ==== - // Create a u64 http.server.request.duration metric (as defined in the OpenTelemetry HTTP - // semantic conventions) - let http_request_duration = HttpServerRequestDuration::::new(&meter); - - // Records a new data point and provide the required and some not required attributes - http_request_duration.record(100, &HttpServerRequestDurationReqAttributes { - http_request_method: HttpRequestMethod::Connect, - url_scheme: "http".to_owned(), - }, Some(&HttpServerRequestDurationOptAttributes { - http_response_status_code: Some(200), - ..Default::default() - })); - - // ==== A TYPE-SAFE UP-DOWN-COUNTER API ==== - // Create a f64 http.server.request.duration metric (as defined in the OpenTelemetry HTTP - // semantic conventions) - let http_client_active_requests = HttpClientActiveRequests::::new(&meter); - - // Adds a new data point and provide the required attributes. Not required attributes are not - // provided in this example. - http_client_active_requests.add(10.0, &HttpClientActiveRequestsReqAttributes { - server_address: "10.0.0.1".to_owned(), - server_port: 8080, - }, None); - - // ==== A TYPE-SAFE COUNTER API ==== - // Create a f64 system.cpu.time metric (as defined in the OpenTelemetry System semantic - // conventions) - let system_cpu_time = SystemCpuTime::::new(&meter); - - // Adds a new data point and provide some not required attributes. - // Note: In the method signature, there is no required attribute. - system_cpu_time.add(10.0, Some(&SystemCpuTimeOptAttributes { - system_cpu_logical_number: Some(0), - system_cpu_state: Some(SystemCpuState::Idle) - })); - // Adds a new data point with a custom CPU state. - system_cpu_time.add(20.0, Some(&SystemCpuTimeOptAttributes { - system_cpu_logical_number: Some(0), - system_cpu_state: Some(SystemCpuState::_Custom("custom".to_owned())) - })); - - // ==== A TYPE-SAFE GAUGE API ==== - // Create a i64 system.cpu.utilization metric (as defined in the OpenTelemetry System semantic - // conventions) - let system_cpu_utilization = SystemCpuUtilization::::new(&meter); - - // Adds a new data point with no not required attributes. - system_cpu_utilization.record(-5, None); - // Adds a new data point with some not required attributes. - system_cpu_utilization.record(10, Some(&SystemCpuUtilizationOptAttributes { - system_cpu_logical_number: Some(0), - system_cpu_state: Some(SystemCpuState::Idle) - })); - - meter_provider.shutdown()?; - Ok(()) -} - -fn init_meter_provider() -> SdkMeterProvider { - let exporter = opentelemetry_stdout::MetricsExporterBuilder::default() - .with_encoder(|writer, data| - Ok(serde_json::to_writer_pretty(writer, &data).unwrap())) - .build(); - let reader = PeriodicReader::builder(exporter, runtime::Tokio).build(); - SdkMeterProvider::builder() - .with_reader(reader) - .with_resource(Resource::new(vec![KeyValue::new( - "service.name", - "metrics-basic-example", - )])) - .build() -} -``` - -The execution of this program will generate the following output: - -``` -KeyValue { key: Static("client.address"), value: String(Static("145.34.23.56")) } -Static("client.address") -KeyValue { key: Static("client.port"), value: I64(8080) } -Static("client.port") -CONNECT -[src/main.rs:39:5] http_client_request_duration = Histogram -{ - "resourceMetrics": { - "resource": { - "attributes": [ - { - "key": "service.name", - "value": { - "stringValue": "metrics-basic-example" - } - } - ] - }, - "scopeMetrics": [ - { - "scope": { - "name": "mylibname" - }, - "metrics": [ - { - "name": "http.client.request.duration", - "description": "Duration of HTTP client requests.", - "unit": "s", - "histogram": { - "dataPoints": [ - { - "attributes": { - "http.request.method": { - "stringValue": "CONNECT" - } - }, - "startTimeUnixNano": 1714780164856054000, - "timeUnixNano": 1714780164856202000, - "startTime": "2024-05-03 23:49:24.856", - "time": "2024-05-03 23:49:24.856", - "count": 1, - "explicitBounds": [ - 0.0, - 5.0, - 10.0, - 25.0, - 50.0, - 75.0, - 100.0, - 250.0, - 500.0, - 750.0, - 1000.0, - 2500.0, - 5000.0, - 7500.0, - 10000.0 - ], - "bucketCounts": [ - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ], - "min": 100, - "max": 100, - "sum": 100, - "exemplars": [], - "flags": 0 - } - ], - "aggregationTemporality": "Cumulative" - } - }, - { - "name": "http.server.request.duration", - "description": "Duration of HTTP server requests.", - "unit": "s", - "histogram": { - "dataPoints": [ - { - "attributes": { - "http.request.method": { - "stringValue": "CONNECT" - }, - "http.response.status_code": { - "intValue": 200 - }, - "url.scheme": { - "stringValue": "http" - } - }, - "startTimeUnixNano": 1714780164856111000, - "timeUnixNano": 1714780164856204000, - "startTime": "2024-05-03 23:49:24.856", - "time": "2024-05-03 23:49:24.856", - "count": 1, - "explicitBounds": [ - 0.0, - 5.0, - 10.0, - 25.0, - 50.0, - 75.0, - 100.0, - 250.0, - 500.0, - 750.0, - 1000.0, - 2500.0, - 5000.0, - 7500.0, - 10000.0 - ], - "bucketCounts": [ - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ], - "min": 100, - "max": 100, - "sum": 100, - "exemplars": [], - "flags": 0 - } - ], - "aggregationTemporality": "Cumulative" - } - }, - { - "name": "http.client.active_requests", - "description": "Number of active HTTP requests.", - "unit": "{request}", - "sum": { - "dataPoints": [ - { - "attributes": { - "server.address": { - "stringValue": "10.0.0.1" - }, - "server.port": { - "intValue": 8080 - } - }, - "startTime": "2024-05-03 23:49:24.856", - "time": "2024-05-03 23:49:24.856", - "startTimeUnixNano": 1714780164856139000, - "timeUnixNano": 1714780164856219000, - "value": 10.0 - } - ], - "aggregationTemporality": "Cumulative", - "isMonotonic": false - } - }, - { - "name": "system.cpu.time", - "description": "Seconds each logical CPU spent on each mode", - "unit": "s", - "sum": { - "dataPoints": [ - { - "attributes": { - "system.cpu.logical_number": { - "intValue": 0 - }, - "system.cpu.state": { - "stringValue": "idle" - } - }, - "startTime": "2024-05-03 23:49:24.856", - "time": "2024-05-03 23:49:24.856", - "startTimeUnixNano": 1714780164856152000, - "timeUnixNano": 1714780164856220000, - "value": 10.0 - }, - { - "attributes": { - "system.cpu.logical_number": { - "intValue": 0 - }, - "system.cpu.state": { - "stringValue": "custom" - } - }, - "startTime": "2024-05-03 23:49:24.856", - "time": "2024-05-03 23:49:24.856", - "startTimeUnixNano": 1714780164856152000, - "timeUnixNano": 1714780164856220000, - "value": 20.0 - } - ], - "aggregationTemporality": "Cumulative", - "isMonotonic": true - } - }, - { - "name": "system.cpu.utilization", - "description": "Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs", - "unit": "1", - "gauge": { - "dataPoints": [ - { - "attributes": { - "system.cpu.logical_number": { - "intValue": 0 - }, - "system.cpu.state": { - "stringValue": "idle" - } - }, - "startTime": null, - "time": "2024-05-03 23:49:24.856", - "startTimeUnixNano": null, - "timeUnixNano": 1714780164856176000, - "value": 10 - }, - { - "attributes": {}, - "startTime": null, - "time": "2024-05-03 23:49:24.856", - "startTimeUnixNano": null, - "timeUnixNano": 1714780164856171000, - "value": -5 - } - ] - } - } - ] - } - ] - } -} -``` \ No newline at end of file diff --git a/crates/weaver_forge/tests/attributes/client.rs b/crates/weaver_forge/tests/attributes/client.rs deleted file mode 100644 index e509e4e9..00000000 --- a/crates/weaver_forge/tests/attributes/client.rs +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! 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 FILE HAS BEEN GENERATED BY WEAVER - -/// 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. -/// -/// Examples: -/// - client.example.com -/// - 10.1.2.80 -/// - /tmp/my.sock -pub const CLIENT_ADDRESS: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("client.address"); - -/// Client port number. -/// -/// 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. -/// -/// Examples: -/// - 65123 -pub const CLIENT_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("client.port"); \ No newline at end of file diff --git a/crates/weaver_forge/tests/attributes/error.rs b/crates/weaver_forge/tests/attributes/error.rs deleted file mode 100644 index 4fd81648..00000000 --- a/crates/weaver_forge/tests/attributes/error.rs +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! This document defines the shared attributes used to report an error. -//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER - -/// Describes a class of error the operation ended with. -/// -/// Notes: -/// The `error.type` SHOULD be predictable, and SHOULD have low cardinality. -/// -/// When `error.type` is set to a type (e.g., an exception type), its -/// canonical class name identifying the type within the artifact SHOULD be used. -/// -/// Instrumentations SHOULD document the list of errors they report. -/// -/// The cardinality of `error.type` within one instrumentation library SHOULD be low. -/// Telemetry consumers that aggregate data from multiple instrumentation libraries and applications -/// should be prepared for `error.type` to have high cardinality at query time when no -/// additional filters are applied. -/// -/// If the operation has completed successfully, instrumentations SHOULD NOT set `error.type`. -/// -/// If a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes), -/// it's RECOMMENDED to: -/// -/// * Use a domain-specific attribute -/// * Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. -/// -/// Examples: -/// - timeout -/// - java.net.UnknownHostException -/// - server_certificate_invalid -/// - 500 -pub const ERROR_TYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("error.type"); - -/// Describes a class of error the operation ended with. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum ErrorType { /// A fallback error value to be used when the instrumentation doesn't define a custom value. - Other, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl ErrorType { - /// Returns the string representation of the [`ErrorType`]. - pub fn as_str(&self) -> &str { - match self { - ErrorType::Other => "_OTHER", - ErrorType::_Custom(v) => v.as_str(), - // 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 ErrorType { - /// Formats the value using the given formatter. - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &ErrorType) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} \ No newline at end of file diff --git a/crates/weaver_forge/tests/attributes/exception.rs b/crates/weaver_forge/tests/attributes/exception.rs deleted file mode 100644 index e7c54bb6..00000000 --- a/crates/weaver_forge/tests/attributes/exception.rs +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! This document defines the shared attributes used to report a single exception associated with a span or log. -//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER - -/// SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span. -/// -/// Notes: -/// An exception is considered to have escaped (or left) the scope of a span, -/// if that span is ended while the exception is still logically "in flight". -/// This may be actually "in flight" in some languages (e.g. if the exception -/// is passed to a Context manager's `__exit__` method in Python) but will -/// usually be caught at the point of recording the exception in most languages. -/// -/// It is usually not possible to determine at the point where an exception is thrown -/// whether it will escape the scope of a span. -/// However, it is trivial to know that an exception -/// will escape, if one checks for an active exception just before ending the span, -/// as done in the [example for recording span exceptions](#recording-an-exception). -/// -/// It follows that an exception may still escape the scope of the span -/// 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: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("exception.escaped"); - -/// The exception message. -/// -/// Examples: -/// - Division by zero -/// - Can't convert 'int' object to str implicitly -pub const EXCEPTION_MESSAGE: crate::attributes::AttributeKey = crate::attributes::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. -/// -/// Example: Exception in thread "main" java.lang.RuntimeException: Test exception\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n at com.example.GenerateTrace.main(GenerateTrace.java:5) -pub const EXCEPTION_STACKTRACE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("exception.stacktrace"); - -/// 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. -/// -/// Examples: -/// - java.net.ConnectException -/// - OSError -pub const EXCEPTION_TYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("exception.type"); \ No newline at end of file diff --git a/crates/weaver_forge/tests/attributes/http.rs b/crates/weaver_forge/tests/attributes/http.rs deleted file mode 100644 index c68fb9fe..00000000 --- a/crates/weaver_forge/tests/attributes/http.rs +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! This document defines semantic convention attributes in the HTTP namespace. -//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER - -/// State of the HTTP connection in the HTTP connection pool. -/// -/// Examples: -/// - active -/// - idle -#[cfg(feature = "semconv_experimental")] -pub const HTTP_CONNECTION_STATE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.connection.state"); - -/// State of the HTTP connection in the HTTP connection pool. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum HttpConnectionState { /// active state. - #[cfg(feature = "semconv_experimental")] - Active, /// idle state. - #[cfg(feature = "semconv_experimental")] - Idle, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl HttpConnectionState { - /// Returns the string representation of the [`HttpConnectionState`]. - pub fn as_str(&self) -> &str { - match self { - #[cfg(feature = "semconv_experimental")] - HttpConnectionState::Active => "active", - #[cfg(feature = "semconv_experimental")] - HttpConnectionState::Idle => "idle", - HttpConnectionState::_Custom(v) => v.as_str(), - // 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()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &HttpConnectionState) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} - -/// 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. -/// -/// Example: 3495 -#[cfg(feature = "semconv_experimental")] -pub const HTTP_REQUEST_BODY_SIZE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.request.body.size"); - -/// HTTP request headers, `` being the normalized HTTP Header name (lowercase), the value being the header values. -/// -/// Notes: -/// 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. -/// -/// Examples: -/// - http.request.header.content-type=["application/json"] -/// - http.request.header.x-forwarded-for=["1.2.3.4", "1.2.3.5"] -pub const HTTP_REQUEST_HEADER: crate::attributes::AttributeKey> = crate::attributes::AttributeKey::new("http.request.header"); - -/// HTTP request method. -/// -/// Notes: -/// HTTP request method value SHOULD be "known" to the instrumentation. -/// By default, this convention defines "known" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods) -/// and the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html). -/// -/// If the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`. -/// -/// If the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override -/// the list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named -/// OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods -/// (this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults). -/// -/// 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. -/// -/// Examples: -/// - GET -/// - POST -/// - HEAD -pub const HTTP_REQUEST_METHOD: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.request.method"); - -/// HTTP request method. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum HttpRequestMethod { /// CONNECT method. - Connect, /// DELETE method. - Delete, /// GET method. - Get, /// HEAD method. - Head, /// OPTIONS method. - Options, /// PATCH method. - Patch, /// POST method. - Post, /// PUT method. - Put, /// TRACE method. - Trace, /// Any HTTP method that the instrumentation has no prior knowledge of. - Other, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl HttpRequestMethod { - /// Returns the string representation of the [`HttpRequestMethod`]. - pub fn as_str(&self) -> &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", - HttpRequestMethod::_Custom(v) => v.as_str(), - // 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()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &HttpRequestMethod) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} - -/// Original HTTP method sent by the client in the request line. -/// -/// Examples: -/// - GeT -/// - ACL -/// - foo -pub const HTTP_REQUEST_METHOD_ORIGINAL: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.request.method_original"); - -/// The ordinal number of request resending attempt (for any reason, including redirects). -/// -/// 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). -/// -/// Example: 3 -pub const HTTP_REQUEST_RESEND_COUNT: crate::attributes::AttributeKey = crate::attributes::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. -/// -/// Example: 1437 -#[cfg(feature = "semconv_experimental")] -pub const HTTP_REQUEST_SIZE: crate::attributes::AttributeKey = crate::attributes::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. -/// -/// Example: 3495 -#[cfg(feature = "semconv_experimental")] -pub const HTTP_RESPONSE_BODY_SIZE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.response.body.size"); - -/// HTTP response headers, `` being the normalized HTTP Header name (lowercase), the value being the header values. -/// -/// Notes: -/// 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. -/// -/// Examples: -/// - http.response.header.content-type=["application/json"] -/// - http.response.header.my-custom-header=["abc", "def"] -pub const HTTP_RESPONSE_HEADER: crate::attributes::AttributeKey> = crate::attributes::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. -/// -/// Example: 1437 -#[cfg(feature = "semconv_experimental")] -pub const HTTP_RESPONSE_SIZE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.response.size"); - -/// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). -/// -/// Examples: -/// - 200 -pub const HTTP_RESPONSE_STATUS_CODE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.response.status_code"); - -/// The matched route, that is, the path template in the format used by the respective server framework. -/// -/// 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. -/// -/// Examples: -/// - /users/:userID? -/// - {controller}/{action}/{id?} -pub const HTTP_ROUTE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("http.route"); \ No newline at end of file diff --git a/crates/weaver_forge/tests/attributes/mod.rs b/crates/weaver_forge/tests/attributes/mod.rs deleted file mode 100644 index 868be073..00000000 --- a/crates/weaver_forge/tests/attributes/mod.rs +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! OpenTelemetry Semantic Convention Attributes -//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER - -use opentelemetry::{Key, KeyValue, StringValue}; - - -/// Attributes for the `client` namespace. -pub mod client; -/// Attributes for the `error` namespace. -pub mod error; -/// Attributes for the `exception` namespace. -pub mod exception; -/// Attributes for the `http` namespace. -pub mod http; -/// Attributes for the `network` namespace. -pub mod network; -/// Attributes for the `server` namespace. -pub mod server; -/// Attributes for the `system` namespace. -pub mod system; -/// Attributes for the `url` namespace. -pub mod url; - -/// A typed attribute key. -pub struct AttributeKey { - key: Key, - phantom: std::marker::PhantomData -} - -impl AttributeKey { - /// Returns a new [`AttributeKey`] with the given key. - pub(crate) const fn new(key: &'static str) -> AttributeKey { - Self { - key: Key::from_static_str(key), - phantom: std::marker::PhantomData - } - } - - /// Returns the key of the attribute. - pub fn key(&self) -> &Key { - &self.key - } -} - -impl AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: StringValue) -> KeyValue { - KeyValue::new(self.key.clone(), v) - } -} - -impl AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: i64) -> KeyValue { - KeyValue::new(self.key.clone(), v) - } -} - -impl AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: f64) -> KeyValue { - KeyValue::new(self.key.clone(), v) - } -} - -impl AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: bool) -> KeyValue { - KeyValue::new(self.key.clone(), v) - } -} \ No newline at end of file diff --git a/crates/weaver_forge/tests/attributes/network.rs b/crates/weaver_forge/tests/attributes/network.rs deleted file mode 100644 index b69454b8..00000000 --- a/crates/weaver_forge/tests/attributes/network.rs +++ /dev/null @@ -1,628 +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 FILE HAS BEEN GENERATED BY WEAVER - -/// Deprecated, use `server.address`. -/// -/// Examples: -/// - example.com -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `server.address`.")] -pub const NET_HOST_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.host.name"); - -/// Deprecated, use `server.port`. -/// -/// Examples: -/// - 8080 -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `server.port`.")] -pub const NET_HOST_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.host.port"); - -/// Deprecated, use `server.address` on client spans and `client.address` on server spans. -/// -/// Examples: -/// - example.com -#[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::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.peer.name"); - -/// Deprecated, use `server.port` on client spans and `client.port` on server spans. -/// -/// Examples: -/// - 8080 -#[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::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.peer.port"); - -/// Deprecated, use `network.protocol.name`. -/// -/// Examples: -/// - amqp -/// - http -/// - mqtt -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `network.protocol.name`.")] -pub const NET_PROTOCOL_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.protocol.name"); - -/// Deprecated, use `network.protocol.version`. -/// -/// Example: 3.1.1 -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `network.protocol.version`.")] -pub const NET_PROTOCOL_VERSION: crate::attributes::AttributeKey = crate::attributes::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::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.family"); - -/// Deprecated, use `network.transport` and `network.type`. -#[derive(Debug, Clone)] -#[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, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl NetSockFamily { - /// Returns the string representation of the [`NetSockFamily`]. - pub fn as_str(&self) -> &str { - match self { - #[cfg(feature = "semconv_experimental")] - NetSockFamily::Inet => "inet", - #[cfg(feature = "semconv_experimental")] - NetSockFamily::Inet6 => "inet6", - #[cfg(feature = "semconv_experimental")] - NetSockFamily::Unix => "unix", - NetSockFamily::_Custom(v) => v.as_str(), - // 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()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &NetSockFamily) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} - -/// Deprecated, use `network.local.address`. -/// -/// Examples: -/// - /var/my.sock -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `network.local.address`.")] -pub const NET_SOCK_HOST_ADDR: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.host.addr"); - -/// Deprecated, use `network.local.port`. -/// -/// Examples: -/// - 8080 -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `network.local.port`.")] -pub const NET_SOCK_HOST_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.host.port"); - -/// Deprecated, use `network.peer.address`. -/// -/// Examples: -/// - 192.168.0.1 -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `network.peer.address`.")] -pub const NET_SOCK_PEER_ADDR: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.peer.addr"); - -/// Deprecated, no replacement at this time. -/// -/// Examples: -/// - /var/my.sock -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Removed.")] -pub const NET_SOCK_PEER_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.peer.name"); - -/// Deprecated, use `network.peer.port`. -/// -/// Examples: -/// - 65531 -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `network.peer.port`.")] -pub const NET_SOCK_PEER_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.sock.peer.port"); - -/// Deprecated, use `network.transport`. -#[cfg(feature = "semconv_experimental")] -#[deprecated(note="Replaced by `network.transport`.")] -pub const NET_TRANSPORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("net.transport"); - -/// Deprecated, use `network.transport`. -#[derive(Debug, Clone)] -#[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, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl NetTransport { - /// Returns the string representation of the [`NetTransport`]. - pub fn as_str(&self) -> &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", - NetTransport::_Custom(v) => v.as_str(), - // 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()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &NetTransport) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} - -/// The ISO 3166-1 alpha-2 2-character country code associated with the mobile carrier network. -/// -/// Example: DE -#[cfg(feature = "semconv_experimental")] -pub const NETWORK_CARRIER_ICC: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.icc"); - -/// The mobile carrier country code. -/// -/// Example: 310 -#[cfg(feature = "semconv_experimental")] -pub const NETWORK_CARRIER_MCC: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.mcc"); - -/// The mobile carrier network code. -/// -/// Example: 001 -#[cfg(feature = "semconv_experimental")] -pub const NETWORK_CARRIER_MNC: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.mnc"); - -/// The name of the mobile carrier. -/// -/// Example: sprint -#[cfg(feature = "semconv_experimental")] -pub const NETWORK_CARRIER_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.carrier.name"); - -/// This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection. -/// -/// Example: LTE -#[cfg(feature = "semconv_experimental")] -pub const NETWORK_CONNECTION_SUBTYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.connection.subtype"); - -/// This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum NetworkConnectionSubtype { /// GPRS - #[cfg(feature = "semconv_experimental")] - Gprs, /// EDGE - #[cfg(feature = "semconv_experimental")] - Edge, /// UMTS - #[cfg(feature = "semconv_experimental")] - Umts, /// CDMA - #[cfg(feature = "semconv_experimental")] - Cdma, /// EVDO Rel. 0 - #[cfg(feature = "semconv_experimental")] - Evdo0, /// EVDO Rev. A - #[cfg(feature = "semconv_experimental")] - EvdoA, /// CDMA2000 1XRTT - #[cfg(feature = "semconv_experimental")] - Cdma20001Xrtt, /// HSDPA - #[cfg(feature = "semconv_experimental")] - Hsdpa, /// HSUPA - #[cfg(feature = "semconv_experimental")] - Hsupa, /// HSPA - #[cfg(feature = "semconv_experimental")] - Hspa, /// IDEN - #[cfg(feature = "semconv_experimental")] - Iden, /// EVDO Rev. B - #[cfg(feature = "semconv_experimental")] - EvdoB, /// LTE - #[cfg(feature = "semconv_experimental")] - Lte, /// EHRPD - #[cfg(feature = "semconv_experimental")] - Ehrpd, /// HSPAP - #[cfg(feature = "semconv_experimental")] - Hspap, /// GSM - #[cfg(feature = "semconv_experimental")] - Gsm, /// TD-SCDMA - #[cfg(feature = "semconv_experimental")] - TdScdma, /// IWLAN - #[cfg(feature = "semconv_experimental")] - Iwlan, /// 5G NR (New Radio) - #[cfg(feature = "semconv_experimental")] - Nr, /// 5G NRNSA (New Radio Non-Standalone) - #[cfg(feature = "semconv_experimental")] - Nrnsa, /// LTE CA - #[cfg(feature = "semconv_experimental")] - LteCa, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl NetworkConnectionSubtype { - /// Returns the string representation of the [`NetworkConnectionSubtype`]. - pub fn as_str(&self) -> &str { - match self { - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Gprs => "gprs", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Edge => "edge", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Umts => "umts", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Cdma => "cdma", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Evdo0 => "evdo_0", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::EvdoA => "evdo_a", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Cdma20001Xrtt => "cdma2000_1xrtt", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Hsdpa => "hsdpa", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Hsupa => "hsupa", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Hspa => "hspa", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Iden => "iden", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::EvdoB => "evdo_b", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Lte => "lte", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Ehrpd => "ehrpd", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Hspap => "hspap", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Gsm => "gsm", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::TdScdma => "td_scdma", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Iwlan => "iwlan", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Nr => "nr", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::Nrnsa => "nrnsa", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionSubtype::LteCa => "lte_ca", - NetworkConnectionSubtype::_Custom(v) => v.as_str(), - // 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 NetworkConnectionSubtype { - /// Formats the value using the given formatter. - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &NetworkConnectionSubtype) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} - -/// The internet connection type. -/// -/// Example: wifi -#[cfg(feature = "semconv_experimental")] -pub const NETWORK_CONNECTION_TYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.connection.type"); - -/// The internet connection type. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum NetworkConnectionType { - #[cfg(feature = "semconv_experimental")] - Wifi, - #[cfg(feature = "semconv_experimental")] - Wired, - #[cfg(feature = "semconv_experimental")] - Cell, - #[cfg(feature = "semconv_experimental")] - Unavailable, - #[cfg(feature = "semconv_experimental")] - Unknown, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl NetworkConnectionType { - /// Returns the string representation of the [`NetworkConnectionType`]. - pub fn as_str(&self) -> &str { - match self { - #[cfg(feature = "semconv_experimental")] - NetworkConnectionType::Wifi => "wifi", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionType::Wired => "wired", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionType::Cell => "cell", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionType::Unavailable => "unavailable", - #[cfg(feature = "semconv_experimental")] - NetworkConnectionType::Unknown => "unknown", - NetworkConnectionType::_Custom(v) => v.as_str(), - // 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 NetworkConnectionType { - /// Formats the value using the given formatter. - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &NetworkConnectionType) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} - -/// The network IO operation direction. -/// -/// Examples: -/// - transmit -#[cfg(feature = "semconv_experimental")] -pub const NETWORK_IO_DIRECTION: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.io.direction"); - -/// The network IO operation direction. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum NetworkIoDirection { - #[cfg(feature = "semconv_experimental")] - Transmit, - #[cfg(feature = "semconv_experimental")] - Receive, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl NetworkIoDirection { - /// Returns the string representation of the [`NetworkIoDirection`]. - pub fn as_str(&self) -> &str { - match self { - #[cfg(feature = "semconv_experimental")] - NetworkIoDirection::Transmit => "transmit", - #[cfg(feature = "semconv_experimental")] - NetworkIoDirection::Receive => "receive", - NetworkIoDirection::_Custom(v) => v.as_str(), - // 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 NetworkIoDirection { - /// Formats the value using the given formatter. - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &NetworkIoDirection) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} - -/// Local address of the network connection - IP address or Unix domain socket name. -/// -/// Examples: -/// - 10.1.2.80 -/// - /tmp/my.sock -pub const NETWORK_LOCAL_ADDRESS: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.local.address"); - -/// Local port number of the network connection. -/// -/// Examples: -/// - 65123 -pub const NETWORK_LOCAL_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.local.port"); - -/// Peer address of the network connection - IP address or Unix domain socket name. -/// -/// Examples: -/// - 10.1.2.80 -/// - /tmp/my.sock -pub const NETWORK_PEER_ADDRESS: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.peer.address"); - -/// Peer port number of the network connection. -/// -/// Examples: -/// - 65123 -pub const NETWORK_PEER_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.peer.port"); - -/// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. -/// -/// Notes: -/// The value SHOULD be normalized to lowercase. -/// -/// Examples: -/// - amqp -/// - http -/// - mqtt -pub const NETWORK_PROTOCOL_NAME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.protocol.name"); - -/// The actual version of the protocol used for network communication. -/// -/// Notes: -/// If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, this attribute SHOULD NOT be set. -/// -/// Examples: -/// - 1.1 -/// - 2 -pub const NETWORK_PROTOCOL_VERSION: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.protocol.version"); - -/// [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). -/// -/// Notes: -/// The value SHOULD be normalized to lowercase. -/// -/// Consider always setting the transport when setting a port number, since -/// a port number is ambiguous without knowing the transport. For example -/// different processes could be listening on TCP port 12345 and UDP port 12345. -/// -/// Examples: -/// - tcp -/// - udp -pub const NETWORK_TRANSPORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.transport"); - -/// [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum NetworkTransport { /// TCP - Tcp, /// UDP - Udp, /// Named or anonymous pipe. - Pipe, /// Unix domain socket - Unix, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl NetworkTransport { - /// Returns the string representation of the [`NetworkTransport`]. - pub fn as_str(&self) -> &str { - match self { - NetworkTransport::Tcp => "tcp", - NetworkTransport::Udp => "udp", - NetworkTransport::Pipe => "pipe", - NetworkTransport::Unix => "unix", - NetworkTransport::_Custom(v) => v.as_str(), - // 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 NetworkTransport { - /// Formats the value using the given formatter. - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &NetworkTransport) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} - -/// [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. -/// -/// Notes: -/// The value SHOULD be normalized to lowercase. -/// -/// Examples: -/// - ipv4 -/// - ipv6 -pub const NETWORK_TYPE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("network.type"); - -/// [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum NetworkType { /// IPv4 - Ipv4, /// IPv6 - Ipv6, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl NetworkType { - /// Returns the string representation of the [`NetworkType`]. - pub fn as_str(&self) -> &str { - match self { - NetworkType::Ipv4 => "ipv4", - NetworkType::Ipv6 => "ipv6", - NetworkType::_Custom(v) => v.as_str(), - // 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 NetworkType { - /// Formats the value using the given formatter. - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &NetworkType) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} \ No newline at end of file diff --git a/crates/weaver_forge/tests/attributes/server.rs b/crates/weaver_forge/tests/attributes/server.rs deleted file mode 100644 index f5b790e3..00000000 --- a/crates/weaver_forge/tests/attributes/server.rs +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! These attributes may be used to describe the server 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 FILE HAS BEEN GENERATED BY WEAVER - -/// Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. -/// -/// Notes: -/// When observed from the client side, and when communicating through an intermediary, `server.address` SHOULD represent the server address behind any intermediaries, for example proxies, if it's available. -/// -/// Examples: -/// - example.com -/// - 10.1.2.80 -/// - /tmp/my.sock -pub const SERVER_ADDRESS: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("server.address"); - -/// Server port number. -/// -/// Notes: -/// When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent the server port behind any intermediaries, for example proxies, if it's available. -/// -/// Examples: -/// - 80 -/// - 8080 -/// - 443 -pub const SERVER_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("server.port"); \ No newline at end of file diff --git a/crates/weaver_forge/tests/attributes/system.rs b/crates/weaver_forge/tests/attributes/system.rs deleted file mode 100644 index c8587be1..00000000 --- a/crates/weaver_forge/tests/attributes/system.rs +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! Describes System CPU attributes -//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER - -/// The logical CPU number [0..n-1] -/// -/// Examples: -/// - 1 -pub const SYSTEM_CPU_LOGICAL_NUMBER: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("system.cpu.logical_number"); - -/// The state of the CPU -/// -/// Examples: -/// - idle -/// - interrupt -pub const SYSTEM_CPU_STATE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("system.cpu.state"); - -/// The state of the CPU -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum SystemCpuState { - User, - System, - Nice, - Idle, - #[cfg(feature = "semconv_experimental")] - Iowait, - #[cfg(feature = "semconv_experimental")] - Interrupt, - #[cfg(feature = "semconv_experimental")] - Steal, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl SystemCpuState { - /// Returns the string representation of the [`SystemCpuState`]. - pub fn as_str(&self) -> &str { - match self { - SystemCpuState::User => "user", - SystemCpuState::System => "system", - SystemCpuState::Nice => "nice", - SystemCpuState::Idle => "idle", - #[cfg(feature = "semconv_experimental")] - SystemCpuState::Iowait => "iowait", - #[cfg(feature = "semconv_experimental")] - SystemCpuState::Interrupt => "interrupt", - #[cfg(feature = "semconv_experimental")] - SystemCpuState::Steal => "steal", - SystemCpuState::_Custom(v) => v.as_str(), - // 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 SystemCpuState { - /// Formats the value using the given formatter. - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &SystemCpuState) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} - -/// The memory state -/// -/// Examples: -/// - free -/// - cached -pub const SYSTEM_MEMORY_STATE: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("system.memory.state"); - -/// The memory state -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum SystemMemoryState { - #[cfg(feature = "semconv_experimental")] - Used, - #[cfg(feature = "semconv_experimental")] - Free, - #[cfg(feature = "semconv_experimental")] - Shared, - #[cfg(feature = "semconv_experimental")] - Buffers, - #[cfg(feature = "semconv_experimental")] - Cached, - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl SystemMemoryState { - /// Returns the string representation of the [`SystemMemoryState`]. - pub fn as_str(&self) -> &str { - match self { - #[cfg(feature = "semconv_experimental")] - SystemMemoryState::Used => "used", - #[cfg(feature = "semconv_experimental")] - SystemMemoryState::Free => "free", - #[cfg(feature = "semconv_experimental")] - SystemMemoryState::Shared => "shared", - #[cfg(feature = "semconv_experimental")] - SystemMemoryState::Buffers => "buffers", - #[cfg(feature = "semconv_experimental")] - SystemMemoryState::Cached => "cached", - SystemMemoryState::_Custom(v) => v.as_str(), - // 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 SystemMemoryState { - /// Formats the value using the given formatter. - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -impl crate::attributes::AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - pub fn value(&self, v: &SystemMemoryState) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} \ No newline at end of file diff --git a/crates/weaver_forge/tests/attributes/url.rs b/crates/weaver_forge/tests/attributes/url.rs deleted file mode 100644 index 82ab6cdc..00000000 --- a/crates/weaver_forge/tests/attributes/url.rs +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! Attributes describing URL. -//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER - -/// Domain extracted from the `url.full`, such as "opentelemetry.io". -/// -/// Notes: -/// In some cases a URL may refer to an IP and/or port directly, without a domain name. In this case, the IP address would go to the domain field. If the URL contains a [literal IPv6 address](https://www.rfc-editor.org/rfc/rfc2732#section-2) enclosed by `[` and `]`, the `[` and `]` characters should also be captured in the domain field. -/// -/// Examples: -/// - www.foo.bar -/// - opentelemetry.io -/// - 3.12.167.2 -/// - [1080:0:0:0:8:800:200C:417A] -#[cfg(feature = "semconv_experimental")] -pub const URL_DOMAIN: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.domain"); - -/// The file extension extracted from the `url.full`, excluding the leading dot. -/// -/// Notes: -/// The file extension is only set if it exists, as not every url has a file extension. When the file name has multiple extensions `example.tar.gz`, only the last one should be captured `gz`, not `tar.gz`. -/// -/// Examples: -/// - png -/// - gz -#[cfg(feature = "semconv_experimental")] -pub const URL_EXTENSION: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.extension"); - -/// The [URI fragment](https://www.rfc-editor.org/rfc/rfc3986#section-3.5) component -/// -/// Examples: -/// - SemConv -pub const URL_FRAGMENT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.fragment"); - -/// Absolute URL describing a network resource according to [RFC3986](https://www.rfc-editor.org/rfc/rfc3986) -/// -/// Notes: -/// For network calls, URL usually has `scheme://host[:port][path][?query][#fragment]` format, where the fragment is not transmitted over HTTP, but if it is known, it SHOULD be included nevertheless. -/// `url.full` MUST NOT contain credentials passed via URL in form of `https://username:password@www.example.com/`. In such case username and password SHOULD be redacted and attribute's value SHOULD be `https://REDACTED:REDACTED@www.example.com/`. -/// `url.full` SHOULD capture the absolute URL when it is available (or can be reconstructed). Sensitive content provided in `url.full` SHOULD be scrubbed when instrumentations can identify it. -/// -/// Examples: -/// - https://www.foo.bar/search?q=OpenTelemetry#SemConv -/// - //localhost -pub const URL_FULL: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.full"); - -/// Unmodified original URL as seen in the event source. -/// -/// Notes: -/// In network monitoring, the observed URL may be a full URL, whereas in access logs, the URL is often just represented as a path. This field is meant to represent the URL as it was observed, complete or not. -/// `url.original` might contain credentials passed via URL in form of `https://username:password@www.example.com/`. In such case password and username SHOULD NOT be redacted and attribute's value SHOULD remain the same. -/// -/// Examples: -/// - https://www.foo.bar/search?q=OpenTelemetry#SemConv -/// - search?q=OpenTelemetry -#[cfg(feature = "semconv_experimental")] -pub const URL_ORIGINAL: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.original"); - -/// The [URI path](https://www.rfc-editor.org/rfc/rfc3986#section-3.3) component -/// -/// Notes: -/// Sensitive content provided in `url.path` SHOULD be scrubbed when instrumentations can identify it. -/// -/// Examples: -/// - /search -pub const URL_PATH: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.path"); - -/// Port extracted from the `url.full` -/// -/// Examples: -/// - 443 -#[cfg(feature = "semconv_experimental")] -pub const URL_PORT: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.port"); - -/// The [URI query](https://www.rfc-editor.org/rfc/rfc3986#section-3.4) component -/// -/// Notes: -/// Sensitive content provided in `url.query` SHOULD be scrubbed when instrumentations can identify it. -/// -/// Examples: -/// - q=OpenTelemetry -pub const URL_QUERY: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.query"); - -/// The highest registered url domain, stripped of the subdomain. -/// -/// Notes: -/// This value can be determined precisely with the [public suffix list](http://publicsuffix.org). For example, the registered domain for `foo.example.com` is `example.com`. Trying to approximate this by simply taking the last two labels will not work well for TLDs such as `co.uk`. -/// -/// Examples: -/// - example.com -/// - foo.co.uk -#[cfg(feature = "semconv_experimental")] -pub const URL_REGISTERED_DOMAIN: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.registered_domain"); - -/// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. -/// -/// Examples: -/// - https -/// - ftp -/// - telnet -pub const URL_SCHEME: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.scheme"); - -/// The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. -/// -/// Notes: -/// The subdomain portion of `www.east.mydomain.co.uk` is `east`. If the domain has multiple levels of subdomain, such as `sub2.sub1.example.com`, the subdomain field should contain `sub2.sub1`, with no trailing period. -/// -/// Examples: -/// - east -/// - sub2.sub1 -#[cfg(feature = "semconv_experimental")] -pub const URL_SUBDOMAIN: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.subdomain"); - -/// The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is `com`. -/// -/// Notes: -/// This value can be determined precisely with the [public suffix list](http://publicsuffix.org). -/// -/// Examples: -/// - com -/// - co.uk -#[cfg(feature = "semconv_experimental")] -pub const URL_TOP_LEVEL_DOMAIN: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("url.top_level_domain"); \ No newline at end of file diff --git a/crates/weaver_forge/tests/codegen.rs b/crates/weaver_forge/tests/codegen.rs deleted file mode 100644 index 4f4646b0..00000000 --- a/crates/weaver_forge/tests/codegen.rs +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -//! Tests for the codegen module - -use opentelemetry::global; -use opentelemetry::metrics::Histogram; - -use attributes::http::{HTTP_REQUEST_METHOD, HttpRequestMethod}; -use attributes::system::SystemCpuState; -use metrics::http::{create_http_client_request_duration, HttpClientActiveRequests, HttpClientActiveRequestsReqAttributes, HttpServerRequestDurationOptAttributes, HttpServerRequestDurationReqAttributes}; -use metrics::http::HttpServerRequestDuration; -use metrics::system::{SystemCpuTime, SystemCpuTimeOptAttributes, SystemCpuUtilization, SystemCpuUtilizationOptAttributes}; - -pub mod attributes; -pub mod metrics; - -#[test] -fn test_semconv_rust_codegen() { - // SemConv attributes are typed, so the compiler will catch type errors - // Experimental attributes are not visible if the `semconv_experimental` feature is not enabled - println!("{:?}", attributes::client::CLIENT_ADDRESS.value("145.34.23.56".into())); - println!("{:?}", attributes::client::CLIENT_ADDRESS.key()); - println!("{:?}", attributes::client::CLIENT_PORT.value(8080)); - println!("{:?}", attributes::client::CLIENT_PORT.key()); - - println!("{}", HttpRequestMethod::Connect); - - let meter = global::meter("mylibname"); - - // Create a u64 http.client.request.duration metric - let http_client_request_duration: Histogram = create_http_client_request_duration(&meter); - http_client_request_duration.record(100, &[ - HTTP_REQUEST_METHOD.value(&HttpRequestMethod::Connect), - // here nothing guarantees that all the required attributes are provided - ]); - - let http_client_request_duration: Histogram = create_http_client_request_duration(&meter); - dbg!(http_client_request_duration); - - // ==== A TYPE-SAFE HISTOGRAM API ==== - // Create a u64 http.server.request.duration metric (as defined in the OpenTelemetry HTTP - // semantic conventions) - let http_request_duration = HttpServerRequestDuration::::new(&meter); - - // Records a new data point and provide the required and some optional attributes - http_request_duration.record(100, &HttpServerRequestDurationReqAttributes { - http_request_method: HttpRequestMethod::Connect, - url_scheme: "http".to_owned(), - }, Some(&HttpServerRequestDurationOptAttributes { - http_response_status_code: Some(200), - ..Default::default() - })); - - // ==== A TYPE-SAFE UP-DOWN-COUNTER API ==== - // Create a f64 http.server.request.duration metric (as defined in the OpenTelemetry HTTP - // semantic conventions) - let http_client_active_requests = HttpClientActiveRequests::::new(&meter); - - // Adds a new data point and provide the required attributes. Optional attributes are not - // provided in this example. - http_client_active_requests.add(10.0, &HttpClientActiveRequestsReqAttributes { - server_address: "10.0.0.1".to_owned(), - server_port: 8080, - }, None); - - // ==== A TYPE-SAFE COUNTER API ==== - // Create a f64 system.cpu.time metric (as defined in the OpenTelemetry System semantic - // conventions) - let system_cpu_time = SystemCpuTime::::new(&meter); - - // Adds a new data point and provide some optional attributes. - // Note: In the method signature, there is no required attribute. - system_cpu_time.add(10.0, Some(&SystemCpuTimeOptAttributes { - system_cpu_logical_number: Some(0), - system_cpu_state: Some(SystemCpuState::Idle) - })); - // Adds a new data point with a custom CPU state. - system_cpu_time.add(20.0, Some(&SystemCpuTimeOptAttributes { - system_cpu_logical_number: Some(0), - system_cpu_state: Some(SystemCpuState::_Custom("custom".to_owned())) - })); - - // ==== A TYPE-SAFE GAUGE API ==== - // Create a i64 system.cpu.utilization metric (as defined in the OpenTelemetry System semantic - // conventions) - let system_cpu_utilization = SystemCpuUtilization::::new(&meter); - - // Adds a new data point with no optional attributes. - system_cpu_utilization.record(-5, None); - // Adds a new data point with some optional attributes. - system_cpu_utilization.record(10, Some(&SystemCpuUtilizationOptAttributes { - system_cpu_logical_number: Some(0), - system_cpu_state: Some(SystemCpuState::Idle) - })); -} \ No newline at end of file diff --git a/crates/weaver_forge/tests/lib.rs b/crates/weaver_forge/tests/lib.rs deleted file mode 100644 index ae1281bf..00000000 --- a/crates/weaver_forge/tests/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! OpenTelemetry Semantic Convention Attributes -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 - -pub mod attributes; -pub mod metrics; diff --git a/crates/weaver_forge/tests/metrics/http.rs b/crates/weaver_forge/tests/metrics/http.rs deleted file mode 100644 index 8f4c1c10..00000000 --- a/crates/weaver_forge/tests/metrics/http.rs +++ /dev/null @@ -1,486 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER - -/// Duration of HTTP server requests. -pub fn create_http_server_request_duration(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram - where opentelemetry::metrics::Meter: crate::metrics::HistogramProvider { - crate::metrics::HistogramProvider::create_histogram(meter, "http.server.request.duration", "Duration of HTTP server requests.", "s") -} - -/// Metric: http.server.request.duration -/// Brief: Duration of HTTP server requests. -/// Unit: s -#[derive(Debug)] -pub struct HttpServerRequestDuration(opentelemetry::metrics::Histogram); - - -/// Attributes for the `http.server.request.duration` metric. -#[derive(Debug, Clone)] -pub struct HttpServerRequestDurationReqAttributes { - - /// HTTP request method. - /// - /// Notes: - /// HTTP request method value SHOULD be "known" to the instrumentation. - /// By default, this convention defines "known" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods) - /// and the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html). - /// - /// If the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`. - /// - /// If the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override - /// the list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named - /// OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods - /// (this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults). - /// - /// 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. - /// - /// Examples: - /// - GET - /// - POST - /// - HEAD - pub http_request_method: crate::attributes::http::HttpRequestMethod, - - /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. - /// - /// Notes: - /// The scheme of the original client request, if known (e.g. from [Forwarded#proto](https://developer.mozilla.org/docs/Web/HTTP/Headers/Forwarded#proto), [X-Forwarded-Proto](https://developer.mozilla.org/docs/Web/HTTP/Headers/X-Forwarded-Proto), or a similar header). Otherwise, the scheme of the immediate peer request. - /// - /// Examples: - /// - http - /// - https - pub url_scheme: String, -} - - - -#[derive(Debug, Clone, Default)] -pub struct HttpServerRequestDurationOptAttributes { - - /// Describes a class of error the operation ended with. - /// - /// Notes: - /// If the request fails with an error before response status code was sent or received, - /// `error.type` SHOULD be set to exception type (its fully-qualified class name, if applicable) - /// or a component-specific low cardinality error identifier. - /// - /// If response status code was sent or received and status indicates an error according to [HTTP span status definition](/docs/http/http-spans.md), - /// `error.type` SHOULD be set to the status code number (represented as a string), an exception type (if thrown) or a component-specific error identifier. - /// - /// The `error.type` value SHOULD be predictable and SHOULD have low cardinality. - /// Instrumentations SHOULD document the list of errors they report. - /// - /// The cardinality of `error.type` within one instrumentation library SHOULD be low, but - /// telemetry consumers that aggregate data from multiple instrumentation libraries and applications - /// should be prepared for `error.type` to have high cardinality at query time, when no - /// additional filters are applied. - /// - /// If the request has completed successfully, instrumentations SHOULD NOT set `error.type`. - /// - /// Examples: - /// - timeout - /// - java.net.UnknownHostException - /// - server_certificate_invalid - /// - 500 - pub error_type: Option, - - /// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). - /// - /// Examples: - /// - 200 - pub http_response_status_code: Option, - - /// The matched route, that is, the path template in the format used by the respective server framework. - /// - /// 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. - /// - /// Examples: - /// - /users/:userID? - /// - {controller}/{action}/{id?} - pub http_route: Option, - - /// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. - /// - /// Notes: - /// The value SHOULD be normalized to lowercase. - /// - /// Examples: - /// - http - /// - spdy - pub network_protocol_name: Option, - - /// The actual version of the protocol used for network communication. - /// - /// Notes: - /// If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, this attribute SHOULD NOT be set. - /// - /// Examples: - /// - 1.0 - /// - 1.1 - /// - 2 - /// - 3 - pub network_protocol_version: Option, - - /// Name of the local HTTP server that received the request. - /// - /// Notes: - /// See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). - /// > **Warning** - /// > Since this attribute is based on HTTP headers, opting in to it may allow an attacker - /// > to trigger cardinality limits, degrading the usefulness of the metric. - /// - /// Examples: - /// - example.com - /// - 10.1.2.80 - /// - /tmp/my.sock - pub server_address: Option, - - /// Port of the local HTTP server that received the request. - /// - /// Notes: - /// See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). - /// > **Warning** - /// > Since this attribute is based on HTTP headers, opting in to it may allow an attacker - /// > to trigger cardinality limits, degrading the usefulness of the metric. - /// - /// Examples: - /// - 80 - /// - 8080 - /// - 443 - pub server_port: Option, -} - - -impl HttpServerRequestDuration { - pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: crate::metrics::HistogramProvider{ - Self(crate::metrics::HistogramProvider::create_histogram(meter, "http.server.request.duration", "Duration of HTTP server requests.", "s")) - } - - /// Adds an additional value to the distribution. - pub fn record( - &self, - value: T, - required_attributes: &HttpServerRequestDurationReqAttributes, - not_required_attributes: Option<&HttpServerRequestDurationOptAttributes>, - ) { - let mut attributes = vec![ - crate::attributes::http::HTTP_REQUEST_METHOD.value(&required_attributes.http_request_method), - crate::attributes::url::URL_SCHEME.value(required_attributes.url_scheme.to_string().into()), - ]; - - if let Some(value) = ¬_required_attributes { - if let Some(error_type) = &value.error_type { - attributes.push(crate::attributes::error::ERROR_TYPE.value(error_type)); - } - if let Some(http_response_status_code) = value.http_response_status_code { - attributes.push(crate::attributes::http::HTTP_RESPONSE_STATUS_CODE.value(http_response_status_code)); - } - if let Some(http_route) = &value.http_route { - attributes.push(crate::attributes::http::HTTP_ROUTE.value(http_route.to_string().into())); - } - if let Some(network_protocol_name) = &value.network_protocol_name { - attributes.push(crate::attributes::network::NETWORK_PROTOCOL_NAME.value(network_protocol_name.to_string().into())); - } - if let Some(network_protocol_version) = &value.network_protocol_version { - attributes.push(crate::attributes::network::NETWORK_PROTOCOL_VERSION.value(network_protocol_version.to_string().into())); - } - if let Some(server_address) = &value.server_address { - attributes.push(crate::attributes::server::SERVER_ADDRESS.value(server_address.to_string().into())); - } - if let Some(server_port) = value.server_port { - attributes.push(crate::attributes::server::SERVER_PORT.value(server_port)); - } - } - self.0.record(value, &attributes) - } -} - -/// Duration of HTTP client requests. -pub fn create_http_client_request_duration(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram - where opentelemetry::metrics::Meter: crate::metrics::HistogramProvider { - crate::metrics::HistogramProvider::create_histogram(meter, "http.client.request.duration", "Duration of HTTP client requests.", "s") -} - -/// Metric: http.client.request.duration -/// Brief: Duration of HTTP client requests. -/// Unit: s -#[derive(Debug)] -pub struct HttpClientRequestDuration(opentelemetry::metrics::Histogram); - - -/// Attributes for the `http.client.request.duration` metric. -#[derive(Debug, Clone)] -pub struct HttpClientRequestDurationReqAttributes { - - /// HTTP request method. - /// - /// Notes: - /// HTTP request method value SHOULD be "known" to the instrumentation. - /// By default, this convention defines "known" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods) - /// and the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html). - /// - /// If the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`. - /// - /// If the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override - /// the list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named - /// OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods - /// (this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults). - /// - /// 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. - /// - /// Examples: - /// - GET - /// - POST - /// - HEAD - pub http_request_method: crate::attributes::http::HttpRequestMethod, - - /// Host identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. - /// - /// Notes: - /// If an HTTP client request is explicitly made to an IP address, e.g. `http://x.x.x.x:8080`, then `server.address` SHOULD be the IP address `x.x.x.x`. A DNS lookup SHOULD NOT be used. - /// - /// Examples: - /// - example.com - /// - 10.1.2.80 - /// - /tmp/my.sock - pub server_address: String, - - /// Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. - /// - /// Notes: - /// When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent the server port behind any intermediaries, for example proxies, if it's available. - /// - /// Examples: - /// - 80 - /// - 8080 - /// - 443 - pub server_port: i64, -} - - - -#[derive(Debug, Clone, Default)] -pub struct HttpClientRequestDurationOptAttributes { - - /// Describes a class of error the operation ended with. - /// - /// Notes: - /// If the request fails with an error before response status code was sent or received, - /// `error.type` SHOULD be set to exception type (its fully-qualified class name, if applicable) - /// or a component-specific low cardinality error identifier. - /// - /// If response status code was sent or received and status indicates an error according to [HTTP span status definition](/docs/http/http-spans.md), - /// `error.type` SHOULD be set to the status code number (represented as a string), an exception type (if thrown) or a component-specific error identifier. - /// - /// The `error.type` value SHOULD be predictable and SHOULD have low cardinality. - /// Instrumentations SHOULD document the list of errors they report. - /// - /// The cardinality of `error.type` within one instrumentation library SHOULD be low, but - /// telemetry consumers that aggregate data from multiple instrumentation libraries and applications - /// should be prepared for `error.type` to have high cardinality at query time, when no - /// additional filters are applied. - /// - /// If the request has completed successfully, instrumentations SHOULD NOT set `error.type`. - /// - /// Examples: - /// - timeout - /// - java.net.UnknownHostException - /// - server_certificate_invalid - /// - 500 - pub error_type: Option, - - /// [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). - /// - /// Examples: - /// - 200 - pub http_response_status_code: Option, - - /// [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. - /// - /// Notes: - /// The value SHOULD be normalized to lowercase. - /// - /// Examples: - /// - http - /// - spdy - pub network_protocol_name: Option, - - /// The actual version of the protocol used for network communication. - /// - /// Notes: - /// If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, this attribute SHOULD NOT be set. - /// - /// Examples: - /// - 1.0 - /// - 1.1 - /// - 2 - /// - 3 - pub network_protocol_version: Option, - - /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. - /// - /// Examples: - /// - http - /// - https - pub url_scheme: Option, -} - - -impl HttpClientRequestDuration { - pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: crate::metrics::HistogramProvider{ - Self(crate::metrics::HistogramProvider::create_histogram(meter, "http.client.request.duration", "Duration of HTTP client requests.", "s")) - } - - /// Adds an additional value to the distribution. - pub fn record( - &self, - value: T, - required_attributes: &HttpClientRequestDurationReqAttributes, - not_required_attributes: Option<&HttpClientRequestDurationOptAttributes>, - ) { - let mut attributes = vec![ - crate::attributes::http::HTTP_REQUEST_METHOD.value(&required_attributes.http_request_method), - crate::attributes::server::SERVER_ADDRESS.value(required_attributes.server_address.to_string().into()), - crate::attributes::server::SERVER_PORT.value(required_attributes.server_port), - ]; - - if let Some(value) = ¬_required_attributes { - if let Some(error_type) = &value.error_type { - attributes.push(crate::attributes::error::ERROR_TYPE.value(error_type)); - } - if let Some(http_response_status_code) = value.http_response_status_code { - attributes.push(crate::attributes::http::HTTP_RESPONSE_STATUS_CODE.value(http_response_status_code)); - } - if let Some(network_protocol_name) = &value.network_protocol_name { - attributes.push(crate::attributes::network::NETWORK_PROTOCOL_NAME.value(network_protocol_name.to_string().into())); - } - if let Some(network_protocol_version) = &value.network_protocol_version { - attributes.push(crate::attributes::network::NETWORK_PROTOCOL_VERSION.value(network_protocol_version.to_string().into())); - } - if let Some(url_scheme) = &value.url_scheme { - attributes.push(crate::attributes::url::URL_SCHEME.value(url_scheme.to_string().into())); - } - } - self.0.record(value, &attributes) - } -} - -/// Number of active HTTP requests. -#[cfg(feature = "semconv_experimental")] -pub fn create_http_client_active_requests(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter - where opentelemetry::metrics::Meter: crate::metrics::UpDownCounterProvider { - crate::metrics::UpDownCounterProvider::create_up_down_counter(meter, "http.client.active_requests", "Number of active HTTP requests.", "{request}") -} - -/// Metric: http.client.active_requests -/// Brief: Number of active HTTP requests. -/// Unit: {request} -#[derive(Debug)] -pub struct HttpClientActiveRequests(opentelemetry::metrics::UpDownCounter); - - -/// Attributes for the `http.client.active_requests` metric. -#[derive(Debug, Clone)] -pub struct HttpClientActiveRequestsReqAttributes { - - /// Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. - /// - /// Notes: - /// When observed from the client side, and when communicating through an intermediary, `server.address` SHOULD represent the server address behind any intermediaries, for example proxies, if it's available. - /// - /// Examples: - /// - example.com - /// - 10.1.2.80 - /// - /tmp/my.sock - pub server_address: String, - - /// Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. - /// - /// Notes: - /// When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent the server port behind any intermediaries, for example proxies, if it's available. - /// - /// Examples: - /// - 80 - /// - 8080 - /// - 443 - pub server_port: i64, -} - - - -#[derive(Debug, Clone, Default)] -pub struct HttpClientActiveRequestsOptAttributes { - - /// HTTP request method. - /// - /// Notes: - /// HTTP request method value SHOULD be "known" to the instrumentation. - /// By default, this convention defines "known" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods) - /// and the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html). - /// - /// If the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`. - /// - /// If the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override - /// the list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named - /// OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods - /// (this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults). - /// - /// 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. - /// - /// Examples: - /// - GET - /// - POST - /// - HEAD - pub http_request_method: Option, - - /// The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. - /// - /// Examples: - /// - http - /// - https - pub url_scheme: Option, -} - - -impl HttpClientActiveRequests { - pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: crate::metrics::UpDownCounterProvider{ - Self(crate::metrics::UpDownCounterProvider::create_up_down_counter(meter, "http.client.active_requests", "Number of active HTTP requests.", "{request}")) - } - - /// Adds an additional value to the up-down-counter. - pub fn add( - &self, - value: T, - required_attributes: &HttpClientActiveRequestsReqAttributes, - not_required_attributes: Option<&HttpClientActiveRequestsOptAttributes>, - ) { - let mut attributes = vec![ - crate::attributes::server::SERVER_ADDRESS.value(required_attributes.server_address.to_string().into()), - crate::attributes::server::SERVER_PORT.value(required_attributes.server_port), - ]; - - if let Some(value) = ¬_required_attributes { - if let Some(http_request_method) = &value.http_request_method { - attributes.push(crate::attributes::http::HTTP_REQUEST_METHOD.value(http_request_method)); - } - if let Some(url_scheme) = &value.url_scheme { - attributes.push(crate::attributes::url::URL_SCHEME.value(url_scheme.to_string().into())); - } - } - self.0.add(value, &attributes) - } -} \ No newline at end of file diff --git a/crates/weaver_forge/tests/metrics/mod.rs b/crates/weaver_forge/tests/metrics/mod.rs deleted file mode 100644 index 4da6cbcd..00000000 --- a/crates/weaver_forge/tests/metrics/mod.rs +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! OpenTelemetry Semantic Convention Metrics -//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER - - -/// Metrics for the `http` namespace. -pub mod http; -/// Metrics for the `system` namespace. -pub mod system; - -/// A trait implemented by histogram providers (e.g. `Meter`). -pub trait HistogramProvider { - /// Creates a new histogram with the given name, description, and unit. - fn create_histogram(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Histogram; -} - -/// This implementation specifies that a Meter is able to create u64 histograms. -impl HistogramProvider for opentelemetry::metrics::Meter { - /// Creates a new u64 histogram with the given name, description, and unit. - fn create_histogram(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Histogram { - self.u64_histogram(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// This implementation specifies that a Meter is able to create u64 histograms. -impl HistogramProvider for opentelemetry::metrics::Meter { - /// Creates a new f64 histogram with the given name, description, and unit. - fn create_histogram(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Histogram { - self.f64_histogram(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// A trait implemented by up-down-counter providers (e.g. `Meter`). -pub trait UpDownCounterProvider { - /// Creates a new up-down-counter with the given name, description, and unit. - fn create_up_down_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::UpDownCounter; -} - -/// This implementation specifies that a Meter is able to create i64 up-down-counters. -impl UpDownCounterProvider for opentelemetry::metrics::Meter { - /// Creates a new i64 up-down-counter with the given name, description, and unit. - fn create_up_down_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::UpDownCounter { - self.i64_up_down_counter(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// This implementation specifies that a Meter is able to create f64 up-down-counters. -impl UpDownCounterProvider for opentelemetry::metrics::Meter { - /// Creates a new f64 up-down-counter with the given name, description, and unit. - fn create_up_down_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::UpDownCounter { - self.f64_up_down_counter(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// A trait implemented by counter providers (e.g. `Meter`). -pub trait CounterProvider { - /// Creates a new counter with the given name, description, and unit. - fn create_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Counter; -} - -/// This implementation specifies that a Meter is able to create u64 counters. -impl CounterProvider for opentelemetry::metrics::Meter { - /// Creates a new u64 counter with the given name, description, and unit. - fn create_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Counter { - self.u64_counter(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// This implementation specifies that a Meter is able to create f64 counters. -impl CounterProvider for opentelemetry::metrics::Meter { - /// Creates a new f64 counter with the given name, description, and unit. - fn create_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Counter { - self.f64_counter(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// A trait implemented by gauge providers (e.g. `Meter`). -pub trait GaugeProvider { - /// Creates a new gauge with the given name, description, and unit. - fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge; -} - -/// This implementation specifies that a Meter is able to create u64 gauges. -impl GaugeProvider for opentelemetry::metrics::Meter { - /// Creates a new u64 gauge with the given name, description, and unit. - fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge { - self.u64_gauge(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// This implementation specifies that a Meter is able to create i64 gauges. -impl GaugeProvider for opentelemetry::metrics::Meter { - /// Creates a new i64 gauge with the given name, description, and unit. - fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge { - self.i64_gauge(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// This implementation specifies that a Meter is able to create f64 gauges. -impl GaugeProvider for opentelemetry::metrics::Meter { - /// Creates a new f64 gauge with the given name, description, and unit. - fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge { - self.f64_gauge(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} \ No newline at end of file diff --git a/crates/weaver_forge/tests/metrics/system.rs b/crates/weaver_forge/tests/metrics/system.rs deleted file mode 100644 index fe89695a..00000000 --- a/crates/weaver_forge/tests/metrics/system.rs +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER - -/// Seconds each logical CPU spent on each mode -#[cfg(feature = "semconv_experimental")] -pub fn create_system_cpu_time(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Counter - where opentelemetry::metrics::Meter: crate::metrics::CounterProvider { - crate::metrics::CounterProvider::create_counter(meter, "system.cpu.time", "Seconds each logical CPU spent on each mode", "s") -} - -/// Metric: system.cpu.time -/// Brief: Seconds each logical CPU spent on each mode -/// Unit: s -#[derive(Debug)] -pub struct SystemCpuTime(opentelemetry::metrics::Counter); - - - - -#[derive(Debug, Clone, Default)] -pub struct SystemCpuTimeOptAttributes { - - /// The logical CPU number [0..n-1] - /// - /// Examples: - /// - 1 - pub system_cpu_logical_number: Option, - - /// The CPU state for this data point. A system's CPU SHOULD be characterized *either* by data points with no `state` labels, *or only* data points with `state` labels. - /// - /// Examples: - /// - idle - /// - interrupt - pub system_cpu_state: Option, -} - - -impl SystemCpuTime { - pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: crate::metrics::CounterProvider{ - Self(crate::metrics::CounterProvider::create_counter(meter, "system.cpu.time", "Seconds each logical CPU spent on each mode", "s")) - } - - /// Adds an additional value to the counter. - pub fn add( - &self, - value: T, - - not_required_attributes: Option<&SystemCpuTimeOptAttributes>, - ) { - let mut attributes = vec![ - ]; - - if let Some(value) = ¬_required_attributes { - if let Some(system_cpu_logical_number) = value.system_cpu_logical_number { - attributes.push(crate::attributes::system::SYSTEM_CPU_LOGICAL_NUMBER.value(system_cpu_logical_number)); - } - if let Some(system_cpu_state) = &value.system_cpu_state { - attributes.push(crate::attributes::system::SYSTEM_CPU_STATE.value(system_cpu_state)); - } - } - self.0.add(value, &attributes) - } -} - -/// Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs -pub fn create_system_cpu_utilization(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Gauge - where opentelemetry::metrics::Meter: crate::metrics::GaugeProvider { - crate::metrics::GaugeProvider::create_gauge(meter, "system.cpu.utilization", "Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs", "1") -} - -/// Metric: system.cpu.utilization -/// Brief: Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs -/// Unit: 1 -#[derive(Debug)] -pub struct SystemCpuUtilization(opentelemetry::metrics::Gauge); - - - - -#[derive(Debug, Clone, Default)] -pub struct SystemCpuUtilizationOptAttributes { - - /// The logical CPU number [0..n-1] - /// - /// Examples: - /// - 1 - pub system_cpu_logical_number: Option, - - /// The CPU state for this data point. A system's CPU SHOULD be characterized *either* by data points with no `state` labels, *or only* data points with `state` labels. - /// - /// Examples: - /// - idle - /// - interrupt - pub system_cpu_state: Option, -} - - -impl SystemCpuUtilization { - pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: crate::metrics::GaugeProvider{ - Self(crate::metrics::GaugeProvider::create_gauge(meter, "system.cpu.utilization", "Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs", "1")) - } - - /// Records an additional value to the gauge. - pub fn record( - &self, - value: T, - - not_required_attributes: Option<&SystemCpuUtilizationOptAttributes>, - ) { - let mut attributes = vec![ - ]; - - if let Some(value) = ¬_required_attributes { - if let Some(system_cpu_logical_number) = value.system_cpu_logical_number { - attributes.push(crate::attributes::system::SYSTEM_CPU_LOGICAL_NUMBER.value(system_cpu_logical_number)); - } - if let Some(system_cpu_state) = &value.system_cpu_state { - attributes.push(crate::attributes::system::SYSTEM_CPU_STATE.value(system_cpu_state)); - } - } - self.0.record(value, &attributes) - } -} - -/// Reports memory in use by state. -pub fn create_system_memory_usage(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter - where opentelemetry::metrics::Meter: crate::metrics::UpDownCounterProvider { - crate::metrics::UpDownCounterProvider::create_up_down_counter(meter, "system.memory.usage", "Reports memory in use by state.", "By") -} - -/// Metric: system.memory.usage -/// Brief: Reports memory in use by state. -/// Unit: By -#[derive(Debug)] -pub struct SystemMemoryUsage(opentelemetry::metrics::UpDownCounter); - - - - -#[derive(Debug, Clone, Default)] -pub struct SystemMemoryUsageOptAttributes { - - /// The memory state - /// - /// Examples: - /// - free - /// - cached - pub system_memory_state: Option, -} - - -impl SystemMemoryUsage { - pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: crate::metrics::UpDownCounterProvider{ - Self(crate::metrics::UpDownCounterProvider::create_up_down_counter(meter, "system.memory.usage", "Reports memory in use by state.", "By")) - } - - /// Adds an additional value to the up-down-counter. - pub fn add( - &self, - value: T, - - not_required_attributes: Option<&SystemMemoryUsageOptAttributes>, - ) { - let mut attributes = vec![ - ]; - - if let Some(value) = ¬_required_attributes { - if let Some(system_memory_state) = &value.system_memory_state { - attributes.push(crate::attributes::system::SYSTEM_MEMORY_STATE.value(system_memory_state)); - } - } - self.0.add(value, &attributes) - } -} \ No newline at end of file diff --git a/docs/images/dependencies.svg b/docs/images/dependencies.svg index 36f9c51e..4dcdd6d6 100644 --- a/docs/images/dependencies.svg +++ b/docs/images/dependencies.svg @@ -35,8 +35,8 @@ 3 - -weaver_diff + +weaver_codegen_test @@ -44,105 +44,111 @@ weaver_forge - - -8 + + +9 weaver_resolver - + -4->8 +4->9 5 - -weaver_resolved_schema + +weaver_diff 6 + +weaver_resolved_schema + + + +7 weaver_semconv - + -5->6 +6->7 - - -7 + + +8 weaver_version - + -5->7 +6->8 - + -6->2 +7->2 - + -8->0 +9->0 - + -8->3 +9->5 - + -8->5 +9->6 - - -9 + + +10 weaver_semconv_gen - + -9->4 +10->4 - - -10 - -xtask - 11 + +xtask + + + +12 weaver - + -11->1 +12->1 - + -11->9 +12->10 From 19e07c2b229b734f7dbef7e21be49175d0fb3943 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Tue, 7 May 2024 10:20:37 -0700 Subject: [PATCH 34/39] chore(forge): Remove duplicated codes and semconv registry --- Cargo.lock | 8 +- .../semconv_registry/http-common.yaml | 87 ---- .../semconv_registry/metrics/http.yaml | 62 --- .../metrics/system-metrics.yaml | 38 -- .../semconv_registry/registry/client.yaml | 28 -- .../registry/deprecated/network.yaml | 121 ------ .../semconv_registry/registry/error.yaml | 40 -- .../semconv_registry/registry/exception.yaml | 54 --- .../semconv_registry/registry/http.yaml | 174 -------- .../semconv_registry/registry/network.yaml | 235 ----------- .../semconv_registry/registry/server.yaml | 28 -- .../semconv_registry/registry/system.yaml | 65 --- .../semconv_registry/registry/url.yaml | 116 ------ .../templates/registry/rust/README.md | 381 ------------------ .../registry/rust/attribute_macros.j2 | 60 --- .../registry/rust/attributes/attributes.rs.j2 | 85 ---- .../registry/rust/attributes/mod.rs.j2 | 71 ---- .../templates/registry/rust/lib.rs | 13 - .../rust/metrics/instruments/counter.j2 | 71 ---- .../rust/metrics/instruments/gauge.j2 | 71 ---- .../rust/metrics/instruments/histogram.j2 | 71 ---- .../rust/metrics/instruments/updowncounter.j2 | 72 ---- .../registry/rust/metrics/metrics.rs.j2 | 13 - .../templates/registry/rust/metrics/mod.rs.j2 | 137 ------- .../templates/registry/rust/weaver.yaml | 156 ------- 25 files changed, 4 insertions(+), 2253 deletions(-) delete mode 100644 crates/weaver_forge/codegen_examples/semconv_registry/http-common.yaml delete mode 100644 crates/weaver_forge/codegen_examples/semconv_registry/metrics/http.yaml delete mode 100644 crates/weaver_forge/codegen_examples/semconv_registry/metrics/system-metrics.yaml delete mode 100644 crates/weaver_forge/codegen_examples/semconv_registry/registry/client.yaml delete mode 100644 crates/weaver_forge/codegen_examples/semconv_registry/registry/deprecated/network.yaml delete mode 100644 crates/weaver_forge/codegen_examples/semconv_registry/registry/error.yaml delete mode 100644 crates/weaver_forge/codegen_examples/semconv_registry/registry/exception.yaml delete mode 100644 crates/weaver_forge/codegen_examples/semconv_registry/registry/http.yaml delete mode 100644 crates/weaver_forge/codegen_examples/semconv_registry/registry/network.yaml delete mode 100644 crates/weaver_forge/codegen_examples/semconv_registry/registry/server.yaml delete mode 100644 crates/weaver_forge/codegen_examples/semconv_registry/registry/system.yaml delete mode 100644 crates/weaver_forge/codegen_examples/semconv_registry/registry/url.yaml delete mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/README.md delete mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/attribute_macros.j2 delete mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 delete mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/mod.rs.j2 delete mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/lib.rs delete mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/counter.j2 delete mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/gauge.j2 delete mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/histogram.j2 delete mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/updowncounter.j2 delete mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 delete mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/mod.rs.j2 delete mode 100644 crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml diff --git a/Cargo.lock b/Cargo.lock index 265c0782..628d953a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2762,9 +2762,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" @@ -2805,9 +2805,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beb461507cee2c2ff151784c52762cf4d9ff6a61f3e80968600ed24fa837fa54" +checksum = "51f344d206c5e1b010eec27349b815a4805f70a778895959d70b74b9b529b30a" [[package]] name = "rustls-webpki" diff --git a/crates/weaver_forge/codegen_examples/semconv_registry/http-common.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/http-common.yaml deleted file mode 100644 index f175215f..00000000 --- a/crates/weaver_forge/codegen_examples/semconv_registry/http-common.yaml +++ /dev/null @@ -1,87 +0,0 @@ -groups: - - id: attributes.http.common - type: attribute_group - brief: "Describes HTTP attributes." - attributes: - - ref: http.request.method - requirement_level: required - - ref: http.response.status_code - requirement_level: - conditionally_required: If and only if one was received/sent. - - ref: error.type - requirement_level: - conditionally_required: If request has ended with an error. - examples: ['timeout', 'java.net.UnknownHostException', 'server_certificate_invalid', '500'] - note: | - If the request fails with an error before response status code was sent or received, - `error.type` SHOULD be set to exception type (its fully-qualified class name, if applicable) - or a component-specific low cardinality error identifier. - - If response status code was sent or received and status indicates an error according to [HTTP span status definition](/docs/http/http-spans.md), - `error.type` SHOULD be set to the status code number (represented as a string), an exception type (if thrown) or a component-specific error identifier. - - The `error.type` value SHOULD be predictable and SHOULD have low cardinality. - Instrumentations SHOULD document the list of errors they report. - - The cardinality of `error.type` within one instrumentation library SHOULD be low, but - telemetry consumers that aggregate data from multiple instrumentation libraries and applications - should be prepared for `error.type` to have high cardinality at query time, when no - additional filters are applied. - - If the request has completed successfully, instrumentations SHOULD NOT set `error.type`. - - ref: network.protocol.name - examples: ['http', 'spdy'] - requirement_level: - conditionally_required: If not `http` and `network.protocol.version` is set. - - ref: network.protocol.version - examples: ['1.0', '1.1', '2', '3'] - - - id: attributes.http.client - type: attribute_group - brief: 'HTTP Client attributes' - extends: attributes.http.common - attributes: - - ref: server.address - requirement_level: required - brief: > - Host identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. - note: > - If an HTTP client request is explicitly made to an IP address, e.g. `http://x.x.x.x:8080`, then - `server.address` SHOULD be the IP address `x.x.x.x`. A DNS lookup SHOULD NOT be used. - - ref: server.port - requirement_level: required - brief: > - Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. - - ref: url.scheme - requirement_level: opt_in - examples: ["http", "https"] - - - id: attributes.http.server - type: attribute_group - brief: 'HTTP Server attributes' - extends: attributes.http.common - attributes: - - ref: http.route - requirement_level: - conditionally_required: If and only if it's available - - ref: server.address - brief: > - Name of the local HTTP server that received the request. - note: > - See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). - - ref: server.port - brief: > - Port of the local HTTP server that received the request. - note: > - See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). - requirement_level: - conditionally_required: If `server.address` is set. - - ref: url.scheme - requirement_level: required - examples: ["http", "https"] - note: > - The scheme of the original client request, if known - (e.g. from [Forwarded#proto](https://developer.mozilla.org/docs/Web/HTTP/Headers/Forwarded#proto), - [X-Forwarded-Proto](https://developer.mozilla.org/docs/Web/HTTP/Headers/X-Forwarded-Proto), - or a similar header). - Otherwise, the scheme of the immediate peer request. \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/semconv_registry/metrics/http.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/metrics/http.yaml deleted file mode 100644 index 9d24d884..00000000 --- a/crates/weaver_forge/codegen_examples/semconv_registry/metrics/http.yaml +++ /dev/null @@ -1,62 +0,0 @@ -groups: - - id: metric_attributes.http.server - type: attribute_group - brief: 'HTTP server attributes' - extends: attributes.http.server - attributes: - - ref: server.address - requirement_level: opt_in - note: | - See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). - > **Warning** - > Since this attribute is based on HTTP headers, opting in to it may allow an attacker - > to trigger cardinality limits, degrading the usefulness of the metric. - - ref: server.port - requirement_level: opt_in - note: | - See [Setting `server.address` and `server.port` attributes](/docs/http/http-spans.md#setting-serveraddress-and-serverport-attributes). - > **Warning** - > Since this attribute is based on HTTP headers, opting in to it may allow an attacker - > to trigger cardinality limits, degrading the usefulness of the metric. - - id: metric_attributes.http.client - type: attribute_group - brief: 'HTTP client attributes' - extends: attributes.http.client - - - id: metric.http.server.request.duration - type: metric - metric_name: http.server.request.duration - brief: "Duration of HTTP server requests." - instrument: histogram - unit: "s" - stability: stable - extends: metric_attributes.http.server - - - id: metric.http.client.request.duration - type: metric - metric_name: http.client.request.duration - brief: "Duration of HTTP client requests." - instrument: histogram - unit: "s" - stability: stable - extends: metric_attributes.http.client - - - id: metric.http.client.active_requests - type: metric - metric_name: http.client.active_requests - stability: experimental - brief: "Number of active HTTP requests." - instrument: updowncounter - unit: "{request}" - attributes: - - ref: http.request.method - requirement_level: recommended - - ref: server.address - requirement_level: required - - ref: server.port - requirement_level: required - brief: > - Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. - - ref: url.scheme - requirement_level: opt_in - examples: ["http", "https"] \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/semconv_registry/metrics/system-metrics.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/metrics/system-metrics.yaml deleted file mode 100644 index 12073142..00000000 --- a/crates/weaver_forge/codegen_examples/semconv_registry/metrics/system-metrics.yaml +++ /dev/null @@ -1,38 +0,0 @@ -groups: - # system.cpu.* metrics - - id: metric.system.cpu.time - type: metric - metric_name: system.cpu.time - stability: experimental - brief: "Seconds each logical CPU spent on each mode" - instrument: counter - unit: "s" - attributes: - - ref: system.cpu.state - brief: "The CPU state for this data point. A system's CPU SHOULD be characterized *either* by data points with no `state` labels, *or only* data points with `state` labels." - - ref: system.cpu.logical_number - - - id: metric.system.cpu.utilization - type: metric - metric_name: system.cpu.utilization - stability: stable - brief: "Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs" - instrument: gauge - unit: "1" - attributes: - - ref: system.cpu.state - brief: "The CPU state for this data point. A system's CPU SHOULD be characterized *either* by data points with no `state` labels, *or only* data points with `state` labels." - - ref: system.cpu.logical_number - - - id: metric.system.memory.usage - type: metric - metric_name: system.memory.usage - stability: stable - brief: "Reports memory in use by state." - note: | - The sum over all `system.memory.state` values SHOULD equal the total memory - available on the system, that is `system.memory.limit`. - instrument: updowncounter - unit: "By" - attributes: - - ref: system.memory.state \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/semconv_registry/registry/client.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/registry/client.yaml deleted file mode 100644 index 3b17ed8b..00000000 --- a/crates/weaver_forge/codegen_examples/semconv_registry/registry/client.yaml +++ /dev/null @@ -1,28 +0,0 @@ -groups: - - id: registry.client - prefix: client - type: attribute_group - brief: > - 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. - attributes: - - id: address - stability: stable - type: string - brief: "Client address - domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name." - note: > - 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. - examples: ['client.example.com', '10.1.2.80', '/tmp/my.sock'] - - id: port - stability: stable - type: int - brief: Client port number. - examples: [65123] - note: > - 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. diff --git a/crates/weaver_forge/codegen_examples/semconv_registry/registry/deprecated/network.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/registry/deprecated/network.yaml deleted file mode 100644 index 66144671..00000000 --- a/crates/weaver_forge/codegen_examples/semconv_registry/registry/deprecated/network.yaml +++ /dev/null @@ -1,121 +0,0 @@ -groups: - - id: registry.network.deprecated - prefix: net - type: attribute_group - brief: > - These attributes may be used for any network related operation. - attributes: - - id: sock.peer.name - type: string - deprecated: "Removed." - stability: experimental - brief: Deprecated, no replacement at this time. - examples: ['/var/my.sock'] - - id: sock.peer.addr - type: string - deprecated: "Replaced by `network.peer.address`." - stability: experimental - brief: Deprecated, use `network.peer.address`. - examples: ['192.168.0.1'] - - id: sock.peer.port - type: int - deprecated: "Replaced by `network.peer.port`." - stability: experimental - examples: [65531] - brief: Deprecated, use `network.peer.port`. - - id: peer.name - type: string - deprecated: "Replaced by `server.address` on client spans and `client.address` on server spans." - stability: experimental - brief: Deprecated, use `server.address` on client spans and `client.address` on server spans. - examples: ['example.com'] - - id: peer.port - type: int - deprecated: "Replaced by `server.port` on client spans and `client.port` on server spans." - stability: experimental - brief: Deprecated, use `server.port` on client spans and `client.port` on server spans. - examples: [8080] - - id: host.name - type: string - deprecated: "Replaced by `server.address`." - stability: experimental - brief: Deprecated, use `server.address`. - examples: ['example.com'] - - id: host.port - type: int - deprecated: "Replaced by `server.port`." - stability: experimental - brief: Deprecated, use `server.port`. - examples: [8080] - - id: sock.host.addr - type: string - deprecated: "Replaced by `network.local.address`." - stability: experimental - brief: Deprecated, use `network.local.address`. - examples: ['/var/my.sock'] - - id: sock.host.port - type: int - deprecated: "Replaced by `network.local.port`." - stability: experimental - brief: Deprecated, use `network.local.port`. - examples: [8080] - - id: transport - type: - allow_custom_values: true - members: - - id: ip_tcp - value: "ip_tcp" - stability: experimental - - id: ip_udp - value: "ip_udp" - stability: experimental - - id: pipe - value: "pipe" - brief: 'Named or anonymous pipe.' - stability: experimental - - id: inproc - value: "inproc" - brief: 'In-process communication.' - stability: experimental - note: > - 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. - - id: other - value: "other" - stability: experimental - brief: 'Something else (non IP-based).' - deprecated: "Replaced by `network.transport`." - stability: experimental - brief: Deprecated, use `network.transport`. - - id: protocol.name - type: string - deprecated: "Replaced by `network.protocol.name`." - stability: experimental - brief: Deprecated, use `network.protocol.name`. - examples: ['amqp', 'http', 'mqtt'] - - id: protocol.version - type: string - deprecated: "Replaced by `network.protocol.version`." - stability: experimental - brief: Deprecated, use `network.protocol.version`. - examples: '3.1.1' - - id: sock.family - type: - allow_custom_values: true - members: - - id: inet - value: 'inet' - brief: "IPv4 address" - stability: experimental - - id: inet6 - value: 'inet6' - brief: "IPv6 address" - stability: experimental - - id: unix - value: 'unix' - brief: "Unix domain socket path" - stability: experimental - deprecated: "Split to `network.transport` and `network.type`." - stability: experimental - brief: Deprecated, use `network.transport` and `network.type`. diff --git a/crates/weaver_forge/codegen_examples/semconv_registry/registry/error.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/registry/error.yaml deleted file mode 100644 index 621022f6..00000000 --- a/crates/weaver_forge/codegen_examples/semconv_registry/registry/error.yaml +++ /dev/null @@ -1,40 +0,0 @@ -groups: - - id: registry.error - type: attribute_group - prefix: error - brief: > - This document defines the shared attributes used to report an error. - attributes: - - id: type - stability: stable - brief: > - Describes a class of error the operation ended with. - type: - allow_custom_values: true - members: - - id: other - value: "_OTHER" - stability: stable - brief: > - A fallback error value to be used when the instrumentation doesn't define a custom value. - examples: ['timeout', 'java.net.UnknownHostException', 'server_certificate_invalid', '500'] - note: | - The `error.type` SHOULD be predictable, and SHOULD have low cardinality. - - When `error.type` is set to a type (e.g., an exception type), its - canonical class name identifying the type within the artifact SHOULD be used. - - Instrumentations SHOULD document the list of errors they report. - - The cardinality of `error.type` within one instrumentation library SHOULD be low. - Telemetry consumers that aggregate data from multiple instrumentation libraries and applications - should be prepared for `error.type` to have high cardinality at query time when no - additional filters are applied. - - If the operation has completed successfully, instrumentations SHOULD NOT set `error.type`. - - If a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes), - it's RECOMMENDED to: - - * Use a domain-specific attribute - * Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/semconv_registry/registry/exception.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/registry/exception.yaml deleted file mode 100644 index 7e1b0118..00000000 --- a/crates/weaver_forge/codegen_examples/semconv_registry/registry/exception.yaml +++ /dev/null @@ -1,54 +0,0 @@ -groups: - - id: registry.exception - type: attribute_group - prefix: exception - brief: > - This document defines the shared attributes used to - report a single exception associated with a span or log. - attributes: - - id: type - type: string - stability: stable - brief: > - 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. - examples: ["java.net.ConnectException", "OSError"] - - id: message - type: string - stability: stable - brief: The exception message. - examples: ["Division by zero", "Can't convert 'int' object to str implicitly"] - - id: stacktrace - type: string - stability: stable - brief: > - 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. - examples: 'Exception in thread "main" java.lang.RuntimeException: Test exception\n - at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n - at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n - at com.example.GenerateTrace.main(GenerateTrace.java:5)' - - id: escaped - type: boolean - stability: stable - brief: > - SHOULD be set to true if the exception event is recorded at a point where - it is known that the exception is escaping the scope of the span. - note: |- - An exception is considered to have escaped (or left) the scope of a span, - if that span is ended while the exception is still logically "in flight". - This may be actually "in flight" in some languages (e.g. if the exception - is passed to a Context manager's `__exit__` method in Python) but will - usually be caught at the point of recording the exception in most languages. - - It is usually not possible to determine at the point where an exception is thrown - whether it will escape the scope of a span. - However, it is trivial to know that an exception - will escape, if one checks for an active exception just before ending the span, - as done in the [example for recording span exceptions](#recording-an-exception). - - It follows that an exception may still escape the scope of the span - 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. diff --git a/crates/weaver_forge/codegen_examples/semconv_registry/registry/http.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/registry/http.yaml deleted file mode 100644 index e013704a..00000000 --- a/crates/weaver_forge/codegen_examples/semconv_registry/registry/http.yaml +++ /dev/null @@ -1,174 +0,0 @@ -groups: - - id: registry.http - prefix: http - type: attribute_group - brief: 'This document defines semantic convention attributes in the HTTP namespace.' - attributes: - - id: request.body.size - type: int - brief: > - 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. - examples: 3495 - stability: experimental # this should not be marked stable with other HTTP attributes - - id: request.header - stability: stable - type: template[string[]] - brief: > - HTTP request headers, `` being the normalized HTTP Header name (lowercase), the value being the header values. - note: > - 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. - examples: ['http.request.header.content-type=["application/json"]', 'http.request.header.x-forwarded-for=["1.2.3.4", "1.2.3.5"]'] - - id: request.method - stability: stable - type: - allow_custom_values: true - members: - - id: connect - value: "CONNECT" - brief: 'CONNECT method.' - stability: stable - - id: delete - value: "DELETE" - brief: 'DELETE method.' - stability: stable - - id: get - value: "GET" - brief: 'GET method.' - stability: stable - - id: head - value: "HEAD" - brief: 'HEAD method.' - stability: stable - - id: options - value: "OPTIONS" - brief: 'OPTIONS method.' - stability: stable - - id: patch - value: "PATCH" - brief: 'PATCH method.' - stability: stable - - id: post - value: "POST" - brief: 'POST method.' - stability: stable - - id: put - value: "PUT" - brief: 'PUT method.' - stability: stable - - id: trace - value: "TRACE" - brief: 'TRACE method.' - stability: stable - - id: other - value: "_OTHER" - brief: 'Any HTTP method that the instrumentation has no prior knowledge of.' - stability: stable - brief: 'HTTP request method.' - examples: ["GET", "POST", "HEAD"] - note: | - HTTP request method value SHOULD be "known" to the instrumentation. - By default, this convention defines "known" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods) - and the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html). - - If the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`. - - If the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override - the list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named - OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods - (this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults). - - 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. - - id: request.method_original - stability: stable - type: string - brief: Original HTTP method sent by the client in the request line. - examples: ["GeT", "ACL", "foo"] - - id: request.resend_count - stability: stable - type: int - brief: > - The ordinal number of request resending attempt (for any reason, including redirects). - note: > - 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). - examples: 3 - - id: request.size - type: int - brief: > - 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. - examples: 1437 - stability: experimental - - id: response.body.size - type: int - brief: > - 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. - examples: 3495 - stability: experimental # this should not be marked stable with other HTTP attributes - - id: response.header - stability: stable - type: template[string[]] - brief: > - HTTP response headers, `` being the normalized HTTP Header name (lowercase), the value being the header values. - note: > - 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. - examples: ['http.response.header.content-type=["application/json"]', 'http.response.header.my-custom-header=["abc", "def"]'] - - id: response.size - type: int - brief: > - 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. - examples: 1437 - stability: experimental - - id: response.status_code - stability: stable - type: int - brief: '[HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6).' - examples: [200] - - id: route - stability: stable - type: string - brief: > - The matched route, that is, the path template in the format used by the respective server framework. - examples: ['/users/:userID?', '{controller}/{action}/{id?}'] - note: > - 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. - - id: connection.state - type: - allow_custom_values: true - members: - - id: active - value: "active" - brief: 'active state.' - stability: experimental - - id: idle - value: "idle" - brief: 'idle state.' - stability: experimental - brief: State of the HTTP connection in the HTTP connection pool. - stability: experimental - examples: ["active", "idle"] diff --git a/crates/weaver_forge/codegen_examples/semconv_registry/registry/network.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/registry/network.yaml deleted file mode 100644 index 591a0188..00000000 --- a/crates/weaver_forge/codegen_examples/semconv_registry/registry/network.yaml +++ /dev/null @@ -1,235 +0,0 @@ -groups: - - id: registry.network - prefix: network - type: attribute_group - brief: > - These attributes may be used for any network related operation. - attributes: - - id: carrier.icc - type: string - stability: experimental - brief: "The ISO 3166-1 alpha-2 2-character country code associated with the mobile carrier network." - examples: "DE" - - id: carrier.mcc - type: string - stability: experimental - brief: "The mobile carrier country code." - examples: "310" - - id: carrier.mnc - type: string - stability: experimental - brief: "The mobile carrier network code." - examples: "001" - - id: carrier.name - type: string - stability: experimental - brief: "The name of the mobile carrier." - examples: "sprint" - - id: connection.subtype - type: - allow_custom_values: true - members: - - id: gprs - brief: GPRS - value: "gprs" - stability: experimental - - id: edge - brief: EDGE - value: "edge" - stability: experimental - - id: umts - brief: UMTS - value: "umts" - stability: experimental - - id: cdma - brief: CDMA - value: "cdma" - stability: experimental - - id: evdo_0 - brief: EVDO Rel. 0 - value: "evdo_0" - stability: experimental - - id: evdo_a - brief: "EVDO Rev. A" - value: "evdo_a" - stability: experimental - - id: cdma2000_1xrtt - brief: CDMA2000 1XRTT - value: "cdma2000_1xrtt" - stability: experimental - - id: hsdpa - brief: HSDPA - value: "hsdpa" - stability: experimental - - id: hsupa - brief: HSUPA - value: "hsupa" - stability: experimental - - id: hspa - brief: HSPA - value: "hspa" - stability: experimental - - id: iden - brief: IDEN - value: "iden" - stability: experimental - - id: evdo_b - brief: "EVDO Rev. B" - value: "evdo_b" - stability: experimental - - id: lte - brief: LTE - value: "lte" - stability: experimental - - id: ehrpd - brief: EHRPD - value: "ehrpd" - stability: experimental - - id: hspap - brief: HSPAP - value: "hspap" - stability: experimental - - id: gsm - brief: GSM - value: "gsm" - stability: experimental - - id: td_scdma - brief: TD-SCDMA - value: "td_scdma" - stability: experimental - - id: iwlan - brief: IWLAN - value: "iwlan" - stability: experimental - - id: nr - brief: "5G NR (New Radio)" - value: "nr" - stability: experimental - - id: nrnsa - brief: "5G NRNSA (New Radio Non-Standalone)" - value: "nrnsa" - stability: experimental - - id: lte_ca - brief: LTE CA - value: "lte_ca" - stability: experimental - stability: experimental - brief: 'This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection.' - examples: 'LTE' - - id: connection.type - type: - allow_custom_values: true - members: - - id: wifi - value: "wifi" - stability: experimental - - id: wired - value: "wired" - stability: experimental - - id: cell - value: "cell" - stability: experimental - - id: unavailable - value: "unavailable" - stability: experimental - - id: unknown - value: "unknown" - stability: experimental - stability: experimental - brief: 'The internet connection type.' - examples: 'wifi' - - id: local.address - stability: stable - type: string - brief: Local address of the network connection - IP address or Unix domain socket name. - examples: ['10.1.2.80', '/tmp/my.sock'] - - id: local.port - stability: stable - type: int - brief: Local port number of the network connection. - examples: [65123] - - id: peer.address - stability: stable - type: string - brief: Peer address of the network connection - IP address or Unix domain socket name. - examples: ['10.1.2.80', '/tmp/my.sock'] - - id: peer.port - stability: stable - type: int - brief: Peer port number of the network connection. - examples: [65123] - - id: protocol.name - stability: stable - type: string - brief: '[OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent.' - note: The value SHOULD be normalized to lowercase. - examples: ['amqp', 'http', 'mqtt'] - - id: protocol.version - stability: stable - type: string - brief: The actual version of the protocol used for network communication. - examples: ['1.1', '2'] - note: > - If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), - this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, - this attribute SHOULD NOT be set. - - id: transport - stability: stable - type: - allow_custom_values: true - members: - - id: tcp - value: 'tcp' - brief: "TCP" - stability: stable - - id: udp - value: 'udp' - brief: "UDP" - stability: stable - - id: pipe - value: "pipe" - brief: 'Named or anonymous pipe.' - stability: stable - - id: unix - value: 'unix' - brief: "Unix domain socket" - stability: stable - brief: > - [OSI transport layer](https://osi-model.com/transport-layer/) or - [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). - note: | - The value SHOULD be normalized to lowercase. - - Consider always setting the transport when setting a port number, since - a port number is ambiguous without knowing the transport. For example - different processes could be listening on TCP port 12345 and UDP port 12345. - examples: ['tcp', 'udp'] - - id: type - stability: stable - type: - allow_custom_values: true - members: - - id: ipv4 - value: 'ipv4' - brief: "IPv4" - stability: stable - - id: ipv6 - value: 'ipv6' - brief: "IPv6" - stability: stable - brief: '[OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent.' - note: The value SHOULD be normalized to lowercase. - examples: ['ipv4', 'ipv6'] - - id: io.direction - type: - allow_custom_values: false - members: - - id: transmit - value: 'transmit' - stability: experimental - - id: receive - value: 'receive' - stability: experimental - stability: experimental - brief: "The network IO operation direction." - examples: ["transmit"] \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/semconv_registry/registry/server.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/registry/server.yaml deleted file mode 100644 index 0afe3fab..00000000 --- a/crates/weaver_forge/codegen_examples/semconv_registry/registry/server.yaml +++ /dev/null @@ -1,28 +0,0 @@ -groups: - - id: registry.server - prefix: server - type: attribute_group - brief: > - These attributes may be used to describe the server 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. - attributes: - - id: address - stability: stable - type: string - brief: "Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name." - note: > - When observed from the client side, and when communicating through an intermediary, `server.address` SHOULD represent - the server address behind any intermediaries, for example proxies, if it's available. - examples: ['example.com', '10.1.2.80', '/tmp/my.sock'] - - id: port - stability: stable - type: int - brief: Server port number. - note: > - When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent - the server port behind any intermediaries, for example proxies, if it's available. - examples: [80, 8080, 443] \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/semconv_registry/registry/system.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/registry/system.yaml deleted file mode 100644 index 1f6bc175..00000000 --- a/crates/weaver_forge/codegen_examples/semconv_registry/registry/system.yaml +++ /dev/null @@ -1,65 +0,0 @@ -groups: - # system.cpu.* attribute group - - id: registry.system.cpu - prefix: system.cpu - type: attribute_group - brief: "Describes System CPU attributes" - attributes: - - id: state - type: - allow_custom_values: true - members: - - id: user - value: 'user' - - id: system - value: 'system' - - id: nice - value: 'nice' - - id: idle - value: 'idle' - - id: iowait - value: 'iowait' - stability: experimental - - id: interrupt - value: 'interrupt' - stability: experimental - - id: steal - value: 'steal' - stability: experimental - brief: "The state of the CPU" - stability: stable - examples: ["idle", "interrupt"] - - id: logical_number - type: int - stability: stable - brief: "The logical CPU number [0..n-1]" - examples: [1] - # sytem.memory.* attribute group - - id: registry.system.memory - prefix: system.memory - type: attribute_group - brief: "Describes System Memory attributes" - attributes: - - id: state - type: - allow_custom_values: true - members: - - id: used - value: 'used' - stability: experimental - - id: free - value: 'free' - stability: experimental - - id: shared - value: 'shared' - stability: experimental - deprecated: 'Removed, report shared memory usage with `metric.system.memory.shared` metric' - - id: buffers - value: 'buffers' - stability: experimental - - id: cached - value: 'cached' - stability: experimental - stability: stable - brief: "The memory state" - examples: ["free", "cached"] \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/semconv_registry/registry/url.yaml b/crates/weaver_forge/codegen_examples/semconv_registry/registry/url.yaml deleted file mode 100644 index 7c132dae..00000000 --- a/crates/weaver_forge/codegen_examples/semconv_registry/registry/url.yaml +++ /dev/null @@ -1,116 +0,0 @@ -groups: - - id: registry.url - brief: Attributes describing URL. - type: attribute_group - prefix: url - attributes: - - id: domain - type: string - stability: experimental - brief: > - Domain extracted from the `url.full`, such as "opentelemetry.io". - note: > - In some cases a URL may refer to an IP and/or port directly, - without a domain name. In this case, the IP address would go to the domain field. - If the URL contains a [literal IPv6 address](https://www.rfc-editor.org/rfc/rfc2732#section-2) - enclosed by `[` and `]`, the `[` and `]` characters should also be captured in the domain field. - examples: ["www.foo.bar", "opentelemetry.io", "3.12.167.2", "[1080:0:0:0:8:800:200C:417A]"] - - id: extension - type: string - stability: experimental - brief: > - The file extension extracted from the `url.full`, excluding the leading dot. - note: > - The file extension is only set if it exists, as not every url has a file extension. - When the file name has multiple extensions `example.tar.gz`, only the last one should be captured `gz`, not `tar.gz`. - examples: [ "png", "gz" ] - - id: fragment - stability: stable - type: string - brief: > - The [URI fragment](https://www.rfc-editor.org/rfc/rfc3986#section-3.5) component - examples: ["SemConv"] - - id: full - stability: stable - type: string - brief: Absolute URL describing a network resource according to [RFC3986](https://www.rfc-editor.org/rfc/rfc3986) - note: > - For network calls, URL usually has `scheme://host[:port][path][?query][#fragment]` format, where the fragment - is not transmitted over HTTP, but if it is known, it SHOULD be included nevertheless. - - `url.full` MUST NOT contain credentials passed via URL in form of `https://username:password@www.example.com/`. - In such case username and password SHOULD be redacted and attribute's value SHOULD be `https://REDACTED:REDACTED@www.example.com/`. - - `url.full` SHOULD capture the absolute URL when it is available (or can be reconstructed). - Sensitive content provided in `url.full` SHOULD be scrubbed when instrumentations can identify it. - examples: ['https://www.foo.bar/search?q=OpenTelemetry#SemConv', '//localhost'] - - id: original - type: string - stability: experimental - brief: > - Unmodified original URL as seen in the event source. - note: > - In network monitoring, the observed URL may be a full URL, whereas in access logs, the URL is often - just represented as a path. This field is meant to represent the URL as it was observed, complete or not. - - `url.original` might contain credentials passed via URL in form of `https://username:password@www.example.com/`. - In such case password and username SHOULD NOT be redacted and attribute's value SHOULD remain the same. - examples: ["https://www.foo.bar/search?q=OpenTelemetry#SemConv", "search?q=OpenTelemetry"] - - id: path - stability: stable - type: string - brief: > - The [URI path](https://www.rfc-editor.org/rfc/rfc3986#section-3.3) component - examples: ["/search"] - note: > - Sensitive content provided in `url.path` SHOULD be scrubbed when instrumentations can identify it. - - id: port - type: int - stability: experimental - brief: > - Port extracted from the `url.full` - examples: [443] - - id: query - stability: stable - type: string - brief: > - The [URI query](https://www.rfc-editor.org/rfc/rfc3986#section-3.4) component - examples: ["q=OpenTelemetry"] - note: > - Sensitive content provided in `url.query` SHOULD be scrubbed when instrumentations can identify it. - - id: registered_domain - type: string - stability: experimental - brief: > - The highest registered url domain, stripped of the subdomain. - examples: ["example.com", "foo.co.uk"] - note: > - This value can be determined precisely with the [public suffix list](http://publicsuffix.org). - For example, the registered domain for `foo.example.com` is `example.com`. - Trying to approximate this by simply taking the last two labels will not work well for TLDs such as `co.uk`. - - id: scheme - stability: stable - type: string - brief: > - The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. - examples: ["https", "ftp", "telnet"] - - id: subdomain - type: string - stability: experimental - brief: > - The subdomain portion of a fully qualified domain name includes all of the names except the host name - under the registered_domain. In a partially qualified domain, or if the qualification level of the - full name cannot be determined, subdomain contains all of the names below the registered domain. - examples: ["east", "sub2.sub1"] - note: > - The subdomain portion of `www.east.mydomain.co.uk` is `east`. If the domain has multiple levels of subdomain, - such as `sub2.sub1.example.com`, the subdomain field should contain `sub2.sub1`, with no trailing period. - - id: top_level_domain - type: string - stability: experimental - brief: > - The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. - For example, the top level domain for example.com is `com`. - examples: ["com", "co.uk"] - note: > - This value can be determined precisely with the [public suffix list](http://publicsuffix.org). \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/README.md b/crates/weaver_forge/codegen_examples/templates/registry/rust/README.md deleted file mode 100644 index c4ce1f7f..00000000 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/README.md +++ /dev/null @@ -1,381 +0,0 @@ -# Semantic Conventions for Rust - -# Usage - -```rust -use opentelemetry::KeyValue; -use opentelemetry::metrics::{Histogram, MeterProvider}; -use opentelemetry_sdk::{Resource, runtime}; -use opentelemetry_sdk::metrics::{PeriodicReader, SdkMeterProvider}; - -use semconv::attributes; -use semconv::attributes::http::{HTTP_REQUEST_METHOD, HttpRequestMethod}; -use semconv::attributes::system::SystemCpuState; -use semconv::metrics::http::{create_http_client_request_duration, HttpClientActiveRequests, HttpClientActiveRequestsReqAttributes, HttpServerRequestDurationOptAttributes, HttpServerRequestDurationReqAttributes}; -use semconv::metrics::http::HttpServerRequestDuration; -use semconv::metrics::system::{SystemCpuTime, SystemCpuTimeOptAttributes, SystemCpuUtilization, SystemCpuUtilizationOptAttributes}; - -/// Main -#[tokio::main] -async fn main() -> Result<(), Box> { - let meter_provider = init_meter_provider(); - - // SemConv attributes are typed, so the compiler will catch type errors - // Experimental attributes are not visible if the `semconv_experimental` feature is not enabled - println!("{:?}", attributes::client::CLIENT_ADDRESS.value("145.34.23.56".into())); - println!("{:?}", attributes::client::CLIENT_ADDRESS.key()); - println!("{:?}", attributes::client::CLIENT_PORT.value(8080)); - println!("{:?}", attributes::client::CLIENT_PORT.key()); - - println!("{}", HttpRequestMethod::Connect); - - let meter = meter_provider.meter("mylibname"); - - // Create a u64 http.client.request.duration metric - let http_client_request_duration: Histogram = create_http_client_request_duration(&meter); - http_client_request_duration.record(100, &[ - HTTP_REQUEST_METHOD.value(&HttpRequestMethod::Connect), - // here nothing guarantees that all the required attributes are provided - ]); - - let http_client_request_duration: Histogram = create_http_client_request_duration(&meter); - dbg!(http_client_request_duration); - - // ==== A TYPE-SAFE HISTOGRAM API ==== - // Create a u64 http.server.request.duration metric (as defined in the OpenTelemetry HTTP - // semantic conventions) - let http_request_duration = HttpServerRequestDuration::::new(&meter); - - // Records a new data point and provide the required and some not required attributes - http_request_duration.record(100, &HttpServerRequestDurationReqAttributes { - http_request_method: HttpRequestMethod::Connect, - url_scheme: "http".to_owned(), - }, Some(&HttpServerRequestDurationOptAttributes { - http_response_status_code: Some(200), - ..Default::default() - })); - - // ==== A TYPE-SAFE UP-DOWN-COUNTER API ==== - // Create a f64 http.server.request.duration metric (as defined in the OpenTelemetry HTTP - // semantic conventions) - let http_client_active_requests = HttpClientActiveRequests::::new(&meter); - - // Adds a new data point and provide the required attributes. Not required attributes are not - // provided in this example. - http_client_active_requests.add(10.0, &HttpClientActiveRequestsReqAttributes { - server_address: "10.0.0.1".to_owned(), - server_port: 8080, - }, None); - - // ==== A TYPE-SAFE COUNTER API ==== - // Create a f64 system.cpu.time metric (as defined in the OpenTelemetry System semantic - // conventions) - let system_cpu_time = SystemCpuTime::::new(&meter); - - // Adds a new data point and provide some not required attributes. - // Note: In the method signature, there is no required attribute. - system_cpu_time.add(10.0, Some(&SystemCpuTimeOptAttributes { - system_cpu_logical_number: Some(0), - system_cpu_state: Some(SystemCpuState::Idle) - })); - // Adds a new data point with a custom CPU state. - system_cpu_time.add(20.0, Some(&SystemCpuTimeOptAttributes { - system_cpu_logical_number: Some(0), - system_cpu_state: Some(SystemCpuState::_Custom("custom".to_owned())) - })); - - // ==== A TYPE-SAFE GAUGE API ==== - // Create a i64 system.cpu.utilization metric (as defined in the OpenTelemetry System semantic - // conventions) - let system_cpu_utilization = SystemCpuUtilization::::new(&meter); - - // Adds a new data point with no not required attributes. - system_cpu_utilization.record(-5, None); - // Adds a new data point with some not required attributes. - system_cpu_utilization.record(10, Some(&SystemCpuUtilizationOptAttributes { - system_cpu_logical_number: Some(0), - system_cpu_state: Some(SystemCpuState::Idle) - })); - - meter_provider.shutdown()?; - Ok(()) -} - -fn init_meter_provider() -> SdkMeterProvider { - let exporter = opentelemetry_stdout::MetricsExporterBuilder::default() - .with_encoder(|writer, data| - Ok(serde_json::to_writer_pretty(writer, &data).unwrap())) - .build(); - let reader = PeriodicReader::builder(exporter, runtime::Tokio).build(); - SdkMeterProvider::builder() - .with_reader(reader) - .with_resource(Resource::new(vec![KeyValue::new( - "service.name", - "metrics-basic-example", - )])) - .build() -} -``` - -The execution of this program will generate the following output: - -``` -KeyValue { key: Static("client.address"), value: String(Static("145.34.23.56")) } -Static("client.address") -KeyValue { key: Static("client.port"), value: I64(8080) } -Static("client.port") -CONNECT -[src/main.rs:39:5] http_client_request_duration = Histogram -{ - "resourceMetrics": { - "resource": { - "attributes": [ - { - "key": "service.name", - "value": { - "stringValue": "metrics-basic-example" - } - } - ] - }, - "scopeMetrics": [ - { - "scope": { - "name": "mylibname" - }, - "metrics": [ - { - "name": "http.client.request.duration", - "description": "Duration of HTTP client requests.", - "unit": "s", - "histogram": { - "dataPoints": [ - { - "attributes": { - "http.request.method": { - "stringValue": "CONNECT" - } - }, - "startTimeUnixNano": 1714780164856054000, - "timeUnixNano": 1714780164856202000, - "startTime": "2024-05-03 23:49:24.856", - "time": "2024-05-03 23:49:24.856", - "count": 1, - "explicitBounds": [ - 0.0, - 5.0, - 10.0, - 25.0, - 50.0, - 75.0, - 100.0, - 250.0, - 500.0, - 750.0, - 1000.0, - 2500.0, - 5000.0, - 7500.0, - 10000.0 - ], - "bucketCounts": [ - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ], - "min": 100, - "max": 100, - "sum": 100, - "exemplars": [], - "flags": 0 - } - ], - "aggregationTemporality": "Cumulative" - } - }, - { - "name": "http.server.request.duration", - "description": "Duration of HTTP server requests.", - "unit": "s", - "histogram": { - "dataPoints": [ - { - "attributes": { - "http.request.method": { - "stringValue": "CONNECT" - }, - "http.response.status_code": { - "intValue": 200 - }, - "url.scheme": { - "stringValue": "http" - } - }, - "startTimeUnixNano": 1714780164856111000, - "timeUnixNano": 1714780164856204000, - "startTime": "2024-05-03 23:49:24.856", - "time": "2024-05-03 23:49:24.856", - "count": 1, - "explicitBounds": [ - 0.0, - 5.0, - 10.0, - 25.0, - 50.0, - 75.0, - 100.0, - 250.0, - 500.0, - 750.0, - 1000.0, - 2500.0, - 5000.0, - 7500.0, - 10000.0 - ], - "bucketCounts": [ - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ], - "min": 100, - "max": 100, - "sum": 100, - "exemplars": [], - "flags": 0 - } - ], - "aggregationTemporality": "Cumulative" - } - }, - { - "name": "http.client.active_requests", - "description": "Number of active HTTP requests.", - "unit": "{request}", - "sum": { - "dataPoints": [ - { - "attributes": { - "server.address": { - "stringValue": "10.0.0.1" - }, - "server.port": { - "intValue": 8080 - } - }, - "startTime": "2024-05-03 23:49:24.856", - "time": "2024-05-03 23:49:24.856", - "startTimeUnixNano": 1714780164856139000, - "timeUnixNano": 1714780164856219000, - "value": 10.0 - } - ], - "aggregationTemporality": "Cumulative", - "isMonotonic": false - } - }, - { - "name": "system.cpu.time", - "description": "Seconds each logical CPU spent on each mode", - "unit": "s", - "sum": { - "dataPoints": [ - { - "attributes": { - "system.cpu.logical_number": { - "intValue": 0 - }, - "system.cpu.state": { - "stringValue": "idle" - } - }, - "startTime": "2024-05-03 23:49:24.856", - "time": "2024-05-03 23:49:24.856", - "startTimeUnixNano": 1714780164856152000, - "timeUnixNano": 1714780164856220000, - "value": 10.0 - }, - { - "attributes": { - "system.cpu.logical_number": { - "intValue": 0 - }, - "system.cpu.state": { - "stringValue": "custom" - } - }, - "startTime": "2024-05-03 23:49:24.856", - "time": "2024-05-03 23:49:24.856", - "startTimeUnixNano": 1714780164856152000, - "timeUnixNano": 1714780164856220000, - "value": 20.0 - } - ], - "aggregationTemporality": "Cumulative", - "isMonotonic": true - } - }, - { - "name": "system.cpu.utilization", - "description": "Difference in system.cpu.time since the last measurement, divided by the elapsed time and number of logical CPUs", - "unit": "1", - "gauge": { - "dataPoints": [ - { - "attributes": { - "system.cpu.logical_number": { - "intValue": 0 - }, - "system.cpu.state": { - "stringValue": "idle" - } - }, - "startTime": null, - "time": "2024-05-03 23:49:24.856", - "startTimeUnixNano": null, - "timeUnixNano": 1714780164856176000, - "value": 10 - }, - { - "attributes": {}, - "startTime": null, - "time": "2024-05-03 23:49:24.856", - "startTimeUnixNano": null, - "timeUnixNano": 1714780164856171000, - "value": -5 - } - ] - } - } - ] - } - ] - } -} -``` \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/attribute_macros.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/attribute_macros.j2 deleted file mode 100644 index 447c6b74..00000000 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/attribute_macros.j2 +++ /dev/null @@ -1,60 +0,0 @@ -{%- macro comments(attribute, prefix) -%} -{%- if attribute.brief %} -{{ attribute.brief | comment_with_prefix(prefix ~ " ") }} -{%- endif %} -{%- if attribute.note %} -{{ prefix }} -{{ prefix }} Notes: -{{ attribute.note | comment_with_prefix(prefix ~ " ") }} -{%- endif %} -{%- if attribute.examples %} -{%- if attribute.examples is sequence %} -{{ prefix }} -{{ prefix }} Examples: -{%- for example in attribute.examples %} -{{ example | comment_with_prefix(prefix ~ " - ") }} -{%- endfor %} -{%- else %} -{{ prefix }} -{{ prefix }} Example: {{ attribute.examples | trim }} -{%- endif %} -{%- endif %} -{%- endmacro %} - -{%- macro attributes_to_key_values(required_attributes, not_required_attributes) -%} - let mut attributes = vec![ - {%- for attribute in required_attributes | attribute_sort %} - {%- if attribute is experimental %} - #[cfg(feature = "semconv_experimental")] - {%- endif %} - {%- if attribute.type.members is defined %} - crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(&required_attributes.{{ attribute.name | snake_case }}), - {%- elif attribute.type == "string" %} - crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(required_attributes.{{ attribute.name | snake_case }}.to_owned().into()), - {%- else %} - crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value(required_attributes.{{ attribute.name | snake_case }}), - {%- endif %} - {%- endfor %} - ]; - - if let Some(value) = ¬_required_attributes { - {%- for attribute in not_required_attributes | attribute_sort %} - {%- if attribute is experimental %} - #[cfg(feature = "semconv_experimental")] - {%- endif %} - {%- if attribute.type.members is defined %} - if let Some({{ attribute.name | snake_case }}) = &value.{{ attribute.name | snake_case }} { - attributes.push(crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value({{ attribute.name | snake_case }})); - } - {%- elif attribute.type == "string" %} - if let Some({{ attribute.name | snake_case }}) = &value.{{ attribute.name | snake_case }} { - attributes.push(crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value({{ attribute.name | snake_case }}.to_owned().into())); - } - {%- else %} - if let Some({{ attribute.name | snake_case }}) = value.{{ attribute.name | snake_case }} { - attributes.push(crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | screaming_snake_case }}.value({{ attribute.name | snake_case }})); - } - {%- endif %} - {%- endfor %} - } -{%- endmacro %} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 deleted file mode 100644 index b14e3465..00000000 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/attributes.rs.j2 +++ /dev/null @@ -1,85 +0,0 @@ -{%- set file_name = ctx.id | attribute_registry_namespace | snake_case -%} -{{- template.set_file_name("attributes/" ~ file_name ~ ".rs") -}} -{%- import 'attribute_macros.j2' as attribute_macros -%} - -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -{{ ctx.brief | comment_with_prefix("//! ") }} -{%- if ctx.note %} -//! -//! Notes: -{{ ctx.note | comment_with_prefix("//! ") }} -{%- endif %} -//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER - -{%- for attribute in ctx.attributes | attribute_sort %} -{{ attribute_macros.comments(attribute, "///") }} -{%- if attribute is experimental %} -#[cfg(feature = "semconv_experimental")] -{%- endif %} -{%- if attribute is deprecated %} -#[deprecated(note="{{ attribute.deprecated }}")] -{%- endif %} -{%- if attribute.type.allow_custom_values is defined %} -pub const {{ attribute.name | screaming_snake_case }}: crate::attributes::AttributeKey<{{ attribute.name | pascal_case }}> = crate::attributes::AttributeKey::new("{{ attribute.name }}"); -{%- elif attribute.type == "string" %} -pub const {{ attribute.name | screaming_snake_case }}: crate::attributes::AttributeKey = crate::attributes::AttributeKey::new("{{ attribute.name }}"); -{%- else %} -pub const {{ attribute.name | screaming_snake_case }}: crate::attributes::AttributeKey<{{ attribute.type | type_mapping }}> = crate::attributes::AttributeKey::new("{{ attribute.name }}"); -{%- endif %} -{%- if attribute.type.members is defined %} - -{% if attribute.brief %}{{ attribute.brief | comment_with_prefix("/// ") }}{%- endif %} -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum {{ attribute.name | pascal_case }} { -{%- for variant in attribute.type.members %} - {{ variant.brief | default("No brief") | comment_with_prefix(" /// ") }} - {%- if variant.note %}{{ variant.note | comment_with_prefix(" /// ") }}{% endif %} - {%- if variant is experimental %} - #[cfg(feature = "semconv_experimental")] {% endif %} - {{ variant.id | pascal_case }}, -{%- endfor %} - /// This variant allows defining a custom entry in the enum. - _Custom(String), -} - -impl {{ attribute.name | pascal_case }} { - /// Returns the string representation of the [`{{ attribute.name | pascal_case }}`]. - #[must_use] - pub fn as_str(&self) -> &str { - match self { - {%- for variant in attribute.type.members %} - {%- if variant is experimental %} - #[cfg(feature = "semconv_experimental")] {% endif %} - {{ attribute.name | pascal_case }}::{{ variant.id | pascal_case }} => "{{ variant.value }}", - {%- endfor %} - {{ attribute.name | pascal_case }}::_Custom(v) => v.as_str(), - // 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 {{ attribute.name | pascal_case }} { - /// Formats the value using the given formatter. - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -impl crate::attributes::AttributeKey<{{ attribute.name | pascal_case }}> { - /// Returns a [`KeyValue`] pair for the given value. - #[must_use] - pub fn value(&self, v: &{{ attribute.name | pascal_case }}) -> opentelemetry::KeyValue { - opentelemetry::KeyValue::new(self.key.clone(), v.to_string()) - } -} -{%- endif %} -{%- endfor %} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/mod.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/mod.rs.j2 deleted file mode 100644 index 064c9ff7..00000000 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/attributes/mod.rs.j2 +++ /dev/null @@ -1,71 +0,0 @@ -{{- template.set_file_name("attributes/mod.rs") -}} - -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! OpenTelemetry Semantic Convention Attributes -//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER - -use opentelemetry::{Key, KeyValue, StringValue}; - -{% for group in ctx %} -/// Attributes for the `{{ group.id | attribute_registry_namespace }}` namespace. -pub mod {{ group.id | attribute_registry_namespace | snake_case }}; -{%- endfor %} - -/// A typed attribute key. -pub struct AttributeKey { - key: Key, - phantom: std::marker::PhantomData -} - -impl AttributeKey { - /// Returns a new [`AttributeKey`] with the given key. - #[must_use] - pub(crate) const fn new(key: &'static str) -> AttributeKey { - Self { - key: Key::from_static_str(key), - phantom: std::marker::PhantomData - } - } - - /// Returns the key of the attribute. - #[must_use] - pub fn key(&self) -> &Key { - &self.key - } -} - -impl AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - #[must_use] - pub fn value(&self, v: StringValue) -> KeyValue { - KeyValue::new(self.key.clone(), v) - } -} - -impl AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - #[must_use] - pub fn value(&self, v: i64) -> KeyValue { - KeyValue::new(self.key.clone(), v) - } -} - -impl AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - #[must_use] - pub fn value(&self, v: f64) -> KeyValue { - KeyValue::new(self.key.clone(), v) - } -} - -impl AttributeKey { - /// Returns a [`KeyValue`] pair for the given value. - #[must_use] - pub fn value(&self, v: bool) -> KeyValue { - KeyValue::new(self.key.clone(), v) - } -} diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/lib.rs b/crates/weaver_forge/codegen_examples/templates/registry/rust/lib.rs deleted file mode 100644 index 529fc3b2..00000000 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/lib.rs +++ /dev/null @@ -1,13 +0,0 @@ -{{- template.set_file_name("lib.rs") -}} - -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! OpenTelemetry Semantic Convention Attributes -//! DO NOT EDIT, this is an Auto-generated file from templates/registry/rust/lib.rs.j2 - -pub mod attributes; -pub mod metrics; - diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/counter.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/counter.j2 deleted file mode 100644 index 8a32cc75..00000000 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/counter.j2 +++ /dev/null @@ -1,71 +0,0 @@ -{%- import 'attribute_macros.j2' as attribute_macros %} -{%- if metric.brief %} -{{ metric.brief | comment_with_prefix("/// ") }} -{%- endif %} -{%- if metric is experimental %} -#[cfg(feature = "semconv_experimental")] -{%- endif %} -#[must_use] -pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Counter - where opentelemetry::metrics::Meter: crate::metrics::CounterProvider { - crate::metrics::CounterProvider::create_counter(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") -} - -/// Metric: {{ metric.metric_name }} -/// Brief: {{ metric.brief }} -/// Unit: {{ metric.unit }} -#[derive(Debug)] -pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::Counter); - -{%- set required_attributes = metric.attributes | required %} -{%- set not_required_attributes = metric.attributes | not_required %} - -{% if required_attributes %} -/// Required attributes for the `{{ metric.metric_name }}` metric. -#[derive(Debug, Clone)] -pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { - {%- for attribute in required_attributes | attribute_sort %} - {{ attribute_macros.comments(attribute, " ///") }} - {%- if attribute.type.members is defined %} - pub {{ attribute.name | snake_case }}: crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | pascal_case }}, - {%- else %} - pub {{ attribute.name | snake_case }}: {{ attribute.type | type_mapping }}, - {%- endif %} - {%- endfor %} -} -{% endif %} - -{% if not_required_attributes %} -/// Not required attributes for the `{{ metric.metric_name }}` metric. -#[derive(Debug, Clone, Default)] -pub struct {{ metric.metric_name | pascal_case }}OptAttributes { - {%- for attribute in not_required_attributes | attribute_sort %} - {{ attribute_macros.comments(attribute, " ///") }} - {%- if attribute.type.members is defined %} - pub {{ attribute.name | snake_case }}: Option, - {%- else %} - pub {{ attribute.name | snake_case }}: Option<{{ attribute.type | type_mapping }}>, - {%- endif %} - {%- endfor %} -} -{% endif %} - -impl {{ metric.metric_name | pascal_case }} { - /// Creates a new `{{ metric.metric_name }}` metric. - #[must_use] - pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: crate::metrics::CounterProvider{ - Self(crate::metrics::CounterProvider::create_counter(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) - } - - /// Adds an additional value to the counter. - pub fn add( - &self, - value: T, - {% if required_attributes %}required_attributes: &{{ metric.metric_name | pascal_case }}ReqAttributes,{% endif %} - {% if not_required_attributes %}not_required_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} - ) { - {{ attribute_macros.attributes_to_key_values(required_attributes, not_required_attributes) }} - self.0.add(value, &attributes); - } -} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/gauge.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/gauge.j2 deleted file mode 100644 index 930cbc6f..00000000 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/gauge.j2 +++ /dev/null @@ -1,71 +0,0 @@ -{%- import 'attribute_macros.j2' as attribute_macros %} -{%- if metric.brief %} -{{ metric.brief | comment_with_prefix("/// ") }} -{%- endif %} -{%- if metric is experimental %} -#[cfg(feature = "semconv_experimental")] -{%- endif %} -#[must_use] -pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Gauge - where opentelemetry::metrics::Meter: crate::metrics::GaugeProvider { - crate::metrics::GaugeProvider::create_gauge(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") -} - -/// Metric: {{ metric.metric_name }} -/// Brief: {{ metric.brief }} -/// Unit: {{ metric.unit }} -#[derive(Debug)] -pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::Gauge); - -{%- set required_attributes = metric.attributes | required %} -{%- set not_required_attributes = metric.attributes | not_required %} - -{% if required_attributes %} -/// Required attributes for the `{{ metric.metric_name }}` metric. -#[derive(Debug, Clone)] -pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { - {%- for attribute in required_attributes | attribute_sort %} - {{ attribute_macros.comments(attribute, " ///") }} - {%- if attribute.type.members is defined %} - pub {{ attribute.name | snake_case }}: crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | pascal_case }}, - {%- else %} - pub {{ attribute.name | snake_case }}: {{ attribute.type | type_mapping }}, - {%- endif %} - {%- endfor %} -} -{% endif %} - -{% if not_required_attributes %} -/// Not required attributes for the `{{ metric.metric_name }}` metric. -#[derive(Debug, Clone, Default)] -pub struct {{ metric.metric_name | pascal_case }}OptAttributes { - {%- for attribute in not_required_attributes | attribute_sort %} - {{ attribute_macros.comments(attribute, " ///") }} - {%- if attribute.type.members is defined %} - pub {{ attribute.name | snake_case }}: Option, - {%- else %} - pub {{ attribute.name | snake_case }}: Option<{{ attribute.type | type_mapping }}>, - {%- endif %} - {%- endfor %} -} -{% endif %} - -impl {{ metric.metric_name | pascal_case }} { - /// Creates a new `{{ metric.metric_name }}` metric. - #[must_use] - pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: crate::metrics::GaugeProvider{ - Self(crate::metrics::GaugeProvider::create_gauge(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) - } - - /// Records an additional value to the gauge. - pub fn record( - &self, - value: T, - {% if required_attributes %}required_attributes: &{{ metric.metric_name | pascal_case }}ReqAttributes,{% endif %} - {% if not_required_attributes %}not_required_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} - ) { - {{ attribute_macros.attributes_to_key_values(required_attributes, not_required_attributes) }} - self.0.record(value, &attributes); - } -} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/histogram.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/histogram.j2 deleted file mode 100644 index ffe08a10..00000000 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/histogram.j2 +++ /dev/null @@ -1,71 +0,0 @@ -{%- import 'attribute_macros.j2' as attribute_macros %} -{%- if metric.brief %} -{{ metric.brief | comment_with_prefix("/// ") }} -{%- endif %} -{%- if metric is experimental %} -#[cfg(feature = "semconv_experimental")] -{%- endif %} -#[must_use] -pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::Histogram - where opentelemetry::metrics::Meter: crate::metrics::HistogramProvider { - crate::metrics::HistogramProvider::create_histogram(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") -} - -/// Metric: {{ metric.metric_name }} -/// Brief: {{ metric.brief }} -/// Unit: {{ metric.unit }} -#[derive(Debug)] -pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::Histogram); - -{%- set required_attributes = metric.attributes | required %} -{%- set not_required_attributes = metric.attributes | not_required %} - -{% if required_attributes %} -/// Required attributes for the `{{ metric.metric_name }}` metric. -#[derive(Debug, Clone)] -pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { - {%- for attribute in required_attributes | attribute_sort %} - {{ attribute_macros.comments(attribute, " ///") }} - {%- if attribute.type.members is defined %} - pub {{ attribute.name | snake_case }}: crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | pascal_case }}, - {%- else %} - pub {{ attribute.name | snake_case }}: {{ attribute.type | type_mapping }}, - {%- endif %} - {%- endfor %} -} -{% endif %} - -{% if not_required_attributes %} -/// Not required attributes for the `{{ metric.metric_name }}` metric. -#[derive(Debug, Clone, Default)] -pub struct {{ metric.metric_name | pascal_case }}OptAttributes { - {%- for attribute in not_required_attributes | attribute_sort %} - {{ attribute_macros.comments(attribute, " ///") }} - {%- if attribute.type.members is defined %} - pub {{ attribute.name | snake_case }}: Option, - {%- else %} - pub {{ attribute.name | snake_case }}: Option<{{ attribute.type | type_mapping }}>, - {%- endif %} - {%- endfor %} -} -{% endif %} - -impl {{ metric.metric_name | pascal_case }} { - /// Creates a new instance of the `{{ metric.metric_name }}` metric. - #[must_use] - pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: crate::metrics::HistogramProvider{ - Self(crate::metrics::HistogramProvider::create_histogram(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) - } - - /// Adds an additional value to the distribution. - pub fn record( - &self, - value: T, - {% if required_attributes %}required_attributes: &{{ metric.metric_name | pascal_case }}ReqAttributes,{% endif %} - {% if not_required_attributes %}not_required_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} - ) { - {{ attribute_macros.attributes_to_key_values(required_attributes, not_required_attributes) }} - self.0.record(value, &attributes); - } -} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/updowncounter.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/updowncounter.j2 deleted file mode 100644 index 3276cb6f..00000000 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/instruments/updowncounter.j2 +++ /dev/null @@ -1,72 +0,0 @@ -{%- import 'attribute_macros.j2' as attribute_macros %} -{%- if metric.brief %} -{{ metric.brief | comment_with_prefix("/// ") }} -{%- endif %} -{%- if metric is experimental %} -#[cfg(feature = "semconv_experimental")] -{%- endif %} -#[must_use] -pub fn create_{{ metric.metric_name | snake_case }}(meter: &opentelemetry::metrics::Meter) -> opentelemetry::metrics::UpDownCounter - where opentelemetry::metrics::Meter: crate::metrics::UpDownCounterProvider { - crate::metrics::UpDownCounterProvider::create_up_down_counter(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}") -} - -/// Metric: {{ metric.metric_name }} -/// Brief: {{ metric.brief }} -/// Unit: {{ metric.unit }} -#[derive(Debug)] -pub struct {{ metric.metric_name | pascal_case }}(opentelemetry::metrics::UpDownCounter); - -{%- set required_attributes = metric.attributes | required %} -{%- set not_required_attributes = metric.attributes | not_required %} - -{% if required_attributes %} -/// Required attributes for the `{{ metric.metric_name }}` metric. -/// Attributes for the `{{ metric.metric_name }}` metric. -#[derive(Debug, Clone)] -pub struct {{ metric.metric_name | pascal_case }}ReqAttributes { - {%- for attribute in required_attributes | attribute_sort %} - {{ attribute_macros.comments(attribute, " ///") }} - {%- if attribute.type.members is defined %} - pub {{ attribute.name | snake_case }}: crate::attributes::{{ attribute.name | attribute_namespace }}::{{ attribute.name | pascal_case }}, - {%- else %} - pub {{ attribute.name | snake_case }}: {{ attribute.type | type_mapping }}, - {%- endif %} - {%- endfor %} -} -{% endif %} - -{% if not_required_attributes %} -/// Not required attributes for the `{{ metric.metric_name }}` metric. -#[derive(Debug, Clone, Default)] -pub struct {{ metric.metric_name | pascal_case }}OptAttributes { - {%- for attribute in not_required_attributes | attribute_sort %} - {{ attribute_macros.comments(attribute, " ///") }} - {%- if attribute.type.members is defined %} - pub {{ attribute.name | snake_case }}: Option, - {%- else %} - pub {{ attribute.name | snake_case }}: Option<{{ attribute.type | type_mapping }}>, - {%- endif %} - {%- endfor %} -} -{% endif %} - -impl {{ metric.metric_name | pascal_case }} { - /// Creates a new instance of the `{{ metric.metric_name }}` metric. - #[must_use] - pub fn new(meter: &opentelemetry::metrics::Meter) -> Self - where opentelemetry::metrics::Meter: crate::metrics::UpDownCounterProvider{ - Self(crate::metrics::UpDownCounterProvider::create_up_down_counter(meter, "{{ metric.metric_name }}", "{{ metric.brief }}", "{{ metric.unit }}")) - } - - /// Adds an additional value to the up-down-counter. - pub fn add( - &self, - value: T, - {% if required_attributes %}required_attributes: &{{ metric.metric_name | pascal_case }}ReqAttributes,{% endif %} - {% if not_required_attributes %}not_required_attributes: Option<&{{ metric.metric_name | pascal_case }}OptAttributes>,{% endif %} - ) { - {{ attribute_macros.attributes_to_key_values(required_attributes, not_required_attributes) }} - self.0.add(value, &attributes); - } -} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 deleted file mode 100644 index 0b23820a..00000000 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/metrics.rs.j2 +++ /dev/null @@ -1,13 +0,0 @@ -{%- set file_name = ctx.prefix | snake_case -%} -{{- template.set_file_name("metrics/" ~ file_name ~ ".rs") -}} - -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER - -{%- for metric in ctx.groups %} -{% include "metrics/instruments/" ~ metric.instrument ~ ".j2" %} -{%- endfor %} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/mod.rs.j2 b/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/mod.rs.j2 deleted file mode 100644 index eec7f03f..00000000 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/metrics/mod.rs.j2 +++ /dev/null @@ -1,137 +0,0 @@ -{{- template.set_file_name("metrics/mod.rs") -}} - -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -//! OpenTelemetry Semantic Convention Metrics -//! DO NOT EDIT, THIS FILE HAS BEEN GENERATED BY WEAVER - -{% for group in ctx %} -/// Metrics for the `{{ group.id | metric_namespace }}` namespace. -pub mod {{ group.id | metric_namespace | snake_case }}; -{%- endfor %} - -/// A trait implemented by histogram providers (e.g. `Meter`). -pub trait HistogramProvider { - /// Creates a new histogram with the given name, description, and unit. - fn create_histogram(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Histogram; -} - -/// This implementation specifies that a Meter is able to create u64 histograms. -impl HistogramProvider for opentelemetry::metrics::Meter { - /// Creates a new u64 histogram with the given name, description, and unit. - fn create_histogram(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Histogram { - self.u64_histogram(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// This implementation specifies that a Meter is able to create u64 histograms. -impl HistogramProvider for opentelemetry::metrics::Meter { - /// Creates a new f64 histogram with the given name, description, and unit. - fn create_histogram(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Histogram { - self.f64_histogram(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// A trait implemented by up-down-counter providers (e.g. `Meter`). -pub trait UpDownCounterProvider { - /// Creates a new up-down-counter with the given name, description, and unit. - fn create_up_down_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::UpDownCounter; -} - -/// This implementation specifies that a Meter is able to create i64 up-down-counters. -impl UpDownCounterProvider for opentelemetry::metrics::Meter { - /// Creates a new i64 up-down-counter with the given name, description, and unit. - fn create_up_down_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::UpDownCounter { - self.i64_up_down_counter(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// This implementation specifies that a Meter is able to create f64 up-down-counters. -impl UpDownCounterProvider for opentelemetry::metrics::Meter { - /// Creates a new f64 up-down-counter with the given name, description, and unit. - fn create_up_down_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::UpDownCounter { - self.f64_up_down_counter(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// A trait implemented by counter providers (e.g. `Meter`). -pub trait CounterProvider { - /// Creates a new counter with the given name, description, and unit. - fn create_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Counter; -} - -/// This implementation specifies that a Meter is able to create u64 counters. -impl CounterProvider for opentelemetry::metrics::Meter { - /// Creates a new u64 counter with the given name, description, and unit. - fn create_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Counter { - self.u64_counter(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// This implementation specifies that a Meter is able to create f64 counters. -impl CounterProvider for opentelemetry::metrics::Meter { - /// Creates a new f64 counter with the given name, description, and unit. - fn create_counter(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Counter { - self.f64_counter(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// A trait implemented by gauge providers (e.g. `Meter`). -pub trait GaugeProvider { - /// Creates a new gauge with the given name, description, and unit. - fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge; -} - -/// This implementation specifies that a Meter is able to create u64 gauges. -impl GaugeProvider for opentelemetry::metrics::Meter { - /// Creates a new u64 gauge with the given name, description, and unit. - fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge { - self.u64_gauge(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// This implementation specifies that a Meter is able to create i64 gauges. -impl GaugeProvider for opentelemetry::metrics::Meter { - /// Creates a new i64 gauge with the given name, description, and unit. - fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge { - self.i64_gauge(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} - -/// This implementation specifies that a Meter is able to create f64 gauges. -impl GaugeProvider for opentelemetry::metrics::Meter { - /// Creates a new f64 gauge with the given name, description, and unit. - fn create_gauge(&self, name: &'static str, description: &'static str, unit: &'static str) -> opentelemetry::metrics::Gauge { - self.f64_gauge(name) - .with_description(description) - .with_unit(opentelemetry::metrics::Unit::new(unit)) - .init() - } -} \ No newline at end of file diff --git a/crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml b/crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml deleted file mode 100644 index eeb0fc6b..00000000 --- a/crates/weaver_forge/codegen_examples/templates/registry/rust/weaver.yaml +++ /dev/null @@ -1,156 +0,0 @@ -type_mapping: - int: i64 - double: f64 - boolean: bool - string: String - string[]: Vec - template[string]: String # Not yet properly handled in codegen - template[string[]]: Vec # Not yet properly handled in codegen - -templates: - - pattern: README.md - filter: . - application_mode: single - - pattern: lib.rs - filter: . - application_mode: single - - # Templates for the `attribute_group` group type - - pattern: attributes/mod.rs.j2 - # The following JQ filter extracts the id, type, brief, and prefix of groups matching the following criteria: - # - groups with an id starting with the prefix `registry.` - # - groups of the type `attribute_group`. - # - groups are deduplicated by namespace. - # - groups are sorted by namespace. - filter: > - .groups - | map(select(.id | startswith("registry."))) - | map(select(.type == "attribute_group") - | { - id, - type, - brief, - prefix}) - | unique_by(.id | split(".") | .[1]) - | sort_by(.id | split(".") | .[1]) - application_mode: single - - pattern: attributes/attributes.rs.j2 - # The following JQ filter extracts the id, type, brief, prefix, and attributes of groups matching the following - # criteria: - # - groups with an id starting with the prefix `registry.` - # - groups of the type `attribute_group`. - # - groups are sorted by namespace. - filter: > - .groups - | map(select(.id | startswith("registry."))) - | map(select(.type == "attribute_group") - | { - id, - type, - brief, - prefix, - attributes}) - | group_by(.id | split(".") | .[1]) - | map({ - id: (map(select(.id | endswith(".deprecated") | not)) | first).id, - type: (map(select(.id | endswith(".deprecated") | not)) | first).type, - brief: (map(select(.id | endswith(".deprecated") | not)) | first).brief, - prefix: (map(select(.id | endswith(".deprecated") | not)) | first).prefix, - attributes: map(.attributes) | add - }) - | sort_by(.id | split(".") | .[1]) - application_mode: each - - # Templates for the `metric` group type - - pattern: metrics/mod.rs.j2 - # The following JQ filter extracts the id, type, brief, and prefix of groups matching the following criteria: - # - groups with an id starting with the prefix `metric.` - # - groups of the type `metric`. - # - groups are deduplicated by namespace. - # - groups are sorted by prefix. - filter: > - .groups - | map(select(.id | startswith("metric."))) - | map(select(.type == "metric") - | { - id, - type, - brief, - prefix}) - | unique_by(.id | split(".") | .[1]) - | sort_by(.id | split(".") | .[1]) - application_mode: single - - pattern: metrics/metrics.rs.j2 - # The following JQ filter extracts the id, type, brief, prefix, and attributes of groups matching the following - # criteria: - # - groups with an id starting with the prefix `metric.` - # - groups of the type `metric`. - # - groups are sorted by namespace. - filter: > - .groups - | map(select(.id | startswith("metric."))) - | group_by(.id | split(".") | .[1]) - | map({ - prefix: .[0].id | split(".") | .[1], - groups: . - }) - 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: -# - groups with an id starting with the prefix `registry.` -# - groups of the type `attribute_group`. -# - groups with a well-defined prefix. -# - groups with a non-empty list of attributes that are neither deprecated nor experimental. -# - groups are deduplicated by prefix. -# - groups are sorted by prefix. -# filter: > -# .groups -# | map(select(.id | startswith("registry."))) -# | map(select(.type == "attribute_group" and .prefix != null and .prefix != "") -# | { -# id, -# type, -# brief, -# prefix, -# attributes: (.attributes -# | map(select(.stability == "experimental" and .deprecated | not)))}) -# | map(select(.attributes | length > 0)) -# | map( -# { -# id, -# type, -# brief, -# prefix -# } -# ) -# | unique_by(.prefix) -# | sort_by(.prefix) - - -# The following JQ filter extracts the id, type, brief, prefix, and attributes of groups matching the following -# criteria: -# - groups with an id starting with the prefix `registry.` -# - groups of the type `attribute_group`. -# - groups with a well-defined prefix. -# - groups with a non-empty list of attributes that are neither deprecated nor experimental. -# - groups are sorted by prefix. -# filter: > -# .groups -# | map(select(.id | startswith("registry."))) -# | map(select(.type == "attribute_group" and .prefix != null and .prefix != "") -# | { -# id, -# type, -# brief, -# prefix, -# attributes: (.attributes | map(select(.stability == "experimental" and .deprecated | not)))}) -# | sort_by(.prefix // empty) \ No newline at end of file From 3534c42ae76cb4e0be948564f10b359d6ba28f3c Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Tue, 7 May 2024 14:37:31 -0700 Subject: [PATCH 35/39] chore(forge): Fix Windows specific issue. --- crates/weaver_codegen_test/build.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/crates/weaver_codegen_test/build.rs b/crates/weaver_codegen_test/build.rs index 888c97ae..979da23b 100644 --- a/crates/weaver_codegen_test/build.rs +++ b/crates/weaver_codegen_test/build.rs @@ -8,7 +8,7 @@ use std::collections::HashMap; use std::io::Write; -use std::path::{Path, PathBuf}; +use std::path::{Component, Path, PathBuf}; use std::process::exit; use weaver_cache::Cache; use weaver_common::in_memory::LogMessage; @@ -100,12 +100,10 @@ fn create_single_generated_rs_file(root: &Path) { .to_str() .expect("Failed to convert to string"); let parent_modules = relative_path.parent().map_or(vec![], |parent| { - let parent = parent.display().to_string(); - if parent.is_empty() { - vec![] - } else { - parent.split('/').map(|s| s.to_owned()).collect::>() - } + parent.components().filter_map(|component| match component { + Component::Normal(part) => Some(part.to_string_lossy().into_owned()), + _ => None, + }).collect() }); // Skip generated.rs From b858e7caa050880d4b7c331fcf41a904af9f58a8 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Tue, 7 May 2024 16:15:44 -0700 Subject: [PATCH 36/39] chore(forge): Improve error message to debug Windows specific issue. --- crates/weaver_forge/src/lib.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/crates/weaver_forge/src/lib.rs b/crates/weaver_forge/src/lib.rs index c69e91a1..019cd91b 100644 --- a/crates/weaver_forge/src/lib.rs +++ b/crates/weaver_forge/src/lib.rs @@ -343,9 +343,13 @@ impl TemplateEngine { log.loading(&format!("Generating file {}", template_file)); let template = engine .get_template(template_file) - .map_err(|e| InvalidTemplateFile { - template: template_path.to_path_buf(), - error: e.to_string(), + .map_err(|e| { + let templates = engine.templates().map(|(name, _)| name.to_owned()).collect::>(); + let error = format!("{}. Available templates: {:?}", e.to_string(), templates); + InvalidTemplateFile { + template: template_path.to_path_buf(), + error, + } })?; let output = template @@ -468,12 +472,6 @@ impl TemplateEngine { // env.add_filter("without_value", extensions::without_value); // env.add_filter("with_enum", extensions::with_enum); // env.add_filter("without_enum", extensions::without_enum); - // env.add_filter( - // "type_mapping", - // extensions::TypeMapping { - // type_mapping: target_config.type_mapping, - // }, - // ); Ok(env) } From baa9e2a6a58de8d52d665634e06a468cc9870c97 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Tue, 7 May 2024 16:46:58 -0700 Subject: [PATCH 37/39] chore(forge): Add traces to debug Windows specific issue. --- crates/weaver_forge/src/lib.rs | 57 +++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/crates/weaver_forge/src/lib.rs b/crates/weaver_forge/src/lib.rs index 019cd91b..2462ff24 100644 --- a/crates/weaver_forge/src/lib.rs +++ b/crates/weaver_forge/src/lib.rs @@ -4,13 +4,13 @@ use std::borrow::Cow; use std::fmt::{Debug, Display, Formatter}; -use std::fs; +use std::{fs, io}; use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex}; use minijinja::syntax::SyntaxConfig; use minijinja::value::{from_args, Object}; -use minijinja::{path_loader, Environment, State, Value}; +use minijinja::{Environment, State, Value, ErrorKind}; use rayon::iter::IntoParallelIterator; use rayon::iter::ParallelIterator; use serde::Serialize; @@ -100,7 +100,7 @@ impl Object for TemplateObject { Ok(Value::from("")) } else { Err(minijinja::Error::new( - minijinja::ErrorKind::UnknownMethod, + ErrorKind::UnknownMethod, format!("template has no method named {name}"), )) } @@ -254,7 +254,13 @@ impl TemplateEngine { } }; + // @todo - remove + println!("cargo:warning=Scanning file {:?}", relative_path); + for template in tmpl_matcher.matches(relative_path) { + // @todo - remove + println!("cargo:warning=Processing file {:?}", relative_path); + let filtered_result = match template.filter.apply(context.clone()) { Ok(result) => result, Err(e) => return Some(e), @@ -341,13 +347,16 @@ impl TemplateEngine { engine.add_global("template", Value::from_object(template_object.clone())); log.loading(&format!("Generating file {}", template_file)); + // @todo - remove + println!("cargo:warning=Loading file {:?}", template_file); + let template = engine .get_template(template_file) .map_err(|e| { let templates = engine.templates().map(|(name, _)| name.to_owned()).collect::>(); - let error = format!("{}. Available templates: {:?}", e.to_string(), templates); + let error = format!("{}. Available templates: {:?}", e, templates); InvalidTemplateFile { - template: template_path.to_path_buf(), + template: template_file.into(), error, } })?; @@ -389,7 +398,7 @@ impl TemplateEngine { error: e.to_string(), })?; - env.set_loader(path_loader(&self.path)); + env.set_loader(my_path_loader(&self.path)); env.set_syntax(syntax); // Register code-oriented filters @@ -505,6 +514,40 @@ impl TemplateEngine { } } +// @todo - remove +fn my_path_loader<'x, P: AsRef + 'x>( + dir: P, +) -> impl for<'a> Fn(&'a str) -> Result, minijinja::Error> + Send + Sync + 'static { + let dir = dir.as_ref().to_path_buf(); + move |name| { + let path = match safe_join(&dir, name) { + Some(path) => path, + None => return Ok(None), + }; + println!("cargo:warning=Loader loading template {:?}", path); + match fs::read_to_string(path) { + Ok(result) => Ok(Some(result)), + Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None), + Err(err) => Err( + minijinja::Error::new(ErrorKind::InvalidOperation, "could not read template").with_source(err), + ), + } + } +} + +fn safe_join(base: &Path, template: &str) -> Option { + let mut rv = base.to_path_buf(); + for segment in template.split('/') { + if segment.starts_with('.') || segment.contains('\\') { + println!("cargo:warning=Safe join return None"); + return None; + } + rv.push(segment); + } + println!("cargo:warning=Safe join returns {:?}", rv); + Some(rv) +} + // Helper filter to work around lack of `list.append()` support in minijinja. // Will take a list of lists and return a new list containing only elements of sublists. fn flatten(value: Value) -> Result { @@ -528,7 +571,7 @@ fn split_id(value: Value) -> Result, minijinja::Error> { Ok(values) } None => Err(minijinja::Error::new( - minijinja::ErrorKind::InvalidOperation, + ErrorKind::InvalidOperation, format!("Expected string, found: {value}"), )), } From 2f2ce452a9d21c9ccf93c938f1ba771578545375 Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Tue, 7 May 2024 17:56:02 -0700 Subject: [PATCH 38/39] chore(forge): Fix MiniJinja template loader for Windows. --- crates/weaver_forge/src/lib.rs | 79 ++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 33 deletions(-) diff --git a/crates/weaver_forge/src/lib.rs b/crates/weaver_forge/src/lib.rs index 2462ff24..09d03688 100644 --- a/crates/weaver_forge/src/lib.rs +++ b/crates/weaver_forge/src/lib.rs @@ -2,15 +2,15 @@ #![doc = include_str!("../README.md")] +use std::{fs, io}; use std::borrow::Cow; use std::fmt::{Debug, Display, Formatter}; -use std::{fs, io}; use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex}; +use minijinja::{Environment, ErrorKind, State, Value}; use minijinja::syntax::SyntaxConfig; use minijinja::value::{from_args, Object}; -use minijinja::{Environment, State, Value, ErrorKind}; use rayon::iter::IntoParallelIterator; use rayon::iter::ParallelIterator; use serde::Serialize; @@ -95,7 +95,7 @@ impl Object for TemplateObject { args: &[Value], ) -> Result { if name == "set_file_name" { - let (file_name,): (&str,) = from_args(args)?; + let (file_name, ): (&str, ) = from_args(args)?; file_name.clone_into(&mut self.file_name.lock().expect("Lock poisoned")); Ok(Value::from("")) } else { @@ -274,8 +274,8 @@ impl TemplateEngine { NewContext { ctx: &filtered_result, } - .try_into() - .ok()?, + .try_into() + .ok()?, relative_path, output_dir, ) { @@ -309,8 +309,8 @@ impl TemplateEngine { NewContext { ctx: &filtered_result, } - .try_into() - .ok()?, + .try_into() + .ok()?, relative_path, output_dir, ) { @@ -398,7 +398,7 @@ impl TemplateEngine { error: e.to_string(), })?; - env.set_loader(my_path_loader(&self.path)); + env.set_loader(cross_platform_loader(&self.path)); env.set_syntax(syntax); // Register code-oriented filters @@ -514,17 +514,14 @@ impl TemplateEngine { } } -// @todo - remove -fn my_path_loader<'x, P: AsRef + 'x>( +// The template loader provided by MiniJinja is not cross-platform. +fn cross_platform_loader<'x, P: AsRef + 'x>( dir: P, ) -> impl for<'a> Fn(&'a str) -> Result, minijinja::Error> + Send + Sync + 'static { let dir = dir.as_ref().to_path_buf(); move |name| { - let path = match safe_join(&dir, name) { - Some(path) => path, - None => return Ok(None), - }; - println!("cargo:warning=Loader loading template {:?}", path); + let path = safe_join(&dir, name)?; + println!("cargo:warning=Loader loading template base: {:?}, path:{:?}", dir, path); match fs::read_to_string(path) { Ok(result) => Ok(Some(result)), Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None), @@ -535,17 +532,33 @@ fn my_path_loader<'x, P: AsRef + 'x>( } } -fn safe_join(base: &Path, template: &str) -> Option { - let mut rv = base.to_path_buf(); - for segment in template.split('/') { - if segment.starts_with('.') || segment.contains('\\') { - println!("cargo:warning=Safe join return None"); - return None; - } - rv.push(segment); +// Combine a root path and a template name, ensuring that the combined path is +// a subdirectory of the base path. +fn safe_join(root: &Path, template: &str) -> Result { + let mut path = root.to_path_buf(); + path.push(template); + + // Canonicalize the paths to resolve any `..` or `.` components + let canonical_root = root.canonicalize() + .map_err(|e| minijinja::Error::new( + ErrorKind::InvalidOperation, + format!("Failed to canonicalize root path: {}", e)))?; + let canonical_combined = path.canonicalize() + .map_err(|e| minijinja::Error::new( + ErrorKind::InvalidOperation, + format!("Failed to canonicalize combined path: {}", e)))?; + + // Verify that the canonical combined path starts with the canonical root path + if canonical_combined.starts_with(&canonical_root) { + Ok(canonical_combined) + } else { + Err(minijinja::Error::new( + ErrorKind::InvalidOperation, + format!( + "The combined path is not a subdirectory of the root path: {:?} -> {:?}", + canonical_root, canonical_combined + ))) } - println!("cargo:warning=Safe join returns {:?}", rv); - Some(rv) } // Helper filter to work around lack of `list.append()` support in minijinja. @@ -579,19 +592,19 @@ fn split_id(value: Value) -> Result, minijinja::Error> { #[cfg(test)] mod tests { - use globset::Glob; use std::collections::HashSet; use std::fs; use std::path::Path; + use globset::Glob; use walkdir::WalkDir; - use crate::config::{ApplicationMode, TemplateConfig}; use weaver_common::TestLogger; use weaver_diff::diff_output; use weaver_resolver::SchemaResolver; use weaver_semconv::registry::SemConvRegistry; + use crate::config::{ApplicationMode, TemplateConfig}; use crate::debug::print_dedup_errors; use crate::filter::Filter; use crate::registry::TemplateRegistry; @@ -743,12 +756,12 @@ mod tests { schema.registry(registry_id).expect("registry not found"), schema.catalog(), ) - .unwrap_or_else(|e| { - panic!( - "Failed to create the context for the template evaluation: {:?}", - e - ) - }); + .unwrap_or_else(|e| { + panic!( + "Failed to create the context for the template evaluation: {:?}", + e + ) + }); engine .generate( From dd0dc61886a9831d37b9caaf3276da70eb9cb5aa Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Tue, 7 May 2024 18:10:14 -0700 Subject: [PATCH 39/39] chore(forge): Fix MiniJinja template loader for Windows. --- Cargo.lock | 20 +++---- crates/weaver_codegen_test/build.rs | 11 ++-- crates/weaver_forge/src/lib.rs | 83 ++++++++++++++--------------- 3 files changed, 58 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 628d953a..845a8073 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2174,9 +2174,9 @@ checksum = "63335b2e2c34fae2fb0aa2cecfd9f0832a1e24b3b32ecec612c3426d46dc8aaa" [[package]] name = "num-complex" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ "num-traits", ] @@ -2805,9 +2805,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51f344d206c5e1b010eec27349b815a4805f70a778895959d70b74b9b529b30a" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" [[package]] name = "rustls-webpki" @@ -2878,18 +2878,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.200" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f" +checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.200" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" +checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" dependencies = [ "proc-macro2", "quote", @@ -2898,9 +2898,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.116" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", diff --git a/crates/weaver_codegen_test/build.rs b/crates/weaver_codegen_test/build.rs index 979da23b..f4873166 100644 --- a/crates/weaver_codegen_test/build.rs +++ b/crates/weaver_codegen_test/build.rs @@ -100,10 +100,13 @@ fn create_single_generated_rs_file(root: &Path) { .to_str() .expect("Failed to convert to string"); let parent_modules = relative_path.parent().map_or(vec![], |parent| { - parent.components().filter_map(|component| match component { - Component::Normal(part) => Some(part.to_string_lossy().into_owned()), - _ => None, - }).collect() + parent + .components() + .filter_map(|component| match component { + Component::Normal(part) => Some(part.to_string_lossy().into_owned()), + _ => None, + }) + .collect() }); // Skip generated.rs diff --git a/crates/weaver_forge/src/lib.rs b/crates/weaver_forge/src/lib.rs index 09d03688..f8502460 100644 --- a/crates/weaver_forge/src/lib.rs +++ b/crates/weaver_forge/src/lib.rs @@ -2,15 +2,15 @@ #![doc = include_str!("../README.md")] -use std::{fs, io}; use std::borrow::Cow; use std::fmt::{Debug, Display, Formatter}; use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex}; +use std::{fs, io}; -use minijinja::{Environment, ErrorKind, State, Value}; use minijinja::syntax::SyntaxConfig; use minijinja::value::{from_args, Object}; +use minijinja::{Environment, ErrorKind, State, Value}; use rayon::iter::IntoParallelIterator; use rayon::iter::ParallelIterator; use serde::Serialize; @@ -95,7 +95,7 @@ impl Object for TemplateObject { args: &[Value], ) -> Result { if name == "set_file_name" { - let (file_name, ): (&str, ) = from_args(args)?; + let (file_name,): (&str,) = from_args(args)?; file_name.clone_into(&mut self.file_name.lock().expect("Lock poisoned")); Ok(Value::from("")) } else { @@ -254,13 +254,7 @@ impl TemplateEngine { } }; - // @todo - remove - println!("cargo:warning=Scanning file {:?}", relative_path); - for template in tmpl_matcher.matches(relative_path) { - // @todo - remove - println!("cargo:warning=Processing file {:?}", relative_path); - let filtered_result = match template.filter.apply(context.clone()) { Ok(result) => result, Err(e) => return Some(e), @@ -274,8 +268,8 @@ impl TemplateEngine { NewContext { ctx: &filtered_result, } - .try_into() - .ok()?, + .try_into() + .ok()?, relative_path, output_dir, ) { @@ -309,8 +303,8 @@ impl TemplateEngine { NewContext { ctx: &filtered_result, } - .try_into() - .ok()?, + .try_into() + .ok()?, relative_path, output_dir, ) { @@ -347,19 +341,18 @@ impl TemplateEngine { engine.add_global("template", Value::from_object(template_object.clone())); log.loading(&format!("Generating file {}", template_file)); - // @todo - remove - println!("cargo:warning=Loading file {:?}", template_file); - let template = engine - .get_template(template_file) - .map_err(|e| { - let templates = engine.templates().map(|(name, _)| name.to_owned()).collect::>(); - let error = format!("{}. Available templates: {:?}", e, templates); - InvalidTemplateFile { - template: template_file.into(), - error, - } - })?; + let template = engine.get_template(template_file).map_err(|e| { + let templates = engine + .templates() + .map(|(name, _)| name.to_owned()) + .collect::>(); + let error = format!("{}. Available templates: {:?}", e, templates); + InvalidTemplateFile { + template: template_file.into(), + error, + } + })?; let output = template .render(ctx.clone()) @@ -521,13 +514,14 @@ fn cross_platform_loader<'x, P: AsRef + 'x>( let dir = dir.as_ref().to_path_buf(); move |name| { let path = safe_join(&dir, name)?; - println!("cargo:warning=Loader loading template base: {:?}, path:{:?}", dir, path); match fs::read_to_string(path) { Ok(result) => Ok(Some(result)), Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None), - Err(err) => Err( - minijinja::Error::new(ErrorKind::InvalidOperation, "could not read template").with_source(err), - ), + Err(err) => Err(minijinja::Error::new( + ErrorKind::InvalidOperation, + "could not read template", + ) + .with_source(err)), } } } @@ -539,14 +533,18 @@ fn safe_join(root: &Path, template: &str) -> Result { path.push(template); // Canonicalize the paths to resolve any `..` or `.` components - let canonical_root = root.canonicalize() - .map_err(|e| minijinja::Error::new( + let canonical_root = root.canonicalize().map_err(|e| { + minijinja::Error::new( ErrorKind::InvalidOperation, - format!("Failed to canonicalize root path: {}", e)))?; - let canonical_combined = path.canonicalize() - .map_err(|e| minijinja::Error::new( + format!("Failed to canonicalize root path: {}", e), + ) + })?; + let canonical_combined = path.canonicalize().map_err(|e| { + minijinja::Error::new( ErrorKind::InvalidOperation, - format!("Failed to canonicalize combined path: {}", e)))?; + format!("Failed to canonicalize combined path: {}", e), + ) + })?; // Verify that the canonical combined path starts with the canonical root path if canonical_combined.starts_with(&canonical_root) { @@ -557,7 +555,8 @@ fn safe_join(root: &Path, template: &str) -> Result { format!( "The combined path is not a subdirectory of the root path: {:?} -> {:?}", canonical_root, canonical_combined - ))) + ), + )) } } @@ -756,12 +755,12 @@ mod tests { schema.registry(registry_id).expect("registry not found"), schema.catalog(), ) - .unwrap_or_else(|e| { - panic!( - "Failed to create the context for the template evaluation: {:?}", - e - ) - }); + .unwrap_or_else(|e| { + panic!( + "Failed to create the context for the template evaluation: {:?}", + e + ) + }); engine .generate(