Skip to content

Commit e89f630

Browse files
1pkgmergify[bot]
authored andcommitted
monitoring: enable tracing self instrumentation in APM Server (#14231)
(cherry picked from commit 56228ce)
1 parent 44ee32d commit e89f630

File tree

6 files changed

+54
-4
lines changed

6 files changed

+54
-4
lines changed

changelogs/8.16.asciidoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@ https://github.com/elastic/apm-server/compare/v8.15.2\...v8.16.0[View commits]
3030
==== Added
3131

3232
- APM Server will no longer retry an HTTP request that returned 502s, 503s, 504s. It will only retry 429s. {pull}13523[13523]
33+
- APM Server now supports emitting distributed tracing for its own operation when running under Elastic Agent, and adds support for configuring a sampling rate {pull}14231[14231]

internal/beatcmd/beat_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ func TestRunManager(t *testing.T) {
183183
},
184184
},
185185
"instrumentation": map[string]interface{}{
186-
"enabled": false,
186+
"enabled": true,
187187
"environment": "testenv",
188188
},
189189
}, m)

internal/beatcmd/reloader.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,7 @@ func (r *Reloader) reload(inputConfig, outputConfig, apmTracingConfig *config.C)
195195
return fmt.Errorf("APM tracing config for elastic not found")
196196
}
197197
// set enabled manually as APMConfig doesn't contain it.
198-
// TODO set "enable" to true after the issue https://github.com/elastic/elastic-agent/issues/5211 gets resolved.
199-
c.SetBool("enabled", -1, false)
198+
c.SetBool("enabled", -1, true)
200199
wrappedApmTracingConfig = config.MustNewConfigFrom(map[string]interface{}{
201200
"instrumentation": c,
202201
})

internal/beatcmd/reloader_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ func TestReloaderNewRunnerParams(t *testing.T) {
186186
args := <-calls
187187
assert.NotNil(t, args.Logger)
188188
assert.Equal(t, info, args.Info)
189-
assert.Equal(t, config.MustNewConfigFrom(`{"revision": 1, "input": 123, "output.console.enabled": true, "instrumentation.enabled":false, "instrumentation.environment":"test"}`), args.Config)
189+
assert.Equal(t, config.MustNewConfigFrom(`{"revision": 1, "input": 123, "output.console.enabled": true, "instrumentation.enabled":true, "instrumentation.environment":"test"}`), args.Config)
190190
}
191191

192192
func expectNoEvent(t testing.TB, ch <-chan struct{}, message string) {

internal/beater/beater.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"net/http"
2727
"os"
2828
"runtime"
29+
"strconv"
2930
"time"
3031

3132
"github.com/dustin/go-humanize"
@@ -525,6 +526,7 @@ func newInstrumentation(rawConfig *agentconfig.C) (instrumentation.Instrumentati
525526
ServerCertificate string `config:"servercert"`
526527
ServerCA string `config:"serverca"`
527528
} `config:"tls"`
529+
SamplingRate *float32 `config:"samplingrate"`
528530
}
529531
cfg, err := rawConfig.Child("instrumentation", -1)
530532
if err != nil || !cfg.Enabled() {
@@ -541,6 +543,7 @@ func newInstrumentation(rawConfig *agentconfig.C) (instrumentation.Instrumentati
541543
envServerCert = "ELASTIC_APM_SERVER_CERT"
542544
envCACert = "ELASTIC_APM_SERVER_CA_CERT_FILE"
543545
envGlobalLabels = "ELASTIC_APM_GLOBAL_LABELS"
546+
envSamplingRate = "ELASTIC_APM_TRANSACTION_SAMPLE_RATE"
544547
)
545548
if apmCfg.APIKey != "" {
546549
os.Setenv(envAPIKey, apmCfg.APIKey)
@@ -566,6 +569,11 @@ func newInstrumentation(rawConfig *agentconfig.C) (instrumentation.Instrumentati
566569
os.Setenv(envGlobalLabels, apmCfg.GlobalLabels)
567570
defer os.Unsetenv(envGlobalLabels)
568571
}
572+
if apmCfg.SamplingRate != nil {
573+
r := max(min(*apmCfg.SamplingRate, 1.0), 0.0)
574+
os.Setenv(envSamplingRate, strconv.FormatFloat(float64(r), 'f', -1, 32))
575+
defer os.Unsetenv(envSamplingRate)
576+
}
569577
return instrumentation.New(rawConfig, "apm-server", version.Version)
570578
}
571579

internal/beater/beater_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@ import (
2424
"encoding/pem"
2525
"errors"
2626
"fmt"
27+
"io"
2728
"net/http"
2829
"net/http/httptest"
2930
"os"
3031
"path/filepath"
32+
"strings"
3133
"testing"
3234
"time"
3335

@@ -285,6 +287,46 @@ func TestNewInstrumentation(t *testing.T) {
285287
assert.Equal(t, "Bearer secret", auth)
286288
}
287289

290+
func TestNewInstrumentationWithSampling(t *testing.T) {
291+
runSampled := func(rate float32) {
292+
var events int
293+
s := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
294+
if r.URL.Path == "/intake/v2/events" {
295+
zr, _ := zlib.NewReader(r.Body)
296+
b, _ := io.ReadAll(zr)
297+
// Skip metadata and transaction keys, only count span.
298+
events = strings.Count(string(b), "\n") - 2
299+
}
300+
w.WriteHeader(http.StatusOK)
301+
}))
302+
defer s.Close()
303+
cfg := agentconfig.MustNewConfigFrom(map[string]interface{}{
304+
"instrumentation": map[string]interface{}{
305+
"enabled": true,
306+
"hosts": []string{s.URL},
307+
"tls": map[string]interface{}{
308+
"skipverify": true,
309+
},
310+
"samplingrate": fmt.Sprintf("%f", rate),
311+
},
312+
})
313+
i, err := newInstrumentation(cfg)
314+
require.NoError(t, err)
315+
tracer := i.Tracer()
316+
tr := tracer.StartTransaction("name", "type")
317+
tr.StartSpan("span", "type", nil).End()
318+
tr.End()
319+
tracer.Flush(nil)
320+
assert.Equal(t, int(rate), events)
321+
}
322+
t.Run("100% sampling", func(t *testing.T) {
323+
runSampled(1.0)
324+
})
325+
t.Run("0% sampling", func(t *testing.T) {
326+
runSampled(0.0)
327+
})
328+
}
329+
288330
func TestProcessMemoryLimit(t *testing.T) {
289331
l := logp.NewLogger("test")
290332
const gb = 1 << 30

0 commit comments

Comments
 (0)