diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index b27dfa59319e..80540ae4848e 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -18,6 +18,6 @@ jobs: with: go-version: "1.21" - name: Set OTEL Exporter Endpoint - run: echo "OTEL_EXPORTER_ENDPOINT=http://172.17.0.1:8080" >> $GITHUB_ENV + run: echo "OTEL_EXPORTER_ENDPOINT=172.17.0.1:4318" >> $GITHUB_ENV - name: Run tests run: make integration-test diff --git a/CHANGELOG.md b/CHANGELOG.md index 8db42118d8cf..01d1f99a8a9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,48 @@ internal API changes are not present. Main (unreleased) ----------------- +### Security fixes + +- Fix CVE-2023-47108 by updating `otelgrpc` from v0.45.0 to v0.46.0. (@hainenber) + +### Features + +- Agent Management: Introduce support for templated configuration. (@jcreixell) + +### Enhancements + +- Flow Windows service: Support environment variables. (@jkroepke) + +- Allow disabling collection of root Cgroup stats in + `prometheus.exporter.cadvisor` (flow mode) and the `cadvisor` integration + (static mode). (@hainenber) + +- Grafana Agent on Windows now automatically restarts on failure. (@hainenber) + +- Added metrics, alerts and dashboard visualisations to help diagnose issues + with unhealthy components and components that take too long to evaluate. (@thampiotr) + +- The `http` config block may now reference exports from any component. + Previously, only `remote.*` and `local.*` components could be referenced + without a circular dependency. (@rfratto) + +- Add a `resource_to_telemetry_conversion` argument to `otelcol.exporter.prometheus` + for converting resource attributes to Prometheus labels. (@hainenber) + +- `pyroscope.ebpf` support python on arm64 platforms. (@korniltsev) + +### Bugfixes + +- Permit `X-Faro-Session-ID` header in CORS requests for the `faro.receiver` + component (flow mode) and the `app_agent_receiver` integration (static mode). + (@cedricziel) + +- Fix issue with windows_exporter defaults not being set correctly. (@mattdurham) + +- Fix agent crash when process null OTel's fan out consumers. (@hainenber) + +- Fix issue in `prometheus.operator.*` where targets would be dropped if two crds share a common prefix in their names. (@Paul424, @captncraig) + v0.38.0 (2023-11-21) -------------------- @@ -91,7 +133,7 @@ v0.38.0 (2023-11-21) - Make component list sortable in web UI. (@hainenber) - Adds new metrics (`mssql_server_total_memory_bytes`, `mssql_server_target_memory_bytes`, - and `mssql_available_commit_memory_bytes`) for `mssql` integration. + and `mssql_available_commit_memory_bytes`) for `mssql` integration (@StefanKurek). - Grafana Agent Operator: `config-reloader` container no longer runs as root. (@rootmout) @@ -108,6 +150,8 @@ v0.38.0 (2023-11-21) - Allow agent to start with `module.git` config if cached before. (@hainenber) +- Adds new optional config parameter `query_config` to `mssql` integration to allow for custom metrics (@StefanKurek) + ### Bugfixes - Set exit code 1 on grafana-agentctl non-runnable command. (@fgouteroux) @@ -193,6 +237,9 @@ v0.37.4 (2023-11-06) - Fix a bug where reloading the configuration of a `loki.write` component lead to a panic. (@tpaschalis) +- Added Kubernetes service resolver to static node's loadbalancing exporter + and to Flow's `otelcol.exporter.loadbalancing`. (@ptodev) + v0.37.3 (2023-10-26) ----------------- diff --git a/cmd/grafana-agent-service/config_windows.go b/cmd/grafana-agent-service/config_windows.go index 961e95ad5e51..e4d712585986 100644 --- a/cmd/grafana-agent-service/config_windows.go +++ b/cmd/grafana-agent-service/config_windows.go @@ -16,6 +16,11 @@ type config struct { // not included. Args []string + // Environment holds environment variables for the Grafana Agent service. + // Each item represents an environment variable in form "key=value". + // All environments variables from the current process with be merged into Environment + Environment []string + // WorkingDirectory points to the working directory to run the Grafana Agent // binary from. WorkingDirectory string @@ -42,9 +47,15 @@ func loadConfig() (*config, error) { return nil, fmt.Errorf("failed to retrieve key Arguments: %w", err) } + env, _, err := agentKey.GetStringsValue("Environment") + if err != nil { + return nil, fmt.Errorf("failed to retrieve key Environment: %w", err) + } + return &config{ ServicePath: servicePath, Args: args, + Environment: env, WorkingDirectory: filepath.Dir(servicePath), }, nil } diff --git a/cmd/grafana-agent-service/main_windows.go b/cmd/grafana-agent-service/main_windows.go index f3660f73e7cc..a94a71228516 100644 --- a/cmd/grafana-agent-service/main_windows.go +++ b/cmd/grafana-agent-service/main_windows.go @@ -29,9 +29,10 @@ func main() { } cfg := serviceManagerConfig{ - Path: managerConfig.ServicePath, - Args: managerConfig.Args, - Dir: managerConfig.WorkingDirectory, + Path: managerConfig.ServicePath, + Args: managerConfig.Args, + Environment: managerConfig.Environment, + Dir: managerConfig.WorkingDirectory, // Send logs directly to the event logger. Stdout: logger, diff --git a/cmd/grafana-agent-service/service.go b/cmd/grafana-agent-service/service.go index 10060e19cc28..c302a98a1a36 100644 --- a/cmd/grafana-agent-service/service.go +++ b/cmd/grafana-agent-service/service.go @@ -24,6 +24,9 @@ type serviceManagerConfig struct { // Args of the binary to run, not including the command itself. Args []string + // Environment of the binary to run, including the command environment itself. + Environment []string + // Dir specifies the working directory to run the binary from. If Dir is // empty, the working directory of the current process is used. Dir string @@ -84,5 +87,7 @@ func (svc *serviceManager) buildCommand(ctx context.Context) *exec.Cmd { cmd.Dir = svc.cfg.Dir cmd.Stdout = svc.cfg.Stdout cmd.Stderr = svc.cfg.Stderr + cmd.Env = os.Environ() + cmd.Env = append(cmd.Env, svc.cfg.Environment...) return cmd } diff --git a/cmd/grafana-agent-service/service_test.go b/cmd/grafana-agent-service/service_test.go index d6389132071b..a1d3124b034c 100644 --- a/cmd/grafana-agent-service/service_test.go +++ b/cmd/grafana-agent-service/service_test.go @@ -30,8 +30,9 @@ func Test_serviceManager(t *testing.T) { listenHost := getListenHost(t) mgr := newServiceManager(l, serviceManagerConfig{ - Path: serviceBinary, - Args: []string{"-listen-addr", listenHost}, + Path: serviceBinary, + Args: []string{"-listen-addr", listenHost}, + Environment: []string{"LISTEN=" + listenHost}, }) go mgr.Run(componenttest.TestContext(t)) @@ -40,6 +41,12 @@ func Test_serviceManager(t *testing.T) { require.NoError(t, err) require.Equal(t, []byte("Hello, world!"), resp) }) + + util.Eventually(t, func(t require.TestingT) { + resp, err := makeServiceRequest(listenHost, "/echo/env", nil) + require.NoError(t, err) + require.Contains(t, string(resp), "LISTEN="+listenHost) + }) }) t.Run("terminates service binary", func(t *testing.T) { diff --git a/cmd/grafana-agent-service/testdata/example_service.go b/cmd/grafana-agent-service/testdata/example_service.go index ff11e61dfd85..64808b1b8608 100644 --- a/cmd/grafana-agent-service/testdata/example_service.go +++ b/cmd/grafana-agent-service/testdata/example_service.go @@ -7,6 +7,7 @@ import ( "net" "net/http" "os" + "strings" ) func main() { @@ -46,6 +47,9 @@ func run() error { mux.HandleFunc("/echo/response", func(w http.ResponseWriter, r *http.Request) { _, _ = io.Copy(w, r.Body) }) + mux.HandleFunc("/echo/env", func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write([]byte(strings.Join(os.Environ(), "\n"))) + }) srv := &http.Server{Handler: mux} _ = srv.Serve(lis) diff --git a/component/faro/receiver/handler.go b/component/faro/receiver/handler.go index fb8511e0bbde..636f00859e2b 100644 --- a/component/faro/receiver/handler.go +++ b/component/faro/receiver/handler.go @@ -69,7 +69,7 @@ func (h *handler) Update(args ServerArguments) { if len(args.CORSAllowedOrigins) > 0 { h.cors = cors.New(cors.Options{ AllowedOrigins: args.CORSAllowedOrigins, - AllowedHeaders: []string{apiKeyHeader, "content-type"}, + AllowedHeaders: []string{apiKeyHeader, "content-type", "x-faro-session-id"}, }) } else { h.cors = nil // Disable cors. diff --git a/component/loki/source/kubernetes/kubernetes.go b/component/loki/source/kubernetes/kubernetes.go index ce11017c6f87..80792520e9c3 100644 --- a/component/loki/source/kubernetes/kubernetes.go +++ b/component/loki/source/kubernetes/kubernetes.go @@ -24,9 +24,8 @@ import ( func init() { component.Register(component.Registration{ - Name: "loki.source.kubernetes", - Args: Arguments{}, - NeedsServices: []string{cluster.ServiceName}, + Name: "loki.source.kubernetes", + Args: Arguments{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { return New(opts, args.(Arguments)) diff --git a/component/loki/source/podlogs/podlogs.go b/component/loki/source/podlogs/podlogs.go index 8fa4b48b96c0..f7a194e4b79a 100644 --- a/component/loki/source/podlogs/podlogs.go +++ b/component/loki/source/podlogs/podlogs.go @@ -26,9 +26,8 @@ import ( func init() { component.Register(component.Registration{ - Name: "loki.source.podlogs", - Args: Arguments{}, - NeedsServices: []string{cluster.ServiceName}, + Name: "loki.source.podlogs", + Args: Arguments{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { return New(opts, args.(Arguments)) diff --git a/component/module/file/file.go b/component/module/file/file.go index 68b20760d5f4..e40c5dc9ca48 100644 --- a/component/module/file/file.go +++ b/component/module/file/file.go @@ -9,19 +9,14 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/local/file" "github.com/grafana/agent/component/module" - "github.com/grafana/agent/service/cluster" - "github.com/grafana/agent/service/http" - "github.com/grafana/agent/service/labelstore" - otel_service "github.com/grafana/agent/service/otel" "github.com/grafana/river/rivertypes" ) func init() { component.Register(component.Registration{ - Name: "module.file", - Args: Arguments{}, - Exports: module.Exports{}, - NeedsServices: []string{http.ServiceName, cluster.ServiceName, otel_service.ServiceName, labelstore.ServiceName}, + Name: "module.file", + Args: Arguments{}, + Exports: module.Exports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { return New(opts, args.(Arguments)) diff --git a/component/module/git/git.go b/component/module/git/git.go index 6a211fdc8843..dfe17ef2cb4a 100644 --- a/component/module/git/git.go +++ b/component/module/git/git.go @@ -14,18 +14,13 @@ import ( "github.com/grafana/agent/component/module" "github.com/grafana/agent/component/module/git/internal/vcs" "github.com/grafana/agent/pkg/flow/logging/level" - "github.com/grafana/agent/service/cluster" - "github.com/grafana/agent/service/http" - "github.com/grafana/agent/service/labelstore" - otel_service "github.com/grafana/agent/service/otel" ) func init() { component.Register(component.Registration{ - Name: "module.git", - Args: Arguments{}, - Exports: module.Exports{}, - NeedsServices: []string{http.ServiceName, cluster.ServiceName, otel_service.ServiceName, labelstore.ServiceName}, + Name: "module.git", + Args: Arguments{}, + Exports: module.Exports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { return New(opts, args.(Arguments)) diff --git a/component/module/http/http.go b/component/module/http/http.go index a2d48f6f53b8..bc1be2158fdb 100644 --- a/component/module/http/http.go +++ b/component/module/http/http.go @@ -9,19 +9,14 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/module" remote_http "github.com/grafana/agent/component/remote/http" - "github.com/grafana/agent/service/cluster" - http_service "github.com/grafana/agent/service/http" - "github.com/grafana/agent/service/labelstore" - otel_service "github.com/grafana/agent/service/otel" "github.com/grafana/river/rivertypes" ) func init() { component.Register(component.Registration{ - Name: "module.http", - Args: Arguments{}, - Exports: module.Exports{}, - NeedsServices: []string{http_service.ServiceName, cluster.ServiceName, otel_service.ServiceName, labelstore.ServiceName}, + Name: "module.http", + Args: Arguments{}, + Exports: module.Exports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { return New(opts, args.(Arguments)) diff --git a/component/module/string/string.go b/component/module/string/string.go index 7305abd75073..bd3e6193f441 100644 --- a/component/module/string/string.go +++ b/component/module/string/string.go @@ -5,19 +5,14 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/module" - "github.com/grafana/agent/service/cluster" - "github.com/grafana/agent/service/http" - "github.com/grafana/agent/service/labelstore" - otel_service "github.com/grafana/agent/service/otel" "github.com/grafana/river/rivertypes" ) func init() { component.Register(component.Registration{ - Name: "module.string", - Args: Arguments{}, - Exports: module.Exports{}, - NeedsServices: []string{http.ServiceName, cluster.ServiceName, otel_service.ServiceName, labelstore.ServiceName}, + Name: "module.string", + Args: Arguments{}, + Exports: module.Exports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { return New(opts, args.(Arguments)) diff --git a/component/otelcol/auth/basic/basic.go b/component/otelcol/auth/basic/basic.go index b82209e388a3..ceae037d7f40 100644 --- a/component/otelcol/auth/basic/basic.go +++ b/component/otelcol/auth/basic/basic.go @@ -4,7 +4,6 @@ package basic import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol/auth" - otel_service "github.com/grafana/agent/service/otel" "github.com/grafana/river/rivertypes" "github.com/open-telemetry/opentelemetry-collector-contrib/extension/basicauthextension" otelcomponent "go.opentelemetry.io/collector/component" @@ -14,10 +13,9 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.auth.basic", - Args: Arguments{}, - Exports: auth.Exports{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.auth.basic", + Args: Arguments{}, + Exports: auth.Exports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := basicauthextension.NewFactory() diff --git a/component/otelcol/auth/bearer/bearer.go b/component/otelcol/auth/bearer/bearer.go index bfcb40e6b55d..d99ea1b7cee9 100644 --- a/component/otelcol/auth/bearer/bearer.go +++ b/component/otelcol/auth/bearer/bearer.go @@ -4,7 +4,6 @@ package bearer import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol/auth" - otel_service "github.com/grafana/agent/service/otel" "github.com/grafana/river/rivertypes" "github.com/open-telemetry/opentelemetry-collector-contrib/extension/bearertokenauthextension" otelcomponent "go.opentelemetry.io/collector/component" @@ -14,10 +13,9 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.auth.bearer", - Args: Arguments{}, - Exports: auth.Exports{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.auth.bearer", + Args: Arguments{}, + Exports: auth.Exports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := bearertokenauthextension.NewFactory() diff --git a/component/otelcol/auth/headers/headers.go b/component/otelcol/auth/headers/headers.go index 56156759cac4..b0530639b8b4 100644 --- a/component/otelcol/auth/headers/headers.go +++ b/component/otelcol/auth/headers/headers.go @@ -8,7 +8,6 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol/auth" - otel_service "github.com/grafana/agent/service/otel" "github.com/grafana/river" "github.com/grafana/river/rivertypes" "github.com/open-telemetry/opentelemetry-collector-contrib/extension/headerssetterextension" @@ -18,10 +17,9 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.auth.headers", - Args: Arguments{}, - Exports: auth.Exports{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.auth.headers", + Args: Arguments{}, + Exports: auth.Exports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := headerssetterextension.NewFactory() diff --git a/component/otelcol/auth/oauth2/oauth2.go b/component/otelcol/auth/oauth2/oauth2.go index 3396dca94d06..6007bd59236a 100644 --- a/component/otelcol/auth/oauth2/oauth2.go +++ b/component/otelcol/auth/oauth2/oauth2.go @@ -7,7 +7,6 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/auth" - otel_service "github.com/grafana/agent/service/otel" "github.com/grafana/river/rivertypes" "github.com/open-telemetry/opentelemetry-collector-contrib/extension/oauth2clientauthextension" otelcomponent "go.opentelemetry.io/collector/component" @@ -17,10 +16,9 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.auth.oauth2", - Args: Arguments{}, - Exports: auth.Exports{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.auth.oauth2", + Args: Arguments{}, + Exports: auth.Exports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := oauth2clientauthextension.NewFactory() diff --git a/component/otelcol/auth/sigv4/sigv4.go b/component/otelcol/auth/sigv4/sigv4.go index 81336757fb6b..0a3db55c546b 100644 --- a/component/otelcol/auth/sigv4/sigv4.go +++ b/component/otelcol/auth/sigv4/sigv4.go @@ -3,7 +3,6 @@ package sigv4 import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol/auth" - otel_service "github.com/grafana/agent/service/otel" "github.com/open-telemetry/opentelemetry-collector-contrib/extension/sigv4authextension" otelcomponent "go.opentelemetry.io/collector/component" otelextension "go.opentelemetry.io/collector/extension" @@ -11,10 +10,9 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.auth.sigv4", - Args: Arguments{}, - Exports: auth.Exports{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.auth.sigv4", + Args: Arguments{}, + Exports: auth.Exports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := sigv4authextension.NewFactory() diff --git a/component/otelcol/connector/servicegraph/servicegraph.go b/component/otelcol/connector/servicegraph/servicegraph.go index ce171700569f..e5370d89f620 100644 --- a/component/otelcol/connector/servicegraph/servicegraph.go +++ b/component/otelcol/connector/servicegraph/servicegraph.go @@ -7,7 +7,6 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/connector" - otel_service "github.com/grafana/agent/service/otel" "github.com/grafana/river" "github.com/open-telemetry/opentelemetry-collector-contrib/connector/servicegraphconnector" "github.com/open-telemetry/opentelemetry-collector-contrib/processor/servicegraphprocessor" @@ -17,10 +16,9 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.connector.servicegraph", - Args: Arguments{}, - Exports: otelcol.ConsumerExports{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.connector.servicegraph", + Args: Arguments{}, + Exports: otelcol.ConsumerExports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := servicegraphconnector.NewFactory() diff --git a/component/otelcol/connector/spanmetrics/spanmetrics.go b/component/otelcol/connector/spanmetrics/spanmetrics.go index 45b8b1f4bd0a..2a32c9b49642 100644 --- a/component/otelcol/connector/spanmetrics/spanmetrics.go +++ b/component/otelcol/connector/spanmetrics/spanmetrics.go @@ -8,7 +8,6 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/connector" - otel_service "github.com/grafana/agent/service/otel" "github.com/grafana/river" "github.com/open-telemetry/opentelemetry-collector-contrib/connector/spanmetricsconnector" otelcomponent "go.opentelemetry.io/collector/component" @@ -17,10 +16,9 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.connector.spanmetrics", - Args: Arguments{}, - Exports: otelcol.ConsumerExports{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.connector.spanmetrics", + Args: Arguments{}, + Exports: otelcol.ConsumerExports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := spanmetricsconnector.NewFactory() diff --git a/component/otelcol/exporter/loadbalancing/loadbalancing.go b/component/otelcol/exporter/loadbalancing/loadbalancing.go index 35a42df3a328..3455318fef38 100644 --- a/component/otelcol/exporter/loadbalancing/loadbalancing.go +++ b/component/otelcol/exporter/loadbalancing/loadbalancing.go @@ -10,7 +10,6 @@ import ( "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/auth" "github.com/grafana/agent/component/otelcol/exporter" - otel_service "github.com/grafana/agent/service/otel" "github.com/grafana/river" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/loadbalancingexporter" otelcomponent "go.opentelemetry.io/collector/component" @@ -24,10 +23,9 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.exporter.loadbalancing", - Args: Arguments{}, - Exports: otelcol.ConsumerExports{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.exporter.loadbalancing", + Args: Arguments{}, + Exports: otelcol.ConsumerExports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := loadbalancingexporter.NewFactory() diff --git a/component/otelcol/exporter/logging/logging.go b/component/otelcol/exporter/logging/logging.go index c4dc735c4fca..13d12fbf312e 100644 --- a/component/otelcol/exporter/logging/logging.go +++ b/component/otelcol/exporter/logging/logging.go @@ -5,7 +5,6 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/exporter" - otel_service "github.com/grafana/agent/service/otel" otelcomponent "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configtelemetry" loggingexporter "go.opentelemetry.io/collector/exporter/loggingexporter" @@ -14,10 +13,9 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.exporter.logging", - Args: Arguments{}, - Exports: otelcol.ConsumerExports{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.exporter.logging", + Args: Arguments{}, + Exports: otelcol.ConsumerExports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := loggingexporter.NewFactory() diff --git a/component/otelcol/exporter/otlp/otlp.go b/component/otelcol/exporter/otlp/otlp.go index c58d434d992a..7ca10d2c2c0b 100644 --- a/component/otelcol/exporter/otlp/otlp.go +++ b/component/otelcol/exporter/otlp/otlp.go @@ -7,7 +7,6 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/exporter" - otel_service "github.com/grafana/agent/service/otel" otelcomponent "go.opentelemetry.io/collector/component" otelpexporterhelper "go.opentelemetry.io/collector/exporter/exporterhelper" "go.opentelemetry.io/collector/exporter/otlpexporter" @@ -16,10 +15,9 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.exporter.otlp", - Args: Arguments{}, - Exports: otelcol.ConsumerExports{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.exporter.otlp", + Args: Arguments{}, + Exports: otelcol.ConsumerExports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := otlpexporter.NewFactory() diff --git a/component/otelcol/exporter/otlphttp/otlphttp.go b/component/otelcol/exporter/otlphttp/otlphttp.go index d70d0f7f8e98..0508ec2e6289 100644 --- a/component/otelcol/exporter/otlphttp/otlphttp.go +++ b/component/otelcol/exporter/otlphttp/otlphttp.go @@ -8,7 +8,6 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/exporter" - otel_service "github.com/grafana/agent/service/otel" otelcomponent "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/exporter/otlphttpexporter" otelextension "go.opentelemetry.io/collector/extension" @@ -16,10 +15,9 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.exporter.otlphttp", - Args: Arguments{}, - Exports: otelcol.ConsumerExports{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.exporter.otlphttp", + Args: Arguments{}, + Exports: otelcol.ConsumerExports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := otlphttpexporter.NewFactory() diff --git a/component/otelcol/exporter/prometheus/internal/convert/convert.go b/component/otelcol/exporter/prometheus/internal/convert/convert.go index 3e2a2578c5a4..0a7039e7195e 100644 --- a/component/otelcol/exporter/prometheus/internal/convert/convert.go +++ b/component/otelcol/exporter/prometheus/internal/convert/convert.go @@ -65,6 +65,8 @@ type Options struct { IncludeScopeLabels bool // AddMetricSuffixes controls whether suffixes are added to metric names. Defaults to true. AddMetricSuffixes bool + // ResourceToTelemetryConversion controls whether to convert resource attributes to Prometheus-compatible datapoint attributes + ResourceToTelemetryConversion bool } var _ consumer.Metrics = (*Converter)(nil) @@ -131,6 +133,7 @@ func (conv *Converter) consumeResourceMetrics(app storage.Appender, rm pmetric.R Type: textparse.MetricTypeGauge, Help: "Target metadata", }) + resAttrs := rm.Resource().Attributes() memResource := conv.getOrCreateResource(rm.Resource()) if conv.getOpts().IncludeTargetInfo { @@ -144,7 +147,7 @@ func (conv *Converter) consumeResourceMetrics(app storage.Appender, rm pmetric.R for smcount := 0; smcount < rm.ScopeMetrics().Len(); smcount++ { sm := rm.ScopeMetrics().At(smcount) - conv.consumeScopeMetrics(app, memResource, sm) + conv.consumeScopeMetrics(app, memResource, sm, resAttrs) } } @@ -219,7 +222,7 @@ func (conv *Converter) getOrCreateResource(res pcommon.Resource) *memorySeries { return entry } -func (conv *Converter) consumeScopeMetrics(app storage.Appender, memResource *memorySeries, sm pmetric.ScopeMetrics) { +func (conv *Converter) consumeScopeMetrics(app storage.Appender, memResource *memorySeries, sm pmetric.ScopeMetrics, resAttrs pcommon.Map) { scopeMD := conv.createOrUpdateMetadata("otel_scope_info", metadata.Metadata{ Type: textparse.MetricTypeGauge, }) @@ -236,7 +239,7 @@ func (conv *Converter) consumeScopeMetrics(app storage.Appender, memResource *me for mcount := 0; mcount < sm.Metrics().Len(); mcount++ { m := sm.Metrics().At(mcount) - conv.consumeMetric(app, memResource, memScope, m) + conv.consumeMetric(app, memResource, memScope, m, resAttrs) } } @@ -274,20 +277,27 @@ func (conv *Converter) getOrCreateScope(res *memorySeries, scope pcommon.Instrum return entry } -func (conv *Converter) consumeMetric(app storage.Appender, memResource *memorySeries, memScope *memorySeries, m pmetric.Metric) { +func (conv *Converter) consumeMetric(app storage.Appender, memResource *memorySeries, memScope *memorySeries, m pmetric.Metric, resAttrs pcommon.Map) { switch m.Type() { case pmetric.MetricTypeGauge: - conv.consumeGauge(app, memResource, memScope, m) + conv.consumeGauge(app, memResource, memScope, m, resAttrs) case pmetric.MetricTypeSum: - conv.consumeSum(app, memResource, memScope, m) + conv.consumeSum(app, memResource, memScope, m, resAttrs) case pmetric.MetricTypeHistogram: - conv.consumeHistogram(app, memResource, memScope, m) + conv.consumeHistogram(app, memResource, memScope, m, resAttrs) case pmetric.MetricTypeSummary: - conv.consumeSummary(app, memResource, memScope, m) + conv.consumeSummary(app, memResource, memScope, m, resAttrs) } } -func (conv *Converter) consumeGauge(app storage.Appender, memResource *memorySeries, memScope *memorySeries, m pmetric.Metric) { +func joinAttributeMaps(from, to pcommon.Map) { + from.Range(func(k string, v pcommon.Value) bool { + v.CopyTo(to.PutEmpty(k)) + return true + }) +} + +func (conv *Converter) consumeGauge(app storage.Appender, memResource *memorySeries, memScope *memorySeries, m pmetric.Metric, resAttrs pcommon.Map) { metricName := prometheus.BuildCompliantName(m, "", conv.opts.AddMetricSuffixes) metricMD := conv.createOrUpdateMetadata(metricName, metadata.Metadata{ @@ -302,6 +312,10 @@ func (conv *Converter) consumeGauge(app storage.Appender, memResource *memorySer for dpcount := 0; dpcount < m.Gauge().DataPoints().Len(); dpcount++ { dp := m.Gauge().DataPoints().At(dpcount) + if conv.getOpts().ResourceToTelemetryConversion { + joinAttributeMaps(resAttrs, dp.Attributes()) + } + memSeries := conv.getOrCreateSeries(memResource, memScope, metricName, dp.Attributes()) if err := writeSeries(app, memSeries, dp, getNumberDataPointValue(dp)); err != nil { level.Error(conv.log).Log("msg", "failed to write metric sample", metricName, "err", err) @@ -389,7 +403,7 @@ func getNumberDataPointValue(dp pmetric.NumberDataPoint) float64 { return 0 } -func (conv *Converter) consumeSum(app storage.Appender, memResource *memorySeries, memScope *memorySeries, m pmetric.Metric) { +func (conv *Converter) consumeSum(app storage.Appender, memResource *memorySeries, memScope *memorySeries, m pmetric.Metric, resAttrs pcommon.Map) { metricName := prometheus.BuildCompliantName(m, "", conv.opts.AddMetricSuffixes) // Excerpt from the spec: @@ -430,6 +444,10 @@ func (conv *Converter) consumeSum(app storage.Appender, memResource *memorySerie for dpcount := 0; dpcount < m.Sum().DataPoints().Len(); dpcount++ { dp := m.Sum().DataPoints().At(dpcount) + if conv.getOpts().ResourceToTelemetryConversion { + joinAttributeMaps(resAttrs, dp.Attributes()) + } + memSeries := conv.getOrCreateSeries(memResource, memScope, metricName, dp.Attributes()) val := getNumberDataPointValue(dp) @@ -447,7 +465,7 @@ func (conv *Converter) consumeSum(app storage.Appender, memResource *memorySerie } } -func (conv *Converter) consumeHistogram(app storage.Appender, memResource *memorySeries, memScope *memorySeries, m pmetric.Metric) { +func (conv *Converter) consumeHistogram(app storage.Appender, memResource *memorySeries, memScope *memorySeries, m pmetric.Metric, resAttrs pcommon.Map) { metricName := prometheus.BuildCompliantName(m, "", conv.opts.AddMetricSuffixes) if m.Histogram().AggregationTemporality() != pmetric.AggregationTemporalityCumulative { @@ -469,6 +487,10 @@ func (conv *Converter) consumeHistogram(app storage.Appender, memResource *memor for dpcount := 0; dpcount < m.Histogram().DataPoints().Len(); dpcount++ { dp := m.Histogram().DataPoints().At(dpcount) + if conv.getOpts().ResourceToTelemetryConversion { + joinAttributeMaps(resAttrs, dp.Attributes()) + } + // Sum metric if dp.HasSum() { sumMetric := conv.getOrCreateSeries(memResource, memScope, metricName+"_sum", dp.Attributes()) @@ -606,7 +628,7 @@ func (conv *Converter) convertExemplar(otelExemplar pmetric.Exemplar, ts time.Ti } } -func (conv *Converter) consumeSummary(app storage.Appender, memResource *memorySeries, memScope *memorySeries, m pmetric.Metric) { +func (conv *Converter) consumeSummary(app storage.Appender, memResource *memorySeries, memScope *memorySeries, m pmetric.Metric, resAttrs pcommon.Map) { metricName := prometheus.BuildCompliantName(m, "", conv.opts.AddMetricSuffixes) metricMD := conv.createOrUpdateMetadata(metricName, metadata.Metadata{ @@ -621,6 +643,10 @@ func (conv *Converter) consumeSummary(app storage.Appender, memResource *memoryS for dpcount := 0; dpcount < m.Summary().DataPoints().Len(); dpcount++ { dp := m.Summary().DataPoints().At(dpcount) + if conv.getOpts().ResourceToTelemetryConversion { + joinAttributeMaps(resAttrs, dp.Attributes()) + } + // Sum metric { sumMetric := conv.getOrCreateSeries(memResource, memScope, metricName+"_sum", dp.Attributes()) diff --git a/component/otelcol/exporter/prometheus/internal/convert/convert_test.go b/component/otelcol/exporter/prometheus/internal/convert/convert_test.go index 80a6bce1a55b..dcace6574b6c 100644 --- a/component/otelcol/exporter/prometheus/internal/convert/convert_test.go +++ b/component/otelcol/exporter/prometheus/internal/convert/convert_test.go @@ -18,12 +18,13 @@ func TestConverter(t *testing.T) { input string expect string - showTimestamps bool - includeTargetInfo bool - includeScopeInfo bool - includeScopeLabels bool - addMetricSuffixes bool - enableOpenMetrics bool + showTimestamps bool + includeTargetInfo bool + includeScopeInfo bool + includeScopeLabels bool + addMetricSuffixes bool + enableOpenMetrics bool + resourceToTelemetryConversion bool }{ { name: "Gauge", @@ -838,6 +839,274 @@ func TestConverter(t *testing.T) { addMetricSuffixes: true, enableOpenMetrics: true, }, + { + name: "Gauge: convert resource attributes to metric label", + input: `{ + "resource_metrics": [{ + "resource": { + "attributes": [{ + "key": "service.name", + "value": { "stringValue": "myservice" } + }, { + "key": "service.instance.id", + "value": { "stringValue": "instance" } + }, { + "key": "raw", + "value": { "stringValue": "test" } + },{ + "key": "foo.one", + "value": { "stringValue": "foo" } + }, { + "key": "bar.one", + "value": { "stringValue": "bar" } + }] + }, + "scope_metrics": [{ + "metrics": [{ + "name": "test_metric_gauge", + "gauge": { + "data_points": [{ + "as_double": 1234.56 + }] + } + }] + }] + }] + }`, + expect: ` + # TYPE test_metric_gauge gauge + test_metric_gauge{bar_one="bar",foo_one="foo",instance="instance",service_instance_id="instance",job="myservice",service_name="myservice",raw="test"} 1234.56 + `, + enableOpenMetrics: true, + resourceToTelemetryConversion: true, + }, + { + name: "Gauge: NOT convert resource attributes to metric label", + input: `{ + "resource_metrics": [{ + "resource": { + "attributes": [{ + "key": "service.name", + "value": { "stringValue": "myservice" } + }, { + "key": "service.instance.id", + "value": { "stringValue": "instance" } + }, { + "key": "raw", + "value": { "stringValue": "test" } + },{ + "key": "foo.one", + "value": { "stringValue": "foo" } + }, { + "key": "bar.one", + "value": { "stringValue": "bar" } + }] + }, + "scope_metrics": [{ + "metrics": [{ + "name": "test_metric_gauge", + "gauge": { + "data_points": [{ + "as_double": 1234.56 + }] + } + }] + }] + }] + }`, + expect: ` + # TYPE test_metric_gauge gauge + test_metric_gauge{instance="instance",job="myservice"} 1234.56 + `, + enableOpenMetrics: true, + resourceToTelemetryConversion: false, + }, + { + name: "Summary: convert resource attributes to metric label", + input: `{ + "resource_metrics": [{ + "resource": { + "attributes": [{ + "key": "service.name", + "value": { "stringValue": "myservice" } + }, { + "key": "service.instance.id", + "value": { "stringValue": "instance" } + }, { + "key": "raw", + "value": { "stringValue": "test" } + },{ + "key": "foo.one", + "value": { "stringValue": "foo" } + }, { + "key": "bar.one", + "value": { "stringValue": "bar" } + }] + }, + "scope_metrics": [{ + "metrics": [{ + "name": "test_metric_summary", + "unit": "seconds", + "summary": { + "data_points": [{ + "start_time_unix_nano": 1000000000, + "time_unix_nano": 1000000000, + "count": 333, + "sum": 100, + "quantile_values": [ + { "quantile": 0, "value": 100 }, + { "quantile": 0.5, "value": 400 }, + { "quantile": 1, "value": 500 } + ] + }] + } + }] + }] + }] + }`, + expect: ` + # TYPE test_metric_summary summary + test_metric_summary{bar_one="bar",foo_one="foo",instance="instance",service_instance_id="instance",job="myservice",service_name="myservice",raw="test",quantile="0.0"} 100.0 + test_metric_summary{bar_one="bar",foo_one="foo",instance="instance",service_instance_id="instance",job="myservice",service_name="myservice",raw="test",quantile="0.5"} 400.0 + test_metric_summary{bar_one="bar",foo_one="foo",instance="instance",service_instance_id="instance",job="myservice",service_name="myservice",raw="test",quantile="1.0"} 500.0 + test_metric_summary_sum{bar_one="bar",foo_one="foo",instance="instance",service_instance_id="instance",job="myservice",service_name="myservice",raw="test"} 100.0 + test_metric_summary_count{bar_one="bar",foo_one="foo",instance="instance",service_instance_id="instance",job="myservice",service_name="myservice",raw="test"} 333 + `, + enableOpenMetrics: true, + resourceToTelemetryConversion: true, + }, + { + name: "Histogram: convert resource attributes to metric label", + input: `{ + "resource_metrics": [{ + "resource": { + "attributes": [{ + "key": "service.name", + "value": { "stringValue": "myservice" } + }, { + "key": "service.instance.id", + "value": { "stringValue": "instance" } + }, { + "key": "raw", + "value": { "stringValue": "test" } + },{ + "key": "foo.one", + "value": { "stringValue": "foo" } + }, { + "key": "bar.one", + "value": { "stringValue": "bar" } + }] + }, + "scope_metrics": [{ + "metrics": [ + { + "name": "test_metric_histogram", + "unit": "seconds", + "histogram": { + "aggregation_temporality": 2, + "data_points": [{ + "start_time_unix_nano": 1000000000, + "time_unix_nano": 1000000000, + "count": 333, + "sum": 100, + "bucket_counts": [0, 111, 0, 222], + "explicit_bounds": [0.25, 0.5, 0.75, 1.0], + "exemplars":[ + { + "time_unix_nano": 1000000001, + "as_double": 0.3, + "span_id": "aaaaaaaaaaaaaaaa", + "trace_id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }, + { + "time_unix_nano": 1000000003, + "as_double": 1.5, + "span_id": "cccccccccccccccc", + "trace_id": "cccccccccccccccccccccccccccccccc" + }, + { + "time_unix_nano": 1000000002, + "as_double": 0.5, + "span_id": "bbbbbbbbbbbbbbbb", + "trace_id": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + } + ] + }] + } + } + ] + }] + }] + }`, + expect: ` + # TYPE test_metric_histogram histogram + test_metric_histogram_bucket{bar_one="bar",foo_one="foo",instance="instance",service_instance_id="instance",job="myservice",service_name="myservice",raw="test",le="0.25"} 0 + test_metric_histogram_bucket{bar_one="bar",foo_one="foo",instance="instance",service_instance_id="instance",job="myservice",service_name="myservice",raw="test",le="0.5"} 111 # {span_id="aaaaaaaaaaaaaaaa",trace_id="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"} 0.3 + test_metric_histogram_bucket{bar_one="bar",foo_one="foo",instance="instance",service_instance_id="instance",job="myservice",service_name="myservice",raw="test",le="0.75"} 111 # {span_id="bbbbbbbbbbbbbbbb",trace_id="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"} 0.5 + test_metric_histogram_bucket{bar_one="bar",foo_one="foo",instance="instance",service_instance_id="instance",job="myservice",service_name="myservice",raw="test",le="1.0"} 333 + test_metric_histogram_bucket{bar_one="bar",foo_one="foo",instance="instance",service_instance_id="instance",job="myservice",service_name="myservice",raw="test",le="+Inf"} 333 # {span_id="cccccccccccccccc",trace_id="cccccccccccccccccccccccccccccccc"} 1.5 + test_metric_histogram_sum{bar_one="bar",foo_one="foo",instance="instance",service_instance_id="instance",job="myservice",service_name="myservice",raw="test"} 100.0 + test_metric_histogram_count{bar_one="bar",foo_one="foo",instance="instance",service_instance_id="instance",job="myservice",service_name="myservice",raw="test"} 333 + `, + enableOpenMetrics: true, + resourceToTelemetryConversion: true, + }, + { + name: "Monotonic sum: convert resource attributes to metric label", + input: `{ + "resource_metrics": [{ + "resource": { + "attributes": [{ + "key": "service.name", + "value": { "stringValue": "myservice" } + }, { + "key": "service.instance.id", + "value": { "stringValue": "instance" } + }, { + "key": "raw", + "value": { "stringValue": "test" } + },{ + "key": "foo.one", + "value": { "stringValue": "foo" } + }, { + "key": "bar.one", + "value": { "stringValue": "bar" } + }] + }, + "scope_metrics": [{ + "metrics": [ + { + "name": "test_metric_mono_sum_total", + "unit": "seconds", + "sum": { + "aggregation_temporality": 2, + "is_monotonic": true, + "data_points": [{ + "start_time_unix_nano": 1000000000, + "time_unix_nano": 1000000000, + "as_double": 15, + "exemplars":[ + { + "time_unix_nano": 1000000001, + "as_double": 0.3, + "span_id": "aaaaaaaaaaaaaaaa", + "trace_id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + } + ] + }] + } + } + ] + }] + }] + }`, + expect: ` + # TYPE test_metric_mono_sum counter + test_metric_mono_sum_total{bar_one="bar",foo_one="foo",instance="instance",service_instance_id="instance",job="myservice",service_name="myservice",raw="test"} 15.0 # {span_id="aaaaaaaaaaaaaaaa",trace_id="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"} 0.3 + `, + enableOpenMetrics: true, + resourceToTelemetryConversion: true, + }, } decoder := &pmetric.JSONUnmarshaler{} @@ -851,10 +1120,11 @@ func TestConverter(t *testing.T) { l := util.TestLogger(t) conv := convert.New(l, appenderAppendable{Inner: &app}, convert.Options{ - IncludeTargetInfo: tc.includeTargetInfo, - IncludeScopeInfo: tc.includeScopeInfo, - IncludeScopeLabels: tc.includeScopeLabels, - AddMetricSuffixes: tc.addMetricSuffixes, + IncludeTargetInfo: tc.includeTargetInfo, + IncludeScopeInfo: tc.includeScopeInfo, + IncludeScopeLabels: tc.includeScopeLabels, + AddMetricSuffixes: tc.addMetricSuffixes, + ResourceToTelemetryConversion: tc.resourceToTelemetryConversion, }) require.NoError(t, conv.ConsumeMetrics(context.Background(), payload)) diff --git a/component/otelcol/exporter/prometheus/prometheus.go b/component/otelcol/exporter/prometheus/prometheus.go index 0dd9ef49e69f..7da1c03868ea 100644 --- a/component/otelcol/exporter/prometheus/prometheus.go +++ b/component/otelcol/exporter/prometheus/prometheus.go @@ -19,10 +19,10 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.exporter.prometheus", - Args: Arguments{}, - Exports: otelcol.ConsumerExports{}, - NeedsServices: []string{labelstore.ServiceName}, + Name: "otelcol.exporter.prometheus", + Args: Arguments{}, + Exports: otelcol.ConsumerExports{}, + Build: func(o component.Options, a component.Arguments) (component.Component, error) { return New(o, a.(Arguments)) }, @@ -31,21 +31,23 @@ func init() { // Arguments configures the otelcol.exporter.prometheus component. type Arguments struct { - IncludeTargetInfo bool `river:"include_target_info,attr,optional"` - IncludeScopeInfo bool `river:"include_scope_info,attr,optional"` - IncludeScopeLabels bool `river:"include_scope_labels,attr,optional"` - GCFrequency time.Duration `river:"gc_frequency,attr,optional"` - ForwardTo []storage.Appendable `river:"forward_to,attr"` - AddMetricSuffixes bool `river:"add_metric_suffixes,attr,optional"` + IncludeTargetInfo bool `river:"include_target_info,attr,optional"` + IncludeScopeInfo bool `river:"include_scope_info,attr,optional"` + IncludeScopeLabels bool `river:"include_scope_labels,attr,optional"` + GCFrequency time.Duration `river:"gc_frequency,attr,optional"` + ForwardTo []storage.Appendable `river:"forward_to,attr"` + AddMetricSuffixes bool `river:"add_metric_suffixes,attr,optional"` + ResourceToTelemetryConversion bool `river:"resource_to_telemetry_conversion,attr,optional"` } // DefaultArguments holds defaults values. var DefaultArguments = Arguments{ - IncludeTargetInfo: true, - IncludeScopeInfo: false, - IncludeScopeLabels: true, - GCFrequency: 5 * time.Minute, - AddMetricSuffixes: true, + IncludeTargetInfo: true, + IncludeScopeInfo: false, + IncludeScopeLabels: true, + GCFrequency: 5 * time.Minute, + AddMetricSuffixes: true, + ResourceToTelemetryConversion: false, } // SetToDefault implements river.Defaulter. @@ -151,8 +153,9 @@ func (c *Component) Update(newConfig component.Arguments) error { func convertArgumentsToConvertOptions(args Arguments) convert.Options { return convert.Options{ - IncludeTargetInfo: args.IncludeTargetInfo, - IncludeScopeInfo: args.IncludeScopeInfo, - AddMetricSuffixes: args.AddMetricSuffixes, + IncludeTargetInfo: args.IncludeTargetInfo, + IncludeScopeInfo: args.IncludeScopeInfo, + AddMetricSuffixes: args.AddMetricSuffixes, + ResourceToTelemetryConversion: args.ResourceToTelemetryConversion, } } diff --git a/component/otelcol/exporter/prometheus/prometheus_test.go b/component/otelcol/exporter/prometheus/prometheus_test.go index 2939c8962346..7e642ff9b585 100644 --- a/component/otelcol/exporter/prometheus/prometheus_test.go +++ b/component/otelcol/exporter/prometheus/prometheus_test.go @@ -23,12 +23,13 @@ func TestArguments_UnmarshalRiver(t *testing.T) { forward_to = [] `, expected: prometheus.Arguments{ - IncludeTargetInfo: true, - IncludeScopeInfo: false, - IncludeScopeLabels: true, - GCFrequency: 5 * time.Minute, - AddMetricSuffixes: true, - ForwardTo: []storage.Appendable{}, + IncludeTargetInfo: true, + IncludeScopeInfo: false, + IncludeScopeLabels: true, + GCFrequency: 5 * time.Minute, + AddMetricSuffixes: true, + ForwardTo: []storage.Appendable{}, + ResourceToTelemetryConversion: false, }, }, { @@ -39,15 +40,17 @@ func TestArguments_UnmarshalRiver(t *testing.T) { include_scope_labels = false gc_frequency = "1s" add_metric_suffixes = false + resource_to_telemetry_conversion = true forward_to = [] `, expected: prometheus.Arguments{ - IncludeTargetInfo: false, - IncludeScopeInfo: true, - IncludeScopeLabels: false, - GCFrequency: 1 * time.Second, - AddMetricSuffixes: false, - ForwardTo: []storage.Appendable{}, + IncludeTargetInfo: false, + IncludeScopeInfo: true, + IncludeScopeLabels: false, + GCFrequency: 1 * time.Second, + AddMetricSuffixes: false, + ForwardTo: []storage.Appendable{}, + ResourceToTelemetryConversion: true, }, }, { diff --git a/component/otelcol/internal/fanoutconsumer/logs.go b/component/otelcol/internal/fanoutconsumer/logs.go index a01202686e01..a8ee4df45b7f 100644 --- a/component/otelcol/internal/fanoutconsumer/logs.go +++ b/component/otelcol/internal/fanoutconsumer/logs.go @@ -29,6 +29,10 @@ func Logs(in []otelcol.Consumer) otelconsumer.Logs { for i := 0; i < len(in)-1; i++ { consumer := in[i] + if consumer == nil { + continue + } + if consumer.Capabilities().MutatesData { clone = append(clone, consumer) } else { @@ -40,10 +44,12 @@ func Logs(in []otelcol.Consumer) otelconsumer.Logs { // The final consumer can be given to the passthrough list regardless of // whether it mutates as long as there's no other read-only consumers. - if len(passthrough) == 0 || !last.Capabilities().MutatesData { - passthrough = append(passthrough, last) - } else { - clone = append(clone, last) + if last != nil { + if len(passthrough) == 0 || !last.Capabilities().MutatesData { + passthrough = append(passthrough, last) + } else { + clone = append(clone, last) + } } return &logsFanout{ diff --git a/component/otelcol/processor/attributes/attributes.go b/component/otelcol/processor/attributes/attributes.go index c71eec8e1415..93f774e54b55 100644 --- a/component/otelcol/processor/attributes/attributes.go +++ b/component/otelcol/processor/attributes/attributes.go @@ -7,7 +7,6 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/processor" - otel_service "github.com/grafana/agent/service/otel" "github.com/mitchellh/mapstructure" "github.com/open-telemetry/opentelemetry-collector-contrib/processor/attributesprocessor" otelcomponent "go.opentelemetry.io/collector/component" @@ -16,10 +15,9 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.processor.attributes", - Args: Arguments{}, - Exports: otelcol.ConsumerExports{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.processor.attributes", + Args: Arguments{}, + Exports: otelcol.ConsumerExports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := attributesprocessor.NewFactory() diff --git a/component/otelcol/processor/batch/batch.go b/component/otelcol/processor/batch/batch.go index 6cc54fa5f333..3c205a0e4320 100644 --- a/component/otelcol/processor/batch/batch.go +++ b/component/otelcol/processor/batch/batch.go @@ -8,7 +8,6 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/processor" - otel_service "github.com/grafana/agent/service/otel" otelcomponent "go.opentelemetry.io/collector/component" otelextension "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/processor/batchprocessor" @@ -16,10 +15,9 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.processor.batch", - Args: Arguments{}, - Exports: otelcol.ConsumerExports{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.processor.batch", + Args: Arguments{}, + Exports: otelcol.ConsumerExports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := batchprocessor.NewFactory() diff --git a/component/otelcol/processor/filter/filter.go b/component/otelcol/processor/filter/filter.go index 864e9887688e..fe0927569558 100644 --- a/component/otelcol/processor/filter/filter.go +++ b/component/otelcol/processor/filter/filter.go @@ -4,7 +4,6 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/processor" - otel_service "github.com/grafana/agent/service/otel" "github.com/mitchellh/mapstructure" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl" "github.com/open-telemetry/opentelemetry-collector-contrib/processor/filterprocessor" @@ -14,10 +13,9 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.processor.filter", - Args: Arguments{}, - Exports: otelcol.ConsumerExports{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.processor.filter", + Args: Arguments{}, + Exports: otelcol.ConsumerExports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := filterprocessor.NewFactory() diff --git a/component/otelcol/processor/memorylimiter/memorylimiter.go b/component/otelcol/processor/memorylimiter/memorylimiter.go index 0321d41cb5c4..edf3bb1016d0 100644 --- a/component/otelcol/processor/memorylimiter/memorylimiter.go +++ b/component/otelcol/processor/memorylimiter/memorylimiter.go @@ -9,7 +9,6 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/processor" - otel_service "github.com/grafana/agent/service/otel" otelcomponent "go.opentelemetry.io/collector/component" otelextension "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/processor/memorylimiterprocessor" @@ -17,10 +16,9 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.processor.memory_limiter", - Args: Arguments{}, - Exports: otelcol.ConsumerExports{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.processor.memory_limiter", + Args: Arguments{}, + Exports: otelcol.ConsumerExports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := memorylimiterprocessor.NewFactory() diff --git a/component/otelcol/processor/probabilistic_sampler/probabilistic_sampler.go b/component/otelcol/processor/probabilistic_sampler/probabilistic_sampler.go index 72b8430de5e1..13321e6af49e 100644 --- a/component/otelcol/processor/probabilistic_sampler/probabilistic_sampler.go +++ b/component/otelcol/processor/probabilistic_sampler/probabilistic_sampler.go @@ -5,7 +5,6 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/processor" - otel_service "github.com/grafana/agent/service/otel" "github.com/grafana/river" "github.com/open-telemetry/opentelemetry-collector-contrib/processor/probabilisticsamplerprocessor" otelcomponent "go.opentelemetry.io/collector/component" @@ -14,10 +13,9 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.processor.probabilistic_sampler", - Args: Arguments{}, - Exports: otelcol.ConsumerExports{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.processor.probabilistic_sampler", + Args: Arguments{}, + Exports: otelcol.ConsumerExports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := probabilisticsamplerprocessor.NewFactory() diff --git a/component/otelcol/processor/span/span.go b/component/otelcol/processor/span/span.go index c62e8e108527..833a899d2c25 100644 --- a/component/otelcol/processor/span/span.go +++ b/component/otelcol/processor/span/span.go @@ -7,7 +7,6 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/processor" - otel_service "github.com/grafana/agent/service/otel" "github.com/mitchellh/mapstructure" "github.com/open-telemetry/opentelemetry-collector-contrib/processor/spanprocessor" otelcomponent "go.opentelemetry.io/collector/component" @@ -17,10 +16,9 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.processor.span", - Args: Arguments{}, - Exports: otelcol.ConsumerExports{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.processor.span", + Args: Arguments{}, + Exports: otelcol.ConsumerExports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := spanprocessor.NewFactory() diff --git a/component/otelcol/processor/tail_sampling/tail_sampling.go b/component/otelcol/processor/tail_sampling/tail_sampling.go index 0a17a49bd3da..dc2f33bb661d 100644 --- a/component/otelcol/processor/tail_sampling/tail_sampling.go +++ b/component/otelcol/processor/tail_sampling/tail_sampling.go @@ -8,7 +8,6 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/processor" - otel_service "github.com/grafana/agent/service/otel" tsp "github.com/open-telemetry/opentelemetry-collector-contrib/processor/tailsamplingprocessor" otelcomponent "go.opentelemetry.io/collector/component" otelextension "go.opentelemetry.io/collector/extension" @@ -16,10 +15,9 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.processor.tail_sampling", - Args: Arguments{}, - Exports: otelcol.ConsumerExports{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.processor.tail_sampling", + Args: Arguments{}, + Exports: otelcol.ConsumerExports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := tsp.NewFactory() diff --git a/component/otelcol/processor/transform/transform.go b/component/otelcol/processor/transform/transform.go index 85f86e5ac1ca..222e7c3289a8 100644 --- a/component/otelcol/processor/transform/transform.go +++ b/component/otelcol/processor/transform/transform.go @@ -8,7 +8,6 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/processor" - otel_service "github.com/grafana/agent/service/otel" "github.com/mitchellh/mapstructure" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl" "github.com/open-telemetry/opentelemetry-collector-contrib/processor/transformprocessor" @@ -18,10 +17,9 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.processor.transform", - Args: Arguments{}, - Exports: otelcol.ConsumerExports{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.processor.transform", + Args: Arguments{}, + Exports: otelcol.ConsumerExports{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := transformprocessor.NewFactory() diff --git a/component/otelcol/receiver/jaeger/jaeger.go b/component/otelcol/receiver/jaeger/jaeger.go index 1858f7a909ba..2cebb37b9114 100644 --- a/component/otelcol/receiver/jaeger/jaeger.go +++ b/component/otelcol/receiver/jaeger/jaeger.go @@ -8,7 +8,6 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/receiver" - otel_service "github.com/grafana/agent/service/otel" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/jaegerreceiver" otelcomponent "go.opentelemetry.io/collector/component" otelconfiggrpc "go.opentelemetry.io/collector/config/configgrpc" @@ -18,9 +17,8 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.receiver.jaeger", - Args: Arguments{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.receiver.jaeger", + Args: Arguments{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := jaegerreceiver.NewFactory() diff --git a/component/otelcol/receiver/kafka/kafka.go b/component/otelcol/receiver/kafka/kafka.go index 2a41159b103b..2111f04c2579 100644 --- a/component/otelcol/receiver/kafka/kafka.go +++ b/component/otelcol/receiver/kafka/kafka.go @@ -7,7 +7,6 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/receiver" - otel_service "github.com/grafana/agent/service/otel" "github.com/grafana/river/rivertypes" "github.com/mitchellh/mapstructure" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/kafkaexporter" @@ -18,9 +17,8 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.receiver.kafka", - Args: Arguments{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.receiver.kafka", + Args: Arguments{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := kafkareceiver.NewFactory() diff --git a/component/otelcol/receiver/opencensus/opencensus.go b/component/otelcol/receiver/opencensus/opencensus.go index 63df3da32118..7f4c64ee0ace 100644 --- a/component/otelcol/receiver/opencensus/opencensus.go +++ b/component/otelcol/receiver/opencensus/opencensus.go @@ -6,7 +6,6 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/receiver" - otel_service "github.com/grafana/agent/service/otel" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/opencensusreceiver" otelcomponent "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/extension" @@ -14,9 +13,8 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.receiver.opencensus", - Args: Arguments{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.receiver.opencensus", + Args: Arguments{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := opencensusreceiver.NewFactory() diff --git a/component/otelcol/receiver/otlp/otlp.go b/component/otelcol/receiver/otlp/otlp.go index 4ca6106551e3..bfdb20365ef8 100644 --- a/component/otelcol/receiver/otlp/otlp.go +++ b/component/otelcol/receiver/otlp/otlp.go @@ -9,7 +9,6 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/receiver" - otel_service "github.com/grafana/agent/service/otel" otelcomponent "go.opentelemetry.io/collector/component" otelextension "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/receiver/otlpreceiver" @@ -17,9 +16,8 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.receiver.otlp", - Args: Arguments{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.receiver.otlp", + Args: Arguments{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := otlpreceiver.NewFactory() diff --git a/component/otelcol/receiver/prometheus/prometheus.go b/component/otelcol/receiver/prometheus/prometheus.go index 7928f504287b..b0493f4d6982 100644 --- a/component/otelcol/receiver/prometheus/prometheus.go +++ b/component/otelcol/receiver/prometheus/prometheus.go @@ -15,21 +15,19 @@ import ( "github.com/grafana/agent/component/otelcol/receiver/prometheus/internal" "github.com/grafana/agent/pkg/build" "github.com/grafana/agent/pkg/util/zapadapter" - otel_service "github.com/grafana/agent/service/otel" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/storage" otelcomponent "go.opentelemetry.io/collector/component" otelreceiver "go.opentelemetry.io/collector/receiver" - "go.opentelemetry.io/otel/metric/noop" - "go.opentelemetry.io/otel/trace" + metricNoop "go.opentelemetry.io/otel/metric/noop" + traceNoop "go.opentelemetry.io/otel/trace/noop" ) func init() { component.Register(component.Registration{ - Name: "otelcol.receiver.prometheus", - Args: Arguments{}, - Exports: Exports{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.receiver.prometheus", + Args: Arguments{}, + Exports: Exports{}, Build: func(o component.Options, a component.Arguments) (component.Component, error) { return New(o, a.(Arguments)) @@ -109,8 +107,8 @@ func (c *Component) Update(newConfig component.Arguments) error { Logger: zapadapter.New(c.opts.Logger), // TODO(tpaschalis): expose tracing and logging statistics. - TracerProvider: trace.NewNoopTracerProvider(), - MeterProvider: noop.NewMeterProvider(), + TracerProvider: traceNoop.NewTracerProvider(), + MeterProvider: metricNoop.NewMeterProvider(), ReportComponentStatus: func(*otelcomponent.StatusEvent) error { return nil diff --git a/component/otelcol/receiver/vcenter/vcenter.go b/component/otelcol/receiver/vcenter/vcenter.go index 88efd9402940..346110da1ecd 100644 --- a/component/otelcol/receiver/vcenter/vcenter.go +++ b/component/otelcol/receiver/vcenter/vcenter.go @@ -8,7 +8,6 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/receiver" - otel_service "github.com/grafana/agent/service/otel" "github.com/grafana/river/rivertypes" "github.com/mitchellh/mapstructure" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/vcenterreceiver" @@ -19,9 +18,8 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.receiver.vcenter", - Args: Arguments{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.receiver.vcenter", + Args: Arguments{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := vcenterreceiver.NewFactory() diff --git a/component/otelcol/receiver/zipkin/zipkin.go b/component/otelcol/receiver/zipkin/zipkin.go index 50ac8fb23cb7..1727d38a0d05 100644 --- a/component/otelcol/receiver/zipkin/zipkin.go +++ b/component/otelcol/receiver/zipkin/zipkin.go @@ -5,7 +5,6 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/receiver" - otel_service "github.com/grafana/agent/service/otel" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinreceiver" otelcomponent "go.opentelemetry.io/collector/component" otelextension "go.opentelemetry.io/collector/extension" @@ -13,9 +12,8 @@ import ( func init() { component.Register(component.Registration{ - Name: "otelcol.receiver.zipkin", - Args: Arguments{}, - NeedsServices: []string{otel_service.ServiceName}, + Name: "otelcol.receiver.zipkin", + Args: Arguments{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { fact := zipkinreceiver.NewFactory() diff --git a/component/prometheus/exporter/agent/agent.go b/component/prometheus/exporter/agent/agent.go index 6d8064d2771b..5a02005c92b1 100644 --- a/component/prometheus/exporter/agent/agent.go +++ b/component/prometheus/exporter/agent/agent.go @@ -9,11 +9,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.agent", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "agent"), + Name: "prometheus.exporter.agent", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "agent"), }) } diff --git a/component/prometheus/exporter/apache/apache.go b/component/prometheus/exporter/apache/apache.go index 802792f545bd..4ba9d8166832 100644 --- a/component/prometheus/exporter/apache/apache.go +++ b/component/prometheus/exporter/apache/apache.go @@ -9,11 +9,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.apache", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "apache"), + Name: "prometheus.exporter.apache", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "apache"), }) } diff --git a/component/prometheus/exporter/azure/azure.go b/component/prometheus/exporter/azure/azure.go index 0b2d8483e6a9..9f454d40ce11 100644 --- a/component/prometheus/exporter/azure/azure.go +++ b/component/prometheus/exporter/azure/azure.go @@ -9,11 +9,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.azure", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "azure"), + Name: "prometheus.exporter.azure", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "azure"), }) } diff --git a/component/prometheus/exporter/blackbox/blackbox.go b/component/prometheus/exporter/blackbox/blackbox.go index 206ac1f1d12b..0388560443a8 100644 --- a/component/prometheus/exporter/blackbox/blackbox.go +++ b/component/prometheus/exporter/blackbox/blackbox.go @@ -19,11 +19,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.blackbox", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.NewWithTargetBuilder(createExporter, "blackbox", buildBlackboxTargets), + Name: "prometheus.exporter.blackbox", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.NewWithTargetBuilder(createExporter, "blackbox", buildBlackboxTargets), }) } diff --git a/component/prometheus/exporter/cadvisor/cadvisor.go b/component/prometheus/exporter/cadvisor/cadvisor.go index 79542dbf0087..2e19f82cf469 100644 --- a/component/prometheus/exporter/cadvisor/cadvisor.go +++ b/component/prometheus/exporter/cadvisor/cadvisor.go @@ -11,11 +11,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.cadvisor", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "cadvisor"), + Name: "prometheus.exporter.cadvisor", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "cadvisor"), }) } @@ -44,7 +44,8 @@ var DefaultArguments = Arguments{ DockerTLSKey: "key.pem", DockerTLSCA: "ca.pem", - DockerOnly: false, + DockerOnly: false, + DisableRootCgroupStats: false, } // Arguments configures the prometheus.exporter.cadvisor component. @@ -66,6 +67,7 @@ type Arguments struct { DockerTLSKey string `river:"docker_tls_key,attr,optional"` DockerTLSCA string `river:"docker_tls_ca,attr,optional"` DockerOnly bool `river:"docker_only,attr,optional"` + DisableRootCgroupStats bool `river:"disable_root_cgroup_stats,attr,optional"` } // SetToDefault implements river.Defaulter. @@ -103,6 +105,7 @@ func (a *Arguments) Convert() *cadvisor.Config { DockerTLSKey: a.DockerTLSKey, DockerTLSCA: a.DockerTLSCA, DockerOnly: a.DockerOnly, + DisableRootCgroupStats: a.DisableRootCgroupStats, } return cfg diff --git a/component/prometheus/exporter/cloudwatch/cloudwatch.go b/component/prometheus/exporter/cloudwatch/cloudwatch.go index 6d8dc2b6d83c..aa957ce56562 100644 --- a/component/prometheus/exporter/cloudwatch/cloudwatch.go +++ b/component/prometheus/exporter/cloudwatch/cloudwatch.go @@ -11,11 +11,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.cloudwatch", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "cloudwatch"), + Name: "prometheus.exporter.cloudwatch", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "cloudwatch"), }) } diff --git a/component/prometheus/exporter/consul/consul.go b/component/prometheus/exporter/consul/consul.go index 862dc7042017..ce301f8ddc6b 100644 --- a/component/prometheus/exporter/consul/consul.go +++ b/component/prometheus/exporter/consul/consul.go @@ -11,11 +11,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.consul", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "consul"), + Name: "prometheus.exporter.consul", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "consul"), }) } diff --git a/component/prometheus/exporter/dnsmasq/dnsmasq.go b/component/prometheus/exporter/dnsmasq/dnsmasq.go index 5daaf17df4c0..f856fc4bd7df 100644 --- a/component/prometheus/exporter/dnsmasq/dnsmasq.go +++ b/component/prometheus/exporter/dnsmasq/dnsmasq.go @@ -9,11 +9,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.dnsmasq", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "dnsmasq"), + Name: "prometheus.exporter.dnsmasq", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "dnsmasq"), }) } diff --git a/component/prometheus/exporter/elasticsearch/elasticsearch.go b/component/prometheus/exporter/elasticsearch/elasticsearch.go index 84904e6e3fee..89123359cb9f 100644 --- a/component/prometheus/exporter/elasticsearch/elasticsearch.go +++ b/component/prometheus/exporter/elasticsearch/elasticsearch.go @@ -11,11 +11,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.elasticsearch", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "elasticsearch"), + Name: "prometheus.exporter.elasticsearch", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "elasticsearch"), }) } diff --git a/component/prometheus/exporter/gcp/gcp.go b/component/prometheus/exporter/gcp/gcp.go index b5581b7884c4..0147b72819b3 100644 --- a/component/prometheus/exporter/gcp/gcp.go +++ b/component/prometheus/exporter/gcp/gcp.go @@ -11,11 +11,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.gcp", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "gcp"), + Name: "prometheus.exporter.gcp", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "gcp"), }) } diff --git a/component/prometheus/exporter/github/github.go b/component/prometheus/exporter/github/github.go index 354005b4e692..4d3dab5a0f2f 100644 --- a/component/prometheus/exporter/github/github.go +++ b/component/prometheus/exporter/github/github.go @@ -11,11 +11,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.github", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "github"), + Name: "prometheus.exporter.github", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "github"), }) } diff --git a/component/prometheus/exporter/kafka/kafka.go b/component/prometheus/exporter/kafka/kafka.go index 1fa01bf4d614..f146c40bae3c 100644 --- a/component/prometheus/exporter/kafka/kafka.go +++ b/component/prometheus/exporter/kafka/kafka.go @@ -50,11 +50,11 @@ type Arguments struct { func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.kafka", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.NewWithTargetBuilder(createExporter, "kafka", customizeTarget), + Name: "prometheus.exporter.kafka", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.NewWithTargetBuilder(createExporter, "kafka", customizeTarget), }) } diff --git a/component/prometheus/exporter/memcached/memcached.go b/component/prometheus/exporter/memcached/memcached.go index de5213a273a2..09d5214855fc 100644 --- a/component/prometheus/exporter/memcached/memcached.go +++ b/component/prometheus/exporter/memcached/memcached.go @@ -12,11 +12,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.memcached", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "memcached"), + Name: "prometheus.exporter.memcached", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "memcached"), }) } diff --git a/component/prometheus/exporter/mongodb/mongodb.go b/component/prometheus/exporter/mongodb/mongodb.go index 6905865285bd..0c0064c5b5c1 100644 --- a/component/prometheus/exporter/mongodb/mongodb.go +++ b/component/prometheus/exporter/mongodb/mongodb.go @@ -11,11 +11,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.mongodb", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "mongodb"), + Name: "prometheus.exporter.mongodb", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "mongodb"), }) } diff --git a/component/prometheus/exporter/mssql/mssql.go b/component/prometheus/exporter/mssql/mssql.go index 819be78a8927..bef73f16a44c 100644 --- a/component/prometheus/exporter/mssql/mssql.go +++ b/component/prometheus/exporter/mssql/mssql.go @@ -2,23 +2,27 @@ package mssql import ( "errors" + "fmt" "time" + "github.com/burningalchemist/sql_exporter/config" "github.com/grafana/agent/component" "github.com/grafana/agent/component/prometheus/exporter" "github.com/grafana/agent/pkg/integrations" "github.com/grafana/agent/pkg/integrations/mssql" + "github.com/grafana/agent/pkg/util" "github.com/grafana/river/rivertypes" config_util "github.com/prometheus/common/config" + "gopkg.in/yaml.v2" ) func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.mssql", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "mssql"), + Name: "prometheus.exporter.mssql", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "mssql"), }) } @@ -36,10 +40,11 @@ var DefaultArguments = Arguments{ // Arguments controls the mssql exporter. type Arguments struct { - ConnectionString rivertypes.Secret `river:"connection_string,attr"` - MaxIdleConnections int `river:"max_idle_connections,attr,optional"` - MaxOpenConnections int `river:"max_open_connections,attr,optional"` - Timeout time.Duration `river:"timeout,attr,optional"` + ConnectionString rivertypes.Secret `river:"connection_string,attr"` + MaxIdleConnections int `river:"max_idle_connections,attr,optional"` + MaxOpenConnections int `river:"max_open_connections,attr,optional"` + Timeout time.Duration `river:"timeout,attr,optional"` + QueryConfig rivertypes.OptionalSecret `river:"query_config,attr,optional"` } // SetToDefault implements river.Defaulter. @@ -60,6 +65,13 @@ func (a *Arguments) Validate() error { if a.Timeout <= 0 { return errors.New("timeout must be positive") } + + var collectorConfig config.CollectorConfig + err := yaml.UnmarshalStrict([]byte(a.QueryConfig.Value), &collectorConfig) + if err != nil { + return fmt.Errorf("invalid query_config: %s", err) + } + return nil } @@ -69,5 +81,6 @@ func (a *Arguments) Convert() *mssql.Config { MaxIdleConnections: a.MaxIdleConnections, MaxOpenConnections: a.MaxOpenConnections, Timeout: a.Timeout, + QueryConfig: util.RawYAML(a.QueryConfig.Value), } } diff --git a/component/prometheus/exporter/mssql/mssql_test.go b/component/prometheus/exporter/mssql/mssql_test.go index b9a47ad3b776..4fad4a819780 100644 --- a/component/prometheus/exporter/mssql/mssql_test.go +++ b/component/prometheus/exporter/mssql/mssql_test.go @@ -4,11 +4,13 @@ import ( "testing" "time" + "github.com/burningalchemist/sql_exporter/config" "github.com/grafana/agent/pkg/integrations/mssql" "github.com/grafana/river" "github.com/grafana/river/rivertypes" config_util "github.com/prometheus/common/config" "github.com/stretchr/testify/require" + "gopkg.in/yaml.v2" ) func TestRiverUnmarshal(t *testing.T) { @@ -16,8 +18,7 @@ func TestRiverUnmarshal(t *testing.T) { connection_string = "sqlserver://user:pass@localhost:1433" max_idle_connections = 3 max_open_connections = 3 - timeout = "10s" - ` + timeout = "10s"` var args Arguments err := river.Unmarshal([]byte(riverConfig), &args) @@ -33,6 +34,64 @@ func TestRiverUnmarshal(t *testing.T) { require.Equal(t, expected, args) } +func TestRiverUnmarshalWithInlineQueryConfig(t *testing.T) { + riverConfig := ` + connection_string = "sqlserver://user:pass@localhost:1433" + max_idle_connections = 3 + max_open_connections = 3 + timeout = "10s" + query_config = "{ collector_name: mssql_standard, metrics: [ { metric_name: mssql_local_time_seconds, type: gauge, help: 'Local time in seconds since epoch (Unix time).', values: [ unix_time ], query: \"SELECT DATEDIFF(second, '19700101', GETUTCDATE()) AS unix_time\" } ] }"` + + var args Arguments + err := river.Unmarshal([]byte(riverConfig), &args) + require.NoError(t, err) + var collectorConfig config.CollectorConfig + err = yaml.UnmarshalStrict([]byte(args.QueryConfig.Value), &collectorConfig) + require.NoError(t, err) + + require.Equal(t, rivertypes.Secret("sqlserver://user:pass@localhost:1433"), args.ConnectionString) + require.Equal(t, 3, args.MaxIdleConnections) + require.Equal(t, 3, args.MaxOpenConnections) + require.Equal(t, 10*time.Second, args.Timeout) + require.Equal(t, "mssql_standard", collectorConfig.Name) + require.Equal(t, 1, len(collectorConfig.Metrics)) + require.Equal(t, "mssql_local_time_seconds", collectorConfig.Metrics[0].Name) + require.Equal(t, "gauge", collectorConfig.Metrics[0].TypeString) + require.Equal(t, "Local time in seconds since epoch (Unix time).", collectorConfig.Metrics[0].Help) + require.Equal(t, 1, len(collectorConfig.Metrics[0].Values)) + require.Contains(t, collectorConfig.Metrics[0].Values, "unix_time") + require.Equal(t, "SELECT DATEDIFF(second, '19700101', GETUTCDATE()) AS unix_time", collectorConfig.Metrics[0].QueryLiteral) +} + +func TestRiverUnmarshalWithInlineQueryConfigYaml(t *testing.T) { + riverConfig := ` + connection_string = "sqlserver://user:pass@localhost:1433" + max_idle_connections = 3 + max_open_connections = 3 + timeout = "10s" + query_config = "collector_name: mssql_standard\nmetrics:\n- metric_name: mssql_local_time_seconds\n type: gauge\n help: 'Local time in seconds since epoch (Unix time).'\n values: [unix_time]\n query: \"SELECT DATEDIFF(second, '19700101', GETUTCDATE()) AS unix_time\""` + + var args Arguments + err := river.Unmarshal([]byte(riverConfig), &args) + require.NoError(t, err) + var collectorConfig config.CollectorConfig + err = yaml.UnmarshalStrict([]byte(args.QueryConfig.Value), &collectorConfig) + require.NoError(t, err) + + require.Equal(t, rivertypes.Secret("sqlserver://user:pass@localhost:1433"), args.ConnectionString) + require.Equal(t, 3, args.MaxIdleConnections) + require.Equal(t, 3, args.MaxOpenConnections) + require.Equal(t, 10*time.Second, args.Timeout) + require.Equal(t, "mssql_standard", collectorConfig.Name) + require.Equal(t, 1, len(collectorConfig.Metrics)) + require.Equal(t, "mssql_local_time_seconds", collectorConfig.Metrics[0].Name) + require.Equal(t, "gauge", collectorConfig.Metrics[0].TypeString) + require.Equal(t, "Local time in seconds since epoch (Unix time).", collectorConfig.Metrics[0].Help) + require.Equal(t, 1, len(collectorConfig.Metrics[0].Values)) + require.Contains(t, collectorConfig.Metrics[0].Values, "unix_time") + require.Equal(t, "SELECT DATEDIFF(second, '19700101', GETUTCDATE()) AS unix_time", collectorConfig.Metrics[0].QueryLiteral) +} + func TestUnmarshalInvalid(t *testing.T) { invalidRiverConfig := ` connection_string = "sqlserver://user:pass@localhost:1433" @@ -44,6 +103,37 @@ func TestUnmarshalInvalid(t *testing.T) { var invalidArgs Arguments err := river.Unmarshal([]byte(invalidRiverConfig), &invalidArgs) require.Error(t, err) + require.EqualError(t, err, "timeout must be positive") +} + +func TestUnmarshalInvalidQueryConfigYaml(t *testing.T) { + invalidRiverConfig := ` + connection_string = "sqlserver://user:pass@localhost:1433" + max_idle_connections = 1 + max_open_connections = 1 + timeout = "1s" + query_config = "{ collector_name: mssql_standard, metrics: [ { metric_name: mssql_local_time_seconds, type: gauge, help: 'Local time in seconds since epoch (Unix time).', values: [ unix_time ], query: \"SELECT DATEDIFF(second, '19700101', GETUTCDATE()) AS unix_time\" }" + ` + + var invalidArgs Arguments + err := river.Unmarshal([]byte(invalidRiverConfig), &invalidArgs) + require.Error(t, err) + require.EqualError(t, err, "invalid query_config: yaml: line 1: did not find expected ',' or ']'") +} + +func TestUnmarshalInvalidProperty(t *testing.T) { + invalidRiverConfig := ` + connection_string = "sqlserver://user:pass@localhost:1433" + max_idle_connections = 1 + max_open_connections = 1 + timeout = "1s" + query_config = "collector_name: mssql_standard\nbad_param: true\nmetrics:\n- metric_name: mssql_local_time_seconds\n type: gauge\n help: 'Local time in seconds since epoch (Unix time).'\n values: [unix_time]\n query: \"SELECT DATEDIFF(second, '19700101', GETUTCDATE()) AS unix_time\"" + ` + + var invalidArgs Arguments + err := river.Unmarshal([]byte(invalidRiverConfig), &invalidArgs) + require.Error(t, err) + require.EqualError(t, err, "invalid query_config: unknown fields in collector: bad_param") } func TestArgumentsValidate(t *testing.T) { @@ -89,6 +179,9 @@ func TestArgumentsValidate(t *testing.T) { MaxIdleConnections: 1, MaxOpenConnections: 1, Timeout: 10 * time.Second, + QueryConfig: rivertypes.OptionalSecret{ + Value: `{ collector_name: mssql_standard, metrics: [ { metric_name: mssql_local_time_seconds, type: gauge, help: 'Local time in seconds since epoch (Unix time).', values: [ unix_time ], query: "SELECT DATEDIFF(second, '19700101', GETUTCDATE()) AS unix_time" } ] }`, + }, }, wantErr: false, }, @@ -107,20 +200,31 @@ func TestArgumentsValidate(t *testing.T) { } func TestConvert(t *testing.T) { - riverConfig := ` - connection_string = "sqlserver://user:pass@localhost:1433" - ` - var args Arguments - err := river.Unmarshal([]byte(riverConfig), &args) - require.NoError(t, err) + strQueryConfig := `collector_name: mssql_standard +metrics: +- metric_name: mssql_local_time_seconds + type: gauge + help: 'Local time in seconds since epoch (Unix time).' + values: [unix_time] + query: "SELECT DATEDIFF(second, '19700101', GETUTCDATE()) AS unix_time"` + args := Arguments{ + ConnectionString: rivertypes.Secret("sqlserver://user:pass@localhost:1433"), + MaxIdleConnections: 1, + MaxOpenConnections: 1, + Timeout: 10 * time.Second, + QueryConfig: rivertypes.OptionalSecret{ + Value: strQueryConfig, + }, + } res := args.Convert() expected := mssql.Config{ ConnectionString: config_util.Secret("sqlserver://user:pass@localhost:1433"), - MaxIdleConnections: DefaultArguments.MaxIdleConnections, - MaxOpenConnections: DefaultArguments.MaxOpenConnections, - Timeout: DefaultArguments.Timeout, + MaxIdleConnections: 1, + MaxOpenConnections: 1, + Timeout: 10 * time.Second, + QueryConfig: []byte(strQueryConfig), } require.Equal(t, expected, *res) } diff --git a/component/prometheus/exporter/mysql/mysql.go b/component/prometheus/exporter/mysql/mysql.go index 90201a450a36..b23f3e170394 100644 --- a/component/prometheus/exporter/mysql/mysql.go +++ b/component/prometheus/exporter/mysql/mysql.go @@ -12,11 +12,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.mysql", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "mysql"), + Name: "prometheus.exporter.mysql", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "mysql"), }) } diff --git a/component/prometheus/exporter/oracledb/oracledb.go b/component/prometheus/exporter/oracledb/oracledb.go index de3fd28ac90b..60926d445fbb 100644 --- a/component/prometheus/exporter/oracledb/oracledb.go +++ b/component/prometheus/exporter/oracledb/oracledb.go @@ -15,11 +15,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.oracledb", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "oracledb"), + Name: "prometheus.exporter.oracledb", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "oracledb"), }) } diff --git a/component/prometheus/exporter/postgres/postgres.go b/component/prometheus/exporter/postgres/postgres.go index 97f940f910bf..9a3f170c1734 100644 --- a/component/prometheus/exporter/postgres/postgres.go +++ b/component/prometheus/exporter/postgres/postgres.go @@ -15,11 +15,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.postgres", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "postgres"), + Name: "prometheus.exporter.postgres", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "postgres"), }) } diff --git a/component/prometheus/exporter/process/process.go b/component/prometheus/exporter/process/process.go index 89aa613d1fae..6d8109d76fd8 100644 --- a/component/prometheus/exporter/process/process.go +++ b/component/prometheus/exporter/process/process.go @@ -10,11 +10,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.process", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createIntegration, "process"), + Name: "prometheus.exporter.process", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createIntegration, "process"), }) } diff --git a/component/prometheus/exporter/redis/redis.go b/component/prometheus/exporter/redis/redis.go index c6fc45822bf3..3522b07fb78e 100644 --- a/component/prometheus/exporter/redis/redis.go +++ b/component/prometheus/exporter/redis/redis.go @@ -15,11 +15,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.redis", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "redis"), + Name: "prometheus.exporter.redis", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "redis"), }) } diff --git a/component/prometheus/exporter/services.go b/component/prometheus/exporter/services.go deleted file mode 100644 index 272c1fde2590..000000000000 --- a/component/prometheus/exporter/services.go +++ /dev/null @@ -1,20 +0,0 @@ -package exporter - -import ( - "github.com/grafana/agent/service/http" - "golang.org/x/exp/maps" -) - -// RequiredServices returns the set of services needed by all -// prometheus.exporter components. Callers may optionally pass in additional -// services to add to the returned list. -func RequiredServices(additionalServices ...string) []string { - services := map[string]struct{}{ - http.ServiceName: {}, - } - for _, svc := range additionalServices { - services[svc] = struct{}{} - } - - return maps.Keys(services) -} diff --git a/component/prometheus/exporter/snmp/snmp.go b/component/prometheus/exporter/snmp/snmp.go index e34feff275db..a050c331a85b 100644 --- a/component/prometheus/exporter/snmp/snmp.go +++ b/component/prometheus/exporter/snmp/snmp.go @@ -17,11 +17,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.snmp", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.NewWithTargetBuilder(createExporter, "snmp", buildSNMPTargets), + Name: "prometheus.exporter.snmp", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.NewWithTargetBuilder(createExporter, "snmp", buildSNMPTargets), }) } diff --git a/component/prometheus/exporter/snowflake/snowflake.go b/component/prometheus/exporter/snowflake/snowflake.go index 4b2314036062..0da475d356d5 100644 --- a/component/prometheus/exporter/snowflake/snowflake.go +++ b/component/prometheus/exporter/snowflake/snowflake.go @@ -11,11 +11,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.snowflake", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "snowflake"), + Name: "prometheus.exporter.snowflake", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "snowflake"), }) } diff --git a/component/prometheus/exporter/squid/squid.go b/component/prometheus/exporter/squid/squid.go index 00449a8cba00..4af71e076a1c 100644 --- a/component/prometheus/exporter/squid/squid.go +++ b/component/prometheus/exporter/squid/squid.go @@ -13,11 +13,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.squid", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "squid"), + Name: "prometheus.exporter.squid", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "squid"), }) } diff --git a/component/prometheus/exporter/statsd/statsd.go b/component/prometheus/exporter/statsd/statsd.go index 10c308077e23..3d7b2c0dafa1 100644 --- a/component/prometheus/exporter/statsd/statsd.go +++ b/component/prometheus/exporter/statsd/statsd.go @@ -8,11 +8,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.statsd", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "statsd"), + Name: "prometheus.exporter.statsd", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "statsd"), }) } diff --git a/component/prometheus/exporter/unix/unix.go b/component/prometheus/exporter/unix/unix.go index e33fa9a63136..b1c3af6cb859 100644 --- a/component/prometheus/exporter/unix/unix.go +++ b/component/prometheus/exporter/unix/unix.go @@ -8,11 +8,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.unix", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "unix"), + Name: "prometheus.exporter.unix", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "unix"), }) } diff --git a/component/prometheus/exporter/vsphere/vsphere.go b/component/prometheus/exporter/vsphere/vsphere.go index d50894b5e446..e8cd625c3cdf 100644 --- a/component/prometheus/exporter/vsphere/vsphere.go +++ b/component/prometheus/exporter/vsphere/vsphere.go @@ -13,11 +13,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.vsphere", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "vsphere"), + Name: "prometheus.exporter.vsphere", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "vsphere"), }) } diff --git a/component/prometheus/exporter/windows/config.go b/component/prometheus/exporter/windows/config.go index 674d355011c5..cc4cb20e4b17 100644 --- a/component/prometheus/exporter/windows/config.go +++ b/component/prometheus/exporter/windows/config.go @@ -6,72 +6,6 @@ import ( windows_integration "github.com/grafana/agent/pkg/integrations/windows_exporter" ) -// DefaultArguments holds non-zero default options for Arguments when it is -// unmarshaled from YAML. -// -// Some defaults are populated from init functions in the github.com/grafana/agent/pkg/integrations/windows_exporter package. - -var DefaultArguments = Arguments{ - EnabledCollectors: strings.Split(windows_integration.DefaultConfig.EnabledCollectors, ","), - Dfsr: DfsrConfig{ - SourcesEnabled: strings.Split(windows_integration.DefaultConfig.Dfsr.SourcesEnabled, ","), - }, - Exchange: ExchangeConfig{ - EnabledList: strings.Split(windows_integration.DefaultConfig.Exchange.EnabledList, ","), - }, - IIS: IISConfig{ - AppBlackList: windows_integration.DefaultConfig.IIS.AppBlackList, - AppWhiteList: windows_integration.DefaultConfig.IIS.AppWhiteList, - SiteBlackList: windows_integration.DefaultConfig.IIS.SiteBlackList, - SiteWhiteList: windows_integration.DefaultConfig.IIS.SiteWhiteList, - AppInclude: windows_integration.DefaultConfig.IIS.AppInclude, - AppExclude: windows_integration.DefaultConfig.IIS.AppExclude, - SiteInclude: windows_integration.DefaultConfig.IIS.SiteInclude, - SiteExclude: windows_integration.DefaultConfig.IIS.SiteExclude, - }, - LogicalDisk: LogicalDiskConfig{ - BlackList: windows_integration.DefaultConfig.LogicalDisk.BlackList, - WhiteList: windows_integration.DefaultConfig.LogicalDisk.WhiteList, - Include: windows_integration.DefaultConfig.LogicalDisk.Include, - Exclude: windows_integration.DefaultConfig.LogicalDisk.Exclude, - }, - MSMQ: MSMQConfig{ - Where: windows_integration.DefaultConfig.MSMQ.Where, - }, - MSSQL: MSSQLConfig{ - EnabledClasses: strings.Split(windows_integration.DefaultConfig.MSSQL.EnabledClasses, ","), - }, - Network: NetworkConfig{ - BlackList: windows_integration.DefaultConfig.Network.BlackList, - WhiteList: windows_integration.DefaultConfig.Network.WhiteList, - Include: windows_integration.DefaultConfig.Network.Include, - Exclude: windows_integration.DefaultConfig.Network.Exclude, - }, - Process: ProcessConfig{ - BlackList: windows_integration.DefaultConfig.Process.BlackList, - WhiteList: windows_integration.DefaultConfig.Process.WhiteList, - Include: windows_integration.DefaultConfig.Process.Include, - Exclude: windows_integration.DefaultConfig.Process.Exclude, - }, - ScheduledTask: ScheduledTaskConfig{ - Include: windows_integration.DefaultConfig.ScheduledTask.Include, - Exclude: windows_integration.DefaultConfig.ScheduledTask.Exclude, - }, - Service: ServiceConfig{ - UseApi: windows_integration.DefaultConfig.Service.UseApi, - Where: windows_integration.DefaultConfig.Service.Where, - }, - SMTP: SMTPConfig{ - BlackList: windows_integration.DefaultConfig.SMTP.BlackList, - WhiteList: windows_integration.DefaultConfig.SMTP.WhiteList, - Include: windows_integration.DefaultConfig.SMTP.Include, - Exclude: windows_integration.DefaultConfig.SMTP.Exclude, - }, - TextFile: TextFileConfig{ - TextFileDirectory: windows_integration.DefaultConfig.TextFile.TextFileDirectory, - }, -} - // Arguments is used for controlling for this exporter. type Arguments struct { // Collectors to mark as enabled @@ -92,11 +26,6 @@ type Arguments struct { TextFile TextFileConfig `river:"text_file,block,optional"` } -// SetToDefault implements river.Defaulter. -func (a *Arguments) SetToDefault() { - *a = DefaultArguments -} - // Convert converts the component's Arguments to the integration's Config. func (a *Arguments) Convert() *windows_integration.Config { return &windows_integration.Config{ diff --git a/component/prometheus/exporter/windows/config_default_windows_test.go b/component/prometheus/exporter/windows/config_default_windows_test.go index c17f6e33fa60..9fddd1d635eb 100644 --- a/component/prometheus/exporter/windows/config_default_windows_test.go +++ b/component/prometheus/exporter/windows/config_default_windows_test.go @@ -1,10 +1,8 @@ package windows import ( - "strings" "testing" - windows_integration "github.com/grafana/agent/pkg/integrations/windows_exporter" "github.com/grafana/river" "github.com/stretchr/testify/require" ) @@ -14,26 +12,26 @@ func TestRiverUnmarshalWithDefaultConfig(t *testing.T) { err := river.Unmarshal([]byte(""), &args) require.NoError(t, err) - require.Equal(t, strings.Split(windows_integration.DefaultConfig.EnabledCollectors, ","), args.EnabledCollectors) - require.Equal(t, strings.Split(windows_integration.DefaultConfig.Dfsr.SourcesEnabled, ","), args.Dfsr.SourcesEnabled) - require.Equal(t, strings.Split(windows_integration.DefaultConfig.Exchange.EnabledList, ","), args.Exchange.EnabledList) - require.Equal(t, windows_integration.DefaultConfig.IIS.AppExclude, args.IIS.AppExclude) - require.Equal(t, windows_integration.DefaultConfig.IIS.AppInclude, args.IIS.AppInclude) - require.Equal(t, windows_integration.DefaultConfig.IIS.SiteExclude, args.IIS.SiteExclude) - require.Equal(t, windows_integration.DefaultConfig.IIS.SiteInclude, args.IIS.SiteInclude) - require.Equal(t, windows_integration.DefaultConfig.LogicalDisk.Exclude, args.LogicalDisk.Exclude) - require.Equal(t, windows_integration.DefaultConfig.LogicalDisk.Include, args.LogicalDisk.Include) - require.Equal(t, windows_integration.DefaultConfig.MSMQ.Where, args.MSMQ.Where) - require.Equal(t, strings.Split(windows_integration.DefaultConfig.MSSQL.EnabledClasses, ","), args.MSSQL.EnabledClasses) - require.Equal(t, windows_integration.DefaultConfig.Network.Exclude, args.Network.Exclude) - require.Equal(t, windows_integration.DefaultConfig.Network.Include, args.Network.Include) - require.Equal(t, windows_integration.DefaultConfig.Process.Exclude, args.Process.Exclude) - require.Equal(t, windows_integration.DefaultConfig.Process.Include, args.Process.Include) - require.Equal(t, windows_integration.DefaultConfig.ScheduledTask.Exclude, args.ScheduledTask.Exclude) - require.Equal(t, windows_integration.DefaultConfig.ScheduledTask.Include, args.ScheduledTask.Include) - require.Equal(t, windows_integration.DefaultConfig.Service.UseApi, args.Service.UseApi) - require.Equal(t, windows_integration.DefaultConfig.Service.Where, args.Service.Where) - require.Equal(t, windows_integration.DefaultConfig.SMTP.Exclude, args.SMTP.Exclude) - require.Equal(t, windows_integration.DefaultConfig.SMTP.Include, args.SMTP.Include) - require.Equal(t, windows_integration.DefaultConfig.TextFile.TextFileDirectory, args.TextFile.TextFileDirectory) + require.Equal(t, DefaultArguments.EnabledCollectors, args.EnabledCollectors) + require.Equal(t, DefaultArguments.Dfsr.SourcesEnabled, args.Dfsr.SourcesEnabled) + require.Equal(t, DefaultArguments.Exchange.EnabledList, args.Exchange.EnabledList) + require.Equal(t, DefaultArguments.IIS.AppExclude, args.IIS.AppExclude) + require.Equal(t, DefaultArguments.IIS.AppInclude, args.IIS.AppInclude) + require.Equal(t, DefaultArguments.IIS.SiteExclude, args.IIS.SiteExclude) + require.Equal(t, DefaultArguments.IIS.SiteInclude, args.IIS.SiteInclude) + require.Equal(t, DefaultArguments.LogicalDisk.Exclude, args.LogicalDisk.Exclude) + require.Equal(t, DefaultArguments.LogicalDisk.Include, args.LogicalDisk.Include) + require.Equal(t, DefaultArguments.MSMQ.Where, args.MSMQ.Where) + require.Equal(t, DefaultArguments.MSSQL.EnabledClasses, args.MSSQL.EnabledClasses) + require.Equal(t, DefaultArguments.Network.Exclude, args.Network.Exclude) + require.Equal(t, DefaultArguments.Network.Include, args.Network.Include) + require.Equal(t, DefaultArguments.Process.Exclude, args.Process.Exclude) + require.Equal(t, DefaultArguments.Process.Include, args.Process.Include) + require.Equal(t, DefaultArguments.ScheduledTask.Exclude, args.ScheduledTask.Exclude) + require.Equal(t, DefaultArguments.ScheduledTask.Include, args.ScheduledTask.Include) + require.Equal(t, DefaultArguments.Service.UseApi, args.Service.UseApi) + require.Equal(t, DefaultArguments.Service.Where, args.Service.Where) + require.Equal(t, DefaultArguments.SMTP.Exclude, args.SMTP.Exclude) + require.Equal(t, DefaultArguments.SMTP.Include, args.SMTP.Include) + require.Equal(t, DefaultArguments.TextFile.TextFileDirectory, args.TextFile.TextFileDirectory) } diff --git a/component/prometheus/exporter/windows/config_windows.go b/component/prometheus/exporter/windows/config_windows.go new file mode 100644 index 000000000000..b634788eda8c --- /dev/null +++ b/component/prometheus/exporter/windows/config_windows.go @@ -0,0 +1,75 @@ +package windows + +import ( + windows_integration "github.com/grafana/agent/pkg/integrations/windows_exporter" + col "github.com/prometheus-community/windows_exporter/pkg/collector" + "strings" +) + +// DefaultArguments holds non-zero default options for Arguments when it is +// unmarshaled from YAML. +var DefaultArguments = Arguments{ + EnabledCollectors: strings.Split(windows_integration.DefaultConfig.EnabledCollectors, ","), + Dfsr: DfsrConfig{ + SourcesEnabled: strings.Split(col.ConfigDefaults.Dfsr.DfsrEnabledCollectors, ","), + }, + Exchange: ExchangeConfig{ + EnabledList: strings.Split(col.ConfigDefaults.Exchange.CollectorsEnabled, ","), + }, + IIS: IISConfig{ + AppBlackList: col.ConfigDefaults.Iis.AppExclude, + AppWhiteList: col.ConfigDefaults.Iis.AppInclude, + SiteBlackList: col.ConfigDefaults.Iis.SiteExclude, + SiteWhiteList: col.ConfigDefaults.Iis.SiteInclude, + AppInclude: col.ConfigDefaults.Iis.AppInclude, + AppExclude: col.ConfigDefaults.Iis.AppExclude, + SiteInclude: col.ConfigDefaults.Iis.SiteInclude, + SiteExclude: col.ConfigDefaults.Iis.SiteExclude, + }, + LogicalDisk: LogicalDiskConfig{ + BlackList: col.ConfigDefaults.LogicalDisk.VolumeExclude, + WhiteList: col.ConfigDefaults.LogicalDisk.VolumeInclude, + Include: col.ConfigDefaults.LogicalDisk.VolumeInclude, + Exclude: col.ConfigDefaults.LogicalDisk.VolumeExclude, + }, + MSMQ: MSMQConfig{ + Where: col.ConfigDefaults.Msmq.QueryWhereClause, + }, + MSSQL: MSSQLConfig{ + EnabledClasses: strings.Split(col.ConfigDefaults.Mssql.EnabledCollectors, ","), + }, + Network: NetworkConfig{ + BlackList: col.ConfigDefaults.Net.NicExclude, + WhiteList: col.ConfigDefaults.Net.NicInclude, + Include: col.ConfigDefaults.Net.NicInclude, + Exclude: col.ConfigDefaults.Net.NicExclude, + }, + Process: ProcessConfig{ + BlackList: col.ConfigDefaults.Process.ProcessExclude, + WhiteList: col.ConfigDefaults.Process.ProcessInclude, + Include: col.ConfigDefaults.Process.ProcessInclude, + Exclude: col.ConfigDefaults.Process.ProcessExclude, + }, + ScheduledTask: ScheduledTaskConfig{ + Include: col.ConfigDefaults.ScheduledTask.TaskInclude, + Exclude: col.ConfigDefaults.ScheduledTask.TaskExclude, + }, + Service: ServiceConfig{ + UseApi: "false", + Where: col.ConfigDefaults.Service.ServiceWhereClause, + }, + SMTP: SMTPConfig{ + BlackList: col.ConfigDefaults.Smtp.ServerExclude, + WhiteList: col.ConfigDefaults.Smtp.ServerInclude, + Include: col.ConfigDefaults.Smtp.ServerInclude, + Exclude: col.ConfigDefaults.Smtp.ServerExclude, + }, + TextFile: TextFileConfig{ + TextFileDirectory: col.ConfigDefaults.Textfile.TextFileDirectories, + }, +} + +// SetToDefault implements river.Defaulter. +func (a *Arguments) SetToDefault() { + *a = DefaultArguments +} diff --git a/component/prometheus/exporter/windows/windows.go b/component/prometheus/exporter/windows/windows.go index 214302748aee..5f05d3cc63e7 100644 --- a/component/prometheus/exporter/windows/windows.go +++ b/component/prometheus/exporter/windows/windows.go @@ -8,11 +8,11 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.exporter.windows", - Args: Arguments{}, - Exports: exporter.Exports{}, - NeedsServices: exporter.RequiredServices(), - Build: exporter.New(createExporter, "windows"), + Name: "prometheus.exporter.windows", + Args: Arguments{}, + Exports: exporter.Exports{}, + + Build: exporter.New(createExporter, "windows"), }) } diff --git a/component/prometheus/operator/common/crdmanager.go b/component/prometheus/operator/common/crdmanager.go index 9f8bd55f79f6..85f13719e970 100644 --- a/component/prometheus/operator/common/crdmanager.go +++ b/component/prometheus/operator/common/crdmanager.go @@ -42,12 +42,19 @@ const informerSyncTimeout = 10 * time.Second // crdManager is all of the fields required to run a crd based component. // on update, this entire thing should be recreated and restarted type crdManager struct { - mut sync.Mutex - discoveryConfigs map[string]discovery.Configs - scrapeConfigs map[string]*config.ScrapeConfig - debugInfo map[string]*operator.DiscoveredResource - discoveryManager *discovery.Manager - scrapeManager *scrape.Manager + mut sync.Mutex + + // these maps are keyed by job name + discoveryConfigs map[string]discovery.Configs + scrapeConfigs map[string]*config.ScrapeConfig + + // list of keys to the above maps for a given resource by `ns/name` + crdsToMapKeys map[string][]string + // debug info by `kind/ns/name` + debugInfo map[string]*operator.DiscoveredResource + + discoveryManager discoveryManager + scrapeManager scrapeManager clusteringUpdated chan struct{} ls labelstore.LabelStore @@ -80,6 +87,7 @@ func newCrdManager(opts component.Options, cluster cluster.Cluster, logger log.L cluster: cluster, discoveryConfigs: map[string]discovery.Configs{}, scrapeConfigs: map[string]*config.ScrapeConfig{}, + crdsToMapKeys: map[string][]string{}, debugInfo: map[string]*operator.DiscoveredResource{}, kind: kind, clusteringUpdated: make(chan struct{}, 1), @@ -392,6 +400,7 @@ func (c *crdManager) addPodMonitor(pm *promopv1.PodMonitor) { AdditionalRelabelConfigs: c.args.RelabelConfigs, ScrapeOptions: c.args.Scrape, } + mapKeys := []string{} for i, ep := range pm.Spec.PodMetricsEndpoints { var scrapeConfig *config.ScrapeConfig scrapeConfig, err = gen.GeneratePodMonitorConfig(pm, ep, i) @@ -400,6 +409,7 @@ func (c *crdManager) addPodMonitor(pm *promopv1.PodMonitor) { level.Error(c.logger).Log("name", pm.Name, "err", err, "msg", "error generating scrapeconfig from podmonitor") break } + mapKeys = append(mapKeys, scrapeConfig.JobName) c.mut.Lock() c.discoveryConfigs[scrapeConfig.JobName] = scrapeConfig.ServiceDiscoveryConfigs c.scrapeConfigs[scrapeConfig.JobName] = scrapeConfig @@ -409,6 +419,9 @@ func (c *crdManager) addPodMonitor(pm *promopv1.PodMonitor) { c.addDebugInfo(pm.Namespace, pm.Name, err) return } + c.mut.Lock() + c.crdsToMapKeys[fmt.Sprintf("%s/%s", pm.Namespace, pm.Name)] = mapKeys + c.mut.Unlock() if err = c.apply(); err != nil { level.Error(c.logger).Log("name", pm.Name, "err", err, "msg", "error applying scrape configs from "+c.kind) } @@ -442,6 +455,8 @@ func (c *crdManager) addServiceMonitor(sm *promopv1.ServiceMonitor) { AdditionalRelabelConfigs: c.args.RelabelConfigs, ScrapeOptions: c.args.Scrape, } + + mapKeys := []string{} for i, ep := range sm.Spec.Endpoints { var scrapeConfig *config.ScrapeConfig scrapeConfig, err = gen.GenerateServiceMonitorConfig(sm, ep, i) @@ -450,6 +465,7 @@ func (c *crdManager) addServiceMonitor(sm *promopv1.ServiceMonitor) { level.Error(c.logger).Log("name", sm.Name, "err", err, "msg", "error generating scrapeconfig from serviceMonitor") break } + mapKeys = append(mapKeys, scrapeConfig.JobName) c.mut.Lock() c.discoveryConfigs[scrapeConfig.JobName] = scrapeConfig.ServiceDiscoveryConfigs c.scrapeConfigs[scrapeConfig.JobName] = scrapeConfig @@ -459,6 +475,9 @@ func (c *crdManager) addServiceMonitor(sm *promopv1.ServiceMonitor) { c.addDebugInfo(sm.Namespace, sm.Name, err) return } + c.mut.Lock() + c.crdsToMapKeys[fmt.Sprintf("%s/%s", sm.Namespace, sm.Name)] = mapKeys + c.mut.Unlock() if err = c.apply(); err != nil { level.Error(c.logger).Log("name", sm.Name, "err", err, "msg", "error applying scrape configs from "+c.kind) } @@ -503,6 +522,7 @@ func (c *crdManager) addProbe(p *promopv1.Probe) { c.mut.Lock() c.discoveryConfigs[pmc.JobName] = pmc.ServiceDiscoveryConfigs c.scrapeConfigs[pmc.JobName] = pmc + c.crdsToMapKeys[fmt.Sprintf("%s/%s", p.Namespace, p.Name)] = []string{pmc.JobName} c.mut.Unlock() if err = c.apply(); err != nil { @@ -533,12 +553,10 @@ func (c *crdManager) onDeleteProbe(obj interface{}) { func (c *crdManager) clearConfigs(ns, name string) { c.mut.Lock() defer c.mut.Unlock() - prefix := fmt.Sprintf("%s/%s/%s", c.kind, ns, name) - for k := range c.discoveryConfigs { - if strings.HasPrefix(k, prefix) { - delete(c.discoveryConfigs, k) - delete(c.scrapeConfigs, k) - } + + for _, k := range c.crdsToMapKeys[fmt.Sprintf("%s/%s", ns, name)] { + delete(c.discoveryConfigs, k) + delete(c.scrapeConfigs, k) } - delete(c.debugInfo, prefix) + delete(c.debugInfo, fmt.Sprintf("%s/%s/%s", c.kind, ns, name)) } diff --git a/component/prometheus/operator/common/crdmanager_test.go b/component/prometheus/operator/common/crdmanager_test.go new file mode 100644 index 000000000000..7e3cd75fbd37 --- /dev/null +++ b/component/prometheus/operator/common/crdmanager_test.go @@ -0,0 +1,168 @@ +package common + +import ( + "testing" + + "golang.org/x/exp/maps" + + "github.com/go-kit/log" + "github.com/grafana/agent/component" + "github.com/grafana/agent/component/prometheus/operator" + "github.com/grafana/agent/service/cluster" + "github.com/grafana/agent/service/labelstore" + "github.com/prometheus/prometheus/config" + "github.com/prometheus/prometheus/discovery" + "github.com/prometheus/prometheus/discovery/targetgroup" + "github.com/prometheus/prometheus/scrape" + "k8s.io/apimachinery/pkg/util/intstr" + + promopv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/stretchr/testify/require" +) + +func TestClearConfigsSameNsSamePrefix(t *testing.T) { + logger := log.NewNopLogger() + m := newCrdManager( + component.Options{ + Logger: logger, + GetServiceData: func(name string) (interface{}, error) { return nil, nil }, + }, + cluster.Mock(), + logger, + &operator.DefaultArguments, + KindServiceMonitor, + labelstore.New(logger), + ) + + m.discoveryManager = newMockDiscoveryManager() + m.scrapeManager = newMockScrapeManager() + + targetPort := intstr.FromInt(9090) + m.onAddServiceMonitor(&promopv1.ServiceMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "monitoring", + Name: "svcmonitor", + }, + Spec: promopv1.ServiceMonitorSpec{ + Selector: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "group": "my-group", + }, + }, + Endpoints: []promopv1.Endpoint{ + { + TargetPort: &targetPort, + ScrapeTimeout: "5s", + Interval: "10s", + }, + }, + }, + }) + m.onAddServiceMonitor(&promopv1.ServiceMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "monitoring", + Name: "svcmonitor-another", + }, + Spec: promopv1.ServiceMonitorSpec{ + Selector: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "group": "my-group", + }, + }, + Endpoints: []promopv1.Endpoint{ + { + TargetPort: &targetPort, + ScrapeTimeout: "5s", + Interval: "10s", + }, + }, + }}) + + require.ElementsMatch(t, []string{"serviceMonitor/monitoring/svcmonitor-another/0", "serviceMonitor/monitoring/svcmonitor/0"}, maps.Keys(m.discoveryConfigs)) + m.clearConfigs("monitoring", "svcmonitor") + require.ElementsMatch(t, []string{"monitoring/svcmonitor", "monitoring/svcmonitor-another"}, maps.Keys(m.crdsToMapKeys)) + require.ElementsMatch(t, []string{"serviceMonitor/monitoring/svcmonitor-another/0"}, maps.Keys(m.discoveryConfigs)) + require.ElementsMatch(t, []string{"serviceMonitor/monitoring/svcmonitor-another"}, maps.Keys(m.debugInfo)) +} + +func TestClearConfigsProbe(t *testing.T) { + logger := log.NewNopLogger() + m := newCrdManager( + component.Options{ + Logger: logger, + GetServiceData: func(name string) (interface{}, error) { return nil, nil }, + }, + cluster.Mock(), + logger, + &operator.DefaultArguments, + KindProbe, + labelstore.New(logger), + ) + + m.discoveryManager = newMockDiscoveryManager() + m.scrapeManager = newMockScrapeManager() + + m.onAddProbe(&promopv1.Probe{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "monitoring", + Name: "probe", + }, + Spec: promopv1.ProbeSpec{}, + }) + m.onAddProbe(&promopv1.Probe{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "monitoring", + Name: "probe-another", + }, + Spec: promopv1.ProbeSpec{}}) + + require.ElementsMatch(t, []string{"probe/monitoring/probe-another", "probe/monitoring/probe"}, maps.Keys(m.discoveryConfigs)) + m.clearConfigs("monitoring", "probe") + require.ElementsMatch(t, []string{"monitoring/probe", "monitoring/probe-another"}, maps.Keys(m.crdsToMapKeys)) + require.ElementsMatch(t, []string{"probe/monitoring/probe-another"}, maps.Keys(m.discoveryConfigs)) + require.ElementsMatch(t, []string{"probe/monitoring/probe-another"}, maps.Keys(m.debugInfo)) +} + +type mockDiscoveryManager struct { +} + +func newMockDiscoveryManager() *mockDiscoveryManager { + return &mockDiscoveryManager{} +} + +func (m *mockDiscoveryManager) Run() error { + return nil +} + +func (m *mockDiscoveryManager) SyncCh() <-chan map[string][]*targetgroup.Group { + return nil +} + +func (m *mockDiscoveryManager) ApplyConfig(cfg map[string]discovery.Configs) error { + return nil +} + +type mockScrapeManager struct { +} + +func newMockScrapeManager() *mockScrapeManager { + return &mockScrapeManager{} +} + +func (m *mockScrapeManager) Run(tsets <-chan map[string][]*targetgroup.Group) error { + return nil +} + +func (m *mockScrapeManager) Stop() { + +} + +func (m *mockScrapeManager) TargetsActive() map[string][]*scrape.Target { + return nil +} + +func (m *mockScrapeManager) ApplyConfig(cfg *config.Config) error { + return nil +} diff --git a/component/prometheus/operator/common/interfaces.go b/component/prometheus/operator/common/interfaces.go new file mode 100644 index 000000000000..4652154f6dc6 --- /dev/null +++ b/component/prometheus/operator/common/interfaces.go @@ -0,0 +1,23 @@ +package common + +import ( + "github.com/prometheus/prometheus/config" + "github.com/prometheus/prometheus/discovery" + "github.com/prometheus/prometheus/discovery/targetgroup" + "github.com/prometheus/prometheus/scrape" +) + +// discoveryManager is an interface around discovery.Manager +type discoveryManager interface { + Run() error + SyncCh() <-chan map[string][]*targetgroup.Group + ApplyConfig(cfg map[string]discovery.Configs) error +} + +// scrapeManager is an interface around scrape.Manager +type scrapeManager interface { + Run(tsets <-chan map[string][]*targetgroup.Group) error + Stop() + TargetsActive() map[string][]*scrape.Target + ApplyConfig(cfg *config.Config) error +} diff --git a/component/prometheus/operator/podmonitors/operator.go b/component/prometheus/operator/podmonitors/operator.go index 41fb781f5db4..ea41d6f0fe27 100644 --- a/component/prometheus/operator/podmonitors/operator.go +++ b/component/prometheus/operator/podmonitors/operator.go @@ -4,16 +4,12 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/prometheus/operator" "github.com/grafana/agent/component/prometheus/operator/common" - "github.com/grafana/agent/service/cluster" - "github.com/grafana/agent/service/http" - "github.com/grafana/agent/service/labelstore" ) func init() { component.Register(component.Registration{ - Name: "prometheus.operator.podmonitors", - Args: operator.Arguments{}, - NeedsServices: []string{cluster.ServiceName, http.ServiceName, labelstore.ServiceName}, + Name: "prometheus.operator.podmonitors", + Args: operator.Arguments{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { return common.New(opts, args, common.KindPodMonitor) diff --git a/component/prometheus/operator/probes/probes.go b/component/prometheus/operator/probes/probes.go index 00dad3fd9821..a8d96b428489 100644 --- a/component/prometheus/operator/probes/probes.go +++ b/component/prometheus/operator/probes/probes.go @@ -4,16 +4,12 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/prometheus/operator" "github.com/grafana/agent/component/prometheus/operator/common" - "github.com/grafana/agent/service/cluster" - "github.com/grafana/agent/service/http" - "github.com/grafana/agent/service/labelstore" ) func init() { component.Register(component.Registration{ - Name: "prometheus.operator.probes", - Args: operator.Arguments{}, - NeedsServices: []string{cluster.ServiceName, http.ServiceName, labelstore.ServiceName}, + Name: "prometheus.operator.probes", + Args: operator.Arguments{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { return common.New(opts, args, common.KindProbe) diff --git a/component/prometheus/operator/servicemonitors/servicemonitors.go b/component/prometheus/operator/servicemonitors/servicemonitors.go index 8df947f10883..55c1e34c2bbe 100644 --- a/component/prometheus/operator/servicemonitors/servicemonitors.go +++ b/component/prometheus/operator/servicemonitors/servicemonitors.go @@ -4,16 +4,12 @@ import ( "github.com/grafana/agent/component" "github.com/grafana/agent/component/prometheus/operator" "github.com/grafana/agent/component/prometheus/operator/common" - "github.com/grafana/agent/service/cluster" - "github.com/grafana/agent/service/http" - "github.com/grafana/agent/service/labelstore" ) func init() { component.Register(component.Registration{ - Name: "prometheus.operator.servicemonitors", - Args: operator.Arguments{}, - NeedsServices: []string{cluster.ServiceName, http.ServiceName, labelstore.ServiceName}, + Name: "prometheus.operator.servicemonitors", + Args: operator.Arguments{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { return common.New(opts, args, common.KindServiceMonitor) diff --git a/component/prometheus/receive_http/receive_http.go b/component/prometheus/receive_http/receive_http.go index 5fc0abb91b1c..3e78e1e7472c 100644 --- a/component/prometheus/receive_http/receive_http.go +++ b/component/prometheus/receive_http/receive_http.go @@ -21,9 +21,9 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.receive_http", - Args: Arguments{}, - NeedsServices: []string{labelstore.ServiceName}, + Name: "prometheus.receive_http", + Args: Arguments{}, + Build: func(opts component.Options, args component.Arguments) (component.Component, error) { return New(opts, args.(Arguments)) }, diff --git a/component/prometheus/relabel/relabel.go b/component/prometheus/relabel/relabel.go index 2f8fd5ab077c..c7b39ad6b0f4 100644 --- a/component/prometheus/relabel/relabel.go +++ b/component/prometheus/relabel/relabel.go @@ -26,10 +26,10 @@ import ( func init() { component.Register(component.Registration{ - Name: "prometheus.relabel", - Args: Arguments{}, - Exports: Exports{}, - NeedsServices: []string{labelstore.ServiceName}, + Name: "prometheus.relabel", + Args: Arguments{}, + Exports: Exports{}, + Build: func(opts component.Options, args component.Arguments) (component.Component, error) { return New(opts, args.(Arguments)) }, diff --git a/component/prometheus/remotewrite/remote_write.go b/component/prometheus/remotewrite/remote_write.go index ed6ec0089b39..e337ff8f8cca 100644 --- a/component/prometheus/remotewrite/remote_write.go +++ b/component/prometheus/remotewrite/remote_write.go @@ -38,10 +38,10 @@ func init() { remote.UserAgent = useragent.Get() component.Register(component.Registration{ - Name: "prometheus.remote_write", - Args: Arguments{}, - Exports: Exports{}, - NeedsServices: []string{labelstore.ServiceName}, + Name: "prometheus.remote_write", + Args: Arguments{}, + Exports: Exports{}, + Build: func(o component.Options, c component.Arguments) (component.Component, error) { return New(o, c.(Arguments)) }, diff --git a/component/prometheus/scrape/scrape.go b/component/prometheus/scrape/scrape.go index d700221d1a15..8db6fc27d47e 100644 --- a/component/prometheus/scrape/scrape.go +++ b/component/prometheus/scrape/scrape.go @@ -30,9 +30,9 @@ func init() { scrape.UserAgent = useragent.Get() component.Register(component.Registration{ - Name: "prometheus.scrape", - Args: Arguments{}, - NeedsServices: []string{http.ServiceName, cluster.ServiceName, labelstore.ServiceName}, + Name: "prometheus.scrape", + Args: Arguments{}, + Build: func(opts component.Options, args component.Arguments) (component.Component, error) { return New(opts, args.(Arguments)) }, diff --git a/component/pyroscope/scrape/scrape.go b/component/pyroscope/scrape/scrape.go index 846fee049e5e..bf84c1567e4f 100644 --- a/component/pyroscope/scrape/scrape.go +++ b/component/pyroscope/scrape/scrape.go @@ -33,9 +33,8 @@ const ( func init() { component.Register(component.Registration{ - Name: "pyroscope.scrape", - Args: Arguments{}, - NeedsServices: []string{cluster.ServiceName}, + Name: "pyroscope.scrape", + Args: Arguments{}, Build: func(opts component.Options, args component.Arguments) (component.Component, error) { return New(opts, args.(Arguments)) diff --git a/component/pyroscope/scrape/scrape_loop.go b/component/pyroscope/scrape/scrape_loop.go index 2b74930ed191..a1f7d2a6c1b7 100644 --- a/component/pyroscope/scrape/scrape_loop.go +++ b/component/pyroscope/scrape/scrape_loop.go @@ -228,7 +228,7 @@ func (t *scrapeLoop) scrape() { } } if err := t.fetchProfile(scrapeCtx, profileType, buf); err != nil { - level.Debug(t.logger).Log("msg", "fetch profile failed", "target", t.Labels().String(), "err", err) + level.Error(t.logger).Log("msg", "fetch profile failed", "target", t.Labels().String(), "err", err) t.updateTargetStatus(start, err) return } diff --git a/component/registry.go b/component/registry.go index 20a364be81c4..79b8bff2b574 100644 --- a/component/registry.go +++ b/component/registry.go @@ -97,8 +97,7 @@ type Options struct { // GetServiceData retrieves data for a service by calling // [service.Service.Data] for the specified service. // - // GetServiceData will return an error if the service does not exist or was - // not listed as a dependency with the registration of the component. + // GetServiceData will return an error if the service does not exist. // // The result of GetServiceData may be cached as the value will not change at // runtime. @@ -127,15 +126,6 @@ type Registration struct { // A component which does not expose exports must leave this set to nil. Exports Exports - // NeedsServices holds the set of service names which this component depends - // on to run. If NeedsServices includes an invalid service name (either - // because of a cyclic dependency or the named service doesn't exist), - // components will fail to evaluate. - // - // Modules which are loaded by the registered component will only be able to - // access services in this list. - NeedsServices []string - // Build should construct a new component from an initial Arguments and set // of options. Build func(opts Options, args Arguments) (Component, error) diff --git a/converter/internal/staticconvert/internal/build/cadvisor_exporter.go b/converter/internal/staticconvert/internal/build/cadvisor_exporter.go index dbedebfb2967..0c6445c5376f 100644 --- a/converter/internal/staticconvert/internal/build/cadvisor_exporter.go +++ b/converter/internal/staticconvert/internal/build/cadvisor_exporter.go @@ -33,5 +33,6 @@ func toCadvisorExporter(config *cadvisor_integration.Config) *cadvisor.Arguments DockerTLSKey: config.DockerTLSKey, DockerTLSCA: config.DockerTLSCA, DockerOnly: config.DockerOnly, + DisableRootCgroupStats: config.DisableRootCgroupStats, } } diff --git a/converter/internal/staticconvert/internal/build/windows_exporter.go b/converter/internal/staticconvert/internal/build/windows_exporter.go index 27e9679887b8..73aa706e8235 100644 --- a/converter/internal/staticconvert/internal/build/windows_exporter.go +++ b/converter/internal/staticconvert/internal/build/windows_exporter.go @@ -47,8 +47,8 @@ func toWindowsExporter(config *windows_exporter.Config) *windows.Arguments { Network: windows.NetworkConfig{ BlackList: config.Network.BlackList, WhiteList: config.Network.WhiteList, - Exclude: config.Network.Include, - Include: config.Network.Exclude, + Exclude: config.Network.Exclude, + Include: config.Network.Include, }, Process: windows.ProcessConfig{ BlackList: config.Process.BlackList, diff --git a/docs/sources/flow/reference/components/otelcol.exporter.prometheus.md b/docs/sources/flow/reference/components/otelcol.exporter.prometheus.md index 8c8f81d133d1..584b30bd97e4 100644 --- a/docs/sources/flow/reference/components/otelcol.exporter.prometheus.md +++ b/docs/sources/flow/reference/components/otelcol.exporter.prometheus.md @@ -46,6 +46,7 @@ Name | Type | Description | Defaul `add_metric_suffixes` | `boolean` | Whether to add type and unit suffixes to metrics names. | `true` | no `gc_frequency` | `duration` | How often to clean up stale metrics from memory. | `"5m"` | no `forward_to` | `list(receiver)` | Where to forward converted Prometheus metrics. | | yes +`resource_to_telemetry_conversion` | `boolean` | Whether to convert OTel resource attributes to Prometheus labels. | `false` | no By default, OpenTelemetry resources are converted into `target_info` metrics. OpenTelemetry instrumentation scopes are converted into `otel_scope_info` diff --git a/docs/sources/flow/reference/components/prometheus.exporter.cadvisor.md b/docs/sources/flow/reference/components/prometheus.exporter.cadvisor.md index 567783c38702..845a0fe0adec 100644 --- a/docs/sources/flow/reference/components/prometheus.exporter.cadvisor.md +++ b/docs/sources/flow/reference/components/prometheus.exporter.cadvisor.md @@ -43,6 +43,7 @@ Name | Type | Description | Default | Required `docker_tls_key` | `string` | Path to private key for TLS connection to docker. | `key.pem` | no `docker_tls_ca` | `string` | Path to a trusted CA for TLS connection to docker. | `ca.pem` | no `docker_only` | `bool` | Only report docker containers in addition to root stats. | `false` | no +`disable_root_cgroup_stats` | `bool` | Disable collecting root Cgroup stats. | `false` | no For `allowlisted_container_labels` to take effect, `store_container_labels` must be set to `false`. diff --git a/docs/sources/flow/reference/components/prometheus.exporter.mssql.md b/docs/sources/flow/reference/components/prometheus.exporter.mssql.md index 84786ee074a0..93fb305f8a5d 100644 --- a/docs/sources/flow/reference/components/prometheus.exporter.mssql.md +++ b/docs/sources/flow/reference/components/prometheus.exporter.mssql.md @@ -12,7 +12,8 @@ title: prometheus.exporter.mssql # prometheus.exporter.mssql The `prometheus.exporter.mssql` component embeds -[sql_exporter](https://github.com/burningalchemist/sql_exporter) for collecting stats from a Microsoft SQL Server. +[sql_exporter](https://github.com/burningalchemist/sql_exporter) for collecting stats from a Microsoft SQL Server and exposing them as +Prometheus metrics. ## Usage @@ -27,12 +28,13 @@ prometheus.exporter.mssql "LABEL" { The following arguments can be used to configure the exporter's behavior. Omitted fields take their default values. -| Name | Type | Description | Default | Required | -| ---------------------- | ---------- | ----------------------------------------------------------------- | ------- | -------- | -| `connection_string` | `secret` | The connection string used to connect to an Microsoft SQL Server. | | yes | -| `max_idle_connections` | `int` | Maximum number of idle connections to any one target. | `3` | no | -| `max_open_connections` | `int` | Maximum number of open connections to any one target. | `3` | no | -| `timeout` | `duration` | The query timeout in seconds. | `"10s"` | no | +| Name | Type | Description | Default | Required | +| ---------------------- | ---------- | ------------------------------------------------------------------- | ------- | -------- | +| `connection_string` | `secret` | The connection string used to connect to an Microsoft SQL Server. | | yes | +| `max_idle_connections` | `int` | Maximum number of idle connections to any one target. | `3` | no | +| `max_open_connections` | `int` | Maximum number of open connections to any one target. | `3` | no | +| `timeout` | `duration` | The query timeout in seconds. | `"10s"` | no | +| `query_config` | `string` | MSSQL query to Prometheus metric configuration as an inline string. | | no | [The sql_exporter examples](https://github.com/burningalchemist/sql_exporter/blob/master/examples/azure-sql-mi/sql_exporter.yml#L21) show the format of the `connection_string` argument: @@ -40,6 +42,15 @@ Omitted fields take their default values. sqlserver://USERNAME_HERE:PASSWORD_HERE@SQLMI_HERE_ENDPOINT.database.windows.net:1433?encrypt=true&hostNameInCertificate=%2A.SQL_MI_DOMAIN_HERE.database.windows.net&trustservercertificate=true ``` +If specified, the `query_config` argument must be a YAML document as string defining which MSSQL queries map to custom Prometheus metrics. +`query_config` is typically loaded by using the exports of another component. For example, + +- `local.file.LABEL.content` +- `remote.http.LABEL.content` +- `remote.s3.LABEL.content` + +See [sql_exporter](https://github.com/burningalchemist/sql_exporter#collectors) for details on how to create a configuration. + ## Blocks The `prometheus.exporter.mssql` component does not support any blocks, and is configured @@ -100,3 +111,222 @@ Replace the following: - `PASSWORD`: The password to use for authentication to the remote_write API. [scrape]: {{< relref "./prometheus.scrape.md" >}} + +## Custom metrics +You can use the optional `query_config` parameter to retrieve custom Prometheus metrics for a MSSQL instance. + +If this is defined, the new configuration will be used to query your MSSQL instance and create whatever Prometheus metrics are defined. +If you want additional metrics on top of the default metrics, the default configuration must be used as a base. + +The default configuration used by this integration is as follows: +``` +collector_name: mssql_standard + +metrics: + - metric_name: mssql_local_time_seconds + type: gauge + help: 'Local time in seconds since epoch (Unix time).' + values: [unix_time] + query: | + SELECT DATEDIFF(second, '19700101', GETUTCDATE()) AS unix_time + - metric_name: mssql_connections + type: gauge + help: 'Number of active connections.' + key_labels: + - db + values: [count] + query: | + SELECT DB_NAME(sp.dbid) AS db, COUNT(sp.spid) AS count + FROM sys.sysprocesses sp + GROUP BY DB_NAME(sp.dbid) + # + # Collected from sys.dm_os_performance_counters + # + - metric_name: mssql_deadlocks_total + type: counter + help: 'Number of lock requests that resulted in a deadlock.' + values: [cntr_value] + query: | + SELECT cntr_value + FROM sys.dm_os_performance_counters WITH (NOLOCK) + WHERE counter_name = 'Number of Deadlocks/sec' AND instance_name = '_Total' + - metric_name: mssql_user_errors_total + type: counter + help: 'Number of user errors.' + values: [cntr_value] + query: | + SELECT cntr_value + FROM sys.dm_os_performance_counters WITH (NOLOCK) + WHERE counter_name = 'Errors/sec' AND instance_name = 'User Errors' + - metric_name: mssql_kill_connection_errors_total + type: counter + help: 'Number of severe errors that caused SQL Server to kill the connection.' + values: [cntr_value] + query: | + SELECT cntr_value + FROM sys.dm_os_performance_counters WITH (NOLOCK) + WHERE counter_name = 'Errors/sec' AND instance_name = 'Kill Connection Errors' + - metric_name: mssql_page_life_expectancy_seconds + type: gauge + help: 'The minimum number of seconds a page will stay in the buffer pool on this node without references.' + values: [cntr_value] + query: | + SELECT top(1) cntr_value + FROM sys.dm_os_performance_counters WITH (NOLOCK) + WHERE counter_name = 'Page life expectancy' + - metric_name: mssql_batch_requests_total + type: counter + help: 'Number of command batches received.' + values: [cntr_value] + query: | + SELECT cntr_value + FROM sys.dm_os_performance_counters WITH (NOLOCK) + WHERE counter_name = 'Batch Requests/sec' + - metric_name: mssql_log_growths_total + type: counter + help: 'Number of times the transaction log has been expanded, per database.' + key_labels: + - db + values: [cntr_value] + query: | + SELECT rtrim(instance_name) AS db, cntr_value + FROM sys.dm_os_performance_counters WITH (NOLOCK) + WHERE counter_name = 'Log Growths' AND instance_name <> '_Total' + - metric_name: mssql_buffer_cache_hit_ratio + type: gauge + help: 'Ratio of requests that hit the buffer cache' + values: [BufferCacheHitRatio] + query: | + SELECT (a.cntr_value * 1.0 / b.cntr_value) * 100.0 as BufferCacheHitRatio + FROM sys.dm_os_performance_counters a + JOIN (SELECT cntr_value, OBJECT_NAME + FROM sys.dm_os_performance_counters + WHERE counter_name = 'Buffer cache hit ratio base' + AND OBJECT_NAME = 'SQLServer:Buffer Manager') b ON a.OBJECT_NAME = b.OBJECT_NAME + WHERE a.counter_name = 'Buffer cache hit ratio' + AND a.OBJECT_NAME = 'SQLServer:Buffer Manager' + + - metric_name: mssql_checkpoint_pages_sec + type: gauge + help: 'Checkpoint Pages Per Second' + values: [cntr_value] + query: | + SELECT cntr_value + FROM sys.dm_os_performance_counters + WHERE [counter_name] = 'Checkpoint pages/sec' + # + # Collected from sys.dm_io_virtual_file_stats + # + - metric_name: mssql_io_stall_seconds_total + type: counter + help: 'Stall time in seconds per database and I/O operation.' + key_labels: + - db + value_label: operation + values: + - read + - write + query_ref: mssql_io_stall + + # + # Collected from sys.dm_os_process_memory + # + - metric_name: mssql_resident_memory_bytes + type: gauge + help: 'SQL Server resident memory size (AKA working set).' + values: [resident_memory_bytes] + query_ref: mssql_process_memory + + - metric_name: mssql_virtual_memory_bytes + type: gauge + help: 'SQL Server committed virtual memory size.' + values: [virtual_memory_bytes] + query_ref: mssql_process_memory + + - metric_name: mssql_available_commit_memory_bytes + type: gauge + help: 'SQL Server available to be committed memory size.' + values: [available_commit_limit_bytes] + query_ref: mssql_process_memory + + - metric_name: mssql_memory_utilization_percentage + type: gauge + help: 'The percentage of committed memory that is in the working set.' + values: [memory_utilization_percentage] + query_ref: mssql_process_memory + + - metric_name: mssql_page_fault_count_total + type: counter + help: 'The number of page faults that were incurred by the SQL Server process.' + values: [page_fault_count] + query_ref: mssql_process_memory + + # + # Collected from sys.dm_os_sys_info + # + - metric_name: mssql_server_total_memory_bytes + type: gauge + help: 'SQL Server committed memory in the memory manager.' + values: [committed_memory_bytes] + query_ref: mssql_os_sys_info + + - metric_name: mssql_server_target_memory_bytes + type: gauge + help: 'SQL Server target committed memory set for the memory manager.' + values: [committed_memory_target_bytes] + query_ref: mssql_os_sys_info + + # + # Collected from sys.dm_os_sys_memory + # + - metric_name: mssql_os_memory + type: gauge + help: 'OS physical memory, used and available.' + value_label: 'state' + values: [used, available] + query: | + SELECT + (total_physical_memory_kb - available_physical_memory_kb) * 1024 AS used, + available_physical_memory_kb * 1024 AS available + FROM sys.dm_os_sys_memory + - metric_name: mssql_os_page_file + type: gauge + help: 'OS page file, used and available.' + value_label: 'state' + values: [used, available] + query: | + SELECT + (total_page_file_kb - available_page_file_kb) * 1024 AS used, + available_page_file_kb * 1024 AS available + FROM sys.dm_os_sys_memory +queries: + # Populates `mssql_io_stall` and `mssql_io_stall_total` + - query_name: mssql_io_stall + query: | + SELECT + cast(DB_Name(a.database_id) as varchar) AS [db], + sum(io_stall_read_ms) / 1000.0 AS [read], + sum(io_stall_write_ms) / 1000.0 AS [write] + FROM + sys.dm_io_virtual_file_stats(null, null) a + INNER JOIN sys.master_files b ON a.database_id = b.database_id AND a.file_id = b.file_id + GROUP BY a.database_id + # Populates `mssql_resident_memory_bytes`, `mssql_virtual_memory_bytes`, mssql_available_commit_memory_bytes, + # and `mssql_memory_utilization_percentage`, and `mssql_page_fault_count_total` + - query_name: mssql_process_memory + query: | + SELECT + physical_memory_in_use_kb * 1024 AS resident_memory_bytes, + virtual_address_space_committed_kb * 1024 AS virtual_memory_bytes, + available_commit_limit_kb * 1024 AS available_commit_limit_bytes, + memory_utilization_percentage, + page_fault_count + FROM sys.dm_os_process_memory + # Populates `mssql_server_total_memory_bytes` and `mssql_server_target_memory_bytes`. + - query_name: mssql_os_sys_info + query: | + SELECT + committed_kb * 1024 AS committed_memory_bytes, + committed_target_kb * 1024 AS committed_memory_target_bytes + FROM sys.dm_os_sys_info +``` diff --git a/docs/sources/flow/reference/config-blocks/http.md b/docs/sources/flow/reference/config-blocks/http.md index 9f56dc9fc5bd..9ee6de41187f 100644 --- a/docs/sources/flow/reference/config-blocks/http.md +++ b/docs/sources/flow/reference/config-blocks/http.md @@ -16,15 +16,6 @@ title: http block HTTP server functions. `http` is specified without a label and can only be provided once per configuration file. -{{% admonition type="note" %}} -While the `http` block can reference component exports, some components that -rely on the HTTP server have a hidden dependency on the `http` block that may -result in a circular dependency error. - -Only references to components named `remote.*` or `local.*` are guaranteed to -work without any circular dependency errors. -{{% /admonition %}} - ## Example ```river @@ -184,7 +175,7 @@ will serve the found certificate even if it is not compatible with the specified ### server block -The `server` block is used to find the certificate to check the signer. If multiple certificates are found the +The `server` block is used to find the certificate to check the signer. If multiple certificates are found the `windows_certificate_filter` will choose the certificate with the expiration farthest in the future. Name | Type | Description | Default | Required diff --git a/docs/sources/flow/setup/install/windows.md b/docs/sources/flow/setup/install/windows.md index 84b0607e139b..f9106e5f936f 100644 --- a/docs/sources/flow/setup/install/windows.md +++ b/docs/sources/flow/setup/install/windows.md @@ -57,6 +57,14 @@ To do a silent install of Grafana Agent on Windows, perform the following steps. * `/CONFIG=` Path to the configuration file. Default: `$INSTDIR\config.river` * `/DISABLEREPORTING=` Disable [data collection][]. Default: `no` * `/DISABLEPROFILING=` Disable profiling endpoint. Default: `no` +* `/ENVIRONMENT="KEY=VALUE\0KEY2=VALUE2"` Define environment variables for Windows Service. Default: `` + +## Service Configuration + +Grafana Agent uses the Windows Registry `HKLM\Software\Grafana\Grafana Agent Flow` for service configuration. + +* `Arguments` (Type `REG_MULTI_SZ`) Each value represents a binary argument for grafana-agent-flow binary. +* `Environment` (Type `REG_MULTI_SZ`) Each value represents a environment value `KEY=VALUE` for grafana-agent-flow binary. ## Uninstall diff --git a/docs/sources/operator/helm-getting-started.md b/docs/sources/operator/helm-getting-started.md index bc2f516e10fa..78245505d859 100644 --- a/docs/sources/operator/helm-getting-started.md +++ b/docs/sources/operator/helm-getting-started.md @@ -20,8 +20,8 @@ In this guide, you'll learn how to deploy [Grafana Agent Operator]({{< relref ". To deploy Agent Operator with Helm, make sure that you have the following: - A Kubernetes cluster -- The `[kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl)` command-line client installed and configured on your machine -- The `[helm](https://helm.sh/docs/intro/install/)` command-line client installed and configured on your machine +- The [`kubectl`](https://kubernetes.io/docs/tasks/tools/#kubectl) command-line client installed and configured on your machine +- The [`helm`](https://helm.sh/docs/intro/install/) command-line client installed and configured on your machine > **Note:** Agent Operator is currently in beta and its custom resources are subject to change. diff --git a/docs/sources/shared/flow/reference/components/authorization-block.md b/docs/sources/shared/flow/reference/components/authorization-block.md index 190cd11f8bb9..11a74326f997 100644 --- a/docs/sources/shared/flow/reference/components/authorization-block.md +++ b/docs/sources/shared/flow/reference/components/authorization-block.md @@ -10,11 +10,10 @@ description: Shared content, authorization block headless: true --- -Name | Type | Description | Default | Required ----- | ---- | ----------- | ------- | -------- -`type` | `string` | Authorization type, for example, "Bearer". | | no -`credentials` | `secret` | Secret value. | | no -`credentials_file` | `string` | File containing the secret value. | | no +Name | Type | Description | Default | Required +-------------------|----------|--------------------------------------------|---------|--------- +`credentials_file` | `string` | File containing the secret value. | | no +`credentials` | `secret` | Secret value. | | no +`type` | `string` | Authorization type, for example, "Bearer". | | no -`credential` and `credentials_file` are mutually exclusive and only one can be -provided inside of an `authorization` block. +`credential` and `credentials_file` are mutually exclusive, and only one can be provided inside an `authorization` block. diff --git a/docs/sources/shared/flow/reference/components/azuread-block.md b/docs/sources/shared/flow/reference/components/azuread-block.md index ebdf436d02fe..07d974385134 100644 --- a/docs/sources/shared/flow/reference/components/azuread-block.md +++ b/docs/sources/shared/flow/reference/components/azuread-block.md @@ -10,11 +10,11 @@ description: Shared content, azuread block headless: true --- -Name | Type | Description | Default | Required ----- | ---- | ----------- | ------- | -------- +Name | Type | Description | Default | Required +--------|----------|------------------|-----------------|--------- `cloud` | `string` | The Azure Cloud. | `"AzurePublic"` | no The supported values for `cloud` are: * `"AzurePublic"` * `"AzureChina"` -* `"AzureGovernment"` \ No newline at end of file +* `"AzureGovernment"` diff --git a/docs/sources/shared/flow/reference/components/basic-auth-block.md b/docs/sources/shared/flow/reference/components/basic-auth-block.md index 06c81f660e3c..62f7e0a25d61 100644 --- a/docs/sources/shared/flow/reference/components/basic-auth-block.md +++ b/docs/sources/shared/flow/reference/components/basic-auth-block.md @@ -10,11 +10,10 @@ description: Shared content, basic auth block headless: true --- -Name | Type | Description | Default | Required ----- | ---- | ----------- | ------- | -------- -`username` | `string` | Basic auth username. | | no -`password` | `secret` | Basic auth password. | | no -`password_file` | `string` | File containing the basic auth password. | | no +Name | Type | Description | Default | Required +----------------|----------|------------------------------------------|---------|--------- +`password_file` | `string` | File containing the basic auth password. | | no +`password` | `secret` | Basic auth password. | | no +`username` | `string` | Basic auth username. | | no -`password` and `password_file` are mutually exclusive and only one can be -provided inside of a `basic_auth` block. +`password` and `password_file` are mutually exclusive, and only one can be provided inside a `basic_auth` block. diff --git a/docs/sources/shared/flow/reference/components/exporter-component-exports.md b/docs/sources/shared/flow/reference/components/exporter-component-exports.md index beb717a13fae..f1a8ca440cd9 100644 --- a/docs/sources/shared/flow/reference/components/exporter-component-exports.md +++ b/docs/sources/shared/flow/reference/components/exporter-component-exports.md @@ -13,15 +13,12 @@ headless: true The following fields are exported and can be referenced by other components. Name | Type | Description ---------- | ------------------- | ----------- +----------|---------------------|---------------------------------------------------------- `targets` | `list(map(string))` | The targets that can be used to collect exporter metrics. -For example, the `targets` can either be passed to a `discovery.relabel` -component to rewrite the targets' label sets, or to a `prometheus.scrape` -component that collects the exposed metrics. +For example, the `targets` can either be passed to a `discovery.relabel` component to rewrite the targets' label sets or to a `prometheus.scrape` component that collects the exposed metrics. -The exported targets will use the configured [in-memory traffic][] address -specified by the [run command][]. +The exported targets use the configured [in-memory traffic][] address specified by the [run command][]. [in-memory traffic]: {{< relref "../../../../flow/concepts/component_controller.md#in-memory-traffic" >}} [run command]: {{< relref "../../../../flow/reference/cli/run.md" >}} diff --git a/docs/sources/shared/flow/reference/components/extract-field-block.md b/docs/sources/shared/flow/reference/components/extract-field-block.md index 5036097d155f..207f2bc6053d 100644 --- a/docs/sources/shared/flow/reference/components/extract-field-block.md +++ b/docs/sources/shared/flow/reference/components/extract-field-block.md @@ -12,31 +12,28 @@ headless: true The following attributes are supported: -Name | Type | Description | Default | Required ----- |----------------|----------------------------------------------------------------------------------------------------------|---------| -------- -`tag_name` | `string` | The name of the resource attribute that will be added to logs, metrics, or spans. | `""` | no -`key` | `string` | The annotation (or label) name. This must exactly match an annotation (or label) name. | `""` | no -`key_regex` | `string` | A regular expression used to extract a key that matches the regex. | `""` | no -`regex` | `string` | An optional field used to extract a sub-string from a complex field value. | `""` | no -`from` | `string` | The source of the labels or annotations. Allowed values are `pod` and `namespace`. | `pod` | no - -When `tag_name` is not specified, a default tag name will be used with the format: +Name | Type | Description | Default | Required +------------|----------|----------------------------------------------------------------------------------------|---------|--------- +`from` | `string` | The source of the labels or annotations. Allowed values are `pod` and `namespace`. | `pod` | no +`key_regex` | `string` | A regular expression used to extract a key that matches the regular expression. | `""` | no +`key` | `string` | The annotation or label name. This key must exactly match an annotation or label name. | `""` | no +`regex` | `string` | An optional field used to extract a sub-string from a complex field value. | `""` | no +`tag_name` | `string` | The name of the resource attribute added to logs, metrics, or spans. | `""` | no + +When you don't specify the `tag_name`, a default tag name is used with the format: * `k8s.pod.annotations.` * `k8s.pod.labels.