Skip to content

Conversation

@lahsivjar
Copy link
Contributor

@lahsivjar lahsivjar commented Dec 9, 2025

Dynamic routing connector allows selecting pipelines based on the configured set of metadata keys. For example: route to different batching pipelines based on observed connection count.

Related to: https://github.com/elastic/hosted-otel-collector/issues/1349

@lahsivjar lahsivjar requested a review from a team as a code owner December 9, 2025 09:33
@lahsivjar lahsivjar requested review from SylvainJuge and xrmx December 9, 2025 09:33
@lahsivjar lahsivjar requested review from a team, axw and vigneshshanmugam December 9, 2025 09:34
Copy link
Contributor

@rogercoll rogercoll left a comment

Choose a reason for hiding this comment

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

Could you add this component to the versions.yaml file? 🙏 (created this issue to add a CI check)

Copy link
Member

@vigneshshanmugam vigneshshanmugam left a comment

Choose a reason for hiding this comment

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

Did a quick pass, Approach looks good to me. However I felt if there is any other way we can make the configuration simpler. I ll do another extensive review in a followup.

Copy link
Member

Choose a reason for hiding this comment

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

We should emit some metrics on the selected pipeline with the provided metadata keys as attributes, but can come as a followup.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, a follow-up is planned.

Copy link
Member

@axw axw left a comment

Choose a reason for hiding this comment

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

Looks good in general, left some suggestions

Copy link
Member

@vigneshshanmugam vigneshshanmugam left a comment

Choose a reason for hiding this comment

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

Looks good

return c.router.Shutdown(ctx)
}

func (c *metricsConnector) Capabilities() consumer.Capabilities {
Copy link
Member

Choose a reason for hiding this comment

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

Ques - Is this required? Shouldn't it default to false anyway?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is no default, we need to implement connector.Metrics interface and this is required.


```yaml
connectors:
dynamicrouting:
Copy link
Member

Choose a reason for hiding this comment

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

After sleeping over it, I think we can still improve the configuration to a better model, currently it leaks metadatakeys across several keys which is a bit confusing. Taking a bit of inspiration from our ratelimiter resolvers, I m thinking something like

connectors:
  dynamicrouting:
    # Metadata configuration
    routing_keys:
      partition_by: ["x-tenant-id"]  # serves the same purpose as primary 
      measure_by: ["x-forwarded-for", "user-agent"]  # replaces the metadata_keys

    routing_class:
      low_cardinality:
        max_cardinality: 10
        pipelines: ["traces/small_batch"]
      
      medium_cardinality:
        max_cardinality: 100
        pipelines: ["traces/medium_batch"]
      
      high_cardinality:
        max_cardinality: .inf
        pipelines: ["traces/large_batch"]

    default_class: ["traces/default"]
    evaluation_interval: 30s

    overrides: #similar to what we do with ratelimiter 
      - matches:
          x-tenant-id: ["premium"]
        pipelines: ["traces/premium"] 

Thoughts? We dont need to introduce overrides, just thought it would be valuable to have it in our sleeves.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't like overrides - atleast for now but I like others. Will make the changes. For overrides, lets follow-up if we see the need.

Copy link
Contributor Author

@lahsivjar lahsivjar Dec 12, 2025

Choose a reason for hiding this comment

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

routing_class:
 low_cardinality:

I am a bit more inclined towards keeping this as a slice instead of a map, and I am not sure about the routing_class name - it is more of a bucket which is chosen based on calculated cardinality. WDYT about keeping this bit the same?

for _, mk := range vs {
if _, err := pkb.WriteString(mk); err != nil {
r.logger.Error(
"unexpected failure on concatenating primary metadata keys",
Copy link
Member

Choose a reason for hiding this comment

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

keys -> values, would be good to log the values to make it easy for debugging?

}
}

func newTestMetrics(resourceIDs, scopeIDs, metricIDs, sumDPIDs string) pmetric.Metrics {
Copy link
Member

Choose a reason for hiding this comment

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

Ques - dont we have any testutil in upstream that can create a dummy Metric, Log, trace record?

Copy link
Member

@axw axw left a comment

Choose a reason for hiding this comment

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

LGTM. I like @vigneshshanmugam's suggestion for the config to be in terms of partition keys and counting keys - seems clearer to me. I'm good with it either way though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants