dev: Unified metric filtering logic across emitters#19026
dev: Unified metric filtering logic across emitters#19026nozjkoitop wants to merge 15 commits intoapache:masterfrom
Conversation
|
Thanks @nozjkoitop for the contribution! Cross-linking the comment here on a similar implementation - #19030 (review) |
|
@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 |
|
@nozjkoitop I will find time later this week to review these changes alongside #19030. Thanks! |
|
Could we make this functionality generic to all types of emitters? |
|
yea, lemme try it out |
|
added couple of emitters as a concept, @jtuglu1 wdyt? |
|
cc @maytasm |
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. |
Yes, and, ideally this can be extended so any new/existing emitter can "plugin" to the existing mechanism.
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). |
abhishekrb19
left a comment
There was a problem hiding this comment.
@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.
| public interface MetricAllowlistParser | ||
| { | ||
| Set<String> parse(JsonNode metricConfig, String source); | ||
| } |
There was a problem hiding this comment.
Please add javadocs for common interfaces.
| public class GlobalEmitterConfig | ||
| { | ||
| @JsonProperty | ||
| boolean filterMetrics; | ||
|
|
| @JsonProperty | ||
| String metricAllowlistPath; | ||
|
|
There was a problem hiding this comment.
These properties can be private-scoped
| catch (IOException e) { | ||
| throw new ISE(e, "Failed to parse metric allowlist file [%s]", allowlistPath); |
There was a problem hiding this comment.
Please use DruidException - style guide ref: https://github.com/apache/druid/blob/master/dev/style-conventions.md#message-formatting-for-logs-and-exceptions
| 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); | ||
| } |
There was a problem hiding this comment.
DruidExceptions here as well similar to #19030:
https://github.com/apache/druid/pull/19030/changes#diff-e6a24d753a6939a848cd7909791a6ceaf358cb5976e7b3ed084912204778cb63R137-R145
| 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(); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
| if (shouldFilterOutMetric(name)) { | ||
| return; | ||
| } |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
added an AbstractFilteringEmitter with shouldFilterMetrics and allowedMetricNames
|
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
| config.isShouldFilterMetrics(), | ||
| config.isShouldFilterMetrics() | ||
| ? config.getMetricSpecPath() | ||
| .or(() -> Optional.ofNullable(config.getDimensionMapPath())) |
Check notice
Code scanning / CodeQL
Deprecated method or constructor invocation Note
|
@maytasm latest master is merged, please take a look when you have some time |
|
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. |
Extends #19030.
Description
This PR expands metric-name-based filtering beyond
LoggingEmitterand introduces shared filtering support that can be reused across multiple emitters.What changed
shouldFilterMetricsmetricSpecPathprocessing:AbstractFilteringEmitterLoggingEmitter,HttpPostEmitter,ParametrizedUriEmitterandPrometheusEmitterto use the shared filtering mechanismBehavior
Release note
Added shared metric allowlist filtering support for multiple emitters.
LoggingEmitter,HttpPostEmitter,ParametrizedUriEmitter, andPrometheusEmittercan optionally restrict emitted metric events to an allowlisted set of metric names using the shared filtering configuration.This PR has: