diff --git a/extension/agenthealth/config.go b/extension/agenthealth/config.go index dd1f94c06c..3952ef3f81 100644 --- a/extension/agenthealth/config.go +++ b/extension/agenthealth/config.go @@ -10,8 +10,9 @@ import ( ) type Config struct { - IsUsageDataEnabled bool `mapstructure:"is_usage_data_enabled"` - Stats agent.StatsConfig `mapstructure:"stats"` + IsUsageDataEnabled bool `mapstructure:"is_usage_data_enabled"` + Stats agent.StatsConfig `mapstructure:"stats"` + IsOnlyStatusCodeEnabled bool `mapstructure:"is_status_code_enabled,omitempty"` } var _ component.Config = (*Config)(nil) diff --git a/extension/agenthealth/extension.go b/extension/agenthealth/extension.go index 14ab08eb57..f479d63b6a 100644 --- a/extension/agenthealth/extension.go +++ b/extension/agenthealth/extension.go @@ -7,6 +7,7 @@ import ( "github.com/amazon-contributing/opentelemetry-collector-contrib/extension/awsmiddleware" "go.opentelemetry.io/collector/component" "go.uber.org/zap" + "golang.org/x/exp/slices" "github.com/aws/amazon-cloudwatch-agent/extension/agenthealth/handler/stats" "github.com/aws/amazon-cloudwatch-agent/extension/agenthealth/handler/useragent" @@ -24,11 +25,24 @@ var _ awsmiddleware.Extension = (*agentHealth)(nil) func (ah *agentHealth) Handlers() ([]awsmiddleware.RequestHandler, []awsmiddleware.ResponseHandler) { var responseHandlers []awsmiddleware.ResponseHandler requestHandlers := []awsmiddleware.RequestHandler{useragent.NewHandler(ah.cfg.IsUsageDataEnabled)} - if ah.cfg.IsUsageDataEnabled { - req, res := stats.NewHandlers(ah.logger, ah.cfg.Stats) - requestHandlers = append(requestHandlers, req...) - responseHandlers = append(responseHandlers, res...) + + if !ah.cfg.IsUsageDataEnabled { + ah.logger.Debug("Usage data is disabled, skipping stats handlers") + return requestHandlers, responseHandlers } + + statusCodeEnabled := false + statusCodeEnabled = ah.cfg.IsOnlyStatusCodeEnabled + + agentStatsEnabled := + slices.Contains(ah.cfg.Stats.Operations, "PutMetricData") || + slices.Contains(ah.cfg.Stats.Operations, "PutLogEvents") || + slices.Contains(ah.cfg.Stats.Operations, "PutTraceSegment") + + statsRequestHandlers, statsResponseHandlers := stats.NewHandlers(ah.logger, ah.cfg.Stats, statusCodeEnabled, agentStatsEnabled) + requestHandlers = append(requestHandlers, statsRequestHandlers...) + responseHandlers = append(responseHandlers, statsResponseHandlers...) + return requestHandlers, responseHandlers } diff --git a/extension/agenthealth/extension_test.go b/extension/agenthealth/extension_test.go index 504dc8c50e..5679ef34d3 100644 --- a/extension/agenthealth/extension_test.go +++ b/extension/agenthealth/extension_test.go @@ -10,11 +10,13 @@ import ( "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/component/componenttest" "go.uber.org/zap" + + "github.com/aws/amazon-cloudwatch-agent/extension/agenthealth/handler/stats/agent" ) func TestExtension(t *testing.T) { ctx := context.Background() - cfg := &Config{IsUsageDataEnabled: true} + cfg := &Config{IsUsageDataEnabled: true, Stats: agent.StatsConfig{Operations: []string{"PutLogEvents"}}} extension := NewAgentHealth(zap.NewNop(), cfg) assert.NotNil(t, extension) assert.NoError(t, extension.Start(ctx, componenttest.NewNopHost())) diff --git a/extension/agenthealth/handler/stats/agent/agent.go b/extension/agenthealth/handler/stats/agent/agent.go index 83237d54e6..5bc84133db 100644 --- a/extension/agenthealth/handler/stats/agent/agent.go +++ b/extension/agenthealth/handler/stats/agent/agent.go @@ -15,21 +15,22 @@ const ( ) type Stats struct { - CpuPercent *float64 `json:"cpu,omitempty"` - MemoryBytes *uint64 `json:"mem,omitempty"` - FileDescriptorCount *int32 `json:"fd,omitempty"` - ThreadCount *int32 `json:"th,omitempty"` - LatencyMillis *int64 `json:"lat,omitempty"` - PayloadBytes *int `json:"load,omitempty"` - StatusCode *int `json:"code,omitempty"` - SharedConfigFallback *int `json:"scfb,omitempty"` - ImdsFallbackSucceed *int `json:"ifs,omitempty"` - AppSignals *int `json:"as,omitempty"` - EnhancedContainerInsights *int `json:"eci,omitempty"` - RunningInContainer *int `json:"ric,omitempty"` - RegionType *string `json:"rt,omitempty"` - Mode *string `json:"m,omitempty"` - EntityRejected *int `json:"ent,omitempty"` + CpuPercent *float64 `json:"cpu,omitempty"` + MemoryBytes *uint64 `json:"mem,omitempty"` + FileDescriptorCount *int32 `json:"fd,omitempty"` + ThreadCount *int32 `json:"th,omitempty"` + LatencyMillis *int64 `json:"lat,omitempty"` + PayloadBytes *int `json:"load,omitempty"` + StatusCode *int `json:"code,omitempty"` + SharedConfigFallback *int `json:"scfb,omitempty"` + ImdsFallbackSucceed *int `json:"ifs,omitempty"` + AppSignals *int `json:"as,omitempty"` + EnhancedContainerInsights *int `json:"eci,omitempty"` + RunningInContainer *int `json:"ric,omitempty"` + RegionType *string `json:"rt,omitempty"` + Mode *string `json:"m,omitempty"` + EntityRejected *int `json:"ent,omitempty"` + StatusCodes map[string][5]int `json:"codes,omitempty"` //represents status codes 200,400,408,413,429, } // Merge the other Stats into the current. If the field is not nil, @@ -80,6 +81,28 @@ func (s *Stats) Merge(other Stats) { if other.EntityRejected != nil { s.EntityRejected = other.EntityRejected } + if other.StatusCodes == nil { + return + } + + if s.StatusCodes == nil { + s.StatusCodes = make(map[string][5]int) + } + + for key, value := range other.StatusCodes { + if existing, ok := s.StatusCodes[key]; ok { + s.StatusCodes[key] = [5]int{ + existing[0] + value[0], // 200 + existing[1] + value[1], // 400 + existing[2] + value[2], // 408 + existing[3] + value[3], // 413 + existing[4] + value[4], // 429 + } + } else { + s.StatusCodes[key] = value + } + } + } func (s *Stats) Marshal() (string, error) { @@ -104,6 +127,26 @@ func (of OperationsFilter) IsAllowed(operationName string) bool { return of.allowAll || of.operations.Contains(operationName) } +var StatusCodeOperations = []string{ // all the operations that are allowed + "DescribeInstances", + "DescribeTags", + "DescribeVolumes", + "DescribeContainerInstances", + "DescribeServices", + "DescribeTaskDefinition", + "ListServices", + "ListTasks", + "CreateLogGroup", + "CreateLogStream", +} + +type StatsConfig struct { + // Operations are the allowed operation names to gather stats for. + Operations []string `mapstructure:"operations,omitempty"` + // UsageFlags are the usage flags to set on start up. + UsageFlags map[Flag]any `mapstructure:"usage_flags,omitempty"` +} + func NewOperationsFilter(operations ...string) OperationsFilter { allowed := collections.NewSet[string](operations...) return OperationsFilter{ @@ -112,9 +155,21 @@ func NewOperationsFilter(operations ...string) OperationsFilter { } } -type StatsConfig struct { - // Operations are the allowed operation names to gather stats for. - Operations []string `mapstructure:"operations,omitempty"` - // UsageFlags are the usage flags to set on start up. - UsageFlags map[Flag]any `mapstructure:"usage_flags,omitempty"` +// NewStatusCodeOperationsFilter creates a new filter for allowed operations and status codes. +func NewStatusCodeOperationsFilter() OperationsFilter { + allowed := make(map[string]struct{}, len(StatusCodeOperations)) + + return OperationsFilter{ + operations: allowed, + allowAll: false, + } +} + +func NewStatusCodeAndOtherOperationsFilter(operations []string) OperationsFilter { + filter := NewStatusCodeOperationsFilter() + for _, operation := range operations { + filter.operations.Add(operation) + } + + return filter } diff --git a/extension/agenthealth/handler/stats/agent/agent_test.go b/extension/agenthealth/handler/stats/agent/agent_test.go index c379facc19..f88ba822eb 100644 --- a/extension/agenthealth/handler/stats/agent/agent_test.go +++ b/extension/agenthealth/handler/stats/agent/agent_test.go @@ -52,6 +52,76 @@ func TestMerge(t *testing.T) { assert.EqualValues(t, "Mode", *stats.Mode) } +func TestMergeWithStatusCodes(t *testing.T) { + stats := &Stats{ + StatusCodes: map[string][5]int{ + "operation1": {1, 2, 3, 4, 5}, + }, + } + + stats.Merge(Stats{ + StatusCodes: map[string][5]int{ + "operation1": {2, 3, 4, 5, 6}, // Existing operation with new values + "operation2": {0, 1, 2, 3, 4}, // New operation + }, + }) + + assert.Equal(t, [5]int{3, 5, 7, 9, 11}, stats.StatusCodes["operation1"]) // Values should sum + assert.Equal(t, [5]int{0, 1, 2, 3, 4}, stats.StatusCodes["operation2"]) // New operation added + + stats.Merge(Stats{ + StatusCodes: nil, + }) + + assert.Equal(t, [5]int{3, 5, 7, 9, 11}, stats.StatusCodes["operation1"]) + assert.Equal(t, [5]int{0, 1, 2, 3, 4}, stats.StatusCodes["operation2"]) +} + +func TestMarshalWithStatusCodes(t *testing.T) { + testCases := map[string]struct { + stats *Stats + want string + }{ + "WithEmptyStatusCodes": { + stats: &Stats{ + StatusCodes: map[string][5]int{}, + }, + want: "", + }, + "WithStatusCodes": { + stats: &Stats{ + StatusCodes: map[string][5]int{ + "operation1": {1, 2, 3, 4, 5}, + "operation2": {0, 1, 2, 3, 4}, + }, + }, + want: `"codes":{"operation1":[1,2,3,4,5],"operation2":[0,1,2,3,4]}`, + }, + } + for name, testCase := range testCases { + t.Run(name, func(t *testing.T) { + got, err := testCase.stats.Marshal() + assert.NoError(t, err) + assert.Contains(t, got, testCase.want) + }) + } +} + +func TestMergeFullWithStatusCodes(t *testing.T) { + stats := &Stats{ + CpuPercent: aws.Float64(1.0), + StatusCodes: map[string][5]int{"operation1": {1, 0, 0, 0, 0}}, + } + stats.Merge(Stats{ + CpuPercent: aws.Float64(2.0), + StatusCodes: map[string][5]int{"operation1": {0, 1, 0, 0, 0}, "operation2": {1, 1, 1, 1, 1}}, + }) + + assert.Equal(t, 2.0, *stats.CpuPercent) + assert.Equal(t, [5]int{1, 1, 0, 0, 0}, stats.StatusCodes["operation1"]) + assert.Equal(t, [5]int{1, 1, 1, 1, 1}, stats.StatusCodes["operation2"]) +} + func TestMarshal(t *testing.T) { testCases := map[string]struct { stats *Stats diff --git a/extension/agenthealth/handler/stats/handler.go b/extension/agenthealth/handler/stats/handler.go index 7e12f12b5c..2f89062bd4 100644 --- a/extension/agenthealth/handler/stats/handler.go +++ b/extension/agenthealth/handler/stats/handler.go @@ -21,12 +21,36 @@ const ( headerKeyAgentStats = "X-Amz-Agent-Stats" ) -func NewHandlers(logger *zap.Logger, cfg agent.StatsConfig) ([]awsmiddleware.RequestHandler, []awsmiddleware.ResponseHandler) { - filter := agent.NewOperationsFilter(cfg.Operations...) - clientStats := client.NewHandler(filter) - stats := newStatsHandler(logger, filter, []agent.StatsProvider{clientStats, provider.GetProcessStats(), provider.GetFlagsStats()}) +func NewHandlers(logger *zap.Logger, cfg agent.StatsConfig, statusCodeEnabled bool, agentStatsEnabled bool) ([]awsmiddleware.RequestHandler, []awsmiddleware.ResponseHandler) { + var requestHandlers []awsmiddleware.RequestHandler + var responseHandlers []awsmiddleware.ResponseHandler + var statsProviders []agent.StatsProvider + + if !statusCodeEnabled && !agentStatsEnabled { + return nil, nil + } + + statusCodeFilter := agent.NewStatusCodeOperationsFilter() + statusCodeStats := provider.GetStatusCodeStats(statusCodeFilter) + if statusCodeEnabled { + requestHandlers = append(requestHandlers, statusCodeStats) + responseHandlers = append(responseHandlers, statusCodeStats) + statsProviders = append(statsProviders, statusCodeStats) + } + + if agentStatsEnabled { + clientStats := client.NewHandler(agent.NewOperationsFilter()) + statsProviders = append(statsProviders, clientStats, provider.GetProcessStats(), provider.GetFlagsStats()) + responseHandlers = append(responseHandlers, clientStats) + requestHandlers = append(requestHandlers, clientStats) + + } + filter := agent.NewStatusCodeAndOtherOperationsFilter(cfg.Operations) + stats := newStatsHandler(logger, filter, statsProviders) + requestHandlers = append(requestHandlers, stats) + agent.UsageFlags().SetValues(cfg.UsageFlags) - return []awsmiddleware.RequestHandler{stats, clientStats}, []awsmiddleware.ResponseHandler{clientStats} + return requestHandlers, responseHandlers } type statsHandler struct { diff --git a/extension/agenthealth/handler/stats/handler_test.go b/extension/agenthealth/handler/stats/handler_test.go index f40bebd481..108c6aa120 100644 --- a/extension/agenthealth/handler/stats/handler_test.go +++ b/extension/agenthealth/handler/stats/handler_test.go @@ -40,6 +40,10 @@ func TestStatsHandler(t *testing.T) { StatusCode: aws.Int(200), ImdsFallbackSucceed: aws.Int(1), SharedConfigFallback: aws.Int(1), + StatusCodes: map[string][5]int{ + "pmd": {1, 0, 0, 0, 0}, + "di": {0, 1, 0, 0, 0}, + }, } handler := newStatsHandler( zap.NewNop(), @@ -59,15 +63,31 @@ func TestStatsHandler(t *testing.T) { assert.Equal(t, "", req.Header.Get(headerKeyAgentStats)) handler.filter = agent.NewOperationsFilter(agent.AllowAllOperations) handler.HandleRequest(ctx, req) - assert.Equal(t, `"cpu":1.2,"mem":123,"fd":456,"th":789,"lat":1234,"load":5678,"code":200,"scfb":1,"ifs":1`, req.Header.Get(headerKeyAgentStats)) + assert.Equal(t, `"cpu":1.2,"mem":123,"fd":456,"th":789,"lat":1234,"load":5678,"code":200,"scfb":1,"ifs":1,"codes":{"di":[0,1,0,0,0],"pmd":[1,0,0,0,0]}`, req.Header.Get(headerKeyAgentStats)) stats.StatusCode = aws.Int(404) stats.LatencyMillis = nil handler.HandleRequest(ctx, req) - assert.Equal(t, `"cpu":1.2,"mem":123,"fd":456,"th":789,"load":5678,"code":404,"scfb":1,"ifs":1`, req.Header.Get(headerKeyAgentStats)) + assert.Equal(t, `"cpu":1.2,"mem":123,"fd":456,"th":789,"load":5678,"code":404,"scfb":1,"ifs":1,"codes":{"di":[0,1,0,0,0],"pmd":[1,0,0,0,0]}`, req.Header.Get(headerKeyAgentStats)) } -func TestNewHandlers(t *testing.T) { - requestHandlers, responseHandlers := NewHandlers(zap.NewNop(), agent.StatsConfig{}) +func TestNewHandlersWithStatusCodeOnly(t *testing.T) { + requestHandlers, responseHandlers := NewHandlers(zap.NewNop(), agent.StatsConfig{}, true, false) + assert.Len(t, requestHandlers, 2) + assert.Len(t, responseHandlers, 1) +} +func TestNewHandlersWithAgentStatsOnly(t *testing.T) { + requestHandlers, responseHandlers := NewHandlers(zap.NewNop(), agent.StatsConfig{}, false, true) assert.Len(t, requestHandlers, 2) assert.Len(t, responseHandlers, 1) } + +func TestNewHandlersWithStatusCodeAndAgenthStats(t *testing.T) { + requestHandlers, responseHandlers := NewHandlers(zap.NewNop(), agent.StatsConfig{}, true, true) + assert.Len(t, requestHandlers, 3) + assert.Len(t, responseHandlers, 2) +} +func TestNewHandlersWithoutStatusCodeAndAgenthStats(t *testing.T) { + requestHandlers, responseHandlers := NewHandlers(zap.NewNop(), agent.StatsConfig{}, false, false) + assert.Len(t, requestHandlers, 0) + assert.Len(t, responseHandlers, 0) +} diff --git a/extension/agenthealth/handler/stats/provider/process_test.go b/extension/agenthealth/handler/stats/provider/process_test.go index 19fac625fb..931f08e6a0 100644 --- a/extension/agenthealth/handler/stats/provider/process_test.go +++ b/extension/agenthealth/handler/stats/provider/process_test.go @@ -11,8 +11,6 @@ import ( "github.com/shirou/gopsutil/v3/process" "github.com/stretchr/testify/assert" - - "github.com/aws/amazon-cloudwatch-agent/extension/agenthealth/handler/stats/agent" ) type mockProcessMetrics struct { @@ -77,6 +75,6 @@ func TestProcessStats(t *testing.T) { mock.mu.Unlock() provider.refresh() assert.Eventually(t, func() bool { - return provider.getStats() == agent.Stats{} + return len(provider.getStats().StatusCodes) == 0 // map isn't comparable, so we check the length }, 5*time.Millisecond, time.Millisecond) } diff --git a/extension/agenthealth/handler/stats/provider/statuscode.go b/extension/agenthealth/handler/stats/provider/statuscode.go new file mode 100644 index 0000000000..241cf8ca58 --- /dev/null +++ b/extension/agenthealth/handler/stats/provider/statuscode.go @@ -0,0 +1,171 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT + +package provider + +import ( + "context" + "log" + "net/http" + "sync" + "time" + + "github.com/amazon-contributing/opentelemetry-collector-contrib/extension/awsmiddleware" + + "github.com/aws/amazon-cloudwatch-agent/extension/agenthealth/handler/stats/agent" +) + +const ( + statusResetInterval = 5 * time.Minute + statusHandlerID = "cloudwatchagent.StatusCodeHandler" +) + +var ( + statusCodeSingleton *StatusCodeHandler + statusCodeStatsOnce sync.Once +) + +// StatusCodeHandler provides monitoring for status codes per operation. +type StatusCodeHandler struct { + statsByOperation sync.Map + resetTimer *time.Timer + filter agent.OperationsFilter +} + +// GetStatusCodeStats retrieves or initializes the singleton StatusCodeHandler. +func GetStatusCodeStats(filter agent.OperationsFilter) *StatusCodeHandler { + statusCodeStatsOnce.Do(func() { + handler := &StatusCodeHandler{} + handler.filter = filter + handler.startResetTimer() + statusCodeSingleton = handler + }) + return statusCodeSingleton +} + +// startResetTimer initializes a reset timer to clear stats every 5 minutes. +func (h *StatusCodeHandler) startResetTimer() { + ticker := time.NewTicker(statusResetInterval) + + go func() { + for range ticker.C { + h.statsByOperation.Clear() + log.Println("Status code stats reset.") + } + }() +} + +// HandleRequest is a no-op for the StatusCodeHandler. +func (h *StatusCodeHandler) HandleRequest(ctx context.Context, _ *http.Request) {} + +// HandleResponse processes the HTTP response to update status code stats. +func (h *StatusCodeHandler) HandleResponse(ctx context.Context, r *http.Response) { + // Extract the operation name + operation := awsmiddleware.GetOperationName(ctx) + if !h.filter.IsAllowed(operation) { + log.Printf("Operation %s is not allowed", operation) + return + } else { + log.Printf("Processing response for operation: %s", operation) + } + + operation = GetShortOperationName(operation) + if operation == "" { + return + } + statusCode := r.StatusCode + + value, loaded := h.statsByOperation.LoadOrStore(operation, &[5]int{}) + if !loaded { + log.Printf("Initializing stats for operation: %s", operation) + } + stats := value.(*[5]int) + + h.updateStatusCodeCount(stats, statusCode, operation) + + h.statsByOperation.Store(operation, stats) + + h.statsByOperation.Range(func(key, value interface{}) bool { + + operation := key.(string) + stats := value.(*[5]int) + log.Printf("Operation: %s, 200=%d, 400=%d, 408=%d, 413=%d, 429=%d", operation, stats[0], stats[1], stats[2], stats[3], stats[4]) + return true + }) +} + +// Helper function to update the status code counts +func (h *StatusCodeHandler) updateStatusCodeCount(stats *[5]int, statusCode int, operation string) { + switch statusCode { + case 200: + stats[0]++ + case 400: + stats[1]++ + case 408: + stats[2]++ + case 413: + stats[3]++ + case 429: + stats[4]++ + default: + log.Printf("Received an untracked status code %d for operation: %s", statusCode, operation) + } +} + +func GetShortOperationName(operation string) string { + switch operation { + case "PutMetricData": + return "pmd" + case "DescribeInstances": + return "di" + case "DescribeTags": + return "dt" + case "DescribeVolumes": + return "dv" + case "DescribeContainerInstances": + return "dci" + case "DescribeServices": + return "ds" + case "DescribeTaskDefinition": + return "dtd" + case "ListServices": + return "ls" + case "ListTasks": + return "lt" + case "CreateLogGroup": + return "clg" + case "CreateLogStream": + return "cls" + case "AssumeRole": + return "ar" + default: + return "" + } +} + +// ID returns the unique identifier for the handler. +func (h *StatusCodeHandler) ID() string { + return statusHandlerID +} + +// Position specifies the handler's position in the middleware chain. +func (h *StatusCodeHandler) Position() awsmiddleware.HandlerPosition { + return awsmiddleware.After +} + +// Stats implements the `Stats` method required by the `agent.StatsProvider` interface. +func (h *StatusCodeHandler) Stats(operation string) agent.Stats { + + statusCodeMap := make(map[string][5]int) + + h.statsByOperation.Range(func(key, value interface{}) bool { + operation := key.(string) + stats := value.(*[5]int) + statusCodeMap[operation] = [5]int{stats[0], stats[1], stats[2], stats[3], stats[4]} + return true + }) + + return agent.Stats{ + StatusCodes: statusCodeMap, + } +} diff --git a/extension/agenthealth/handler/stats/provider/statuscode_test.go b/extension/agenthealth/handler/stats/provider/statuscode_test.go new file mode 100644 index 0000000000..0d8a850e17 --- /dev/null +++ b/extension/agenthealth/handler/stats/provider/statuscode_test.go @@ -0,0 +1,26 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT + +package provider + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/aws/amazon-cloudwatch-agent/extension/agenthealth/handler/stats/agent" +) + +func TestStatusCodeHandler(t *testing.T) { + filter := agent.NewStatusCodeOperationsFilter() + handler := GetStatusCodeStats(filter) + require.NotNil(t, handler) + handler.statsByOperation.Store("pmd", &[5]int{1, 2, 0, 1, 0}) + stats := handler.Stats("pmd") + expected := [5]int{1, 2, 0, 1, 0} + actualStats := stats.StatusCodes["pmd"] + assert.Equal(t, expected, actualStats, "Unexpected stats values for operation 'pmd'") + assert.Contains(t, stats.StatusCodes, "pmd", "Status code map should contain 'pmd'") + assert.Equal(t, expected, stats.StatusCodes["pmd"], "Stats for 'pmd' do not match") +} diff --git a/internal/tls/testdata/server.crt b/internal/tls/testdata/server.crt index 12424f7b27..900f44dbbe 100644 --- a/internal/tls/testdata/server.crt +++ b/internal/tls/testdata/server.crt @@ -1,24 +1,24 @@ -----BEGIN CERTIFICATE----- -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 -----END CERTIFICATE----- diff --git a/internal/tls/testdata/server.key b/internal/tls/testdata/server.key index 0efcb40bb3..57fc5d831f 100644 --- a/internal/tls/testdata/server.key +++ b/internal/tls/testdata/server.key @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQD9zHhy7+7K2oJM -w/Ijo++WAibzqMrOCMvhFcGYSwHbcfivPSDia+hCpJ6CNPxWaMIOcbs+LBN7CvLk -FQI7TdLuDLuqEJveLkgeUcRr5AVer5/tycVHQvn4/iok4NMfqRKA8VV0qy94Bdmb -b3zXQtOfhQpN/aXRD3ubW54fiD7XF0qlprVhAS4hz4UlNBzeSVrH0GdlZAfKxUrU -PAsBRtA1vYuhklbDdc5psy0HVTwMj+FM8vPOOP3HmbJpZCHurpNwYkUTU4VHCSpR -SSa6AgSfMuwCQPLN7Xi1rJES4pPtMYp7ZHnes3zGkEYMzkjw3NOtkEzgxwdiJEoV -WQHi4eznAgMBAAECggEAGv7z1O32jXc+ouG40NewNVmXQRW0NMQ0w4Vn6UYZNXlj -BWjQJaVquCQAhEMUkDBma9jnHM7dZ5obie0+Joa5p/6Mu6M2oSR1IVx7Myq284Jk -1Ys/w7u5ESYf33pWmqiGQlbpSxamXvLoWaM7OT5veilRlkgjqiAmerj9EceRP5mR -aheVE5ctY5oZmdnvA9OcN6B8Oxk59EWEOECs8qAF/ChYfC8pWKOp4U0RILQ/9jXD -lu4p0C2XyadrJReer3whudUADWa/WSxgVCrx85/g/RTKs38KTPy7W4g3bv8KBRhc -bjLzoYTl6esRAi8nMG5Fc/85t07hkVv+j5a1NccxgQKBgQD/y/tdH90C8CrAn9y5 -mgr+1QcqJeJWaBpNf+yBqtLbybl6uLY2OzbZtzllU+TDUVlKZB36t2GnG6EIRUcd -WTHUVq8zEIRtDBa12SZlJ08FrNFyKfBByehEOvMazTxb7rdGbiv5+XztCrcPUn1f -cu30v5nBRjqDxtiAbKccFcZPpwKBgQD+ABUQ0h3aX5qDqzhvSLNuqy+hOZPLsqva -VxsDsIlzzzGwmdf+m2Dn9JR/xJNMPf717LJs8IYIqW4KX/HW0pC3Y8fu/6h4fFM9 -ZpJkM2hjRu0uLxDWLc+AombMavFtkZ1tffKxv6mG7Ud163ulBIt24b701XfhR5UX -RWvWI50gwQKBgQCFa1i9luwJJ0m1VOyk5kML7gMhqcbneL8XYzzx2S7IMuyKpSNt -H++ZGWdXga2Vbq3bDmNQrSvDJLcWgEP6e9ZwwZH6WYgo9KA3036iTiF6fUx1doh5 -WB3M0M6SUTBFZzqzAq3vYYEWhns7A7Se/2w8N1+0HrRQnXu5aHK1RGo+iwKBgEST -hRx7fi/dK/xsl9oDyN4SPdPLlcmjPZ6/cb23RgUMZaAGiThmfu1hLU6pphMpkdKX -yzx6W9Wu2NTYPpT/WK8Ks4olYDjXaCnlrZR8BKz5E0Qq1OLej21ta0+5d+FbNSPA -o2u2EXEqUubVYxaUeYrpPAMiNzGNgAU+avTvvJaBAoGBAKely84irwZicpex79T/ -KYV3VOMYs6wETNSLdKkR9G2WEI4OsEw0qGm9pZXzS6lKOSXxW6fOzwI0/vhnmT4O -hBxeR+PriPFqD80ASXeVeVOEjMXQEjZ8Po+FfUvVu8zMNIPDwJ+hy94FE5kkDBte -vy6FnjMquTvekIsRwo/OOdz3 +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwhKHYT43zWeBH +XyQuzhD/VHKlbA9A4405noSr2hDEVfnX6J8IumAgq47ceuhuoqwxCVDw9/BJwqRg +6exF/4yVSTSqkrN7bqHxls6joay9f89EJ21ofTJUBX2xf4w5YaS57JdAALsz0PWE +9k666ai+JLMA0UGBzplxJd7fhV+7SqW+LfInJ3DJmq4TWS7QxkoJWEZz/HjBJ3RJ +EZNpc+NYCKzloF318ya9YvKphcO1Q88h5qtJ60zaDtDWudruUZmTsrsmWg4zJgcL +g5AVhWlfYzX3TYBOkdrW0QGYvWw10Q65bY/ttM38FqGA9O+q3irtvWy8/uHl5tDN +l+9uzIP7AgMBAAECggEAZo9JceMXOPNZal6PKVq1aYTpb8/PNQaBgZ7muurinxDN +L3OLI4kWXSUQxm3rKoz9uygMjVWhmVmsJFsF2s3WIs77+Ldv7SGkmjfjLBO9yATA +qnq2COXlHghqtXzEPnrLOPOMFbXXDw4z+OMbb2Jflsq/7pOmmgMuCB3W1swpiSmo +6IVd9ty45lgSf6j7VcOpNU7zWVy/ApEEMhynqqipgbRzDQoYEk7KkKtU5e34CdyO +PcCmTx7P5IvrudGv0jdvAYp/VczBaK9mHIspX3PHc46B/T4dHbtW6U18lcz8/IFh +JaCJtxPdCQRi3cUWu6A44/qYaeSf70T7175exchSMQKBgQDN2a+1vsiw/Ec7OIhV +I1hbr3SNh0ZoWIz7MqlR8F9cjTgcpFPL5ksjB3vYNZND404SLeY7RmQjvbYEMbMb +ibabLn6Ws9UXePc3qFN07zcv4oLOSmjPHrDgMkCywb23NH3V+Z8nHoBK4aP0Kl4o +JqvVgESKW8G8L1Zyxg+u757ZnQKBgQDbhZNKDc5d5NmfGBtH+H4Bi63oHklIY6ey +5eo6ItJDW4/lbQ7z/+6Zvt86EdNKiNKaUF7NQB83Lf1IlDWRvoLPOEwOm+EB7n8C +uZjrOUG9kroL3f9rqIp54PlqsQQ7q843IQKZHD2WZHxpsJ/Pzs1xuvO2LeUMuyST +dZLUnioMdwKBgDoHkvQOO29BPydfsXcmxqLaHGZFa0DBLcUmq/rQY2Go4deZL5I8 +cpQGaRAzUjeCHaEcVVoCZvp4YZZfGFm8AcFPYxpCyeCbFj4Xcqd1RD54gV18Nn2k +7kHViM2btkquPocSnp4diBcT8u9C/lYdSLWgOjIy2bOeOKWUVhl/rW01AoGBAJpj +m29dvmHy7csinS1E6voTTsANbOToka0UXmN80fxljRKCXR3mRd0DjOO+XafyCoxV +MheQnWOliJlfAz35iu5KXdN4dgtxvQohlhb5Me8uHoLyIw2If7uwKjqLPLrq3iGP +qdAdOINpMMb0XbE9dOgj3/uk047cn6DF8/ptMo2JAoGBALUVdOoFOyAnSCuOYYrO +nNMQ6F1Qut5pgtab4vJv0QyhbQsSUbsdnySBx8cegVDccLnAi2sjpPyxaebcxELd +yaW6CjDPs0EjozkW1ywdUazpJJZrme7dGJ26uxGH4WJ6abn4U31ItfqqaIAVSEAT +RPLrxJiFVDDcElvkvX7ypNbF -----END PRIVATE KEY----- diff --git a/internal/tls/testdata/tls-ca.crt b/internal/tls/testdata/tls-ca.crt index 4b861f4f40..ed672ec812 100644 --- a/internal/tls/testdata/tls-ca.crt +++ b/internal/tls/testdata/tls-ca.crt @@ -1,29 +1,29 @@ -----BEGIN CERTIFICATE----- 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 -qubuxdWE+FRLgfs3Ywv1JckNAec7Jg0FA2w= +BBQgcadhkwjSOcUSAHdQH39IRo7UTzANBgkqhkiG9w0BAQsFAAOCAgEAUiN53OqO +bH2V4JPKajN9JbqBF5RkhPAndV5TgaS0/ip4KFGImhb43I2+2Xv3NIWhdLW9LCPe +OgN5QdILMafNvhJsTz6sIjAxsSrYmYA6AZTlvdl2WZglrxU7QL4hkvi69Tbof4xT +T4BieKVgQ9buUxyk3ihj3BICcFrhXVBZIeJ+gmOpzoPviTBYWRzLrHNt7guYNS0y +f/H//TKXOBvPjDOSOMLItDu14Vu4sXQCYckXAcIqJ97CnlWKi45Rma1qD12LigaG +gk8cO879XqZrlMKZwe9Cjf18FKs6lhNLZp95GAqgQ6J7LZPVNWGabsiPluUxzIME +EoL+q5io5ndoTVothhCZJs4CT2fT+wRklHn5xa7k11cVm//rabwLxq+kTmKPZvNY +jkdtpQwF/oauN/ykCESdOZu4RE6dz49yAKQmUe2ZLwrC4i/Hp4031kyXF3vZZF4c +kvA3M1tJxVWJpRc4laJvcKWQIxFMyZirvfWNJt9Nmd2e2Yq0jeu73uVhDDLLf9nB +GmRvzbFetuuiyl/b27Nwnweobcy5fJewhnbo2NuJYxwfQDZv5SlnbrBiJRKzqPFQ +Cj28AriR+kyXhPfjyT0A9kH9A8GQQ51DPjDEbdGjSzatzTOYPPdBLSaHK+nNV3uM +ePw/GTTH5O72x6IyZJIE5OCUZrKlNUlUIXk= -----END CERTIFICATE----- diff --git a/translator/translate/otel/extension/agenthealth/translator.go b/translator/translate/otel/extension/agenthealth/translator.go index ef39f9390c..c4320374bf 100644 --- a/translator/translate/otel/extension/agenthealth/translator.go +++ b/translator/translate/otel/extension/agenthealth/translator.go @@ -35,10 +35,21 @@ type translator struct { operations []string isUsageDataEnabled bool factory extension.Factory + statuscodeonly bool } var _ common.Translator[component.Config] = (*translator)(nil) +func NewTranslatorWithStatusCode(name component.DataType, operations []string, statuscodeonly bool) common.Translator[component.Config] { + return &translator{ + name: name.String(), + operations: operations, + factory: agenthealth.NewFactory(), + isUsageDataEnabled: envconfig.IsUsageDataEnabled(), + statuscodeonly: statuscodeonly, + } +} + func NewTranslator(name component.DataType, operations []string) common.Translator[component.Config] { return &translator{ name: name.String(), @@ -59,6 +70,10 @@ func (t *translator) Translate(conf *confmap.Conf) (component.Config, error) { if usageData, ok := common.GetBool(conf, common.ConfigKey(common.AgentKey, usageDataKey)); ok { cfg.IsUsageDataEnabled = cfg.IsUsageDataEnabled && usageData } + cfg.IsOnlyStatusCodeEnabled = t.statuscodeonly + if t.statuscodeonly != false && t.statuscodeonly { + return cfg, nil + } cfg.Stats = agent.StatsConfig{ Operations: t.operations, UsageFlags: map[agent.Flag]any{