Skip to content

Commit 4a9f6bf

Browse files
committed
Add spans to resolved registry.
1 parent a3bb434 commit 4a9f6bf

File tree

3 files changed

+162
-2
lines changed

3 files changed

+162
-2
lines changed

crates/weaver_forge/src/v2/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
pub mod attribute;
44
pub mod metric;
55
pub mod registry;
6+
pub mod span;

crates/weaver_forge/src/v2/registry.rs

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::{
88
error::Error,
99
v2::{
1010
attribute::Attribute,
11-
metric::{Metric, MetricAttribute, MetricRefinement},
11+
metric::{Metric, MetricAttribute, MetricRefinement}, span::{Span, SpanAttribute, SpanRefinement},
1212
},
1313
};
1414

@@ -35,6 +35,8 @@ pub struct ResolvedRegistry {
3535
pub struct Signals {
3636
/// The metric signals defined.
3737
pub metrics: Vec<Metric>,
38+
/// The span signals defined.
39+
pub spans: Vec<Span>,
3840
}
3941

4042
/// The set of all refinements for a semantic convention registry.
@@ -47,6 +49,8 @@ pub struct Signals {
4749
pub struct Refinements {
4850
/// The metric refinements defined.
4951
pub metrics: Vec<MetricRefinement>,
52+
/// The span refinements defined.
53+
pub spans: Vec<SpanRefinement>,
5054
}
5155

5256
impl ResolvedRegistry {
@@ -127,15 +131,89 @@ impl ResolvedRegistry {
127131
});
128132
}
129133

134+
let mut spans = Vec::new();
135+
for span in schema.registry.spans {
136+
let attributes = span
137+
.attributes
138+
.iter()
139+
.filter_map(|ar| {
140+
let attr = schema.catalog.attribute(&ar.base).map(|a| SpanAttribute {
141+
base: Attribute {
142+
key: a.key.clone(),
143+
r#type: a.r#type.clone(),
144+
examples: a.examples.clone(),
145+
common: a.common.clone(),
146+
},
147+
requirement_level: ar.requirement_level.clone(),
148+
sampling_relevant: ar.sampling_relevant.clone(),
149+
});
150+
if attr.is_none() {
151+
errors.push(Error::AttributeNotFound {
152+
group_id: format!("span.{}", &span.r#type),
153+
attr_ref: AttributeRef(ar.base.0),
154+
});
155+
}
156+
attr
157+
})
158+
.collect();
159+
spans.push(Span {
160+
r#type: span.r#type,
161+
kind: span.kind,
162+
name: span.name,
163+
attributes,
164+
entity_associations: span.entity_associations,
165+
common: span.common,
166+
});
167+
}
168+
let mut span_refinements = Vec::new();
169+
for span in schema.registry.span_refinements {
170+
let attributes = span
171+
.span
172+
.attributes
173+
.iter()
174+
.filter_map(|ar| {
175+
let attr = schema.catalog.attribute(&ar.base).map(|a| SpanAttribute {
176+
base: Attribute {
177+
key: a.key.clone(),
178+
r#type: a.r#type.clone(),
179+
examples: a.examples.clone(),
180+
common: a.common.clone(),
181+
},
182+
requirement_level: ar.requirement_level.clone(),
183+
sampling_relevant: ar.sampling_relevant.clone(),
184+
});
185+
if attr.is_none() {
186+
errors.push(Error::AttributeNotFound {
187+
group_id: format!("span.{}", &span.id),
188+
attr_ref: AttributeRef(ar.base.0),
189+
});
190+
}
191+
attr
192+
})
193+
.collect();
194+
span_refinements.push(
195+
SpanRefinement {
196+
id: span.id,
197+
span: Span {
198+
r#type: span.span.r#type,
199+
kind: span.span.kind,
200+
name: span.span.name,
201+
attributes,
202+
entity_associations: span.span.entity_associations,
203+
common: span.span.common,
204+
}
205+
});
206+
}
130207
if !errors.is_empty() {
131208
return Err(Error::CompoundError(errors));
132209
}
133210

134211
Ok(Self {
135212
registry_url: schema.schema_url.clone(),
136-
signals: Signals { metrics },
213+
signals: Signals { metrics, spans },
137214
refinements: Refinements {
138215
metrics: metric_refinements,
216+
spans: span_refinements,
139217
},
140218
})
141219
}

crates/weaver_forge/src/v2/span.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//! Span related definitions structs.
2+
3+
use crate::v2::attribute::Attribute;
4+
use schemars::JsonSchema;
5+
use serde::{Deserialize, Serialize};
6+
use weaver_semconv::{
7+
attribute::RequirementLevel,
8+
group::SpanKindSpec,
9+
v2::{signal_id::SignalId, span::SpanName, CommonFields},
10+
};
11+
12+
/// The definition of a span signal.
13+
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema)]
14+
#[serde(deny_unknown_fields)]
15+
pub struct Span {
16+
/// The type of the Span. This denotes the identity
17+
/// of the "shape" of this span, and must be unique.
18+
pub r#type: SignalId,
19+
/// Specifies the kind of the span.
20+
pub kind: SpanKindSpec,
21+
/// The name pattern for the span.
22+
pub name: SpanName,
23+
/// List of attributes that should be included on this span.
24+
#[serde(default)]
25+
#[serde(skip_serializing_if = "Vec::is_empty")]
26+
pub attributes: Vec<SpanAttribute>,
27+
/// Which resources this span should be associated with.
28+
///
29+
/// This list is an "any of" list, where a span may be associated with one or more entities, but should
30+
/// be associated with at least one in this list.
31+
#[serde(default)]
32+
#[serde(skip_serializing_if = "Vec::is_empty")]
33+
pub entity_associations: Vec<String>,
34+
35+
/// Common fields (like brief, note, annotations).
36+
#[serde(flatten)]
37+
pub common: CommonFields,
38+
}
39+
40+
/// A special type of reference to attributes that remembers span-specicific information.
41+
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema)]
42+
#[serde(deny_unknown_fields)]
43+
pub struct SpanAttribute {
44+
/// Base attribute definitions.
45+
#[serde(flatten)]
46+
pub base: Attribute,
47+
/// Specifies if the attribute is mandatory. Can be "required",
48+
/// "conditionally_required", "recommended" or "opt_in". When omitted,
49+
/// the attribute is "recommended". When set to
50+
/// "conditionally_required", the string provided as <condition> MUST
51+
/// specify the conditions under which the attribute is required.
52+
///
53+
/// Note: For attributes that are "recommended" or "opt-in" - not all metric source will
54+
/// create timeseries with these attributes, but for any given timeseries instance, the attributes that *were* present
55+
/// should *remain* present. That is - a metric timeseries cannot drop attributes during its lifetime.
56+
pub requirement_level: RequirementLevel,
57+
58+
/// Specifies if the attribute is (especially) relevant for sampling
59+
/// and thus should be set at span start. It defaults to false.
60+
#[serde(skip_serializing_if = "Option::is_none")]
61+
pub sampling_relevant: Option<bool>,
62+
}
63+
64+
/// A refinement of a span signal, for use in code-gen or specific library application.
65+
///
66+
/// A refinement represents a "view" of a Span that is highly optimised for a particular implementation.
67+
/// e.g. for HTTP spans, there may be a refinement that provides only the necessary information for dealing with Java's HTTP
68+
/// client library, and drops optional or extraneous information from the underlying http span.
69+
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema)]
70+
pub struct SpanRefinement {
71+
/// The identity of the refinement.
72+
pub id: SignalId,
73+
74+
// TODO - This is a lazy way of doing this. We use `type` to refer
75+
// to the underlying span defintiion, but override all fields here.
76+
// We probably should copy-paste all the "span" attributes here
77+
// including the `ty`
78+
/// The definition of the metric refinement.
79+
#[serde(flatten)]
80+
pub span: Span,
81+
}

0 commit comments

Comments
 (0)