forked from open-telemetry/opentelemetry-collector-contrib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
config.go
181 lines (139 loc) · 5.04 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http:https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package metricsgenerationprocessor // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/metricsgenerationprocessor"
import (
"fmt"
"sort"
"go.opentelemetry.io/collector/config"
)
const (
// nameFieldName is the mapstructure field name for name field
nameFieldName = "name"
// typeFieldName is the mapstructure field name for Type field
typeFieldName = "type"
// metric1FieldName is the mapstructure field name for Metric1 field
metric1FieldName = "metric1"
// metric2FieldName is the mapstructure field name for Metric2 field
metric2FieldName = "metric2"
// scaleByFieldName is the mapstructure field name for ScaleBy field
scaleByFieldName = "scale_by"
// operationFieldName is the mapstructure field name for Operation field
operationFieldName = "operation"
)
// Config defines the configuration for the processor.
type Config struct {
config.ProcessorSettings `mapstructure:",squash"` // squash ensures fields are correctly decoded in embedded struct
// Set of rules for generating new metrics
Rules []Rule `mapstructure:"rules"`
}
type Rule struct {
// Name of the new metric being generated. This is a required field.
Name string `mapstructure:"name"`
// Unit for the new metric being generated.
Unit string `mapstructure:"unit"`
// The rule type following which the new metric will be generated. This is a required field.
Type GenerationType `mapstructure:"type"`
// First operand metric to use in the calculation. This is a required field.
Metric1 string `mapstructure:"metric1"`
// Second operand metric to use in the calculation. A required field if the type is calculate.
Metric2 string `mapstructure:"metric2"`
// The arithmetic operation to apply for the calculation. This is a required field.
Operation OperationType `mapstructure:"operation"`
// A constant number by which the first operand will be scaled. A required field if the type is scale.
ScaleBy float64 `mapstructure:"scale_by"`
}
type GenerationType string
const (
// Generates a new metric applying an arithmatic operation with two operands
calculate GenerationType = "calculate"
// Generates a new metric scaling the value of s given metric with a provided constant
scale GenerationType = "scale"
)
var generationTypes = map[GenerationType]struct{}{calculate: {}, scale: {}}
func (gt GenerationType) isValid() bool {
_, ok := generationTypes[gt]
return ok
}
var generationTypeKeys = func() []string {
ret := make([]string, len(generationTypes))
i := 0
for k := range generationTypes {
ret[i] = string(k)
i++
}
sort.Strings(ret)
return ret
}
type OperationType string
const (
// Adds two operands
add OperationType = "add"
// subtract the second operand from the first operand
subtract OperationType = "subtract"
// multiply two operands
multiply OperationType = "multiply"
// Divides the first operand with the second operand
divide OperationType = "divide"
// Calculates the percentage: (Metric1 / Metric2) * 100
percent OperationType = "percent"
)
var operationTypes = map[OperationType]struct{}{
add: {},
subtract: {},
multiply: {},
divide: {},
percent: {},
}
func (ot OperationType) isValid() bool {
_, ok := operationTypes[ot]
return ok
}
var operationTypeKeys = func() []string {
ret := make([]string, len(operationTypes))
i := 0
for k := range operationTypes {
ret[i] = string(k)
i++
}
sort.Strings(ret)
return ret
}
// Validate checks whether the input configuration has all of the required fields for the processor.
// An error is returned if there are any invalid inputs.
func (config *Config) Validate() error {
for _, rule := range config.Rules {
if rule.Name == "" {
return fmt.Errorf("missing required field %q", nameFieldName)
}
if rule.Type == "" {
return fmt.Errorf("missing required field %q", typeFieldName)
}
if !rule.Type.isValid() {
return fmt.Errorf("%q must be in %q", typeFieldName, generationTypeKeys())
}
if rule.Metric1 == "" {
return fmt.Errorf("missing required field %q", metric1FieldName)
}
if rule.Type == calculate && rule.Metric2 == "" {
return fmt.Errorf("missing required field %q for generation type %q", metric2FieldName, calculate)
}
if rule.Type == scale && rule.ScaleBy <= 0 {
return fmt.Errorf("field %q required to be greater than 0 for generation type %q", scaleByFieldName, scale)
}
if rule.Operation != "" && !rule.Operation.isValid() {
return fmt.Errorf("%q must be in %q", operationFieldName, operationTypeKeys())
}
}
return nil
}