Skip to content

Commit

Permalink
[Flow] Add new discovery.file component (#4404)
Browse files Browse the repository at this point in the history
  • Loading branch information
spartan0x117 authored Jul 13, 2023
1 parent 600dcb9 commit 000b569
Show file tree
Hide file tree
Showing 5 changed files with 263 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,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)
}
168 changes: 168 additions & 0 deletions docs/sources/flow/reference/components/discovery.file.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
---
title: discovery.file
---

# discovery.file

> **NOTE:** In `v0.35.0` of the Grafana Agent, the `discovery.file` component was renamed to [local.file_match][],
> and `discovery.file` was repurposed to discover scrape targets from one or more files.
>
> <br>
>
> If you are trying to discover files on the local filesystem rather than scrape
> targets within a set of files, you should use [local.file_match][] 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.

0 comments on commit 000b569

Please sign in to comment.