Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add metric for instrumented processes #928

Merged
merged 6 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/sources/metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,4 @@ Beyla can be [configured to report internal metrics]({{< relref "./configure/opt
| `otel_trace_exports` | Counter | Length of the trace batches submitted to the remote OTEL collector |
| `otel_trace_export_errors` | CounterVec | Error count on each failed OTEL trace export, by error type |
| `prometheus_http_requests` | CounterVec | Number of requests towards the Prometheus Scrape endpoint, faceted by HTTP port and path |
| `beyla_instrumented_processes` | GaugeVec | Instrumented processes by Beyla, with process name |
3 changes: 3 additions & 0 deletions pkg/internal/discover/attacher.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,15 @@ func (ta *TraceAttacher) getTracer(ie *Instrumentable) (*ebpf.ProcessTracer, boo
ie.FileInfo.Service.SDKLanguage = ie.Type
// allowing the tracer to forward traces from the new PID and its children processes
monitorPIDs(tracer, ie)
ta.Metrics.InstrumentProcess(ie.FileInfo.ExecutableName())
if tracer.Type == ebpf.Generic {
monitorPIDs(ta.reusableTracer, ie)
}
ta.log.Debug(".done")
return nil, false
}
ta.log.Info("instrumenting process", "cmd", ie.FileInfo.CmdExePath, "pid", ie.FileInfo.Pid)
ta.Metrics.InstrumentProcess(ie.FileInfo.ExecutableName())

// builds a tracer for that executable
var programs []ebpf.Tracer
Expand Down Expand Up @@ -205,6 +207,7 @@ func (ta *TraceAttacher) notifyProcessDeletion(ie *Instrumentable) {
// notifying the tracer to block any trace from that PID
// to avoid that a new process reusing this PID could send traces
// unless explicitly allowed
ta.Metrics.UninstrumentProcess(ie.FileInfo.ExecutableName())
tracer.BlockPID(uint32(ie.FileInfo.Pid), ie.FileInfo.Ns)

// if there are no more trace instances for a Go program, we need to notify that
Expand Down
6 changes: 6 additions & 0 deletions pkg/internal/imetrics/imetrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ type Reporter interface {
OTELTraceExportError(err error)
// PrometheusRequest is invoked every time the Prometheus exporter is invoked, for a given port and path
PrometheusRequest(port, path string)
// InstrumentProcess is invoked every time a new process is instrumented
InstrumentProcess(processName string)
// UninstrumentProcess is invoked every time a process is removed from the instrumented processed
UninstrumentProcess(processName string)
}

// NoopReporter is a metrics Reporter that just does nothing
Expand All @@ -40,3 +44,5 @@ func (n NoopReporter) OTELMetricExportError(_ error) {}
func (n NoopReporter) OTELTraceExport(_ int) {}
func (n NoopReporter) OTELTraceExportError(_ error) {}
func (n NoopReporter) PrometheusRequest(_, _ string) {}
func (n NoopReporter) InstrumentProcess(_ string) {}
func (n NoopReporter) UninstrumentProcess(_ string) {}
30 changes: 22 additions & 8 deletions pkg/internal/imetrics/iprom.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@ type PrometheusConfig struct {

// PrometheusReporter is an internal metrics Reporter that exports to Prometheus
type PrometheusReporter struct {
connector *connector.PrometheusManager
tracerFlushes prometheus.Histogram
otelMetricExports prometheus.Counter
otelMetricExportErrs *prometheus.CounterVec
otelTraceExports prometheus.Counter
otelTraceExportErrs *prometheus.CounterVec
prometheusRequests *prometheus.CounterVec
connector *connector.PrometheusManager
tracerFlushes prometheus.Histogram
otelMetricExports prometheus.Counter
otelMetricExportErrs *prometheus.CounterVec
otelTraceExports prometheus.Counter
otelTraceExportErrs *prometheus.CounterVec
prometheusRequests *prometheus.CounterVec
instrumentedProcesses *prometheus.GaugeVec
}

func NewPrometheusReporter(cfg *PrometheusConfig, manager *connector.PrometheusManager) *PrometheusReporter {
Expand Down Expand Up @@ -61,14 +62,19 @@ func NewPrometheusReporter(cfg *PrometheusConfig, manager *connector.PrometheusM
Name: "prometheus_http_requests",
Help: "requests towards the Prometheus Scrape endpoint",
}, []string{"port", "path"}),
instrumentedProcesses: prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "beyla_instrumented_processes",
Help: "instrumented processes by Beyla",
}, []string{"process_name"}),
}
manager.Register(cfg.Port, cfg.Path,
pr.tracerFlushes,
pr.otelMetricExports,
pr.otelMetricExportErrs,
pr.otelTraceExports,
pr.otelTraceExportErrs,
pr.prometheusRequests)
pr.prometheusRequests,
pr.instrumentedProcesses)

return pr
}
Expand Down Expand Up @@ -100,3 +106,11 @@ func (p *PrometheusReporter) OTELTraceExportError(err error) {
func (p *PrometheusReporter) PrometheusRequest(port, path string) {
p.prometheusRequests.WithLabelValues(port, path).Inc()
}

func (p *PrometheusReporter) InstrumentProcess(processName string) {
p.instrumentedProcesses.WithLabelValues(processName).Inc()
}

func (p *PrometheusReporter) UninstrumentProcess(processName string) {
p.instrumentedProcesses.WithLabelValues(processName).Dec()
}
5 changes: 5 additions & 0 deletions test/integration/configs/prometheus-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,8 @@ scrape_configs:
static_configs:
- targets:
- 'otelcol:8888'
- job_name: autoinstrumenter-collector
honor_labels: true
static_configs:
- targets:
- '172.17.0.1:8999'
5 changes: 5 additions & 0 deletions test/integration/docker-compose-multiexec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ services:
BEYLA_METRICS_REPORT_TARGET: "true"
BEYLA_METRICS_REPORT_PEER: "true"
BEYLA_HOSTNAME: "beyla"
BEYLA_INTERNAL_METRICS_PROMETHEUS_PORT: 8999
BEYLA_INTERNAL_METRICS_PROMETHEUS_PATH: /metrics
ports:
- "8999:8999"

# OpenTelemetry Collector
otelcol:
Expand Down Expand Up @@ -166,6 +170,7 @@ services:
- --storage.tsdb.path=/prometheus
- --web.enable-lifecycle
- --web.route-prefix=/
- --log.level=debug
volumes:
- ./configs/:/etc/prometheus
ports:
Expand Down
33 changes: 33 additions & 0 deletions test/integration/multiprocess_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
package integration

import (
"fmt"
"net/http"
"path"
"strconv"
"testing"
"time"

Expand Down Expand Up @@ -96,6 +98,10 @@ func TestMultiProcess(t *testing.T) {
})
}

