Skip to content

Commit a9aab0d

Browse files
djaglowskimterhar
authored andcommitted
[connector/routing] Deprecate match_once parameter (open-telemetry#36824)
This PR deprecates the `match_once` parameter. It defines a multi-step process which hopefully gives users plenty of time to make necessary changes. It also provides several detailed examples of how to migrate a configuration. Resolves open-telemetry#29882
1 parent 08967b1 commit a9aab0d

File tree

5 files changed

+214
-0
lines changed

5 files changed

+214
-0
lines changed

.chloggen/deprecate-matchonce.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: deprecation
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: connector/routing
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Deprecate `match_once` parameter.
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [29882]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: []

connector/routingconnector/README.md

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,21 @@
2626

2727
Routes logs, metrics or traces based on resource attributes to specific pipelines using [OpenTelemetry Transformation Language (OTTL)](../../pkg/ottl/README.md) statements as routing conditions.
2828

29+
## Notice
30+
31+
The `match_once` field is deprecated as of `v0.115.0`. The deprecation schedule is planned as follows:
32+
33+
- `v0.115.0`: The field is deprecated. If `false` is used, a warning will be logged.
34+
- `v0.116.0`: The default value will change from `false` to `true`. If `false` is used, an error will be logged.
35+
- `v0.117.0`: The field will be disconnected from behavior of the connector. If used (either `false` or `true`), an error will be logged.
36+
- `v0.119.0`: The field will be removed.
37+
38+
### Migration
39+
40+
It is recommended to set `match_once: true` until `v0.116.0` and then remove all usage of the field before `v0.119.0`.
41+
42+
For detailed guidance on how to migrate configuration from `match_once: false` to `match_once: true`, see [Config Migration](#config-migration.md).
43+
2944
## Configuration
3045

3146
If you are not already familiar with connectors, you may find it helpful to first visit the [Connectors README].
@@ -285,6 +300,163 @@ service:
285300
exporters: [file/ecorp]
286301
```
287302
303+
## Config Migration
304+
305+
The following examples demonstrate some strategies for migrating a configuration to `match_once: true`.
306+
307+
### Example without `default_pipelines`
308+
309+
If not using `default_pipelines`, you may be able to split the router into multiple parallel routers.
310+
In the following example, the `"env"` and `"region"` are not directly related.
311+
312+
```yaml
313+
routing:
314+
match_once: false
315+
table:
316+
- condition: attributes["env"] == "prod"
317+
pipelines: [ logs/prod ]
318+
- condition: attributes["env"] == "dev"
319+
pipelines: [ logs/dev ]
320+
- condition: attributes["region"] == "east"
321+
pipelines: [ logs/east ]
322+
- condition: attributes["region"] == "west"
323+
pipelines: [ logs/west ]
324+
325+
service:
326+
pipelines:
327+
logs/in::exporters: [routing]
328+
logs/prod::receivers: [routing]
329+
logs/dev::receivers: [routing]
330+
logs/east::receivers: [routing]
331+
logs/west::receivers: [routing]
332+
```
333+
334+
Therefore, the same behavior can be achieved using separate routers. Listing both routers in the pipeline configuration will
335+
result in each receiving an independent handle to the data. The same data can then match routes in both routers.
336+
337+
```yaml
338+
routing/env:
339+
match_once: true
340+
table:
341+
- condition: attributes["env"] == "prod"
342+
pipelines: [ logs/prod ]
343+
- condition: attributes["env"] == "dev"
344+
pipelines: [ logs/dev ]
345+
routing/region:
346+
match_once: true
347+
table:
348+
- condition: attributes["region"] == "east"
349+
pipelines: [ logs/east ]
350+
- condition: attributes["region"] == "west"
351+
pipelines: [ logs/west ]
352+
353+
service:
354+
pipelines:
355+
logs/in::exporters: [routing/env, routing/region]
356+
logs/prod::receivers: [routing/env]
357+
logs/dev::receivers: [routing/env]
358+
logs/east::receivers: [routing/region]
359+
logs/west::receivers: [routing/region]
360+
```
361+
362+
### Example with `default_pipelines`
363+
364+
The following example demonstrates strategies for migrating to `match_once: true` while using `default_pipelines`.
365+
366+
```yaml
367+
routing:
368+
match_once: false
369+
default_pipelines: [ logs/default ]
370+
table:
371+
- condition: attributes["env"] == "prod"
372+
pipelines: [ logs/prod ]
373+
- condition: attributes["env"] == "dev"
374+
pipelines: [ logs/dev ]
375+
- condition: attributes["region"] == "east"
376+
pipelines: [ logs/east ]
377+
- condition: attributes["region"] == "west"
378+
pipelines: [ logs/west ]
379+
380+
service:
381+
pipelines:
382+
logs/in::exporters: [routing]
383+
logs/default::receivers: [routing]
384+
logs/prod::receivers: [routing]
385+
logs/dev::receivers: [routing]
386+
logs/east::receivers: [routing]
387+
logs/west::receivers: [routing]
388+
```
389+
390+
If the number of routes are limited, you may be able to articulate a route for each combination of conditions. This avoids the need to change any pipelines.
391+
392+
```yaml
393+
routing:
394+
match_once: true
395+
default_pipelines: [ logs/default ]
396+
table:
397+
- condition: attributes["env"] == "prod" and attributes["region"] == "east"
398+
pipelines: [ logs/prod, logs/east ]
399+
- condition: attributes["env"] == "prod" and attributes["region"] == "west"
400+
pipelines: [ logs/prod, logs/west ]
401+
- condition: attributes["env"] == "dev" and attributes["region"] == "east"
402+
pipelines: [ logs/dev, logs/east ]
403+
- condition: attributes["env"] == "dev" and attributes["region"] == "west"
404+
pipelines: [ logs/dev, logs/west ]
405+
406+
service:
407+
pipelines:
408+
logs/in::exporters: [routing]
409+
logs/default::receivers: [routing]
410+
logs/prod::receivers: [routing]
411+
logs/dev::receivers: [routing]
412+
logs/east::receivers: [routing]
413+
logs/west::receivers: [routing]
414+
```
415+
416+
A more general solution is to use a layered approach. In this design, the first layer is a single router that sorts data according to whether it matches
417+
_any route_ or _no route_. This allows the second layer to work without `default_pipelines`. The downside to this approach is that the set of conditions
418+
in the first and second layers must be kept in sync.
419+
420+
```yaml
421+
# First layer separates logs that match no routes
422+
routing:
423+
match_once: true
424+
default_pipelines: [ logs/default ]
425+
table: # all routes forward to second layer
426+
- condition: attributes["env"] == "prod"
427+
pipelines: [ logs/env, logs/region ]
428+
- condition: attributes["env"] == "dev"
429+
pipelines: [ logs/env, logs/region ]
430+
- condition: attributes["region"] == "east"
431+
pipelines: [ logs/env, logs/region ]
432+
- condition: attributes["region"] == "west"
433+
pipelines: [ logs/env, logs/region ]
434+
435+
# Second layer routes logs based on environment and region
436+
routing/env:
437+
match_once: true
438+
table:
439+
- condition: attributes["env"] == "prod"
440+
pipelines: [ logs/prod ]
441+
- condition: attributes["env"] == "dev"
442+
pipelines: [ logs/dev ]
443+
routing/region:
444+
match_once: true
445+
table:
446+
- condition: attributes["region"] == "east"
447+
pipelines: [ logs/east ]
448+
- condition: attributes["region"] == "west"
449+
pipelines: [ logs/west ]
450+
451+
service:
452+
pipelines:
453+
logs/in::exporters: [routing]
454+
logs/prod::receivers: [routing/env]
455+
logs/dev::receivers: [routing/env]
456+
logs/east::receivers: [routing/region]
457+
logs/west::receivers: [routing/region]
458+
```
459+
288460
[Connectors README]:https://github.com/open-telemetry/opentelemetry-collector/blob/main/connector/README.md
289461

290462
[OTTL]: https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/pkg/ottl/README.md

connector/routingconnector/logs.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ func newLogsConnector(
3535
) (*logsConnector, error) {
3636
cfg := config.(*Config)
3737

38+
// TODO update log from warning to error in v0.116.0
39+
if !cfg.MatchOnce {
40+
set.Logger.Warn("The 'match_once' field has been deprecated. Set to 'true' to suppress this warning.")
41+
}
42+
3843
lr, ok := logs.(connector.LogsRouterAndConsumer)
3944
if !ok {
4045
return nil, errUnexpectedConsumer

connector/routingconnector/metrics.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ func newMetricsConnector(
3636
) (*metricsConnector, error) {
3737
cfg := config.(*Config)
3838

39+
// TODO update log from warning to error in v0.116.0
40+
if !cfg.MatchOnce {
41+
set.Logger.Warn("The 'match_once' field has been deprecated. Set to 'true' to suppress this warning.")
42+
}
43+
3944
mr, ok := metrics.(connector.MetricsRouterAndConsumer)
4045
if !ok {
4146
return nil, errUnexpectedConsumer

connector/routingconnector/traces.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ func newTracesConnector(
3535
) (*tracesConnector, error) {
3636
cfg := config.(*Config)
3737

38+
// TODO update log from warning to error in v0.116.0
39+
if !cfg.MatchOnce {
40+
set.Logger.Warn("The 'match_once' field has been deprecated. Set to 'true' to suppress this warning.")
41+
}
42+
3843
tr, ok := traces.(connector.TracesRouterAndConsumer)
3944
if !ok {
4045
return nil, errUnexpectedConsumer

0 commit comments

Comments
 (0)