Skip to content

Commit 2150fbc

Browse files
feat: line_format bypass template execution if possible (#15411)
Co-authored-by: Ed Welch <ed@edjusted.com>
1 parent b8168a8 commit 2150fbc

File tree

2 files changed

+51
-4
lines changed

2 files changed

+51
-4
lines changed

‎pkg/logql/log/fmt.go

+22-1
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ type LineFormatter struct {
194194

195195
currentLine []byte
196196
currentTs int64
197+
simpleKey string
197198
}
198199

199200
// NewFormatter creates a new log line formatter from a given text template.
@@ -213,10 +214,30 @@ func NewFormatter(tmpl string) (*LineFormatter, error) {
213214
return nil, fmt.Errorf("invalid line template: %w", err)
214215
}
215216
lf.Template = t
217+
218+
// determine if the template is a simple key substitution, e.g. line_format `{{.message}}`
219+
// if it is, save the key name and we can use it later to directly copy the string
220+
// bytes of the value to avoid copying and allocating a new string.
221+
if len(t.Root.Nodes) == 1 && t.Root.Nodes[0].Type() == parse.NodeAction {
222+
actionNode := t.Root.Nodes[0].(*parse.ActionNode)
223+
if len(actionNode.Pipe.Cmds) == 1 && len(actionNode.Pipe.Cmds[0].Args) == 1 {
224+
if fieldNode, ok := actionNode.Pipe.Cmds[0].Args[0].(*parse.FieldNode); ok && len(fieldNode.Ident) == 1 {
225+
lf.simpleKey = fieldNode.Ident[0]
226+
}
227+
}
228+
}
229+
216230
return lf, nil
217231
}
218232

219233
func (lf *LineFormatter) Process(ts int64, line []byte, lbs *LabelsBuilder) ([]byte, bool) {
234+
if lf.simpleKey != "" {
235+
if val, ok := lbs.Get(lf.simpleKey); ok {
236+
return unsafeGetBytes(val), true
237+
}
238+
return []byte{}, true
239+
}
240+
220241
lf.buf.Reset()
221242
lf.currentLine = line
222243
lf.currentTs = ts
@@ -387,7 +408,7 @@ func (lf *LabelsFormatter) Process(ts int64, l []byte, lbs *LabelsBuilder) ([]by
387408
lf.currentLine = l
388409
lf.currentTs = ts
389410

390-
var m = smp.Get()
411+
m := smp.Get()
391412
defer smp.Put(m)
392413
for _, f := range lf.formats {
393414
if f.Rename {

‎pkg/logql/log/fmt_test.go

+29-3
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,33 @@ func Test_lineFormatter_Format(t *testing.T) {
479479
labels.FromStrings("foo", "hello"),
480480
[]byte("1"),
481481
},
482+
{
483+
"simple key template",
484+
newMustLineFormatter("{{.foo}}"),
485+
labels.FromStrings("foo", "bar"),
486+
0,
487+
[]byte("bar"),
488+
labels.FromStrings("foo", "bar"),
489+
nil,
490+
},
491+
{
492+
"simple key template with space",
493+
newMustLineFormatter("{{.foo}} "),
494+
labels.FromStrings("foo", "bar"),
495+
0,
496+
[]byte("bar "),
497+
labels.FromStrings("foo", "bar"),
498+
nil,
499+
},
500+
{
501+
"simple key template with missing key",
502+
newMustLineFormatter("{{.missing}}"),
503+
labels.FromStrings("foo", "bar"),
504+
0,
505+
[]byte{},
506+
labels.FromStrings("foo", "bar"),
507+
nil,
508+
},
482509
}
483510
for _, tt := range tests {
484511
t.Run(tt.name, func(t *testing.T) {
@@ -916,7 +943,7 @@ func TestLabelFormatter_RequiredLabelNames(t *testing.T) {
916943
}
917944

918945
func TestDecolorizer(t *testing.T) {
919-
var decolorizer, _ = NewDecolorizer()
946+
decolorizer, _ := NewDecolorizer()
920947
tests := []struct {
921948
name string
922949
src []byte
@@ -927,7 +954,7 @@ func TestDecolorizer(t *testing.T) {
927954
}
928955
for _, tt := range tests {
929956
t.Run(tt.name, func(t *testing.T) {
930-
var result, _ = decolorizer.Process(0, tt.src, nil)
957+
result, _ := decolorizer.Process(0, tt.src, nil)
931958
require.Equal(t, tt.expected, result)
932959
})
933960
}
@@ -979,7 +1006,6 @@ func TestMapPoolPanic(_ *testing.T) {
9791006
}
9801007
smp.Put(m)
9811008
wgFinished.Done()
982-
9831009
}()
9841010
}
9851011
wg.Done()

0 commit comments

Comments
 (0)