Skip to content

Commit 284e48f

Browse files
authored
feat(local.file_match, loki.source.file): Match multiple files using doublestar {...} expressions (#5470)
1 parent b7a1d05 commit 284e48f

25 files changed

Lines changed: 729 additions & 128 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ node_modules
3434
.image-tag
3535
/alloy
3636
collector/otel_engine
37+
collector/otel_engine.exe
3738

3839
# local testing files
3940
/targets.yaml

collector/go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,6 @@ require (
332332
github.com/beorn7/perks v1.0.1 // indirect
333333
github.com/bitfield/gotestdox v0.2.2 // indirect
334334
github.com/blang/semver/v4 v4.0.0 // indirect
335-
github.com/bmatcuk/doublestar v1.3.4 // indirect
336335
github.com/bmatcuk/doublestar/v4 v4.9.1 // indirect
337336
github.com/boynux/squid-exporter v1.10.5-0.20230618153315-c1fae094e18e // indirect
338337
github.com/bradleyfalzon/ghinstallation/v2 v2.11.0 // indirect

collector/go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -602,8 +602,6 @@ github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwj
602602
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
603603
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
604604
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
605-
github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0=
606-
github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=
607605
github.com/bmatcuk/doublestar/v4 v4.9.1 h1:X8jg9rRZmJd4yRy7ZeNDRnM+T3ZfHv15JiBJ/avrEXE=
608606
github.com/bmatcuk/doublestar/v4 v4.9.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
609607
github.com/boynux/squid-exporter v1.10.5-0.20230618153315-c1fae094e18e h1:C1vYe728vM2FpXaICJuDRt5zgGyRdMmUGYnVfM7WcLY=

docs/sources/reference/components/local/local.file_match.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ The `__path__` field uses [doublestar][] style glob patterns:
5757
* `/tmp/**/*.log` matches all subdirectories of `tmp` and include any files that end in `*.log`.
5858
* `/tmp/apache/*.log` matches only files in `/tmp/apache/` that end in `*.log`.
5959
* `/tmp/**` matches all subdirectories of `tmp`, `tmp` itself, and all files.
60+
* `/tmp/*.{log,txt,json}` matches files with `.log`, `.txt`, or `.json` extensions in `/tmp/`.
61+
* `/var/log/{nginx,apache}/*.log` matches `.log` files in either the `nginx` or `apache` subdirectories.
6062

6163
`local.file_match` doesn't ignore files when you set `ignore_older_than` to the default, `0s`.
6264

@@ -181,6 +183,35 @@ Replace the following:
181183
* _`<USERNAME>`_: The username to use for authentication to the Loki API.
182184
* _`<PASSWORD>`_: The password to use for authentication to the Loki API.
183185

186+
### Match multiple patterns
187+
188+
This example shows how to use the `{a,b,c}` pattern syntax to match multiple file extensions, multiple directories, and exclude multiple file types in a single configuration.
189+
190+
```alloy
191+
local.file_match "logs" {
192+
path_targets = [
193+
// Match .log, .txt, and .json files from nginx, apache, or caddy directories
194+
// Exclude compressed and backup files
195+
{
196+
"__path__" = "/var/log/{nginx,apache,caddy}/*.{log,txt,json}",
197+
"__path_exclude__" = "/var/log/{nginx,apache,caddy}/*.{gz,zip,bak,old}",
198+
"job" = "webserver",
199+
},
200+
]
201+
}
202+
203+
loki.source.file "logs" {
204+
targets = local.file_match.logs.targets
205+
forward_to = [loki.write.endpoint.receiver]
206+
}
207+
208+
loki.write "endpoint" {
209+
endpoint {
210+
url = "<LOKI_URL>"
211+
}
212+
}
213+
```
214+
184215
### Send Kubernetes Pod logs to Loki
185216

186217
This example finds all the logs on Pods and monitors them.

docs/sources/reference/components/loki/loki.source.file.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,11 @@ Benefits of using `file_match` over `local.file_match`:
142142
When `enabled` is set to `true`, you can use glob patterns, for example, `/tmp/*.log` or `/var/log/**/*.log`, directly in the `targets` argument's `__path__` label.
143143
The component periodically scans the filesystem based on `sync_period` and automatically discovers new files, removes deleted files, and ignores files older than `ignore_older_than` if specified.
144144

145+
The glob patterns support the `{a,b,c}` syntax for matching multiple alternatives:
146+
147+
* `/tmp/*.{log,txt,json}` matches files with `.log`, `.txt`, or `.json` extensions.
148+
* `/var/log/{nginx,apache}/*.log` matches `.log` files in either the `nginx` or `apache` subdirectories.
149+
145150
## Exported fields
146151

147152
`loki.source.file` doesn't export any fields.
@@ -262,6 +267,34 @@ loki.write "local" {
262267
}
263268
```
264269

270+
### Match multiple patterns
271+
272+
This example shows how to use the `{a,b,c}` pattern syntax to match multiple file extensions, multiple directories, and exclude multiple file types in a single configuration.
273+
274+
```alloy
275+
loki.source.file "logs" {
276+
targets = [
277+
// Match .log, .txt, and .json files from nginx, apache, or caddy directories
278+
// Exclude compressed and backup files
279+
{
280+
__path__ = "/var/log/{nginx,apache,caddy}/*.{log,txt,json}",
281+
__path_exclude__ = "/var/log/{nginx,apache,caddy}/*.{gz,zip,bak,old}",
282+
"job" = "webserver",
283+
},
284+
]
285+
forward_to = [loki.write.local.receiver]
286+
file_match {
287+
enabled = true
288+
}
289+
}
290+
291+
loki.write "local" {
292+
endpoint {
293+
url = "loki:3100/api/v1/push"
294+
}
295+
}
296+
```
297+
265298
### Decompression
266299

267300
This example collects log entries from compressed files matching the `*.gz` pattern using the built-in `file_match` block with decompression enabled.

extension/alloyengine/go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,6 @@ require (
251251
github.com/beorn7/perks v1.0.1 // indirect
252252
github.com/bitfield/gotestdox v0.2.2 // indirect
253253
github.com/blang/semver/v4 v4.0.0 // indirect
254-
github.com/bmatcuk/doublestar v1.3.4 // indirect
255254
github.com/bmatcuk/doublestar/v4 v4.9.1 // indirect
256255
github.com/boynux/squid-exporter v1.10.5-0.20230618153315-c1fae094e18e // indirect
257256
github.com/bradleyfalzon/ghinstallation/v2 v2.11.0 // indirect

extension/alloyengine/go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -612,8 +612,6 @@ github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwj
612612
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
613613
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
614614
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
615-
github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0=
616-
github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=
617615
github.com/bmatcuk/doublestar/v4 v4.9.1 h1:X8jg9rRZmJd4yRy7ZeNDRnM+T3ZfHv15JiBJ/avrEXE=
618616
github.com/bmatcuk/doublestar/v4 v4.9.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
619617
github.com/boynux/squid-exporter v1.10.5-0.20230618153315-c1fae094e18e h1:C1vYe728vM2FpXaICJuDRt5zgGyRdMmUGYnVfM7WcLY=

go.mod

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ require (
3131
github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0
3232
github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.39.17
3333
github.com/blang/semver/v4 v4.0.0
34-
github.com/bmatcuk/doublestar v1.3.4
34+
github.com/bmatcuk/doublestar/v4 v4.9.1
3535
github.com/boynux/squid-exporter v1.10.5-0.20230618153315-c1fae094e18e
3636
github.com/buger/jsonparser v1.1.1
3737
github.com/burningalchemist/sql_exporter v0.0.0-20240103092044-466b38b6abc4
@@ -524,7 +524,6 @@ require (
524524
github.com/beevik/ntp v1.3.0 // indirect
525525
github.com/benbjohnson/clock v1.3.5 // indirect
526526
github.com/beorn7/perks v1.0.1 // indirect
527-
github.com/bmatcuk/doublestar/v4 v4.9.1 // indirect
528527
github.com/caarlos0/env/v9 v9.0.0
529528
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
530529
github.com/cenkalti/backoff/v5 v5.0.3 // indirect

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -616,8 +616,6 @@ github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwj
616616
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
617617
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
618618
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
619-
github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0=
620-
github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=
621619
github.com/bmatcuk/doublestar/v4 v4.9.1 h1:X8jg9rRZmJd4yRy7ZeNDRnM+T3ZfHv15JiBJ/avrEXE=
622620
github.com/bmatcuk/doublestar/v4 v4.9.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
623621
github.com/boynux/squid-exporter v1.10.5-0.20230618153315-c1fae094e18e h1:C1vYe728vM2FpXaICJuDRt5zgGyRdMmUGYnVfM7WcLY=

internal/component/local/file_match/file.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/grafana/alloy/internal/component/discovery"
1010
"github.com/grafana/alloy/internal/featuregate"
1111
"github.com/grafana/alloy/internal/runtime/logging/level"
12+
"github.com/grafana/alloy/internal/util/glob"
1213
)
1314

1415
func init() {
@@ -42,10 +43,15 @@ type Component struct {
4243
watches []watch
4344
watchDog *time.Ticker
4445
targetsChanged chan struct{}
46+
globber glob.Globber
4547
}
4648

4749
// New creates a new local.file_match component.
4850
func New(o component.Options, args Arguments) (*Component, error) {
51+
return newComponent(o, args, glob.NewGlobber())
52+
}
53+
54+
func newComponent(o component.Options, args Arguments, globber glob.Globber) (*Component, error) {
4955
c := &Component{
5056
opts: o,
5157
mut: sync.Mutex{},
@@ -54,6 +60,7 @@ func New(o component.Options, args Arguments) (*Component, error) {
5460
watchDog: time.NewTicker(args.SyncPeriod),
5561
// Buffered channel to avoid blocking
5662
targetsChanged: make(chan struct{}, 1),
63+
globber: globber,
5764
}
5865

5966
if err := c.Update(args); err != nil {
@@ -92,6 +99,7 @@ func (c *Component) Update(args component.Arguments) error {
9299
target: v,
93100
log: c.opts.Logger,
94101
ignoreOlderThan: c.args.IgnoreOlderThan,
102+
globber: c.globber,
95103
})
96104
}
97105

0 commit comments

Comments
 (0)