Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[Flow] Add new discovery.file component #4404

Merged
merged 8 commits into from
Jul 13, 2023
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ Main (unreleased)

- New Grafana Agent Flow components:

- `discovery.file` discovers scrape targets from files. (@spartan0x117)
- `discovery.kubelet` collect scrape targets from the Kubelet API. (@gcampbell12)
- `module.http` runs a Grafana Agent Flow module loaded from a remote HTTP endpoint. (@spartan0x117)
- `otelcol.processor.attributes` accepts telemetry data from other `otelcol`
Expand Down
1 change: 1 addition & 0 deletions component/all/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
_ "github.com/grafana/agent/component/discovery/digitalocean" // Import discovery.digitalocean
_ "github.com/grafana/agent/component/discovery/dns" // Import discovery.dns
_ "github.com/grafana/agent/component/discovery/docker" // Import discovery.docker
_ "github.com/grafana/agent/component/discovery/file" // Import discovery.file
_ "github.com/grafana/agent/component/discovery/gce" // Import discovery.gce
_ "github.com/grafana/agent/component/discovery/http" // Import discovery.http
_ "github.com/grafana/agent/component/discovery/kubelet" // Import discovery.kubelet
Expand Down
50 changes: 50 additions & 0 deletions component/discovery/file/file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package file

import (
"time"

"github.com/grafana/agent/component"
"github.com/grafana/agent/component/discovery"
"github.com/prometheus/common/model"
prom_discovery "github.com/prometheus/prometheus/discovery/file"
)

func init() {
component.Register(component.Registration{
Name: "discovery.file",
Args: Arguments{},
Exports: discovery.Exports{},

Build: func(opts component.Options, args component.Arguments) (component.Component, error) {
return New(opts, args.(Arguments))
},
})
}

type Arguments struct {
Files []string `river:"files,attr"`
RefreshInterval time.Duration `river:"refresh_interval,attr,optional"`
}

var DefaultArguments = Arguments{
RefreshInterval: 5 * time.Minute,
}

// SetToDefault implements river.Defaulter.
func (a *Arguments) SetToDefault() {
*a = DefaultArguments
}

func (a *Arguments) Convert() *prom_discovery.SDConfig {
return &prom_discovery.SDConfig{
Files: a.Files,
RefreshInterval: model.Duration(a.RefreshInterval),
}
}

func New(opts component.Options, args Arguments) (*discovery.Component, error) {
return discovery.New(opts, args, func(args component.Arguments) (discovery.Discoverer, error) {
newArgs := args.(Arguments)
return prom_discovery.NewDiscovery(newArgs.Convert(), opts.Logger), nil
})
}
43 changes: 43 additions & 0 deletions component/discovery/file/file_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package file

import (
"testing"
"time"

"github.com/grafana/agent/pkg/river"
"github.com/prometheus/common/model"
"github.com/stretchr/testify/require"
)

func TestUnmarshal(t *testing.T) {
cfg := `
refresh_interval = "10m"
files = ["file1", "file2"]`

var args Arguments
err := river.Unmarshal([]byte(cfg), &args)
require.NoError(t, err)
require.Equal(t, 2, len(args.Files))
require.Equal(t, 10*time.Minute, args.RefreshInterval)
}

func TestUnmarshal_Defaults(t *testing.T) {
cfg := `files = ["file1"]`

var args Arguments
err := river.Unmarshal([]byte(cfg), &args)
require.NoError(t, err)
require.Equal(t, 1, len(args.Files))
require.Equal(t, 5*time.Minute, args.RefreshInterval)
}

func TestConvert(t *testing.T) {
args := Arguments{
Files: []string{"file1", "file2"},
RefreshInterval: 10 * time.Minute,
}

promSDConfig := args.Convert()
require.Equal(t, 2, len(promSDConfig.Files))
require.Equal(t, model.Duration(10*time.Minute), promSDConfig.RefreshInterval)
}
163 changes: 163 additions & 0 deletions docs/sources/flow/reference/components/discovery.file.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
---
title: discovery.file
---

