Skip to content

dev: Unified metric filtering logic across emitters#19026

Open
nozjkoitop wants to merge 15 commits intoapache:masterfrom
deep-bi:feature-metric-logging-filtering
Open

dev: Unified metric filtering logic across emitters#19026
nozjkoitop wants to merge 15 commits intoapache:masterfrom
deep-bi:feature-metric-logging-filtering

Conversation

@nozjkoitop
Copy link
Copy Markdown
Contributor

@nozjkoitop nozjkoitop commented Feb 17, 2026

Extends #19030.

Description

This PR expands metric-name-based filtering beyond LoggingEmitter and introduces shared filtering support that can be reused across multiple emitters.

What changed

  • Added shared emitter metric-filtering config:
    • shouldFilterMetrics
    • metricSpecPath
  • Added common filtering support in processing:
    • AbstractFilteringEmitter
    • shared allowlist loading/parsing utilities
  • Updated LoggingEmitter, HttpPostEmitter, ParametrizedUriEmitter and PrometheusEmitter to use the shared filtering mechanism

Behavior

  • filtering is optional and disabled by default
  • when filtering is enabled, metric events are emitted only if their metric name is present in the configured allowlist
  • when no custom spec path is configured, the emitter uses its bundled default metric spec
  • when a custom spec path is configured, that file is used as the allowlist source
  • non-metric event handling remains emitter-specific

Release note

Added shared metric allowlist filtering support for multiple emitters. LoggingEmitter, HttpPostEmitter, ParametrizedUriEmitter, and PrometheusEmitter can optionally restrict emitted metric events to an allowlisted set of metric names using the shared filtering configuration.

This PR has:

  • been self-reviewed.
  • added documentation for new or modified features or behaviors.
  • a release note entry in the PR description.
  • added Javadocs for most classes and all non-trivial methods. Linked related entities via Javadoc links.
  • added or updated version, license, or notice information in licenses.yaml
  • added comments explaining the "why" and the intent of the code wherever would not be obvious for an unfamiliar reader.
  • added unit tests or modified existing tests to cover new code paths, ensuring the threshold for code coverage is met.
  • added integration tests.
  • been tested in a test Druid cluster.

@abhishekrb19
Copy link
Copy Markdown
Contributor

Thanks @nozjkoitop for the contribution! Cross-linking the comment here on a similar implementation - #19030 (review)

@nozjkoitop
Copy link
Copy Markdown
Contributor Author

@abhishekrb19 quick ping, could you take a look at the latest updates here when you have a moment? I incorporated the schema + test coverage deltas discussed on #19030 (along with your comment from the review), so we can move this feature forward

@abhishekrb19
Copy link
Copy Markdown
Contributor

@nozjkoitop I will find time later this week to review these changes alongside #19030. Thanks!

@jtuglu1
Copy link
Copy Markdown
Contributor

jtuglu1 commented Mar 5, 2026

Could we make this functionality generic to all types of emitters?

@nozjkoitop
Copy link
Copy Markdown
Contributor Author

yea, lemme try it out
perhaps i can add a shared util to the emitters

@nozjkoitop
Copy link
Copy Markdown
Contributor Author

added couple of emitters as a concept, @jtuglu1 wdyt?

@jtuglu1 jtuglu1 self-requested a review March 6, 2026 20:28
@jtuglu1
Copy link
Copy Markdown
Contributor

jtuglu1 commented Mar 6, 2026

cc @maytasm

@abhishekrb19
Copy link
Copy Markdown
Contributor

Could we make this functionality generic to all types of emitters?

Agreed, this will be broadly useful as a core concept for all emitters. Can we do this as a separate change though and scope this PR down to only add the functionality for the LoggingEmitter as mentioned in #19021?

