Skip to content

Commit

Permalink
Support sampling rate in APM configuration (#4037) (#4052)
Browse files Browse the repository at this point in the history
* Support sampling rate in APM configuration

(cherry picked from commit dbdd056)

Co-authored-by: Paolo Chilà <[email protected]>
  • Loading branch information
mergify[bot] and pchila authored Oct 30, 2024
1 parent a01ac52 commit a3d14ee
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 4 deletions.
7 changes: 7 additions & 0 deletions internal/pkg/server/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"io"
"strconv"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -556,6 +557,12 @@ func apmConfigToInstrumentation(src *proto.APMConfig) (config.Instrumentation, e
Hosts: apmest.GetHosts(),
GlobalLabels: apmest.GetGlobalLabels(),
}

if apmest.SamplingRate != nil {
// set the sampling rate in config
cfg.TransactionSampleRate = strconv.FormatFloat(float64(*apmest.SamplingRate), 'f', -1, 32)
}

return cfg, nil
}
return config.Instrumentation{}, fmt.Errorf("unable to transform APMConfig to instrumentation")
Expand Down
93 changes: 89 additions & 4 deletions internal/pkg/server/agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,78 @@ func Test_Agent_configFromUnits(t *testing.T) {
assert.Equal(t, "fleet-server", cfg.Inputs[0].Type)
require.Len(t, cfg.Output.Elasticsearch.Hosts, 2)
})
t.Run("Minimal APM config is specified", func(t *testing.T) {
outStruct, err := structpb.NewStruct(map[string]interface{}{
"service_token": "test-token",
})
require.NoError(t, err)
mockOutClient := &mockClientUnit{}
mockOutClient.On("Expected").Return(
client.Expected{
State: client.UnitStateHealthy,
LogLevel: client.UnitLogLevelInfo,
Config: &proto.UnitExpectedConfig{Source: outStruct},
})

inStruct, err := structpb.NewStruct(map[string]interface{}{
"type": "fleet-server",
"server": map[string]interface{}{
"host": "0.0.0.0",
},
"policy": map[string]interface{}{
"id": "test-policy",
},
})
require.NoError(t, err)

mockInClient := &mockClientUnit{}
mockInClient.On("Expected").Return(
client.Expected{
State: client.UnitStateHealthy,
LogLevel: client.UnitLogLevelInfo,
Config: &proto.UnitExpectedConfig{Source: inStruct},
APMConfig: &proto.APMConfig{
Elastic: &proto.ElasticAPM{
Environment: "test",
SecretToken: "secretToken",
Hosts: []string{"testhost:8080"},
},
},
})

cliCfg, err := ucfg.NewFrom(map[string]interface{}{
"inputs": []interface{}{
map[string]interface{}{
"policy": map[string]interface{}{
"id": "test-policy",
},
},
},
})
require.NoError(t, err)
a := &Agent{
cliCfg: cliCfg,
agent: mockAgent,
inputUnit: mockInClient,
outputUnit: mockOutClient,
}

cfg, err := a.configFromUnits(context.Background())
require.NoError(t, err)
require.Len(t, cfg.Inputs, 1)
assert.Equal(t, "fleet-server", cfg.Inputs[0].Type)
assert.Equal(t, "test-policy", cfg.Inputs[0].Policy.ID)
assert.Equal(t, "0.0.0.0", cfg.Inputs[0].Server.Host)
assert.True(t, cfg.Inputs[0].Server.Instrumentation.Enabled)
assert.False(t, cfg.Inputs[0].Server.Instrumentation.TLS.SkipVerify)
assert.Empty(t, cfg.Inputs[0].Server.Instrumentation.TLS.ServerCA)
assert.Equal(t, "test", cfg.Inputs[0].Server.Instrumentation.Environment)
assert.Empty(t, cfg.Inputs[0].Server.Instrumentation.APIKey)
assert.Equal(t, "secretToken", cfg.Inputs[0].Server.Instrumentation.SecretToken)
assert.Equal(t, []string{"testhost:8080"}, cfg.Inputs[0].Server.Instrumentation.Hosts)
assert.Empty(t, cfg.Inputs[0].Server.Instrumentation.GlobalLabels)
assert.Equal(t, "test-token", cfg.Output.Elasticsearch.ServiceToken)
})
t.Run("APM config is specified", func(t *testing.T) {
outStruct, err := structpb.NewStruct(map[string]interface{}{
"service_token": "test-token",
Expand All @@ -262,6 +334,8 @@ func Test_Agent_configFromUnits(t *testing.T) {
},
})
require.NoError(t, err)

samplingRate := float32(0.5)
mockInClient := &mockClientUnit{}
mockInClient.On("Expected").Return(
client.Expected{
Expand All @@ -279,6 +353,7 @@ func Test_Agent_configFromUnits(t *testing.T) {
SecretToken: "secretToken",
Hosts: []string{"testhost:8080"},
GlobalLabels: "test",
SamplingRate: &samplingRate,
},
},
})
Expand Down Expand Up @@ -315,6 +390,7 @@ func Test_Agent_configFromUnits(t *testing.T) {
assert.Equal(t, []string{"testhost:8080"}, cfg.Inputs[0].Server.Instrumentation.Hosts)
assert.Equal(t, "test", cfg.Inputs[0].Server.Instrumentation.GlobalLabels)
assert.Equal(t, "test-token", cfg.Output.Elasticsearch.ServiceToken)
assert.Equal(t, "0.5", cfg.Inputs[0].Server.Instrumentation.TransactionSampleRate)
})
t.Run("APM config no tls", func(t *testing.T) {
outStruct, err := structpb.NewStruct(map[string]interface{}{
Expand All @@ -336,6 +412,8 @@ func Test_Agent_configFromUnits(t *testing.T) {
},
})
require.NoError(t, err)

samplingRate := float32(0.01)
mockInClient := &mockClientUnit{}
mockInClient.On("Expected").Return(
client.Expected{
Expand All @@ -349,6 +427,7 @@ func Test_Agent_configFromUnits(t *testing.T) {
SecretToken: "secretToken",
Hosts: []string{"testhost:8080"},
GlobalLabels: "test",
SamplingRate: &samplingRate,
},
},
})
Expand All @@ -374,6 +453,7 @@ func Test_Agent_configFromUnits(t *testing.T) {
assert.Equal(t, []string{"testhost:8080"}, cfg.Inputs[0].Server.Instrumentation.Hosts)
assert.Equal(t, "test", cfg.Inputs[0].Server.Instrumentation.GlobalLabels)
assert.Equal(t, "test-token", cfg.Output.Elasticsearch.ServiceToken)
assert.Equal(t, "0.01", cfg.Inputs[0].Server.Instrumentation.TransactionSampleRate)
})
t.Run("APM config and instrumentation is specified", func(t *testing.T) {
outStruct, err := structpb.NewStruct(map[string]interface{}{
Expand All @@ -398,14 +478,17 @@ func Test_Agent_configFromUnits(t *testing.T) {
"skip_verify": true,
"server_certificate": "/path/to/cert.crt",
},
"environment": "replace",
"api_key": "replace",
"secret_token": "replace",
"hosts": []interface{}{"replace"},
"environment": "replace",
"api_key": "replace",
"secret_token": "replace",
"hosts": []interface{}{"replace"},
"transaction_sample_rate": "0.75",
},
},
})
require.NoError(t, err)

samplingRate := float32(0.01)
mockInClient := &mockClientUnit{}
mockInClient.On("Expected").Return(
client.Expected{
Expand All @@ -423,6 +506,7 @@ func Test_Agent_configFromUnits(t *testing.T) {
SecretToken: "secretToken",
Hosts: []string{"testhost:8080"},
GlobalLabels: "test",
SamplingRate: &samplingRate,
},
},
})
Expand All @@ -449,6 +533,7 @@ func Test_Agent_configFromUnits(t *testing.T) {
assert.Equal(t, []string{"testhost:8080"}, cfg.Inputs[0].Server.Instrumentation.Hosts)
assert.Equal(t, "test", cfg.Inputs[0].Server.Instrumentation.GlobalLabels)
assert.Equal(t, "test-token", cfg.Output.Elasticsearch.ServiceToken)
assert.Equal(t, "0.01", cfg.Inputs[0].Server.Instrumentation.TransactionSampleRate)
})
t.Run("APM config error", func(t *testing.T) {
outStruct, err := structpb.NewStruct(map[string]interface{}{
Expand Down

0 comments on commit a3d14ee

Please sign in to comment.