Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .chloggen/mdatagen_add_semconv_ref.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver)
component: cmd/mdatagen

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Add semconv reference for metrics

# One or more tracking issues or pull requests related to the change
issues: [13920]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:

# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: [user]
22 changes: 21 additions & 1 deletion cmd/mdatagen/internal/loader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func TestLoadMetadata(t *testing.T) {
GithubProject: "open-telemetry/opentelemetry-collector",
GeneratedPackageName: "metadata",
Type: "sample",
SemConvVersion: "1.9.0",
SemConvVersion: "1.37.0",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure what this field is, but it seems like we should either drop this or make sure that sem_conv_version and the version linked in semconv_ref are aligned somehow

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is sth that already exists and links the whole component to a specific version of SemConv. It's not really used apart from a few places inside the templates that mdatagen populates i.e. logs.go.tmpl and metrics.go.tmpl.

The PR comes with a pattern checking that also verifies if the provided reference's version matches with this generic one: https://github.com/open-telemetry/opentelemetry-collector/pull/13920/files#diff-b33d4fa1a4595583d310c0a381ce3849aefb42419451584fd0e1c43bd16f5263R124-R128. (also covered by this test)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, sorry, another thing I missed. I think that makes sense, though maybe we can remove it entirely if it's not widely used?

I am worried that we won't be able to support transition scenarios where we want to target two semconv versions

PackageName: "go.opentelemetry.io/collector/cmd/mdatagen/internal/samplereceiver",
Status: &Status{
DisableCodeCov: true,
Expand Down Expand Up @@ -261,6 +261,21 @@ func TestLoadMetadata(t *testing.T) {
Mono: Mono{Monotonic: true},
},
},
"system.cpu.time": {
Signal: Signal{
Enabled: true,
Stability: Stability{Level: component.StabilityLevelBeta},
SemanticConvention: &SemanticConvention{SemanticConventionRef: "https://github.com/open-telemetry/semantic-conventions/blob/v1.37.0/docs/system/system-metrics.md#metric-systemcputime"},
Description: "Monotonic cumulative sum int metric enabled by default.",
ExtendedDocumentation: "The metric will be become optional soon.",
},
Unit: strPtr("s"),
Sum: &Sum{
MetricValueType: MetricValueType{pmetric.NumberDataPointValueTypeInt},
AggregationTemporality: AggregationTemporality{Aggregation: pmetric.AggregationTemporalityCumulative},
Mono: Mono{Monotonic: true},
},
},
"optional.metric": {
Signal: Signal{
Enabled: false,
Expand Down Expand Up @@ -524,6 +539,11 @@ func TestLoadMetadata(t *testing.T) {
want: Metadata{},
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\"",
},
{
name: "testdata/invalid_metric_semconvref.yaml",
want: Metadata{},
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\"",
},
{
name: "testdata/no_metric_stability.yaml",
want: Metadata{},
Expand Down
15 changes: 11 additions & 4 deletions cmd/mdatagen/internal/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ func (md *Metadata) validateMetricsAndEvents() error {
var errs error
usedAttrs := map[AttributeName]bool{}
errs = errors.Join(errs,
validateMetrics(md.Metrics, md.Attributes, usedAttrs),
validateMetrics(md.Telemetry.Metrics, md.Attributes, usedAttrs),
validateMetrics(md.Metrics, md.Attributes, usedAttrs, md.SemConvVersion),
validateMetrics(md.Telemetry.Metrics, md.Attributes, usedAttrs, md.SemConvVersion),
validateEvents(md.Events, md.Attributes, usedAttrs),
md.validateAttributes(usedAttrs))
return errs
Expand Down Expand Up @@ -171,10 +171,10 @@ func (md *Metadata) supportsSignal(signal string) bool {
return false
}

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

type SemanticConvention struct {
SemanticConventionRef string `mapstructure:"semconv_ref"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the semconv_ prefix here is redundant since this is already in the semantic_convention section.

}

type Warnings struct {
// A warning that will be displayed if the field is enabled in user config.
IfEnabled string `mapstructure:"if_enabled"`
Expand Down Expand Up @@ -423,6 +427,9 @@ type Signal struct {
// Description of the signal.
Description string `mapstructure:"description"`

// The semantic convention reference of the signal.
SemanticConvention *SemanticConvention `mapstructure:"semantic_convention"`

// The stability level of the signal.
Stability Stability `mapstructure:"stability"`

Expand Down
46 changes: 45 additions & 1 deletion cmd/mdatagen/internal/metric.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ package internal // import "go.opentelemetry.io/collector/cmd/mdatagen/internal"
import (
"errors"
"fmt"
"regexp"
"strings"

"golang.org/x/text/cases"
"golang.org/x/text/language"
Expand All @@ -15,6 +17,8 @@ import (
"go.opentelemetry.io/collector/pdata/pmetric"
)

var reNonAlnum = regexp.MustCompile(`[^a-z0-9]+`)

type MetricName string

func (mn MetricName) Render() (string, error) {
Expand Down Expand Up @@ -69,7 +73,7 @@ func (s *Stability) Unmarshal(parser *confmap.Conf) error {
return parser.Unmarshal(s)
}

func (m *Metric) validate() error {
func (m *Metric) validate(metricName MetricName, semConvVersion string) error {
var errs error
if m.Sum == nil && m.Gauge == nil && m.Histogram == nil {
errs = errors.Join(errs, errors.New("missing metric type key, "+
Expand All @@ -91,9 +95,49 @@ func (m *Metric) validate() error {
if m.Gauge != nil {
errs = errors.Join(errs, m.Gauge.Validate())
}
if m.SemanticConvention != nil {
if err := validateSemConvMetricURL(m.SemanticConvention.SemanticConventionRef, semConvVersion, string(metricName)); err != nil {
errs = errors.Join(errs, err)
}
}
return errs
}

func metricAnchor(metricName string) string {
m := strings.ToLower(strings.TrimSpace(metricName))
m = reNonAlnum.ReplaceAllString(m, "")
return "metric-" + m
}

// validateSemConvMetricURL verifies the URL matches exactly:
// https://github.com/open-telemetry/semantic-conventions/blob/<semConvVersion>/*#metric-<metricName>
func validateSemConvMetricURL(rawURL, semConvVersion, metricName string) error {
if strings.TrimSpace(rawURL) == "" {
return errors.New("url is empty")
}
if strings.TrimSpace(semConvVersion) == "" {
return errors.New("semConvVersion is empty")
}
if strings.TrimSpace(metricName) == "" {
return errors.New("metricName is empty")
}
semConvVersion = "v" + semConvVersion

anchor := metricAnchor(metricName)
// Build a strict regex that enforces https, repo, blob, given version, any doc path, and exact anchor.
pattern := fmt.Sprintf(`^https://github\.com/open-telemetry/semantic-conventions/blob/%s/[^#\s]+#%s$`,
semConvVersion,
anchor,
)
re := regexp.MustCompile(pattern)
if !re.MatchString(rawURL) {
return fmt.Errorf(
"invalid semantic-conventions URL: want https://github.com/open-telemetry/semantic-conventions/blob/%s/*#%s, got %q",
semConvVersion, anchor, rawURL)
}
return nil
}

func (m *Metric) Unmarshal(parser *confmap.Conf) error {
if !parser.IsSet("enabled") {
return errors.New("missing required field: `enabled`")
Expand Down
10 changes: 10 additions & 0 deletions cmd/mdatagen/internal/samplereceiver/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,16 @@ Monotonic cumulative sum int metric with string input_type enabled by default.
| slice_attr | Attribute with a slice value. | Any Slice | Recommended |
| map_attr | Attribute with a map value. | Any Map | Recommended |

### system.cpu.time

Monotonic cumulative sum int metric enabled by default.

The metric will be become optional soon.

| Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | Semantic Convention |
| ---- | ----------- | ---------- | ----------------------- | --------- | --------- | ------------------- |
| 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) |

## Optional Metrics

The following metrics are not emitted by default. Each of them can be enabled by applying the following configuration:
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading