Skip to content

Commit 5687ddb

Browse files
Implement "split" metric action
1 parent 886822b commit 5687ddb

File tree

9 files changed

+268
-125
lines changed

9 files changed

+268
-125
lines changed

.idea/watcherTasks.xml

-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

schema/ast/metrics.go

+17-17
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,30 @@ type VersionOfMetrics struct {
88
}
99

1010
type MetricTranslationAction struct {
11-
RenameMetrics map[types.MetricName]types.MetricName `yaml:"rename_metrics"`
12-
RenameLabels *LabelMapForMetrics `yaml:"rename_labels"`
13-
AddLabels *LabelMapForMetrics `yaml:"add_labels"`
14-
DuplicateLabels *LabelMapForMetrics `yaml:"duplicate_labels"`
15-
Split *SplitMetric `yaml:"split"`
16-
Merge *MergeMetric `yaml:"merge"`
17-
ToDelta []types.MetricName `yaml:"to_delta"`
11+
RenameMetrics map[types.MetricName]types.MetricName `yaml:"rename_metrics"`
12+
RenameLabels *AttributeMapForMetrics `yaml:"rename_attributes"`
13+
AddAttributes *AttributeMapForMetrics `yaml:"add_attributes"`
14+
DuplicateAttributes *AttributeMapForMetrics `yaml:"duplicate_attributes"`
15+
Split *SplitMetric `yaml:"split"`
16+
Merge *MergeMetric `yaml:"merge"`
17+
ToDelta []types.MetricName `yaml:"to_delta"`
1818
}
1919

20-
type LabelMapForMetrics struct {
20+
type AttributeMapForMetrics struct {
2121
ApplyToMetrics []types.MetricName `yaml:"apply_to_metrics"`
22-
LabelMap map[string]string `yaml:"label_map"`
22+
AttributeMap map[string]string `yaml:"label_map"`
2323
}
2424

2525
type SplitMetric struct {
26-
ApplyToMetric types.MetricName `yaml:"apply_to_metric"`
27-
ByLabel string `yaml:"by_label"`
28-
LabelsToMetrics map[types.LabelValue]types.MetricName `yaml:"labels_to_metrics"`
26+
ApplyToMetric types.MetricName `yaml:"apply_to_metric"`
27+
ByAttribute types.AttributeName `yaml:"by_attribute"`
28+
AttributesToMetrics map[types.MetricName]types.AttributeValue `yaml:"metrics_from_attributes"`
2929
}
3030

3131
type MergeMetric struct {
32-
CreateMetric types.MetricName `yaml:"create_metric"`
33-
ByLabel string `yaml:"by_label"`
34-
LabelsForMetrics map[types.LabelValue]types.MetricName `yaml:"labels_for_metrics"`
32+
CreateMetric types.MetricName `yaml:"create_metric"`
33+
ByAttribute string `yaml:"by_attribute"`
34+
AttributesForMetrics map[types.MetricName]types.AttributeValue `yaml:"attributes_for_metrics"`
3535
}
3636

3737
type MetricSchema struct {
@@ -40,10 +40,10 @@ type MetricSchema struct {
4040
ValueType string `yaml:"value_type"`
4141
Temporality string
4242
Monotonic bool
43-
Labels map[string]LabelSchema
43+
Attributes map[string]AttributesSchema
4444
}
4545

46-
type LabelSchema struct {
46+
type AttributesSchema struct {
4747
Values []string
4848
Description string
4949
Required string

schema/compiled/compiled_schema.go

+39-35
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
otlpmetric "github.com/open-telemetry/opentelemetry-proto/gen/go/metrics/v1"
77
otlpresource "github.com/open-telemetry/opentelemetry-proto/gen/go/resource/v1"
88
otlptrace "github.com/open-telemetry/opentelemetry-proto/gen/go/trace/v1"
9-
109
"github.com/tigrannajaryan/telemetry-schema/schema/types"
1110
)
1211

@@ -39,24 +38,18 @@ func (acts ResourceActions) Apply(resource *otlpresource.Resource) error {
3938
}
4039

4140
type MetricActions struct {
42-
ByName map[types.MetricName][]MetricAction
43-
OtherMetrics []MetricAction
41+
Actions []MetricAction
4442
}
4543

46-
func (acts MetricActions) Apply(metric *otlpmetric.Metric) error {
47-
metricName := metric.MetricDescriptor.Name
48-
actions, exists := acts.ByName[types.MetricName(metricName)]
49-
if !exists {
50-
actions = acts.OtherMetrics
51-
}
52-
53-
for _, a := range actions {
54-
err := a.Apply(metric)
44+
func (acts MetricActions) Apply(metrics []*otlpmetric.Metric) ([]*otlpmetric.Metric, error) {
45+
for _, a := range acts.Actions {
46+
var err error
47+
metrics, err = a.Apply(metrics)
5548
if err != nil {
56-
return err
49+
return metrics, err
5750
}
5851
}
59-
return nil
52+
return metrics, nil
6053
}
6154

6255
type ResourceAction interface {
@@ -82,7 +75,7 @@ func (acts SpanActions) Apply(span *otlptrace.Span) error {
8275
}
8376

8477
type MetricAction interface {
85-
Apply(metric *otlpmetric.Metric) error
78+
Apply(metrics []*otlpmetric.Metric) ([]*otlpmetric.Metric, error)
8679
}
8780

8881
//type LogRecordAction interface {
@@ -101,11 +94,15 @@ func (afv ActionsForVersions) Swap(i, j int) {
10194
afv[i], afv[j] = afv[j], afv[i]
10295
}
10396

104-
func (s *Schema) ConvertResourceToLatest(fromVersion types.TelemetryVersion, resource *otlpresource.Resource) error {
105-
startIndex := sort.Search(len(s.Versions), func(i int) bool {
106-
// TODO: use proper semver comparison.
107-
return s.Versions[i].VersionNum > fromVersion
108-
})
97+
func (s *Schema) ConvertResourceToLatest(
98+
fromVersion types.TelemetryVersion, resource *otlpresource.Resource,
99+
) error {
100+
startIndex := sort.Search(
101+
len(s.Versions), func(i int) bool {
102+
// TODO: use proper semver comparison.
103+
return s.Versions[i].VersionNum > fromVersion
104+
},
105+
)
109106
if startIndex > len(s.Versions) {
110107
// Nothing to do
111108
return nil
@@ -120,11 +117,15 @@ func (s *Schema) ConvertResourceToLatest(fromVersion types.TelemetryVersion, res
120117
return nil
121118
}
122119

123-
func (s *Schema) ConvertSpansToLatest(fromVersion types.TelemetryVersion, spans []*otlptrace.Span) error {
124-
startIndex := sort.Search(len(s.Versions), func(i int) bool {
125-
// TODO: use proper semver comparison.
126-
return s.Versions[i].VersionNum > fromVersion
127-
})
120+
func (s *Schema) ConvertSpansToLatest(
121+
fromVersion types.TelemetryVersion, spans []*otlptrace.Span,
122+
) error {
123+
startIndex := sort.Search(
124+
len(s.Versions), func(i int) bool {
125+
// TODO: use proper semver comparison.
126+
return s.Versions[i].VersionNum > fromVersion
127+
},
128+
)
128129
if startIndex > len(s.Versions) {
129130
// Nothing to do
130131
return nil
@@ -142,22 +143,25 @@ func (s *Schema) ConvertSpansToLatest(fromVersion types.TelemetryVersion, spans
142143
return nil
143144
}
144145

145-
func (s *Schema) ConvertMetricsToLatest(fromVersion types.TelemetryVersion, metrics []*otlpmetric.Metric) error {
146-
startIndex := sort.Search(len(s.Versions), func(i int) bool {
147-
// TODO: use proper semver comparison.
148-
return s.Versions[i].VersionNum > fromVersion
149-
})
146+
func (s *Schema) ConvertMetricsToLatest(
147+
fromVersion types.TelemetryVersion, metrics *[]*otlpmetric.Metric,
148+
) error {
149+
startIndex := sort.Search(
150+
len(s.Versions), func(i int) bool {
151+
// TODO: use proper semver comparison.
152+
return s.Versions[i].VersionNum > fromVersion
153+
},
154+
)
150155
if startIndex > len(s.Versions) {
151156
// Nothing to do
152157
return nil
153158
}
154159

155160
for i := startIndex; i < len(s.Versions); i++ {
156-
for j := 0; j < len(metrics); j++ {
157-
metric := metrics[j]
158-
if err := s.Versions[i].Metrics.Apply(metric); err != nil {
159-
return err
160-
}
161+
var err error
162+
*metrics, err = s.Versions[i].Metrics.Apply(*metrics)
163+
if err != nil {
164+
return err
161165
}
162166
}
163167

schema/compiled/metric_actions.go

+89-21
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,19 @@ import (
55

66
otlpcommon "github.com/open-telemetry/opentelemetry-proto/gen/go/common/v1"
77
otlpmetric "github.com/open-telemetry/opentelemetry-proto/gen/go/metrics/v1"
8-
98
"github.com/tigrannajaryan/telemetry-schema/schema/types"
109
)
1110

1211
type MetricRenameAction map[types.MetricName]types.MetricName
1312

14-
func (act MetricRenameAction) Apply(metric *otlpmetric.Metric) error {
15-
newName, exists := act[types.MetricName(metric.MetricDescriptor.Name)]
16-
if exists {
17-
metric.MetricDescriptor.Name = string(newName)
13+
func (act MetricRenameAction) Apply(metrics []*otlpmetric.Metric) ([]*otlpmetric.Metric, error) {
14+
for _, metric := range metrics {
15+
newName, exists := act[types.MetricName(metric.MetricDescriptor.Name)]
16+
if exists {
17+
metric.MetricDescriptor.Name = string(newName)
18+
}
1819
}
19-
return nil
20+
return metrics, nil
2021
}
2122

2223
type MetricLabelRenameAction struct {
@@ -26,27 +27,34 @@ type MetricLabelRenameAction struct {
2627
LabelMap map[string]string
2728
}
2829

29-
func (act MetricLabelRenameAction) Apply(metric *otlpmetric.Metric) error {
30-
if len(act.ApplyOnlyToMetrics) > 0 {
31-
if _, exists := act.ApplyOnlyToMetrics[types.MetricName(metric.MetricDescriptor.Name)]; !exists {
32-
return nil
30+
func (act MetricLabelRenameAction) Apply(metrics []*otlpmetric.Metric) (
31+
[]*otlpmetric.Metric, error,
32+
) {
33+
var retErr error
34+
for _, metric := range metrics {
35+
36+
if len(act.ApplyOnlyToMetrics) > 0 {
37+
if _, exists := act.ApplyOnlyToMetrics[types.MetricName(metric.MetricDescriptor.Name)]; !exists {
38+
continue
39+
}
3340
}
34-
}
3541

36-
dt := metric.MetricDescriptor.Type
37-
switch dt {
38-
case otlpmetric.MetricDescriptor_INT64:
39-
dps := metric.Int64DataPoints
40-
for i := 0; i < len(dps); i++ {
41-
dp := dps[i]
42-
err := renameLabels(dp.Labels, act.LabelMap)
43-
if err != nil {
44-
return err
42+
dt := metric.MetricDescriptor.Type
43+
switch dt {
44+
case otlpmetric.MetricDescriptor_INT64:
45+
dps := metric.Int64DataPoints
46+
for i := 0; i < len(dps); i++ {
47+
dp := dps[i]
48+
err := renameLabels(dp.Labels, act.LabelMap)
49+
if err != nil {
50+
retErr = err
51+
}
4552
}
4653
}
54+
4755
}
4856

49-
return nil
57+
return metrics, retErr
5058
}
5159

5260
func renameLabels(labels []*otlpcommon.StringKeyValue, renameRules map[string]string) error {
@@ -74,3 +82,63 @@ func renameLabels(labels []*otlpcommon.StringKeyValue, renameRules map[string]st
7482
}
7583
return err
7684
}
85+
86+
type MetricSplitAction struct {
87+
// ApplyOnlyToMetrics limits which metrics this action should apply to. If empty then
88+
// there is no limitation.
89+
MetricName types.MetricName
90+
AttributeName types.AttributeName
91+
SplitMap map[types.AttributeValue]types.MetricName
92+
}
93+
94+
func (act MetricSplitAction) Apply(metrics []*otlpmetric.Metric) ([]*otlpmetric.Metric, error) {
95+
for i := 0; i < len(metrics); i++ {
96+
metric := metrics[i]
97+
if act.MetricName != types.MetricName(metric.MetricDescriptor.Name) {
98+
continue
99+
}
100+
101+
var outputMetrics []*otlpmetric.Metric
102+
dt := metric.MetricDescriptor.Type
103+
switch dt {
104+
case otlpmetric.MetricDescriptor_INT64:
105+
dps := metric.Int64DataPoints
106+
for j := 0; j < len(dps); j++ {
107+
dp := dps[j]
108+
outputMetric := splitMetric(act.AttributeName, act.SplitMap, metric, dp)
109+
outputMetrics = append(outputMetrics, outputMetric)
110+
}
111+
}
112+
113+
metrics = append(append(metrics[0:i], outputMetrics...), metrics[i+1:]...)
114+
}
115+
116+
return metrics, nil
117+
}
118+
119+
func splitMetric(
120+
splitByAttr types.AttributeName,
121+
splitRules map[types.AttributeValue]types.MetricName,
122+
input *otlpmetric.Metric,
123+
inputDp *otlpmetric.Int64DataPoint,
124+
) *otlpmetric.Metric {
125+
output := &otlpmetric.Metric{}
126+
descr := *input.MetricDescriptor
127+
output.MetricDescriptor = &descr
128+
129+
outputDp := *inputDp
130+
outputDp.Labels = nil
131+
132+
for _, label := range inputDp.Labels {
133+
if label.Key == string(splitByAttr) {
134+
if convertTo, exists := splitRules[types.AttributeValue(label.Value)]; exists {
135+
newMetricName := string(convertTo)
136+
output.MetricDescriptor.Name = newMetricName
137+
}
138+
continue
139+
}
140+
outputDp.Labels = append(outputDp.Labels, label)
141+
}
142+
output.Int64DataPoints = []*otlpmetric.Int64DataPoint{&outputDp}
143+
return output
144+
}

0 commit comments

Comments
 (0)