diff --git a/crates/weaver_resolved_schema/src/attribute.rs b/crates/weaver_resolved_schema/src/attribute.rs index 09acd37f..7d9238d6 100644 --- a/crates/weaver_resolved_schema/src/attribute.rs +++ b/crates/weaver_resolved_schema/src/attribute.rs @@ -11,6 +11,7 @@ use serde::{Deserialize, Serialize}; use std::fmt::Display; use weaver_semconv::attribute::{AttributeSpec, AttributeType, Examples, RequirementLevel}; use weaver_semconv::stability::Stability; +use std::ops::Not; /// An attribute definition. #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, JsonSchema)] @@ -64,6 +65,13 @@ pub struct Attribute { /// to use instead. See also stability. #[serde(skip_serializing_if = "Option::is_none")] pub deprecated: Option, + /// Specifies the prefix of the attribute. + /// If this parameter is set, the resolved id of the referenced attribute will + /// have group prefix added to it. + /// It defaults to false. + #[serde(default)] + #[serde(skip_serializing_if = "<&bool>::not")] + pub prefix: bool, /// A set of tags for the attribute. #[serde(skip_serializing_if = "Option::is_none")] pub tags: Option, diff --git a/crates/weaver_resolved_schema/src/lineage.rs b/crates/weaver_resolved_schema/src/lineage.rs index 9dca09c5..bc128c01 100644 --- a/crates/weaver_resolved_schema/src/lineage.rs +++ b/crates/weaver_resolved_schema/src/lineage.rs @@ -74,6 +74,7 @@ impl AttributeLineage { note, stability, deprecated, + prefix, .. } => { if brief.is_some() { @@ -106,6 +107,9 @@ impl AttributeLineage { .inherited_fields .insert("deprecated".to_owned()); } + if *prefix { + _ = attr_lineage.inherited_fields.insert("prefix".to_owned()); + } } AttributeSpec::Id { brief, @@ -394,6 +398,32 @@ impl AttributeLineage { *parent_value } } + + /// Determines the value of the tags field by evaluating the presence of + /// a local value. If a local value is provided, it is used, and the tags + /// field's lineage is marked as local. Otherwise, the specified parent + /// value is used, and the tags field's lineage is marked as inherited + /// from the parent. + /// This method updates the lineage information for the tags field to + /// reflect the source of its value. + pub fn prefix( + &mut self, + local_value: &bool, + parent_value: &bool, + ) -> bool { + if *local_value { + _ = self + .locally_overridden_fields + .insert("prefix".to_owned()); + _ = self.inherited_fields.remove("prefix"); + *local_value + } else { + if *parent_value { + _ = self.inherited_fields.insert("prefix".to_owned()); + } + *parent_value + } + } } impl GroupLineage { diff --git a/crates/weaver_resolver/src/attribute.rs b/crates/weaver_resolver/src/attribute.rs index dd745d44..020f77bf 100644 --- a/crates/weaver_resolver/src/attribute.rs +++ b/crates/weaver_resolver/src/attribute.rs @@ -66,6 +66,7 @@ impl AttributeCatalog { pub fn resolve( &mut self, group_id: &str, + group_prefix: &str, attr: &AttributeSpec, lineage: Option<&mut GroupLineage>, ) -> Option { @@ -80,16 +81,25 @@ impl AttributeCatalog { note, stability, deprecated, + prefix, } => { + let name; let root_attr = self.root_attributes.get(r#ref); if let Some(root_attr) = root_attr { let mut attr_lineage = AttributeLineage::new(&root_attr.group_id); + if *prefix { + // depending on the prefix we either create embedded attribute or normal reference + name = format!("{}.{}", group_prefix, r#ref.clone()); + } else { + name = r#ref.clone(); + } + // Create a fully resolved attribute from an attribute spec // (ref) and override the root attribute with the new // values if they are present. let resolved_attr = attribute::Attribute { - name: r#ref.clone(), + name: name.clone(), r#type: root_attr.attribute.r#type.clone(), brief: attr_lineage.brief(brief, &root_attr.attribute.brief), examples: attr_lineage.examples(examples, &root_attr.attribute.examples), @@ -109,16 +119,30 @@ impl AttributeCatalog { .deprecated(deprecated, &root_attr.attribute.deprecated), tags: root_attr.attribute.tags.clone(), value: root_attr.attribute.value.clone(), + prefix: *prefix, }; - let attr_ref = self.attribute_ref(resolved_attr); + let attr_ref = self.attribute_ref(resolved_attr.clone()); // Update the lineage based on the inherited fields. // Note: the lineage is only updated if a group lineage is provided. if let Some(lineage) = lineage { - lineage.add_attribute_lineage(r#ref.to_owned(), attr_lineage); + lineage.add_attribute_lineage(name.clone(), attr_lineage); } + if *prefix { + // if it's a prefix with reference + // we need to add it to the dictionary of resolved attributes + _ = self.root_attributes.insert( + name, + AttributeWithGroupId { + attribute: resolved_attr, + group_id: group_id.to_owned(), + }, + ); + } + + Some(attr_ref) } else { None @@ -153,6 +177,7 @@ impl AttributeCatalog { deprecated: deprecated.clone(), tags: None, value: None, + prefix: false, }; _ = self.root_attributes.insert( diff --git a/crates/weaver_resolver/src/registry.rs b/crates/weaver_resolver/src/registry.rs index 3df9bf2f..fa7c6241 100644 --- a/crates/weaver_resolver/src/registry.rs +++ b/crates/weaver_resolver/src/registry.rs @@ -318,6 +318,7 @@ fn resolve_attribute_references( .filter_map(|attr| { let attr_ref = attr_catalog.resolve( &unresolved_group.group.id, + &unresolved_group.group.prefix, &attr.spec, unresolved_group.group.lineage.as_mut(), ); @@ -616,6 +617,7 @@ fn resolve_inheritance_attr( note, stability, deprecated, + prefix, } => { match parent_attr { AttributeSpec::Ref { @@ -627,6 +629,7 @@ fn resolve_inheritance_attr( note: parent_note, stability: parent_stability, deprecated: parent_deprecated, + prefix: parent_prefix, .. } => { // attr and attr_parent are both references. @@ -644,6 +647,7 @@ fn resolve_inheritance_attr( note: lineage.optional_note(note, parent_note), stability: lineage.stability(stability, parent_stability), deprecated: lineage.deprecated(deprecated, parent_deprecated), + prefix: lineage.prefix(prefix, parent_prefix), } } AttributeSpec::Id { diff --git a/crates/weaver_semconv/src/attribute.rs b/crates/weaver_semconv/src/attribute.rs index 0bb2084a..e3b03356 100644 --- a/crates/weaver_semconv/src/attribute.rs +++ b/crates/weaver_semconv/src/attribute.rs @@ -8,6 +8,7 @@ use ordered_float::OrderedFloat; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::fmt::{Display, Formatter}; +use std::ops::Not; use crate::stability::Stability; @@ -67,6 +68,13 @@ pub enum AttributeSpec { /// to use instead. See also stability. #[serde(skip_serializing_if = "Option::is_none")] deprecated: Option, + /// Specifies the prefix of the attribute. + /// If this parameter is set, the resolved id of the referenced attribute will + /// have group prefix added to it. + /// It defaults to false. + #[serde(default)] + #[serde(skip_serializing_if = "<&bool>::not")] + prefix: bool, }, /// Attribute definition. Id {