Existing emitters like prometheus-emitter, dropwizard-emitter, opentsdb-emitter, etc. already have a notion of an allow list, so we’ll need to be careful not to break compatibility with them. IMO it will be better to come up with a common interface and enable it for all the emitters in a backwards-compatible manner to existing emitters in a separate change (or alternatively define the interface in this patch, but only integrate it with the LoggingEmitter, but I'd prefer that we do this separately too). Please let me know what you think @nozjkoitop @jtuglu1.

@jtuglu1
Copy link
Copy Markdown
Contributor

jtuglu1 commented Mar 7, 2026

Existing emitters like prometheus-emitter, dropwizard-emitter, opentsdb-emitter, etc. already have a notion of an allow list, so we’ll need to be careful not to break compatibility with them.

Yes, and, ideally this can be extended so any new/existing emitter can "plugin" to the existing mechanism.

or alternatively define the interface in this patch, but only integrate it with the LoggingEmitter

I'd prefer this if possible, since we'd just be deferring the unavoidable unification of all these emitters' filtering mechanisms to down-the-line and I don't want to keep adding more risk that these various different emitter filtering mechanisms become too disparate and a "clean" interface is hard to do.

If possible, I'd like to define it in this PR (and let users of other emitters "opt-in" as necessary via changes down-the-line).

Copy link
Copy Markdown
Contributor

@abhishekrb19 abhishekrb19 left a comment

Choose a reason for hiding this comment

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

@nozjkoitop, thanks for the changes! I left some high-level comments on the common config that would apply to all emitters.

Since the scope of this PR has expanded and we’ve been porting some of the logging-emitter changes from #19030, I’ll go ahead and merge 19030 to keep the drift minimal and make things easier to review. Then we can repurpose this PR to extend the filtering functionality broadly across all emitter types, as @jtuglu1 suggested. Please let me know what you think.

Comment on lines +26 to +29
public interface MetricAllowlistParser
{
Set<String> parse(JsonNode metricConfig, String source);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please add javadocs for common interfaces.

Comment on lines +26 to +30
public class GlobalEmitterConfig
{
@JsonProperty
boolean filterMetrics;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please add javadocs

Comment on lines +31 to +33
@JsonProperty
String metricAllowlistPath;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These properties can be private-scoped

Comment on lines +47 to +48
catch (IOException e) {
throw new ISE(e, "Failed to parse metric allowlist file [%s]", allowlistPath);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Comment on lines +55 to +66
throw new IAE("Metric allowlist file path is empty");
}
try {
return new FileInputStream(allowlistPath);
}
catch (FileNotFoundException e) {
final InputStream classpathInputStream = MetricAllowlistLoader.class.getClassLoader().getResourceAsStream(allowlistPath);
if (classpathInputStream != null) {
return classpathInputStream;
}
throw new IAE(e, "Metric allowlist file [%s] not found", allowlistPath);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Comment on lines +33 to +36
if (!metricConfig.isObject()) {
throw new ISE("Metric allowlist file [%s] must be a JSON object of metric names", source);
}
final ImmutableSet.Builder<String> metricNames = ImmutableSet.builder();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does this work with the different defaultMetrics.json formats that emitters support (they look close enough but have slight differences). Could you also update some of the existing emitters like prometheus-emitter to exercise these code paths?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It does work with the json objects, as long as the metric names are the field names
In case of other structure there is an abstract getMetricAllowlistParser where custom parser can be provided

Comment on lines +170 to +172
if (shouldFilterOutMetric(name)) {
return;
}
Copy link
Copy Markdown
Contributor

@abhishekrb19 abhishekrb19 Mar 7, 2026

Choose a reason for hiding this comment

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

Hmm, instead of doing this for every single emitter, what do you think about adding an abstract class that implements MetricFilteringEmitter implements Emitter and overrides emit() ? This class can have awareness about global configs instantiated from the specific sub-class Emitters like PrometheusEmitter, LoggingEmitter, etc and delegate the filtering to it if the config is enabled or just fall back to current behavior? I will think about this more. @jtuglu1 - do you have suggestions here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

added an AbstractFilteringEmitter with shouldFilterMetrics and allowedMetricNames

@maytasm maytasm self-requested a review March 8, 2026 22:59
@maytasm
Copy link
Copy Markdown
Contributor

maytasm commented Mar 9, 2026

Since @abhishekrb19 merged #19030, this PR will have to be rebased. There are also duplicate configs between the two PRs too. @nozjkoitop please comment here when the PR is ready for review. Thanks!

{
String namespace = config.getNamespace();
String path = config.getDimensionMapPath();
String path = config.getMetricSpecPath().orElse(config.getDimensionMapPath());

Check notice

Code scanning / CodeQL

Deprecated method or constructor invocation Note

Invoking
PrometheusEmitterConfig.getDimensionMapPath
should be avoided because it has been deprecated.
config.isShouldFilterMetrics(),
config.isShouldFilterMetrics()
? config.getMetricSpecPath()
.or(() -> Optional.ofNullable(config.getDimensionMapPath()))

Check notice

Code scanning / CodeQL

Deprecated method or constructor invocation Note

Invoking
PrometheusEmitterConfig.getDimensionMapPath
should be avoided because it has been deprecated.
@nozjkoitop
Copy link
Copy Markdown
Contributor Author

@maytasm latest master is merged, please take a look when you have some time

@nozjkoitop nozjkoitop requested a review from abhishekrb19 March 16, 2026 13:03
@nozjkoitop nozjkoitop changed the title Enabled filtering of metrics in the LoggingEmitter dev: Enabled filtering of metrics in the LoggingEmitter Mar 26, 2026
@nozjkoitop nozjkoitop changed the title dev: Enabled filtering of metrics in the LoggingEmitter dev: Unified metric filtering logic for emitters Mar 26, 2026
@nozjkoitop nozjkoitop changed the title dev: Unified metric filtering logic for emitters dev: Unified metric filtering logic across emitters Mar 26, 2026
@nozjkoitop
Copy link
Copy Markdown
Contributor Author

Hi @abhishekrb19, following up on this PR. It has been rebased and updated based on the latest review comments, so I’d appreciate another look when you get a chance.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants