Skip to content

Commit 82896f5

Browse files
authored
Increase metrics interval to 60s (#3578)
* Increase elastic-agent monitoring metrics interval to 60s
1 parent e20c34d commit 82896f5

File tree

3 files changed

+141
-6
lines changed

3 files changed

+141
-6
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Kind can be one of:
2+
# - breaking-change: a change to previously-documented behavior
3+
# - deprecation: functionality that is being removed in a later release
4+
# - bug-fix: fixes a problem in a previous version
5+
# - enhancement: extends functionality but does not break or fix existing behavior
6+
# - feature: new functionality
7+
# - known-issue: problems that we are aware of in a given version
8+
# - security: impacts on the security of a product or a user’s deployment.
9+
# - upgrade: important information for someone upgrading from a prior version
10+
# - other: does not fit into any of the other categories
11+
kind: enhancement
12+
13+
# Change summary; a 80ish characters long description of the change.
14+
summary: Increase agent monitoring metrics interval from 10s to 60s to reduce load
15+
16+
# Long description; in case the summary is not enough to describe the change
17+
# this field accommodate a description without length limits.
18+
# NOTE: This field will be rendered only for breaking-change and known-issue kinds at the moment.
19+
#description:
20+
21+
# Affected component; a word indicating the component this changeset affects.
22+
component: monitoring
23+
24+
# PR URL; optional; the PR number that added the changeset.
25+
# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added.
26+
# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number.
27+
# Please provide it if you are adding a fragment for a different PR.
28+
#pr: https://github.com/owner/repo/1234
29+
30+
# Issue URL; optional; the GitHub issue related to this changeset (either closes or is part of).
31+
# If not present is automatically filled by the tooling with the issue linked to the PR number.
32+
#issue: https://github.com/owner/repo/1234

internal/pkg/agent/application/monitoring/v1_monitor.go

+13-6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"path/filepath"
1313
"runtime"
1414
"strings"
15+
"time"
1516
"unicode"
1617

1718
"github.com/elastic/elastic-agent/pkg/component"
@@ -51,6 +52,10 @@ const (
5152
agentName = "elastic-agent"
5253

5354
windowsOS = "windows"
55+
56+
// metricset execution period used for the monitoring metrics inputs
57+
// we set this to 60s to reduce the load/data volume on the monitoring cluster
58+
metricsCollectionInterval = 60 * time.Second
5459
)
5560

5661
var (
@@ -517,6 +522,8 @@ func (b *BeatsMonitor) monitoringNamespace() string {
517522
}
518523

519524
func (b *BeatsMonitor) injectMetricsInput(cfg map[string]interface{}, componentIDToBinary map[string]string, monitoringOutputName string, componentList []component.Component) error {
525+
526+
metricsCollectionIntervalString := metricsCollectionInterval.String()
520527
monitoringNamespace := b.monitoringNamespace()
521528
fixedAgentName := strings.ReplaceAll(agentName, "-", "_")
522529
beatsStreams := make([]interface{}, 0, len(componentIDToBinary))
@@ -532,7 +539,7 @@ func (b *BeatsMonitor) injectMetricsInput(cfg map[string]interface{}, componentI
532539
"path": "/stats",
533540
"hosts": []interface{}{HttpPlusAgentMonitoringEndpoint(b.operatingSystem, b.config.C)},
534541
"namespace": "agent",
535-
"period": "10s",
542+
"period": metricsCollectionIntervalString,
536543
"index": fmt.Sprintf("metrics-elastic_agent.%s-%s", fixedAgentName, monitoringNamespace),
537544
"processors": []interface{}{
538545
map[string]interface{}{
@@ -608,7 +615,7 @@ func (b *BeatsMonitor) injectMetricsInput(cfg map[string]interface{}, componentI
608615
},
609616
"metricsets": []interface{}{"stats", "state"},
610617
"hosts": endpoints,
611-
"period": "10s",
618+
"period": metricsCollectionIntervalString,
612619
"index": fmt.Sprintf("metrics-elastic_agent.%s-%s", name, monitoringNamespace),
613620
"processors": []interface{}{
614621
map[string]interface{}{
@@ -663,7 +670,7 @@ func (b *BeatsMonitor) injectMetricsInput(cfg map[string]interface{}, componentI
663670
"hosts": endpoints,
664671
"path": "/stats",
665672
"namespace": "agent",
666-
"period": "10s",
673+
"period": metricsCollectionIntervalString,
667674
"index": fmt.Sprintf("metrics-elastic_agent.%s-%s", fixedAgentName, monitoringNamespace),
668675
"processors": []interface{}{
669676
map[string]interface{}{
@@ -725,7 +732,7 @@ func (b *BeatsMonitor) injectMetricsInput(cfg map[string]interface{}, componentI
725732
"path": "/inputs/",
726733
"namespace": fbDataStreamName,
727734
"json.is_array": true,
728-
"period": "10s",
735+
"period": metricsCollectionIntervalString,
729736
"index": fmt.Sprintf("metrics-elastic_agent.%s-%s", fbDataStreamName, monitoringNamespace),
730737
"processors": []interface{}{
731738
map[string]interface{}{
@@ -799,7 +806,7 @@ func (b *BeatsMonitor) injectMetricsInput(cfg map[string]interface{}, componentI
799806
"path": "/shipper",
800807
"hosts": endpoints,
801808
"namespace": "application",
802-
"period": "10s",
809+
"period": metricsCollectionIntervalString,
803810
"processors": createProcessorsForJSONInput(name, monitoringNamespace, b.agentInfo),
804811
},
805812
map[string]interface{}{
@@ -813,7 +820,7 @@ func (b *BeatsMonitor) injectMetricsInput(cfg map[string]interface{}, componentI
813820
"path": "/stats",
814821
"hosts": endpoints,
815822
"namespace": "agent",
816-
"period": "10s",
823+
"period": metricsCollectionIntervalString,
817824
"processors": createProcessorsForJSONInput(name, monitoringNamespace, b.agentInfo),
818825
})
819826
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2+
// or more contributor license agreements. Licensed under the Elastic License;
3+
// you may not use this file except in compliance with the Elastic License.
4+
5+
package monitoring
6+
7+
import (
8+
"context"
9+
"runtime"
10+
"testing"
11+
"time"
12+
13+
"github.com/stretchr/testify/assert"
14+
"github.com/stretchr/testify/require"
15+
"gopkg.in/yaml.v2"
16+
17+
"github.com/elastic/elastic-agent/internal/pkg/agent/application/info"
18+
monitoringcfg "github.com/elastic/elastic-agent/internal/pkg/core/monitoring/config"
19+
)
20+
21+
func TestMonitoringConfigMetricsInterval(t *testing.T) {
22+
23+
agentInfo, err := info.NewAgentInfo(context.Background(), false)
24+
require.NoError(t, err, "Error creating agent info")
25+
26+
mCfg := &monitoringConfig{
27+
C: &monitoringcfg.MonitoringConfig{
28+
Enabled: true,
29+
MonitorMetrics: true,
30+
HTTP: &monitoringcfg.MonitoringHTTPConfig{
31+
Enabled: false,
32+
},
33+
},
34+
}
35+
36+
policy := map[string]any{
37+
"agent": map[string]any{
38+
"monitoring": map[string]any{
39+
"metrics": true,
40+
"http": map[string]any{
41+
"enabled": false,
42+
},
43+
},
44+
},
45+
"outputs": map[string]any{
46+
"default": map[string]any{},
47+
},
48+
}
49+
b := &BeatsMonitor{
50+
enabled: true,
51+
config: mCfg,
52+
operatingSystem: runtime.GOOS,
53+
agentInfo: agentInfo,
54+
}
55+
got, err := b.MonitoringConfig(policy, nil, map[string]string{"foobeat": "filebeat"}) // put a componentID/binary mapping to have something in the beats monitoring input
56+
assert.NoError(t, err)
57+
58+
rawInputs, ok := got["inputs"]
59+
require.True(t, ok, "monitoring config contains no input")
60+
inputs, ok := rawInputs.([]any)
61+
require.True(t, ok, "monitoring inputs are not a list")
62+
marshaledInputs, err := yaml.Marshal(inputs)
63+
if assert.NoError(t, err, "error marshaling monitoring inputs") {
64+
t.Logf("marshaled monitoring inputs:\n%s\n", marshaledInputs)
65+
}
66+
67+
// loop over the created inputs
68+
for _, i := range inputs {
69+
input, ok := i.(map[string]any)
70+
if assert.Truef(t, ok, "input is not represented as a map: %v", i) {
71+
inputID := input["id"]
72+
t.Logf("input %q", inputID)
73+
// check the streams created for the input, should be a list of objects
74+
if assert.Contains(t, input, "streams", "input %q does not contain any stream", inputID) &&
75+
assert.IsTypef(t, []any{}, input["streams"], "streams for input %q are not a list of objects", inputID) {
76+
// loop over streams and cast to map[string]any to access keys
77+
for _, rawStream := range input["streams"].([]any) {
78+
if assert.IsTypef(t, map[string]any{}, rawStream, "stream %v for input %q is not a map", rawStream, inputID) {
79+
stream := rawStream.(map[string]any)
80+
// check period and assert its value
81+
streamID := stream["id"]
82+
if assert.Containsf(t, stream, "period", "stream %q for input %q does not contain a period", streamID, inputID) &&
83+
assert.IsType(t, "", stream["period"], "period for stream %q of input %q is not represented as a string", streamID, inputID) {
84+
periodString := stream["period"].(string)
85+
duration, err := time.ParseDuration(periodString)
86+
if assert.NoErrorf(t, err, "Unparseable period duration %s for stream %q of input %q", periodString, streamID, inputID) {
87+
assert.Equalf(t, duration, 60*time.Second, "unexpected duration for stream %q of input %q", streamID, inputID)
88+
}
89+
}
90+
}
91+
}
92+
}
93+
}
94+
95+
}
96+
}

0 commit comments

Comments
 (0)