Skip to content

Commit 884d211

Browse files
authored
[exporter/elasticsearch] Profiling: Store sampling frequency (#41017)
#### Description Add support for profiles variable sampling frequencies by storing the frequency with every profiling event. #### Link to tracking issue Fixes #40115
1 parent 16ff298 commit 884d211

File tree

5 files changed

+57
-9
lines changed

5 files changed

+57
-9
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: elasticsearchexporter
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Support profiles variable sampling frequency.
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: [40115]
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]

exporter/elasticsearchexporter/internal/serializer/otelserializer/profile_test.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ func TestSerializeProfile(t *testing.T) {
104104
pt := profile.PeriodType()
105105
pt.SetTypeStrindex(2)
106106
pt.SetUnitStrindex(3)
107+
profile.SetPeriod(1e9 / 20)
107108

108109
profile.AttributeIndices().Append(2)
109110

@@ -119,12 +120,13 @@ func TestSerializeProfile(t *testing.T) {
119120
"ecs.version": "1.12.0",
120121
},
121122
{
122-
"@timestamp": "1970-01-01T00:00:00Z",
123-
"Stacktrace.count": json.Number("1"),
124-
"Stacktrace.id": "02VzuClbpt_P3xxwox83Ng",
125-
"ecs.version": "1.12.0",
126-
"host.id": "localhost",
127-
"process.thread.name": "",
123+
"@timestamp": "1970-01-01T00:00:00Z",
124+
"Stacktrace.count": json.Number("1"),
125+
"Stacktrace.sampling_frequency": json.Number("20"),
126+
"Stacktrace.id": "02VzuClbpt_P3xxwox83Ng",
127+
"ecs.version": "1.12.0",
128+
"host.id": "localhost",
129+
"process.thread.name": "",
128130
},
129131
{
130132
"script": map[string]any{

exporter/elasticsearchexporter/internal/serializer/otelserializer/serializeprofiles/model.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ type StackTraceEvent struct {
4646
ContainerName string `json:"container.name,omitempty"`
4747
K8sNamespaceName string `json:"k8s.namespace.name,omitempty"`
4848
ThreadName string `json:"process.thread.name"`
49+
Frequency int64 `json:"Stacktrace.sampling_frequency"`
4950
Count uint16 `json:"Stacktrace.count"`
5051
}
5152

exporter/elasticsearchexporter/internal/serializer/otelserializer/serializeprofiles/transform.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"bytes"
88
"fmt"
99
"hash/fnv"
10+
"math"
1011
"strconv"
1112
"strings"
1213
"time"
@@ -83,6 +84,12 @@ func stackPayloads(dic pprofile.ProfilesDictionary, resource pcommon.Resource, s
8384

8485
hostMetadata := newHostMetadata(dic, resource, scope, profile)
8586

87+
frequency := int64(math.Round(1e9 / float64(profile.Period())))
88+
if frequency <= 0 {
89+
// The lowest sensical frequency is 1Hz.
90+
frequency = 1
91+
}
92+
8693
for i := 0; i < profile.Sample().Len(); i++ {
8794
sample := profile.Sample().At(i)
8895

@@ -99,7 +106,7 @@ func stackPayloads(dic pprofile.ProfilesDictionary, resource pcommon.Resource, s
99106
return nil, fmt.Errorf("failed to create stacktrace ID: %w", err)
100107
}
101108

102-
event := stackTraceEvent(dic, traceID, sample, hostMetadata)
109+
event := stackTraceEvent(dic, traceID, sample, frequency, hostMetadata)
103110

104111
// Set the stacktrace and stackframes to the payload.
105112
// The docs only need to be written once.
@@ -209,12 +216,13 @@ func isFrameSymbolized(frame StackFrame) bool {
209216
return len(frame.FileName) > 0 || len(frame.FunctionName) > 0
210217
}
211218

212-
func stackTraceEvent(dic pprofile.ProfilesDictionary, traceID string, sample pprofile.Sample, hostMetadata map[string]string) StackTraceEvent {
219+
func stackTraceEvent(dic pprofile.ProfilesDictionary, traceID string, sample pprofile.Sample, frequency int64, hostMetadata map[string]string) StackTraceEvent {
213220
event := StackTraceEvent{
214221
EcsVersion: EcsVersion{V: EcsVersionString},
215222
HostID: hostMetadata[string(semconv.HostIDKey)],
216223
StackTraceID: traceID,
217224
Count: 1, // TODO: Check whether count can be dropped with nanosecond timestamps
225+
Frequency: frequency,
218226
}
219227

220228
// Store event-specific attributes.

exporter/elasticsearchexporter/internal/serializer/otelserializer/serializeprofiles/transform_test.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ func TestTransform(t *testing.T) {
192192

193193
sp := rp.ScopeProfiles().AppendEmpty()
194194
p := sp.Profiles().AppendEmpty()
195+
p.SetPeriod(1e9 / 20)
195196

196197
st := p.SampleType().AppendEmpty()
197198
st.SetTypeStrindex(2)
@@ -260,6 +261,7 @@ func TestTransform(t *testing.T) {
260261
EcsVersion: EcsVersion{V: EcsVersionString},
261262
TimeStamp: 42000000000,
262263
StackTraceID: wantedTraceID,
264+
Frequency: 20,
263265
Count: 1,
264266
},
265267
},
@@ -337,6 +339,7 @@ func TestStackPayloads(t *testing.T) {
337339

338340
sp := rp.ScopeProfiles().AppendEmpty()
339341
p := sp.Profiles().AppendEmpty()
342+
p.SetPeriod(1e9 / 20)
340343

341344
s := p.Sample().AppendEmpty()
342345
s.TimestampsUnixNano().Append(1)
@@ -398,6 +401,7 @@ func TestStackPayloads(t *testing.T) {
398401
EcsVersion: EcsVersion{V: EcsVersionString},
399402
TimeStamp: 1000000000,
400403
StackTraceID: wantedTraceID,
404+
Frequency: 20,
401405
Count: 1,
402406
},
403407
},
@@ -442,6 +446,7 @@ func TestStackPayloads(t *testing.T) {
442446

443447
sp := rp.ScopeProfiles().AppendEmpty()
444448
p := sp.Profiles().AppendEmpty()
449+
p.SetPeriod(1e9 / 20)
445450

446451
s := p.Sample().AppendEmpty()
447452
s.TimestampsUnixNano().Append(1)
@@ -503,6 +508,7 @@ func TestStackPayloads(t *testing.T) {
503508
EcsVersion: EcsVersion{V: EcsVersionString},
504509
TimeStamp: 1000000000,
505510
StackTraceID: wantedTraceID,
511+
Frequency: 20,
506512
Count: 2,
507513
},
508514
},
@@ -558,6 +564,7 @@ func TestStackTraceEvent(t *testing.T) {
558564
wantEvent: StackTraceEvent{
559565
EcsVersion: EcsVersion{V: EcsVersionString},
560566
StackTraceID: stacktraceIDBase64,
567+
Frequency: 20,
561568
Count: 1,
562569
},
563570
},
@@ -584,6 +591,7 @@ func TestStackTraceEvent(t *testing.T) {
584591
EcsVersion: EcsVersion{V: EcsVersionString},
585592
TimeStamp: 1000000000000000000,
586593
StackTraceID: stacktraceIDBase64,
594+
Frequency: 20,
587595
Count: 1,
588596
},
589597
},
@@ -608,6 +616,7 @@ func TestStackTraceEvent(t *testing.T) {
608616
wantEvent: StackTraceEvent{
609617
EcsVersion: EcsVersion{V: EcsVersionString},
610618
StackTraceID: stacktraceIDBase64,
619+
Frequency: 20,
611620
Count: 1,
612621
},
613622
},
@@ -649,6 +658,7 @@ func TestStackTraceEvent(t *testing.T) {
649658
ContainerName: "my_container",
650659
ThreadName: "my_thread",
651660
StackTraceID: stacktraceIDBase64,
661+
Frequency: 20,
652662
Count: 1,
653663
},
654664
},
@@ -659,7 +669,7 @@ func TestStackTraceEvent(t *testing.T) {
659669
p := rp.ScopeProfiles().At(0).Profiles().At(0)
660670
s := p.Sample().At(0)
661671

662-
event := stackTraceEvent(dic, stacktraceIDBase64, s, map[string]string{})
672+
event := stackTraceEvent(dic, stacktraceIDBase64, s, 20, map[string]string{})
663673
event.TimeStamp = newUnixTime64(tt.timestamp)
664674

665675
assert.Equal(t, tt.wantEvent, event)

0 commit comments

Comments
 (0)