Skip to content

Commit 7191356

Browse files
authored
feat(v2): recording rules of function names (#4232)
* feat(v2): function totals recording rules * PR fixes * revert oneOf * poc * multiple rules * remove comments, force a dataset switch on tenant switch * remove comments * fix testsg * comments and clean up * callback setup * TODO: tests * make generate * linter: remove always-nil error
1 parent 7021209 commit 7191356

File tree

11 files changed

+1199
-219
lines changed

11 files changed

+1199
-219
lines changed

api/gen/proto/go/settings/v1/recording_rules.pb.go

Lines changed: 354 additions & 137 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/gen/proto/go/settings/v1/recording_rules_vtproto.pb.go

Lines changed: 546 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/openapiv2/gen/phlare.swagger.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1679,6 +1679,13 @@
16791679
}
16801680
}
16811681
},
1682+
"v1MetricType": {
1683+
"type": "string",
1684+
"enum": [
1685+
"TOTAL"
1686+
],
1687+
"default": "TOTAL"
1688+
},
16821689
"v1Point": {
16831690
"type": "object",
16841691
"properties": {
@@ -2044,6 +2051,10 @@
20442051
"type": "string",
20452052
"format": "int64",
20462053
"description": "The observed generation of this recording rule. This value should be\nprovided when making updates to this record, to avoid conflicting\nconcurrent updates."
2054+
},
2055+
"stacktraceFilter": {
2056+
"$ref": "#/definitions/v1StacktraceFilter",
2057+
"description": "The stacktrace filter allows filtering on particular function names in the stacktrace.\nThis allows recording rules to focus on specific functions and calculate their \"total\"\nresource usage."
20472058
}
20482059
}
20492060
},
@@ -2339,6 +2350,25 @@
23392350
},
23402351
"description": "StackTraceSelector is used for filtering stack traces by locations."
23412352
},
2353+
"v1StacktraceFilter": {
2354+
"type": "object",
2355+
"properties": {
2356+
"functionName": {
2357+
"$ref": "#/definitions/v1StacktraceFilterFunctionName"
2358+
}
2359+
}
2360+
},
2361+
"v1StacktraceFilterFunctionName": {
2362+
"type": "object",
2363+
"properties": {
2364+
"functionName": {
2365+
"type": "string"
2366+
},
2367+
"metricType": {
2368+
"$ref": "#/definitions/v1MetricType"
2369+
}
2370+
}
2371+
},
23422372
"v1StacktraceSample": {
23432373
"type": "object",
23442374
"properties": {

api/settings/v1/recording_rules.proto

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ message UpsertRecordingRuleRequest {
3939
// The observed generation of this recording rule. If this value does not
4040
// match the generation stored in the database, this upsert will be rejected.
4141
int64 generation = 6;
42+
43+
optional StacktraceFilter stacktrace_filter = 7;
4244
}
4345

4446
message UpsertRecordingRuleResponse {
@@ -79,6 +81,24 @@ message RecordingRule {
7981
// provided when making updates to this record, to avoid conflicting
8082
// concurrent updates.
8183
int64 generation = 7;
84+
85+
// The stacktrace filter allows filtering on particular function names in the stacktrace.
86+
// This allows recording rules to focus on specific functions and calculate their "total"
87+
// resource usage.
88+
optional StacktraceFilter stacktrace_filter = 8;
89+
}
90+
91+
message StacktraceFilter {
92+
optional StacktraceFilterFunctionName function_name = 1;
93+
}
94+
95+
enum MetricType {
96+
TOTAL = 0;
97+
}
98+
99+
message StacktraceFilterFunctionName {
100+
string function_name = 1;
101+
MetricType metric_type = 2;
82102
}
83103

84104
message RecordingRuleStore {
@@ -89,6 +109,7 @@ message RecordingRuleStore {
89109
repeated string group_by = 5;
90110
repeated types.v1.LabelPair external_labels = 6;
91111
int64 generation = 7;
112+
optional StacktraceFilter stacktrace_filter = 8;
92113
}
93114

94115
message RecordingRulesStore {

pkg/experiment/block/compaction.go

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,12 @@ type compactionConfig struct {
6767
}
6868

6969
type SampleObserver interface {
70-
// Observe is called before the compactor appends the entry
71-
// to the output block. This method must not modify the entry.
72-
Observe(ProfileEntry)
70+
symdb.SymbolsObserver
71+
72+
// Evaluate is called before the compactor rewrites any symbols.
73+
// An "observe" callback function is returned to be called after writing the resulting blocks.
74+
// This method must not modify the entry.
75+
Evaluate(ProfileEntry) (observe func())
7376
}
7477

7578
func Compact(
@@ -382,7 +385,7 @@ func (m *datasetCompaction) open(ctx context.Context, w io.Writer) (err error) {
382385
m.profilesWriter = newProfileWriter(pageBufferSize, w)
383386

384387
m.indexRewriter = newIndexRewriter()
385-
m.symbolsRewriter = newSymbolsRewriter()
388+
m.symbolsRewriter = newSymbolsRewriter(m.observer)
386389

387390
g, ctx := errgroup.WithContext(ctx)
388391
for _, s := range m.datasets {
@@ -431,18 +434,15 @@ func (m *datasetCompaction) merge(ctx context.Context) (err error) {
431434
}
432435

433436
func (m *datasetCompaction) writeRow(r ProfileEntry) (err error) {
434-
if err = m.parent.datasetIndex.writeRow(r); err != nil {
435-
return err
436-
}
437-
if err = m.indexRewriter.rewriteRow(r); err != nil {
438-
return err
437+
if m.observer != nil {
438+
observe := m.observer.Evaluate(r)
439+
defer observe()
439440
}
441+
m.parent.datasetIndex.writeRow(r)
442+
m.indexRewriter.rewriteRow(r)
440443
if err = m.symbolsRewriter.rewriteRow(r); err != nil {
441444
return err
442445
}
443-
if m.observer != nil {
444-
m.observer.Observe(r)
445-
}
446446
return m.profilesWriter.writeRow(r)
447447
}
448448

@@ -488,7 +488,7 @@ type seriesLabels struct {
488488
fingerprint model.Fingerprint
489489
}
490490

491-
func (rw *indexRewriter) rewriteRow(e ProfileEntry) error {
491+
func (rw *indexRewriter) rewriteRow(e ProfileEntry) {
492492
if rw.previousFp != e.Fingerprint || len(rw.series) == 0 {
493493
series := e.Labels.Clone()
494494
for _, l := range series {
@@ -508,7 +508,6 @@ func (rw *indexRewriter) rewriteRow(e ProfileEntry) error {
508508
}
509509
rw.chunks[len(rw.chunks)-1].MaxTime = e.Timestamp
510510
e.Row.SetSeriesIndex(rw.chunks[len(rw.chunks)-1].SeriesIndex)
511-
return nil
512511
}
513512

514513
func (rw *indexRewriter) NumSeries() uint64 { return uint64(len(rw.series)) }
@@ -549,15 +548,16 @@ func (rw *indexRewriter) Flush() error {
549548
}
550549

551550
type symbolsRewriter struct {
552-
buf *bytes.Buffer
553-
w *symdb.SymDB
554-
rw map[*Dataset]*symdb.Rewriter
555-
samples uint64
551+
buf *bytes.Buffer
552+
w *symdb.SymDB
553+
rw map[*Dataset]*symdb.Rewriter
554+
samples uint64
555+
observer SampleObserver
556556

557557
stacktraces []uint32
558558
}
559559

560-
func newSymbolsRewriter() *symbolsRewriter {
560+
func newSymbolsRewriter(observer SampleObserver) *symbolsRewriter {
561561
// TODO(kolesnikovae):
562562
// * Estimate size.
563563
// * Use buffer pool.
@@ -569,6 +569,7 @@ func newSymbolsRewriter() *symbolsRewriter {
569569
Version: symdb.FormatV3,
570570
Writer: &nopWriteCloser{buf},
571571
}),
572+
observer: observer,
572573
}
573574
}
574575

@@ -594,7 +595,7 @@ func (s *symbolsRewriter) rewriteRow(e ProfileEntry) (err error) {
594595
func (s *symbolsRewriter) rewriterFor(x *Dataset) *symdb.Rewriter {
595596
rw, ok := s.rw[x]
596597
if !ok {
597-
rw = symdb.NewRewriter(s.w, x.Symbols())
598+
rw = symdb.NewRewriter(s.w, x.Symbols(), s.observer)
598599
s.rw[x] = rw
599600
}
600601
return rw
@@ -628,7 +629,7 @@ func newDatasetIndexWriter() *datasetIndexWriter {
628629

629630
func (rw *datasetIndexWriter) setIndex(i uint32) { rw.idx = i }
630631

631-
func (rw *datasetIndexWriter) writeRow(e ProfileEntry) error {
632+
func (rw *datasetIndexWriter) writeRow(e ProfileEntry) {
632633
if rw.previous != e.Fingerprint || len(rw.series) == 0 {
633634
series := e.Labels.Clone()
634635
for _, l := range series {
@@ -644,7 +645,6 @@ func (rw *datasetIndexWriter) writeRow(e ProfileEntry) error {
644645
})
645646
rw.previous = e.Fingerprint
646647
}
647-
return nil
648648
}
649649

650650
func (rw *datasetIndexWriter) Flush() error {

0 commit comments

Comments
 (0)