Skip to content

Commit 9dc5682

Browse files
authored
[mdatagen] Add event type definition (#12822)
<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue. Ex. Adding a feature - Explain what this achieves.--> #### Description This PR added type definition needed for supporting structured events in mdatagen. Note: the NewLogsBuilder function signature is generated dynamically according to logs config: ``` func NewLogsBuilder({{ if .Events }}lbc LogsBuilderConfig, {{ end }}settings {{ .Status.Class }}.Settings) *LogsBuilder {} ``` <!-- Issue number if applicable --> #### Link to tracking issue Part of #12571 <!--Describe what testing was performed and which tests were added.--> #### Testing Added <!--Describe the documentation added.--> #### Documentation Added <!--Please delete paragraphs that you did not use before submitting.-->
1 parent e94ced8 commit 9dc5682

25 files changed

+528
-13
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 type definition for events in mdatagen
11+
12+
# One or more tracking issues or pull requests related to the change
13+
issues: [12571]
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: [api]

cmd/mdatagen/internal/command.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ func run(ymlPath string) error {
162162
toGenerate[filepath.Join(tmplDir, "documentation.md.tmpl")] = filepath.Join(ymlDir, "documentation.md")
163163
}
164164

165-
if len(md.Metrics) > 0 || len(md.ResourceAttributes) > 0 {
165+
if len(md.Metrics) > 0 || len(md.Events) > 0 || len(md.ResourceAttributes) > 0 {
166166
testdataDir := filepath.Join(codeDir, "testdata")
167167
if err = os.MkdirAll(filepath.Join(codeDir, "testdata"), 0o700); err != nil {
168168
return fmt.Errorf("unable to create output directory %q: %w", testdataDir, err)

cmd/mdatagen/internal/event.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package internal // import "go.opentelemetry.io/collector/cmd/mdatagen/internal"
5+
6+
import (
7+
"errors"
8+
9+
"go.opentelemetry.io/collector/confmap"
10+
)
11+
12+
type (
13+
EventName string
14+
)
15+
16+
func (ln EventName) Render() (string, error) {
17+
return FormatIdentifier(string(ln), true)
18+
}
19+
20+
func (ln EventName) RenderUnexported() (string, error) {
21+
return FormatIdentifier(string(ln), false)
22+
}
23+
24+
type Event struct {
25+
// Enabled defines whether the event is enabled by default.
26+
Enabled bool `mapstructure:"enabled"`
27+
28+
// Warnings that will be shown to user under specified conditions.
29+
Warnings Warnings `mapstructure:"warnings"`
30+
31+
// Description of the event.
32+
Description string `mapstructure:"description"`
33+
34+
// The stability level of the event.
35+
Stability Stability `mapstructure:"stability"`
36+
37+
// Extended documentation of the event. If specified, this will be appended to the description used in generated documentation.
38+
ExtendedDocumentation string `mapstructure:"extended_documentation"`
39+
40+
// Attributes is the list of attributes that the event emits.
41+
Attributes []AttributeName `mapstructure:"attributes"`
42+
}
43+
44+
func (l *Event) validate() error {
45+
var errs error
46+
if l.Description == "" {
47+
errs = errors.Join(errs, errors.New(`missing event description`))
48+
}
49+
return errs
50+
}
51+
52+
func (l *Event) Unmarshal(parser *confmap.Conf) error {
53+
if !parser.IsSet("enabled") {
54+
return errors.New("missing required field: `enabled`")
55+
}
56+
return parser.Unmarshal(l)
57+
}

cmd/mdatagen/internal/event_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package internal
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/require"
11+
)
12+
13+
func TestEventNameRender(t *testing.T) {
14+
for _, tt := range []struct {
15+
name EventName
16+
success bool
17+
expectedExported string
18+
expectedUnExported string
19+
}{
20+
{"", false, "", ""},
21+
{"otel.val", true, "OtelVal", "otelVal"},
22+
{"otel_val_2", true, "OtelVal2", "otelVal2"},
23+
} {
24+
exported, err := tt.name.Render()
25+
if tt.success {
26+
require.NoError(t, err)
27+
assert.Equal(t, tt.expectedExported, exported)
28+
} else {
29+
require.Error(t, err)
30+
}
31+
32+
unexported, err := tt.name.RenderUnexported()
33+
if tt.success {
34+
require.NoError(t, err)
35+
assert.Equal(t, tt.expectedUnExported, unexported)
36+
} else {
37+
require.Error(t, err)
38+
}
39+
}
40+
}

cmd/mdatagen/internal/loader_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,17 @@ func TestLoadMetadata(t *testing.T) {
247247
Attributes: []AttributeName{"string_attr", "overridden_int_attr", "enum_attr", "slice_attr", "map_attr"},
248248
},
249249
},
250+
Events: map[EventName]Event{
251+
"default.event": {
252+
Enabled: true,
253+
Description: "Example event enabled by default.",
254+
ExtendedDocumentation: "The event will be renamed soon.",
255+
Warnings: Warnings{
256+
IfEnabledNotSet: "This event will be disabled by default soon.",
257+
},
258+
Attributes: []AttributeName{"string_attr", "boolean_attr"},
259+
},
260+
},
250261
Telemetry: Telemetry{
251262
Metrics: map[MetricName]Metric{
252263
"batch_size_trigger_send": {
@@ -352,6 +363,11 @@ func TestLoadMetadata(t *testing.T) {
352363
want: Metadata{},
353364
wantErr: "decoding failed due to the following error(s):\n\nerror decoding 'metrics[system.cpu.time]': missing required field: `enabled`",
354365
},
366+
{
367+
name: "testdata/events/no_enabled.yaml",
368+
want: Metadata{},
369+
wantErr: "decoding failed due to the following error(s):\n\nerror decoding 'events[system.event]': missing required field: `enabled`",
370+
},
355371
{
356372
name: "testdata/no_value_type.yaml",
357373
want: Metadata{},

cmd/mdatagen/internal/metadata.go

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ type Metadata struct {
3333
Attributes map[AttributeName]Attribute `mapstructure:"attributes"`
3434
// Metrics that can be emitted by the component.
3535
Metrics map[MetricName]Metric `mapstructure:"metrics"`
36+
// Events that can be emitted by the component.
37+
Events map[EventName]Event `mapstructure:"events"`
3638
// GithubProject is the project where the component README lives in the format of org/repo, defaults to open-telemetry/opentelemetry-collector-contrib
3739
GithubProject string `mapstructure:"github_project"`
3840
// ScopeName of the metrics emitted by the component.
@@ -62,9 +64,10 @@ func (md *Metadata) Validate() error {
6264
errs = errors.Join(errs, err)
6365
}
6466

65-
if err := md.validateMetrics(); err != nil {
67+
if err := md.validateMetricsAndEvents(); err != nil {
6668
errs = errors.Join(errs, err)
6769
}
70+
6871
return errs
6972
}
7073

@@ -105,11 +108,13 @@ func (md *Metadata) validateResourceAttributes() error {
105108
return errs
106109
}
107110

108-
func (md *Metadata) validateMetrics() error {
111+
func (md *Metadata) validateMetricsAndEvents() error {
109112
var errs error
110113
usedAttrs := map[AttributeName]bool{}
111-
errs = errors.Join(errs, validateMetrics(md.Metrics, md.Attributes, usedAttrs),
114+
errs = errors.Join(errs,
115+
validateMetrics(md.Metrics, md.Attributes, usedAttrs),
112116
validateMetrics(md.Telemetry.Metrics, md.Attributes, usedAttrs),
117+
validateEvents(md.Events, md.Attributes, usedAttrs),
113118
md.validateAttributes(usedAttrs))
114119
return errs
115120
}
@@ -173,6 +178,28 @@ func validateMetrics(metrics map[MetricName]Metric, attributes map[AttributeName
173178
return errs
174179
}
175180

181+
func validateEvents(events map[EventName]Event, attributes map[AttributeName]Attribute, usedAttrs map[AttributeName]bool) error {
182+
var errs error
183+
for en, e := range events {
184+
if err := e.validate(); err != nil {
185+
errs = errors.Join(errs, fmt.Errorf(`event "%v": %w`, en, err))
186+
continue
187+
}
188+
unknownAttrs := make([]AttributeName, 0, len(e.Attributes))
189+
for _, attr := range e.Attributes {
190+
if _, ok := attributes[attr]; ok {
191+
usedAttrs[attr] = true
192+
} else {
193+
unknownAttrs = append(unknownAttrs, attr)
194+
}
195+
}
196+
if len(unknownAttrs) > 0 {
197+
errs = errors.Join(errs, fmt.Errorf(`event "%v" refers to undefined attributes: %v`, en, unknownAttrs))
198+
}
199+
}
200+
return errs
201+
}
202+
176203
type AttributeName string
177204

178205
func (mn AttributeName) Render() (string, error) {

cmd/mdatagen/internal/metadata_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ func TestValidate(t *testing.T) {
7777
name: "testdata/no_metric_description.yaml",
7878
wantErr: "metric \"default.metric\": missing metric description",
7979
},
80+
{
81+
name: "testdata/events/no_description.yaml",
82+
wantErr: "event \"default.event\": missing event description",
83+
},
8084
{
8185
name: "testdata/no_metric_unit.yaml",
8286
wantErr: "metric \"default.metric\": missing metric unit",
@@ -99,6 +103,10 @@ func TestValidate(t *testing.T) {
99103
name: "testdata/unknown_metric_attribute.yaml",
100104
wantErr: "metric \"system.cpu.time\" refers to undefined attributes: [missing]",
101105
},
106+
{
107+
name: "testdata/events/unknown_attribute.yaml",
108+
wantErr: "event \"system.event\" refers to undefined attributes: [missing]",
109+
},
102110
{
103111
name: "testdata/unused_attribute.yaml",
104112
wantErr: "unused attributes: [unused_attr]",

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

Lines changed: 2 additions & 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_config.go

Lines changed: 31 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: 12 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)