-
Notifications
You must be signed in to change notification settings - Fork 139
Expand file tree
/
Copy pathinternal_metrics_test.go
More file actions
142 lines (115 loc) · 4.9 KB
/
Copy pathinternal_metrics_test.go
File metadata and controls
142 lines (115 loc) · 4.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package integration
import (
"net/http"
"path"
"strconv"
"testing"
"time"
"github.com/prometheus/common/expfmt"
"github.com/prometheus/common/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
dockercompose "go.opentelemetry.io/obi/internal/test/integration/components/docker"
"go.opentelemetry.io/obi/internal/test/integration/components/promtest"
ti "go.opentelemetry.io/obi/pkg/test/integration"
)
func TestInstrumentationErrors(t *testing.T) {
compose, err := dockercompose.ComposeSuite("docker-compose-error-test.yml", path.Join(pathOutput, "test-suite-instrumentation-errors.log"))
require.NoError(t, err)
// Run OBI without privileged mode to force instrumentation errors
compose.Env = append(compose.Env, `OTEL_EBPF_EXECUTABLE_PATH=`, `OTEL_EBPF_OPEN_PORT=`)
require.NoError(t, compose.Up())
t.Run("Instrumentation error metrics", func(t *testing.T) {
checkInstrumentationErrorMetrics(t)
})
require.NoError(t, compose.Close())
}
func TestAvoidedServicesMetrics(t *testing.T) {
network := setupDockerNetwork(t)
setupContainerPrometheus(t, network, "prometheus-config.yml")
setupContainerJaeger(t, network)
setupContainerCollector(t, network, "otelcol-config.yml")
setupGoOTelTestServer(t, network, []string{
"OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=http://otelcol:4318",
"OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://jaeger:4318",
})
if t.Failed() {
return
}
// Start OBI to instrument the test server
o := obi{
Env: []string{
"OTEL_EBPF_OPEN_PORT=8080",
"OTEL_EBPF_INTERNAL_METRICS_PROMETHEUS_PORT=8999",
},
}
if !KernelLockdownMode() {
o.SecurityConfigSuffix = "_none"
}
o.instrument(t, network, "obi-config-go-otel.yml")
t.Run("Avoided services metrics are recorded", func(t *testing.T) {
// Wait for the service to start and make some requests to trigger OTLP detection
otelWaitForTestComponents(t, "http://localhost:8080", "/smoke")
// Give time for the service to export metrics/traces
time.Sleep(15 * time.Second)
// Make additional requests to ensure OTLP endpoints are hit
for i := 0; i < 3; i++ {
ti.DoHTTPGet(t, "http://localhost:8080/rolldice", 200)
time.Sleep(1 * time.Second)
}
// Check that avoided services metrics are present
checkAvoidedServicesMetrics(t)
})
}
func checkInstrumentationErrorMetrics(t *testing.T) {
pq := promtest.Client{HostPort: prometheusHostPort}
require.EventuallyWithT(t, func(ct *assert.CollectT) {
results, err := pq.Query(`obi_instrumentation_errors_total`)
require.NoError(ct, err)
require.GreaterOrEqual(ct, len(results), 1, "obi_instrumentation_errors_total metric should be present")
// Verify we have some errors and proper labels
totalErrors := 0
for _, result := range results {
labels := result.Metric
require.Contains(ct, labels, "process_name", "process_name label should be present")
require.Contains(ct, labels, "error_type", "error_type label should be present")
value, err := strconv.Atoi(result.Value[1].(string))
require.NoError(ct, err)
totalErrors += value
}
// We should have at least some errors when running without privileges
require.Positive(ct, totalErrors, "Should have instrumentation errors when running without privileges")
}, testTimeout, 1000*time.Millisecond)
}
func checkAvoidedServicesMetrics(t *testing.T) {
const internalMetricsURL = "http://localhost:8999/internal/metrics"
require.EventuallyWithT(t, func(ct *assert.CollectT) {
parser := expfmt.NewTextParser(model.UTF8Validation)
resp, err := http.Get(internalMetricsURL)
require.NoError(ct, err)
require.Equal(ct, http.StatusOK, resp.StatusCode)
metrics, err := parser.TextToMetricFamilies(resp.Body)
require.NoError(ct, err)
metricFamily, ok := metrics["obi_avoided_services"]
require.True(ct, ok, "Expected obi_avoided_services metric to be present")
require.NotEmpty(ct, metricFamily.Metric, "Expected avoided services metrics to have values")
// Just check the first occurrence
metric := metricFamily.Metric[0]
labelMap := make(map[string]string)
for _, label := range metric.Label {
labelMap[label.GetName()] = label.GetValue()
}
// Assert specific values for service_name and service_namespace
assert.Equal(ct, "rolldice", labelMap["service_name"], "service_name label should be 'rolldice'")
assert.Equal(ct, "integration-test", labelMap["service_namespace"], "service_namespace label should be 'integration-test'")
assert.NotEmpty(ct, labelMap["telemetry_type"], "telemetry_type label should not be empty")
assert.Condition(ct, func() bool {
return labelMap["telemetry_type"] == "metrics" || labelMap["telemetry_type"] == "traces"
}, "telemetry_type label should be either 'metrics' or 'traces'")
if metric.Gauge != nil {
assert.Greater(ct, metric.Gauge.GetValue(), float64(0), "Expected avoided service metric value to be > 0")
}
}, testTimeout, 1000*time.Millisecond)
}