t.Run("Instrumented processes metric", func(t *testing.T) {
checkInstrumentedProcessesMetric(t)
})

t.Run("BPF pinning folders mounted", func(t *testing.T) {
// 1 beyla pinned map folder for all processes
testBPFPinningMounted(t)
Expand Down Expand Up @@ -130,3 +136,30 @@ func checkReportedOnlyOnce(t *testing.T, baseURL, serviceName string) {
}, test.Interval(1000*time.Millisecond))

}

func checkInstrumentedProcessesMetric(t *testing.T) {
pq := prom.Client{HostPort: prometheusHostPort}
test.Eventually(t, testTimeout, func(t require.TestingT) {
// we expected to have this in Prometheus at this point
processes := map[string]int{
"python3.11": 10,
"greetings": 2,
"java": 1,
"node": 2,
"ruby": 2,
"duped_service": 1,
"testserver": 2,
"rename1": 1,
}

for processName, expectedCount := range processes {
results, err := pq.Query(fmt.Sprintf(`beyla_instrumented_processes{process_name="%s"}`, processName))
require.NoError(t, err)
value, err := strconv.Atoi(results[0].Value[1].(string))
require.NoError(t, err)
assert.Equal(t, expectedCount, value)
}

}, test.Interval(1000*time.Millisecond))

}
Loading