Skip to content

Commit

Permalink
Add benchmarks for loki.secretfilter component (#1887)
Browse files Browse the repository at this point in the history
* Add benchmarks

* More benchmarks

* Don't fail tests if the temp file can't be deleted

* Don't fail tests if the temp file can't be deleted
  • Loading branch information
romain-gaillard authored Oct 15, 2024
1 parent af04c73 commit fc7f41b
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 2 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/iam v1.33.1 // indirect
github.com/checkpoint-restore/go-criu/v6 v6.3.0 // indirect
github.com/containerd/platforms v0.2.1 // indirect
github.com/jaswdr/faker/v2 v2.3.2
)

// NOTE: replace directives below must always be *temporary*.
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1539,6 +1539,8 @@ github.com/jaegertracing/jaeger v1.60.0/go.mod h1:CMrmMLIWn7xLP0IwBgpbxtgIuOT6TF
github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4=
github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww=
github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
github.com/jaswdr/faker/v2 v2.3.2 h1:7MI1X2GVAQmhbSis3B2ddAkLE9zbx9hZnc0LRlPNyJY=
github.com/jaswdr/faker/v2 v2.3.2/go.mod h1:ROK8xwQV0hYOLDUtxCQgHGcl10jbVzIvqHxcIDdwY2Q=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
Expand Down
2 changes: 1 addition & 1 deletion internal/component/loki/secretfilter/secretfilter.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ func (c *Component) Update(args component.Arguments) error {
// Compile regexes
for _, rule := range gitleaksCfg.Rules {
// If specific secret types are provided, only include rules that match the types
if c.args.Types != nil && len(c.args.Types) > 0 {
if len(c.args.Types) > 0 {
var found bool
for _, t := range c.args.Types {
if strings.HasPrefix(strings.ToLower(rule.ID), strings.ToLower(t)) {
Expand Down
100 changes: 99 additions & 1 deletion internal/component/loki/secretfilter/secretfilter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@ package secretfilter

import (
"fmt"
"math/rand"
"os"
"strings"
"testing"
"time"

"github.com/grafana/alloy/internal/component"
"github.com/grafana/alloy/internal/component/common/loki"
"github.com/grafana/alloy/internal/runtime/componenttest"
"github.com/grafana/alloy/internal/service/livedebugging"
"github.com/grafana/alloy/internal/util"
"github.com/grafana/alloy/syntax"
"github.com/grafana/loki/v3/pkg/logproto"
"github.com/jaswdr/faker/v2"
"github.com/prometheus/common/model"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -66,6 +70,11 @@ var testConfigs = map[string]string{
redact_with = "<` + customRedactionString + `:$SECRET_NAME>"
types = ["aws", "gcp"]
`,
"custom_type": `
forward_to = []
redact_with = "<` + customRedactionString + `:$SECRET_NAME>"
types = ["gcp"]
`,
"allow_list": `
forward_to = []
allowlist = [".*foobar.*"]
Expand Down Expand Up @@ -334,5 +343,94 @@ func createTempGitleaksConfig(t *testing.T, content string) string {
}

func deleteTempGitLeaksConfig(t *testing.T, path string) {
require.NoError(t, os.Remove(path))
if err := os.Remove(path); err != nil {
t.Logf("Error deleting temporary gitleaks config file: %v", err)
}
}

func BenchmarkAllTypesNoSecret(b *testing.B) {
// Run benchmarks with no secrets in the logs, with all regexes enabled
runBenchmarks(b, testConfigs["default"], 0, "")
}

func BenchmarkAllTypesWithSecret(b *testing.B) {
// Run benchmarks with secrets in the logs (20% of log entries), with all regexes enabled
runBenchmarks(b, testConfigs["default"], 20, "gcp_secret")
}

func BenchmarkAllTypesWithLotsOfSecrets(b *testing.B) {
// Run benchmarks with secrets in the logs (80% of log entries), with all regexes enabled
runBenchmarks(b, testConfigs["default"], 80, "gcp_secret")
}

func BenchmarkOneRuleNoSecret(b *testing.B) {
// Run benchmarks with no secrets in the logs, with a single regex enabled
runBenchmarks(b, testConfigs["custom_type"], 0, "")
}

func BenchmarkOneRuleWithSecret(b *testing.B) {
// Run benchmarks with secrets in the logs (20% of log entries), with a single regex enabled
runBenchmarks(b, testConfigs["custom_type"], 20, "gcp_secret")
}

func BenchmarkOneRuleWithLotsOfSecrets(b *testing.B) {
// Run benchmarks with secrets in the logs (80% of log entries), with a single regex enabled
runBenchmarks(b, testConfigs["custom_type"], 80, "gcp_secret")
}

func runBenchmarks(b *testing.B, config string, percentageSecrets int, secretName string) {
ch1 := loki.NewLogsReceiver()
var args Arguments
require.NoError(b, syntax.Unmarshal([]byte(config), &args))
args.ForwardTo = []loki.LogsReceiver{ch1}

opts := component.Options{
Logger: &noopLogger{}, // Disable logging so that it keeps a clean benchmark output
OnStateChange: func(e component.Exports) {},
GetServiceData: getServiceData,
}

// Create component
c, err := New(opts, args)
require.NoError(b, err)

// Generate fake log entries with a fixed seed so that it's reproducible
fake := faker.NewWithSeed(rand.NewSource(2014))
nbLogs := 100
benchInputs := make([]string, nbLogs)
for i := range benchInputs {
beginningStr := fake.Lorem().Paragraph(2)
middleStr := fake.Lorem().Sentence(10)
endingStr := fake.Lorem().Paragraph(2)

// Add fake secrets in some log entries
if i < nbLogs*percentageSecrets/100 {
middleStr = testLogs[secretName].log
}

benchInputs[i] = beginningStr + middleStr + endingStr
}

// Run benchmarks
for i := 0; i < b.N; i++ {
for _, input := range benchInputs {
entry := loki.Entry{Labels: model.LabelSet{}, Entry: logproto.Entry{Timestamp: time.Now(), Line: input}}
c.processEntry(entry)
}
}
}

func getServiceData(name string) (interface{}, error) {
switch name {
case livedebugging.ServiceName:
return livedebugging.NewLiveDebugging(), nil
default:
return nil, fmt.Errorf("service not found %s", name)
}
}

type noopLogger struct{}

func (d *noopLogger) Log(_ ...interface{}) error {
return nil
}

0 comments on commit fc7f41b

Please sign in to comment.