# discovery.file

> **NOTE:** In `v0.35.0` of the Grafana Agent, the `discovery.file` component was renamed to [local.file_match][]. From `v0.35.0` onwards, the `discovery.file`
> component behaves as documented here.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe specify here briefly what local.file_match does, and why they may want to go there instead.


[local.file_match]: {{< relref "./local.file_match.md" >}}

`discovery.file` discovers targets from a set of files, similar to the [Prometheus file_sd_config](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#file_sd_config).

## Usage

```river
discovery.file "LABEL" {
files = [FILE_PATH_1, FILE_PATH_2, ...]
}
```

## Arguments

The following arguments are supported:

Name | Type | Description | Default | Required
------------------ | ------------------- | ------------------------------------------ |---------| --------
`files` | `list(string)` | Files to read and discover targets from. | | yes
`refresh_interval` | `duration` | How often to sync targets. | "5m" | no

The last path segment of each element in `files` may contain a single * that matches any character sequence, e.g. `my/path/tg_*.json`.

## Exported fields

The following fields are exported and can be referenced by other components:

Name | Type | Description
--------- | ------------------- | -----------
`targets` | `list(map(string))` | The set of targets discovered from the filesystem.

Each target includes the following labels:

* `__meta_filepath`: The absolute path to the file the target was discovered from.

## Component health

`discovery.file` is only reported as unhealthy when given an invalid
configuration. In those cases, exported fields retain their last healthy
values.

## Debug information

`discovery.file` does not expose any component-specific debug information.

### Debug metrics

`discovery.file` does not expose any component-specific debug metrics.

## Examples

### Example target files
```json
[
{
"targets": [ "127.0.0.1:9091", "127.0.0.1:9092" ],
"labels": {
"environment": "dev"
}
},
{
"targets": [ "127.0.0.1:9093" ],
"labels": {
"environment": "prod"
}
}
]
```

```yaml
- targets:
- 127.0.0.1:9999
- 127.0.0.1:10101
labels:
job: worker
- targets:
- 127.0.0.1:9090
labels:
job: prometheus
```

### Basic file discovery

This example discovers targets from a single file, scrapes them, and writes metrics
to a Prometheus remote write endpoint.

```river
discovery.file "example" {
files = ["/tmp/example.json"]
}

prometheus.scrape "default" {
targets = discovery.file.example.targets
forward_to = [prometheus.remote_write.demo.receiver]
}

prometheus.remote_write "demo" {
endpoint {
url = PROMETHEUS_REMOTE_WRITE_URL

basic_auth {
username = USERNAME
password = PASSWORD
}
}
}
```

Replace the following:
- `PROMETHEUS_REMOTE_WRITE_URL`: The URL of the Prometheus remote_write-compatible server to send metrics to.
- `USERNAME`: The username to use for authentication to the remote_write API.
- `PASSWORD`: The password to use for authentication to the remote_write API.

### File discovery with retained file path label

This example discovers targets from a wildcard file path, scrapes them, and writes metrics
to a Prometheus remote write endpoint.

It also uses a relabeling rule to retain the file path as a label on each target.

```river
discovery.file "example" {
files = ["/tmp/example_*.yaml"]
}

discovery.relabel "keep_filepath" {
targets = discovery.file.example.targets
rule {
source_labels = ["__meta_filepath"]
target_label = "filepath"
}
}

prometheus.scrape "default" {
targets = discovery.relabel.keep_filepath.output
forward_to = [prometheus.remote_write.demo.receiver]
}

prometheus.remote_write "demo" {
endpoint {
url = PROMETHEUS_REMOTE_WRITE_URL

basic_auth {
username = USERNAME
password = PASSWORD
}
}
}
```

Replace the following:
- `PROMETHEUS_REMOTE_WRITE_URL`: The URL of the Prometheus remote_write-compatible server to send metrics to.
- `USERNAME`: The username to use for authentication to the remote_write API.
- `PASSWORD`: The password to use for authentication to the remote_write API.