Skip to content

Commit c156b07

Browse files
committed
[mdatagen] Add semconv ref for metrics
Signed-off-by: ChrsMark <[email protected]>
1 parent 6f29b34 commit c156b07

23 files changed

+375
-16
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver)
7+
component: cmd/mdatagen
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Add semconv reference for metrics
11+
12+
# One or more tracking issues or pull requests related to the change
13+
issues: [13920]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# Optional: The change log or logs in which this entry should be included.
21+
# e.g. '[user]' or '[user, api]'
22+
# Include 'user' if the change is relevant to end users.
23+
# Include 'api' if there is a change to a library API.
24+
# Default: '[user]'
25+
change_logs: [user]

cmd/mdatagen/internal/loader_test.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func TestLoadMetadata(t *testing.T) {
4747
GithubProject: "open-telemetry/opentelemetry-collector",
4848
GeneratedPackageName: "metadata",
4949
Type: "sample",
50-
SemConvVersion: "1.9.0",
50+
SemConvVersion: "1.37.0",
5151
PackageName: "go.opentelemetry.io/collector/cmd/mdatagen/internal/samplereceiver",
5252
Status: &Status{
5353
DisableCodeCov: true,
@@ -261,6 +261,21 @@ func TestLoadMetadata(t *testing.T) {
261261
Mono: Mono{Monotonic: true},
262262
},
263263
},
264+
"system.cpu.time": {
265+
Signal: Signal{
266+
Enabled: true,
267+
Stability: Stability{Level: component.StabilityLevelBeta},
268+
SemanticConvention: &SemanticConvention{SemanticConventionRef: "https://github.com/open-telemetry/semantic-conventions/blob/v1.37.0/docs/system/system-metrics.md#metric-systemcputime"},
269+
Description: "Monotonic cumulative sum int metric enabled by default.",
270+
ExtendedDocumentation: "The metric will be become optional soon.",
271+
},
272+
Unit: strPtr("s"),
273+
Sum: &Sum{
274+
MetricValueType: MetricValueType{pmetric.NumberDataPointValueTypeInt},
275+
AggregationTemporality: AggregationTemporality{Aggregation: pmetric.AggregationTemporalityCumulative},
276+
Mono: Mono{Monotonic: true},
277+
},
278+
},
264279
"optional.metric": {
265280
Signal: Signal{
266281
Enabled: false,
@@ -524,6 +539,11 @@ func TestLoadMetadata(t *testing.T) {
524539
want: Metadata{},
525540
wantErr: "decoding failed due to the following error(s):\n\n'metrics[default.metric]' decoding failed due to the following error(s):\n\n'stability' decoding failed due to the following error(s):\n\n'level' unsupported stability level: \"development42\"",
526541
},
542+
{
543+
name: "testdata/invalid_metric_semconvref.yaml",
544+
want: Metadata{},
545+
wantErr: "metric \"default.metric\": invalid semantic-conventions URL: want https://github.com/open-telemetry/semantic-conventions/blob/v1.37.2/*#metric-defaultmetric, got \"https://github.com/open-telemetry/semantic-conventions/blob/v1.38.0/docs/system/system-metrics.md#metric-systemcputime\"",
546+
},
527547
{
528548
name: "testdata/no_metric_stability.yaml",
529549
want: Metadata{},

cmd/mdatagen/internal/metadata.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ func (md *Metadata) validateMetricsAndEvents() error {
126126
var errs error
127127
usedAttrs := map[AttributeName]bool{}
128128
errs = errors.Join(errs,
129-
validateMetrics(md.Metrics, md.Attributes, usedAttrs),
130-
validateMetrics(md.Telemetry.Metrics, md.Attributes, usedAttrs),
129+
validateMetrics(md.Metrics, md.Attributes, usedAttrs, md.SemConvVersion),
130+
validateMetrics(md.Telemetry.Metrics, md.Attributes, usedAttrs, md.SemConvVersion),
131131
validateEvents(md.Events, md.Attributes, usedAttrs),
132132
md.validateAttributes(usedAttrs))
133133
return errs
@@ -171,10 +171,10 @@ func (md *Metadata) supportsSignal(signal string) bool {
171171
return false
172172
}
173173

174-
func validateMetrics(metrics map[MetricName]Metric, attributes map[AttributeName]Attribute, usedAttrs map[AttributeName]bool) error {
174+
func validateMetrics(metrics map[MetricName]Metric, attributes map[AttributeName]Attribute, usedAttrs map[AttributeName]bool, semConvVersion string) error {
175175
var errs error
176176
for mn, m := range metrics {
177-
if err := m.validate(); err != nil {
177+
if err := m.validate(mn, semConvVersion); err != nil {
178178
errs = errors.Join(errs, fmt.Errorf(`metric "%v": %w`, mn, err))
179179
continue
180180
}
@@ -312,6 +312,10 @@ func (mvt ValueType) Primitive() string {
312312
}
313313
}
314314

315+
type SemanticConvention struct {
316+
SemanticConventionRef string `mapstructure:"semconv_ref"`
317+
}
318+
315319
type Warnings struct {
316320
// A warning that will be displayed if the field is enabled in user config.
317321
IfEnabled string `mapstructure:"if_enabled"`
@@ -423,6 +427,9 @@ type Signal struct {
423427
// Description of the signal.
424428
Description string `mapstructure:"description"`
425429

430+
// The semantic convention reference of the signal.
431+
SemanticConvention *SemanticConvention `mapstructure:"semantic_convention"`
432+
426433
// The stability level of the signal.
427434
Stability Stability `mapstructure:"stability"`
428435

cmd/mdatagen/internal/metric.go

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ package internal // import "go.opentelemetry.io/collector/cmd/mdatagen/internal"
66
import (
77
"errors"
88
"fmt"
9+
"regexp"
10+
"strings"
911

1012
"golang.org/x/text/cases"
1113
"golang.org/x/text/language"
@@ -15,6 +17,8 @@ import (
1517
"go.opentelemetry.io/collector/pdata/pmetric"
1618
)
1719

20+
var reNonAlnum = regexp.MustCompile(`[^a-z0-9]+`)
21+
1822
type MetricName string
1923

2024
func (mn MetricName) Render() (string, error) {
@@ -69,7 +73,7 @@ func (s *Stability) Unmarshal(parser *confmap.Conf) error {
6973
return parser.Unmarshal(s)
7074
}
7175

72-
func (m *Metric) validate() error {
76+
func (m *Metric) validate(metricName MetricName, semConvVersion string) error {
7377
var errs error
7478
if m.Sum == nil && m.Gauge == nil && m.Histogram == nil {
7579
errs = errors.Join(errs, errors.New("missing metric type key, "+
@@ -91,9 +95,49 @@ func (m *Metric) validate() error {
9195
if m.Gauge != nil {
9296
errs = errors.Join(errs, m.Gauge.Validate())
9397
}
98+
if m.SemanticConvention != nil {
99+
if err := validateSemConvMetricURL(m.SemanticConvention.SemanticConventionRef, semConvVersion, string(metricName)); err != nil {
100+
errs = errors.Join(errs, err)
101+
}
102+
}
94103
return errs
95104
}
96105

106+
func metricAnchor(metricName string) string {
107+
m := strings.ToLower(strings.TrimSpace(metricName))
108+
m = reNonAlnum.ReplaceAllString(m, "")
109+
return "metric-" + m
110+
}
111+
112+
// validateSemConvMetricURL verifies the URL matches exactly:
113+
// https://github.com/open-telemetry/semantic-conventions/blob/<semConvVersion>/*#metric-<metricName>
114+
func validateSemConvMetricURL(rawURL, semConvVersion, metricName string) error {
115+
if strings.TrimSpace(rawURL) == "" {
116+
return fmt.Errorf("url is empty")
117+
}
118+
if strings.TrimSpace(semConvVersion) == "" {
119+
return fmt.Errorf("semConvVersion is empty")
120+
}
121+
if strings.TrimSpace(metricName) == "" {
122+
return fmt.Errorf("metricName is empty")
123+
}
124+
semConvVersion = "v" + semConvVersion
125+
126+
anchor := metricAnchor(metricName)
127+
// Build a strict regex that enforces https, repo, blob, given version, any doc path, and exact anchor.
128+
pattern := fmt.Sprintf(`^https://github\.com/open-telemetry/semantic-conventions/blob/%s/[^#\s]+#%s$`,
129+
semConvVersion,
130+
anchor,
131+
)
132+
re := regexp.MustCompile(pattern)
133+
if !re.MatchString(rawURL) {
134+
return fmt.Errorf(
135+
"invalid semantic-conventions URL: want https://github.com/open-telemetry/semantic-conventions/blob/%s/*#%s, got %q",
136+
semConvVersion, anchor, rawURL)
137+
}
138+
return nil
139+
}
140+
97141
func (m *Metric) Unmarshal(parser *confmap.Conf) error {
98142
if !parser.IsSet("enabled") {
99143
return errors.New("missing required field: `enabled`")

cmd/mdatagen/internal/samplereceiver/documentation.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,16 @@ Monotonic cumulative sum int metric with string input_type enabled by default.
6363
| slice_attr | Attribute with a slice value. | Any Slice | Recommended |
6464
| map_attr | Attribute with a map value. | Any Map | Recommended |
6565
66+
### system.cpu.time
67+
68+
Monotonic cumulative sum int metric enabled by default.
69+
70+
The metric will be become optional soon.
71+
72+
| Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | Semantic Convention |
73+
| ---- | ----------- | ---------- | ----------------------- | --------- | --------- | ------------------- |
74+
| s | Sum | Int | Cumulative | true | Beta | [system.cpu.time](https://github.com/open-telemetry/semantic-conventions/blob/v1.37.0/docs/system/system-metrics.md#metric-systemcputime) |
75+
6676
## Optional Metrics
6777
6878
The following metrics are not emitted by default. Each of them can be enabled by applying the following configuration:

cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_config.go

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_config_test.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_logs.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_metrics.go

Lines changed: 64 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)