Skip to content

Commit 8e9e6c1

Browse files
claudiobastosAlex BotenMovieStoreGuy
authored andcommitted
[cmd/telemetrygen] Add support for metric name/attributes (open-telemetry#26506)
**Description:** Add support to customize metric name and its attributes. **Link to tracking Issue:** open-telemetry#26505 **Testing:** - **Documentation:** self-documented in added flags --------- Signed-off-by: Claudio B <[email protected]> Co-authored-by: Alex Boten <[email protected]> Co-authored-by: Sean Marciniak <[email protected]>
1 parent dac8719 commit 8e9e6c1

File tree

11 files changed

+491
-18
lines changed

11 files changed

+491
-18
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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. filelogreceiver)
7+
component: cmd/telemetrygen
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Add support for custom telemetry attributes
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [26505]
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+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: [user]

cmd/telemetrygen/internal/common/config.go

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,13 @@ type Config struct {
5151
SkipSettingGRPCLogger bool
5252

5353
// OTLP config
54-
Endpoint string
55-
Insecure bool
56-
UseHTTP bool
57-
HTTPPath string
58-
Headers KeyValue
59-
ResourceAttributes KeyValue
54+
Endpoint string
55+
Insecure bool
56+
UseHTTP bool
57+
HTTPPath string
58+
Headers KeyValue
59+
ResourceAttributes KeyValue
60+
TelemetryAttributes KeyValue
6061
}
6162

