forked from open-telemetry/weaver
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcatalog.rs
More file actions
181 lines (166 loc) · 6.68 KB
/
catalog.rs
File metadata and controls
181 lines (166 loc) · 6.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// SPDX-License-Identifier: Apache-2.0
//! Defines the catalog of attributes, metrics, and other telemetry items
//! that are shared across multiple signals in the Resolved Telemetry Schema.
use crate::attribute::{Attribute, AttributeRef};
use serde::Serialize;
use std::collections::{BTreeMap, HashMap};
use std::fmt::Debug;
use weaver_semconv::attribute::{AttributeType, BasicRequirementLevelSpec, RequirementLevel};
use weaver_semconv::stability::Stability;
/// A catalog of indexed attributes shared across semconv groups, or signals.
/// Attribute references are used to refer to attributes in the catalog.
///
/// Note : In the future, this catalog could be extended with other entities.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
#[must_use]
pub struct Catalog {
/// Catalog of attribute definitions and refinements used in the schema.
/// Contains elements with the same attribute key.
/// Use root_attributes for original attribute definitions.
attributes: Vec<Attribute>,
/// Attribute definitions available in this registry (including those
/// from dependencies). Used for cross-registry attribute lookup.
/// Not serialized — populated only for freshly resolved schemas.
root_attributes: HashMap<String, (Attribute, String)>,
}
/// Statistics on a catalog.
#[derive(Debug, Serialize)]
#[must_use]
pub struct Stats {
/// Total number of attributes.
pub attribute_count: usize,
/// Breakdown of attribute types.
pub attribute_type_breakdown: BTreeMap<String, usize>,
/// Breakdown of requirement levels.
pub requirement_level_breakdown: BTreeMap<String, usize>,
/// Breakdown of stability levels.
pub stability_breakdown: HashMap<Stability, usize>,
/// Number of deprecated attributes.
pub deprecated_count: usize,
}
impl Catalog {
/// Creates a catalog from a list of attributes and root attribute definitions.
pub fn new(
attributes: Vec<Attribute>,
root_attributes: HashMap<String, (Attribute, String)>,
) -> Self {
Self {
attributes,
root_attributes,
}
}
/// Looks up an attribute by name in the root attribute definitions.
#[must_use]
pub fn root_attribute(&self, name: &str) -> Option<(&Attribute, &str)> {
self.root_attributes
.get(name)
.map(|(attr, group_id)| (attr, group_id.as_str()))
}
/// Counts the number of attributes in the catalog.
#[must_use]
pub fn count_attributes(&self) -> usize {
self.attributes.len()
}
/// Return an iterator over the attributes in the catalog.
pub fn attributes(&self) -> impl Iterator<Item = &Attribute> {
self.attributes.iter()
}
/// Returns the attribute from an attribute ref if it exists.
#[must_use]
pub fn attribute(&self, attribute_ref: &AttributeRef) -> Option<&Attribute> {
self.attributes.get(attribute_ref.0 as usize)
}
/// Statistics on the catalog.
pub fn stats(&self) -> Stats {
Stats {
attribute_count: self.attributes.len(),
attribute_type_breakdown: self
.attributes
.iter()
.map(|attr| {
if let AttributeType::Enum { members, .. } = &attr.r#type {
(format!("enum(card:{:03})", members.len()), 1)
} else {
(format!("{:#}", attr.r#type), 1)
}
})
.fold(BTreeMap::new(), |mut acc, (k, v)| {
*acc.entry(k).or_insert(0) += v;
acc
}),
requirement_level_breakdown: self
.attributes
.iter()
.map(|attr| {
let requirement_level = match &attr.requirement_level {
RequirementLevel::Basic(BasicRequirementLevelSpec::Required) => "required",
RequirementLevel::Basic(BasicRequirementLevelSpec::Recommended) => {
"recommended"
}
RequirementLevel::Basic(BasicRequirementLevelSpec::OptIn) => "opt_in",
RequirementLevel::Recommended { .. } => "recommended",
RequirementLevel::ConditionallyRequired { .. } => "conditionally_required",
RequirementLevel::OptIn { .. } => "opt_in",
};
(requirement_level.to_owned(), 1)
})
.fold(BTreeMap::new(), |mut acc, (k, v)| {
*acc.entry(k).or_insert(0) += v;
acc
}),
stability_breakdown: self
.attributes
.iter()
.filter_map(|attr| attr.stability.as_ref())
.map(|stability| (stability.clone(), 1))
.fold(HashMap::new(), |mut acc, (k, v)| {
*acc.entry(k).or_insert(0) += v;
acc
}),
deprecated_count: self
.attributes
.iter()
.filter(|attr| attr.deprecated.is_some())
.count(),
}
}
}
#[cfg(test)]
/// Test utilities for building [`Catalog`] instances.
pub mod test_utils {
use super::*;
/// A builder for constructing a [`Catalog`] in tests.
#[derive(Default)]
pub struct CatalogBuilder {
attributes: Vec<Attribute>,
root_attributes: HashMap<String, (Attribute, String)>,
}
impl CatalogBuilder {
/// Creates a builder pre-populated with all attributes from an existing catalog.
/// Root attributes are not copied — use [`CatalogBuilder::add`] with a `group_id` for that.
#[must_use]
pub fn from_catalog(catalog: &Catalog) -> Self {
let mut builder = Self::default();
for attr in catalog.attributes() {
let _ = builder.add(attr.clone(), None);
}
builder
}
/// Adds an attribute to the catalog. If `group_id` is `Some`, the attribute
/// is also registered as a root definition for cross-registry lookup.
pub fn add(&mut self, attr: Attribute, group_id: Option<&str>) -> AttributeRef {
if let Some(gid) = group_id {
let _ = self
.root_attributes
.insert(attr.name.clone(), (attr.clone(), gid.to_owned()));
}
let idx = self.attributes.len();
self.attributes.push(attr);
AttributeRef(idx as u32)
}
/// Builds the [`Catalog`].
pub fn build(self) -> Catalog {
Catalog::new(self.attributes, self.root_attributes)
}
}
}