Skip to content

Commit 8f4c949

Browse files
committed
fixup
Signed-off-by: Florian Lehner <florian.lehner@elastic.co>
1 parent ee029a3 commit 8f4c949

File tree

2 files changed

+67
-47
lines changed

2 files changed

+67
-47
lines changed

connector/profilingmetricsconnector/frame.go

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package profilingmetricsconnector // import "github.com/elastic/opentelemetry-co
1919

2020
import (
2121
"fmt"
22+
"log/slog"
2223
"regexp"
2324

2425
"go.opentelemetry.io/collector/pdata/pcommon"
@@ -44,19 +45,20 @@ const (
4445
)
4546

4647
var (
47-
metricUser = metric{name: "samples.user.count", desc: "Number of samples executing userspace code (self)"}
48-
metricKernel = metric{name: "samples.kernel.count", desc: "Number of samples executing kernel code (self)"}
49-
metricNative = metric{name: "samples.native.count", desc: "Number of samples executing native code (self)"}
50-
metricJVM = metric{name: "samples.jvm.count", desc: "Number of samples executing HotSpot code (self)"}
51-
metricPython = metric{name: "samples.cpython.count", desc: "Number of samples executing Python code (self)"}
52-
metricGo = metric{name: "samples.go.count", desc: "Number of samples executing Go code (self)"}
53-
metricV8JS = metric{name: "samples.v8js.count", desc: "Number of samples executing V8 JS code (self)"}
54-
metricPHP = metric{name: "samples.php.count", desc: "Number of samples executing PHP code (self)"}
55-
metricPerl = metric{name: "samples.perl.count", desc: "Number of samples executing Perl code (self)"}
56-
metricRuby = metric{name: "samples.ruby.count", desc: "Number of samples executing Ruby code (self)"}
57-
metricDotnet = metric{name: "samples.dotnet.count", desc: "Number of samples executing Dotnet code (self)"}
58-
metricRust = metric{name: "samples.rust.count", desc: "Number of samples executing Rust code (self)"}
59-
metricBeam = metric{name: "samples.beam.count", desc: "Number of samples executing Beam code (self)"}
48+
metricUser = metric{name: "samples.user.count", desc: "Number of samples executing userspace code (self)"}
49+
metricKernel = metric{name: "samples.kernel.count", desc: "Number of samples executing kernel code (self)"}
50+
metricSyscall = metric{name: "samples.syscall.count", desc: "Number of samples executing syscall code (self)"}
51+
metricNative = metric{name: "samples.native.count", desc: "Number of samples executing native code (self)"}
52+
metricJVM = metric{name: "samples.jvm.count", desc: "Number of samples executing HotSpot code (self)"}
53+
metricPython = metric{name: "samples.cpython.count", desc: "Number of samples executing Python code (self)"}
54+
metricGo = metric{name: "samples.go.count", desc: "Number of samples executing Go code (self)"}
55+
metricV8JS = metric{name: "samples.v8js.count", desc: "Number of samples executing V8 JS code (self)"}
56+
metricPHP = metric{name: "samples.php.count", desc: "Number of samples executing PHP code (self)"}
57+
metricPerl = metric{name: "samples.perl.count", desc: "Number of samples executing Perl code (self)"}
58+
metricRuby = metric{name: "samples.ruby.count", desc: "Number of samples executing Ruby code (self)"}
59+
metricDotnet = metric{name: "samples.dotnet.count", desc: "Number of samples executing Dotnet code (self)"}
60+
metricRust = metric{name: "samples.rust.count", desc: "Number of samples executing Rust code (self)"}
61+
metricBeam = metric{name: "samples.beam.count", desc: "Number of samples executing Beam code (self)"}
6062

6163
allowedFrameTypes = map[string]metric{
6264
frameTypeNative: metricNative,
@@ -77,7 +79,7 @@ var (
7779
rx = regexp.MustCompile(`(?:.*/)?(.+)\.so`)
7880

7981
// match syscalls
80-
syscallRx = regexp.MustCompile(`^__(?:x64|arm64)_sys_(\w+)`)
82+
syscallRx = regexp.MustCompile(`^(?:__x64_sys|__arm64_sys|ksys)_(\w+)`)
8183
)
8284

8385
func fetchLeafFrameInfo(dictionary pprofile.ProfilesDictionary,
@@ -155,10 +157,8 @@ func fetchLeafFrameInfo(dictionary pprofile.ProfilesDictionary,
155157
// classifyFrame classifies sample into one or more categories based on frame type.
156158
// This takes place by incrementing the associated metric count.
157159
func classifyFrame(dictionary pprofile.ProfilesDictionary,
158-
locationIndices pcommon.Int32Slice,
159-
sample pprofile.Sample,
160-
counts map[metric]int64,
161-
nativeCounts map[string]int64,
160+
locationIndices pcommon.Int32Slice, sample pprofile.Sample,
161+
counts map[metric]int64, nativeCounts map[string]int64,
162162
) error {
163163
leaf, err := fetchLeafFrameInfo(dictionary, locationIndices, 0)
164164
if err != nil {
@@ -196,11 +196,8 @@ func classifyFrame(dictionary pprofile.ProfilesDictionary,
196196
// identifySyscall walks the frames and extracts the syscall information.
197197
func identifySyscall(dictionary pprofile.ProfilesDictionary,
198198
locationIndices pcommon.Int32Slice,
199-
syscallCounts map[string]int64,
199+
syscallCounts map[string]int64, multiplier int64,
200200
) error {
201-
// TODO: Scale syscallCounts by number of events in each Sample. Currently,
202-
// this logic assumes 1 event per Sample (thus the increments by 1 below),
203-
// which isn't necessarily the case.
204201
attrTable := dictionary.AttributeTable()
205202
locationTable := dictionary.LocationTable()
206203
strTable := dictionary.StringTable()
@@ -213,18 +210,21 @@ func identifySyscall(dictionary pprofile.ProfilesDictionary,
213210

214211
for _, li := range locationIndices.All() {
215212
if li >= int32(locTblLen) {
216-
// log error
213+
slog.Error("identifySyscall", slog.Any("li", li),
214+
slog.Any("locTblLen", locTblLen))
217215
continue
218216
}
219217
loc := locationTable.At(int(li))
220218
for _, attrIdx := range loc.AttributeIndices().All() {
221219
if attrIdx >= int32(attrTblLen) {
222-
// log error
220+
slog.Error("identifySyscall", slog.Any("attrIdx", attrIdx),
221+
slog.Any("attrTblLen", attrTblLen))
223222
continue
224223
}
225224
attr := attrTable.At(int(attrIdx))
226225
if int(attr.KeyStrindex()) >= strTblLen {
227-
// log error
226+
slog.Error("identifySyscall", slog.Any("attr.KeyStrindex()", attr.KeyStrindex()),
227+
slog.Any("strTblLen", strTblLen))
228228
continue
229229
}
230230

@@ -233,12 +233,14 @@ func identifySyscall(dictionary pprofile.ProfilesDictionary,
233233
if frameType == frameTypeKernel {
234234
for _, ln := range loc.Line().All() {
235235
if ln.FunctionIndex() >= int32(funcTblLen) {
236-
// log error
236+
slog.Error("identifySyscall", slog.Any("ln.FunctionIndex()", ln.FunctionIndex()),
237+
slog.Any("funcTblLen", funcTblLen))
237238
continue
238239
}
239240
fn := funcTable.At(int(ln.FunctionIndex()))
240241
if fn.NameStrindex() >= int32(strTblLen) {
241-
// log error
242+
slog.Error("identifySyscall", slog.Any("fn.NameStrindex()", fn.NameStrindex()),
243+
slog.Any("strTblLen", strTblLen))
242244
continue
243245
}
244246
fnName := strTable.At(int(fn.NameStrindex()))
@@ -247,16 +249,14 @@ func identifySyscall(dictionary pprofile.ProfilesDictionary,
247249
indices := syscallRx.FindStringSubmatchIndex(fnName)
248250
if len(indices) == 4 {
249251
syscall := fnName[indices[2]:indices[3]]
250-
syscallCounts[syscall]++
252+
syscallCounts[syscall] += multiplier
251253
return nil
252254
}
253255
}
254256

255257
}
256258
}
257-
258259
}
259-
260260
}
261261
return nil
262262
}
@@ -272,17 +272,18 @@ func (c *profilesToMetricsConnector) addFrameMetrics(dictionary pprofile.Profile
272272

273273
// Process all samples and extract metric counts
274274
for _, sample := range profile.Sample().All() {
275+
multiplier := int64(sample.TimestampsUnixNano().Len())
275276
stack := stackTable.At(int(sample.StackIndex()))
276277
if err := classifyFrame(dictionary, stack.LocationIndices(),
277278
sample, counts, nativeCounts); err != nil {
278279
// Should not happen with well-formed profile data
279-
// TODO: Add error metric or log error
280+
slog.Error("classifyFrame", slog.Any("error", err))
280281
}
281282

282283
if err := identifySyscall(dictionary, stack.LocationIndices(),
283-
syscallCounts); err != nil {
284+
syscallCounts, multiplier); err != nil {
284285
// Should not happen with well-formed profile data
285-
// TODO: Add error metric or log error
286+
slog.Error("identifySyscall", slog.Any("error", err))
286287
}
287288
}
288289

@@ -320,8 +321,8 @@ func (c *profilesToMetricsConnector) addFrameMetrics(dictionary pprofile.Profile
320321

321322
for sysCall, count := range syscallCounts {
322323
m := scopeMetrics.Metrics().AppendEmpty()
323-
m.SetName(c.config.MetricsPrefix + metricNative.name)
324-
m.SetDescription(metricNative.desc)
324+
m.SetName(c.config.MetricsPrefix + metricSyscall.name)
325+
m.SetDescription(metricSyscall.desc)
325326
m.SetUnit("1")
326327

327328
sum := m.SetEmptySum()

connector/profilingmetricsconnector/frame_test.go

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -73,17 +73,21 @@ func (m *metricsConsumerStub) ConsumeMetrics(ctx context.Context, md pmetric.Met
7373
assert.Equal(m.t, pmetric.AggregationTemporalityDelta,
7474
sum.AggregationTemporality())
7575
assert.Equal(m.t, 1, sum.DataPoints().Len())
76-
dp := sum.DataPoints().At(0)
77-
// For native metrics, this is convenient way to test library name extraction
78-
if strings.HasSuffix(name, metricNative.name) {
79-
if shlibName, exists := dp.Attributes().Get(nativeLibraryAttrName); exists {
80-
name = fmt.Sprintf("%v/%v", name, shlibName.AsString())
76+
for _, dp := range sum.DataPoints().All() {
77+
switch {
78+
case strings.HasSuffix(name, metricNative.name):
79+
// For native metrics, this is convenient way to test library name extraction
80+
if shlibName, exists := dp.Attributes().Get(nativeLibraryAttrName); exists {
81+
name = fmt.Sprintf("%v/%v", name, shlibName.AsString())
82+
}
83+
case strings.HasSuffix(name, metricSyscall.name):
84+
// For syscall metrics, this is convenient way to test syscall name extraction
85+
if syscallName, exists := dp.Attributes().Get(syscallAttrName); exists {
86+
name = fmt.Sprintf("%v/%v", name, syscallName.AsString())
87+
}
8188
}
82-
} else {
83-
// Non-native metrics should not have attributes attached
84-
assert.Equal(m.t, 0, dp.Attributes().Len())
89+
m.counts[name] += dp.IntValue()
8590
}
86-
m.counts[name] += dp.IntValue()
8791
}
8892
}
8993
}
@@ -98,6 +102,7 @@ func newProfiles() (pprofile.Profiles,
98102
pprofile.KeyValueAndUnitSlice,
99103
pprofile.LocationSlice,
100104
pprofile.StackSlice,
105+
pprofile.FunctionSlice,
101106
) {
102107
profiles := pprofile.NewProfiles()
103108
dict := profiles.Dictionary()
@@ -107,6 +112,7 @@ func newProfiles() (pprofile.Profiles,
107112
locTable := dict.LocationTable()
108113
mappingTable := dict.MappingTable()
109114
stackTable := dict.StackTable()
115+
funcTable := dict.FunctionTable()
110116

111117
strTable.Append("")
112118
strTable.Append("samples")
@@ -116,8 +122,9 @@ func newProfiles() (pprofile.Profiles,
116122
mappingTable.AppendEmpty()
117123
attrTable.AppendEmpty()
118124
stackTable.AppendEmpty()
125+
funcTable.AppendEmpty()
119126

120-
return profiles, dict, strTable, attrTable, locTable, stackTable
127+
return profiles, dict, strTable, attrTable, locTable, stackTable, funcTable
121128
}
122129

123130
// newProfile initializes and appends a Profile to a Profiles instance.
@@ -146,11 +153,12 @@ func TestConsumeProfiles_FrameMetrics(t *testing.T) {
146153
}
147154

148155
// Create a Profile and higher-level envelopes
149-
profiles, _, strTable, attrTable, locTable, stackTable := newProfiles()
156+
profiles, _, strTable, attrTable, locTable, stackTable, _ := newProfiles()
150157
prof := newProfile(profiles)
151158

152159
// Create a profiles object with a sample that has a location with a frame type attribute.
153160
sample := prof.Sample().AppendEmpty()
161+
sample.TimestampsUnixNano().Append(1, 2, 3, 4)
154162

155163
// Add an attribute for frame type
156164
attr := attrTable.AppendEmpty()
@@ -191,7 +199,7 @@ func TestConsumeProfiles_FrameMetricsMultiple(t *testing.T) {
191199
}
192200

193201
// Create a Profile and higher-level envelopes
194-
profiles, dict, strTable, attrTable, locTable, stackTable := newProfiles()
202+
profiles, dict, strTable, attrTable, locTable, stackTable, funcTable := newProfiles()
195203
prof := newProfile(profiles)
196204

197205
mappingTable := dict.MappingTable()
@@ -218,6 +226,7 @@ func TestConsumeProfiles_FrameMetricsMultiple(t *testing.T) {
218226
locPy.AttributeIndices().Append(2)
219227
locKernel := locTable.AppendEmpty()
220228
locKernel.AttributeIndices().Append(3)
229+
locKernel.Line().AppendEmpty().SetFunctionIndex(1)
221230

222231
locNative := locTable.AppendEmpty()
223232
locNative.AttributeIndices().Append(4)
@@ -249,20 +258,29 @@ func TestConsumeProfiles_FrameMetricsMultiple(t *testing.T) {
249258
// Eight samples
250259
sampleKernel := prof.Sample().AppendEmpty()
251260
sampleKernel.SetStackIndex(3)
261+
sampleKernel.TimestampsUnixNano().Append(1, 2, 3)
252262
sampleNative := prof.Sample().AppendEmpty()
253263
sampleNative.SetStackIndex(4)
254264
sampleNative = prof.Sample().AppendEmpty()
255265
sampleNative.SetStackIndex(5)
266+
sampleNative.TimestampsUnixNano().Append(2)
256267
sampleGo := prof.Sample().AppendEmpty()
257268
sampleGo.SetStackIndex(1)
269+
sampleGo.TimestampsUnixNano().Append(3)
258270
samplePy := prof.Sample().AppendEmpty()
259271
samplePy.SetStackIndex(2)
260272
samplePy = prof.Sample().AppendEmpty()
261273
samplePy.SetStackIndex(2)
262274
samplePy = prof.Sample().AppendEmpty()
263275
samplePy.SetStackIndex(2)
276+
samplePy.TimestampsUnixNano().Append(4)
264277
sampleGo = prof.Sample().AppendEmpty()
265278
sampleGo.SetStackIndex(1)
279+
sampleGo.TimestampsUnixNano().Append(5)
280+
281+
syscallFunc := funcTable.AppendEmpty()
282+
syscallFunc.SetNameStrindex(int32(strTable.Len()))
283+
strTable.Append("__x64_sys_bpf")
266284

267285
err := conn.ConsumeProfiles(context.Background(), profiles)
268286
assert.NoError(t, err)
@@ -274,6 +292,7 @@ func TestConsumeProfiles_FrameMetricsMultiple(t *testing.T) {
274292
"frametest.samples.kernel.count": 1,
275293
"frametest.samples.native.count": 1,
276294
"frametest.samples.native.count/libc": 1,
295+
"frametest.samples.syscall.count/bpf": 3,
277296
},
278297
m.counts)
279298
}

0 commit comments

Comments
 (0)