6263
func (c *Config) GetAttributes() []attribute.KeyValue {
@@ -70,6 +71,17 @@ func (c *Config) GetAttributes() []attribute.KeyValue {
7071
return attributes
7172
}
7273

74+
func (c *Config) GetTelemetryAttributes() []attribute.KeyValue {
75+
var attributes []attribute.KeyValue
76+
77+
if len(c.TelemetryAttributes) > 0 {
78+
for k, v := range c.TelemetryAttributes {
79+
attributes = append(attributes, attribute.String(k, v))
80+
}
81+
}
82+
return attributes
83+
}
84+
7385
// CommonFlags registers common config flags.
7486
func (c *Config) CommonFlags(fs *pflag.FlagSet) {
7587
fs.IntVar(&c.WorkerCount, "workers", 1, "Number of workers (goroutines) to run")
@@ -93,4 +105,8 @@ func (c *Config) CommonFlags(fs *pflag.FlagSet) {
93105
fs.Var(&c.ResourceAttributes, "otlp-attributes", "Custom resource attributes to use. The value is expected in the format key=\"value\"."+
94106
"Note you may need to escape the quotes when using the tool from a cli."+
95107
"Flag may be repeated to set multiple attributes (e.g -otlp-attributes key1=\"value1\" -otlp-attributes key2=\"value2\")")
108+
109+
c.TelemetryAttributes = make(map[string]string)
110+
fs.Var(&c.TelemetryAttributes, "telemetry-attributes", "Custom telemetry attributes to use. The value is expected in the format \"key=\\\"value\\\"\". "+
111+
"Flag may be repeated to set multiple attributes (e.g --telemetry-attributes \"key1=\\\"value1\\\"\" --telemetry-attributes \"key2=\\\"value2\\\"\")")
96112
}

cmd/telemetrygen/internal/logs/logs.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func Run(c *Config, exp exporter, logger *zap.Logger) error {
105105
index: i,
106106
}
107107

108-
go w.simulateLogs(res, exp)
108+
go w.simulateLogs(res, exp, c.GetTelemetryAttributes())
109109
}
110110
if c.TotalDuration > 0 {
111111
time.Sleep(c.TotalDuration)

cmd/telemetrygen/internal/logs/worker.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
"go.opentelemetry.io/collector/pdata/pcommon"
1313
"go.opentelemetry.io/collector/pdata/plog"
14+
"go.opentelemetry.io/otel/attribute"
1415
"go.opentelemetry.io/otel/sdk/resource"
1516
"go.uber.org/zap"
1617
"golang.org/x/time/rate"
@@ -27,7 +28,7 @@ type worker struct {
2728
index int // worker index
2829
}
2930

30-
func (w worker) simulateLogs(res *resource.Resource, exporter exporter) {
31+
func (w worker) simulateLogs(res *resource.Resource, exporter exporter, telemetryAttributes []attribute.KeyValue) {
3132
limiter := rate.NewLimiter(w.limitPerSecond, 1)
3233
var i int64
3334

@@ -44,9 +45,14 @@ func (w worker) simulateLogs(res *resource.Resource, exporter exporter) {
4445
log.SetDroppedAttributesCount(1)
4546
log.SetSeverityNumber(plog.SeverityNumberInfo)
4647
log.SetSeverityText("Info")
48+
log.Attributes()
4749
lattrs := log.Attributes()
4850
lattrs.PutStr("app", "server")
4951

52+
for i, key := range telemetryAttributes {
53+
lattrs.PutStr(key.Value.AsString(), telemetryAttributes[i].Value.AsString())
54+
}
55+
5056
if err := exporter.export(logs); err != nil {
5157
w.logger.Fatal("exporter failed", zap.Error(err))
5258
}

cmd/telemetrygen/internal/logs/worker_test.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ import (
1515
"github.com/open-telemetry/opentelemetry-collector-contrib/cmd/telemetrygen/internal/common"
1616
)
1717

18+
const (
19+
telemetryAttrKeyOne = "k1"
20+
telemetryAttrKeyTwo = "k2"
21+
telemetryAttrValueOne = "v1"
22+
telemetryAttrValueTwo = "v2"
23+
)
24+
1825
type mockExporter struct {
1926
logs []plog.Logs
2027
}
@@ -96,3 +103,105 @@ func TestCustomBody(t *testing.T) {
96103

97104
assert.Equal(t, "custom body", exp.logs[0].ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).Body().AsString())
98105
}
106+
107+
func TestLogsWithNoTelemetryAttributes(t *testing.T) {
108+
cfg := configWithNoAttributes(2, "custom body")
109+
110+
exp := &mockExporter{}
111+
112+
// test
113+
logger, _ := zap.NewDevelopment()
114+
require.NoError(t, Run(cfg, exp, logger))
115+
116+
time.Sleep(1 * time.Second)
117+
118+
// verify
119+
require.Len(t, exp.logs, 2)
120+
for _, log := range exp.logs {
121+
rlogs := log.ResourceLogs()
122+
for i := 0; i < rlogs.Len(); i++ {
123+
attrs := rlogs.At(i).ScopeLogs().At(0).LogRecords().At(0).Attributes()
124+
assert.Equal(t, 1, attrs.Len(), "shouldn't have more than 1 attribute")
125+
}
126+
}
127+
}
128+
129+
func TestLogsWithOneTelemetryAttributes(t *testing.T) {
130+
qty := 1
131+
cfg := configWithOneAttribute(qty, "custom body")
132+
133+
exp := &mockExporter{}
134+
135+
// test
136+
logger, _ := zap.NewDevelopment()
137+
require.NoError(t, Run(cfg, exp, logger))
138+
139+
time.Sleep(1 * time.Second)
140+
141+
// verify
142+
require.Len(t, exp.logs, qty)
143+
for _, log := range exp.logs {
144+
rlogs := log.ResourceLogs()
145+
for i := 0; i < rlogs.Len(); i++ {
146+
attrs := rlogs.At(i).ScopeLogs().At(0).LogRecords().At(0).Attributes()
147+
assert.Equal(t, 2, attrs.Len(), "shouldn't have less than 2 attributes")
148+
}
149+
}
150+
}
151+
152+
func TestLogsWithMultipleTelemetryAttributes(t *testing.T) {
153+
qty := 1
154+
cfg := configWithMultipleAttributes(qty, "custom body")
155+
156+
exp := &mockExporter{}
157+
158+
// test
159+
logger, _ := zap.NewDevelopment()
160+
require.NoError(t, Run(cfg, exp, logger))
161+
162+
time.Sleep(1 * time.Second)
163+
164+
// verify
165+
require.Len(t, exp.logs, qty)
166+
for _, log := range exp.logs {
167+
rlogs := log.ResourceLogs()
168+
for i := 0; i < rlogs.Len(); i++ {
169+
attrs := rlogs.At(i).ScopeLogs().At(0).LogRecords().At(0).Attributes()
170+
assert.Equal(t, 3, attrs.Len(), "shouldn't have less than 3 attributes")
171+
}
172+
}
173+
}
174+
175+
func configWithNoAttributes(qty int, body string) *Config {
176+
return &Config{
177+
Body: body,
178+
NumLogs: qty,
179+
Config: common.Config{
180+
WorkerCount: 1,
181+
TelemetryAttributes: nil,
182+
},
183+
}
184+
}
185+
186+
func configWithOneAttribute(qty int, body string) *Config {
187+
return &Config{
188+
Body: body,
189+
NumLogs: qty,
190+
Config: common.Config{
191+
WorkerCount: 1,
192+
TelemetryAttributes: common.KeyValue{telemetryAttrKeyOne: telemetryAttrValueOne},
193+
},
194+
}
195+
}
196+
197+
func configWithMultipleAttributes(qty int, body string) *Config {
198+
kvs := common.KeyValue{telemetryAttrKeyOne: telemetryAttrValueOne, telemetryAttrKeyTwo: telemetryAttrValueTwo}
199+
return &Config{
200+
Body: body,
201+
NumLogs: qty,
202+
Config: common.Config{
203+
WorkerCount: 1,
204+
TelemetryAttributes: kvs,
205+
},
206+
}
207+
}

cmd/telemetrygen/internal/metrics/metrics.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ func Run(c *Config, exp sdkmetric.Exporter, logger *zap.Logger) error {
114114
index: i,
115115
}
116116

117-
go w.simulateMetrics(res, exp)
117+
go w.simulateMetrics(res, exp, c.GetTelemetryAttributes())
118118
}
119119
if c.TotalDuration > 0 {
120120
time.Sleep(c.TotalDuration)

cmd/telemetrygen/internal/metrics/worker.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"sync/atomic"
1010
"time"
1111

12+
"go.opentelemetry.io/otel/attribute"
1213
sdkmetric "go.opentelemetry.io/otel/sdk/metric"
1314
"go.opentelemetry.io/otel/sdk/metric/metricdata"
1415
"go.opentelemetry.io/otel/sdk/resource"
@@ -27,7 +28,7 @@ type worker struct {
2728
index int // worker index
2829
}
2930

30-
func (w worker) simulateMetrics(res *resource.Resource, exporter sdkmetric.Exporter) {
31+
func (w worker) simulateMetrics(res *resource.Resource, exporter sdkmetric.Exporter, signalAttrs []attribute.KeyValue) {
3132
limiter := rate.NewLimiter(w.limitPerSecond, 1)
3233

3334
var i int64
@@ -41,8 +42,9 @@ func (w worker) simulateMetrics(res *resource.Resource, exporter sdkmetric.Expor
4142
Data: metricdata.Gauge[int64]{
4243
DataPoints: []metricdata.DataPoint[int64]{
4344
{
44-
Time: time.Now(),
45-
Value: i,
45+
Time: time.Now(),
46+
Value: i,
47+
Attributes: attribute.NewSet(signalAttrs...),
4648
},
4749
},
4850
},
@@ -55,9 +57,10 @@ func (w worker) simulateMetrics(res *resource.Resource, exporter sdkmetric.Expor
5557
Temporality: metricdata.CumulativeTemporality,
5658
DataPoints: []metricdata.DataPoint[int64]{
5759
{
58-
StartTime: time.Now().Add(-1 * time.Second),
59-
Time: time.Now(),
60-
Value: i,
60+
StartTime: time.Now().Add(-1 * time.Second),
61+
Time: time.Now(),
62+
Value: i,
63+
Attributes: attribute.NewSet(signalAttrs...),
6164
},
6265
},
6366
},

0 commit comments

Comments
 (0)