Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce IgnoredTypesConfigurer SPI to enable defining per-module ignores #3219

Merged
merged 5 commits into from
Jun 11, 2021

Conversation

mateuszrzeszutek
Copy link
Member

When I was writing the spring-integration javaagent instrumentation I had to add yet another entry (a few of them, in fact) into the AdditionalLibraryIgnoresMatcher - an I thought that maybe it's a good idea to finally make the first step towards splitting that class and keeping the lib-specific ignores in the lib instrumentation itself.

This PR introduces a new IgnoredTypesConfigurer SPI that allows adding ignored/allowed classes to the agent builder in any instrumentation module (or extension jar). All those ignores are still kept in one place, but now it's possible to split that one giant class and move some of those overrides to related instrumentation modules. I still don't have a good idea what to do about our tests that verify that classes matched by AdditionalLibraryIgnoresMatcher were not instrumented, but maybe it'll become clear with the first instrumentation.

The same SPI could be used to exclude task classes (ExecutorInstrumentationUtils) from context propagation, although it's not implemented yet.

The new SPI stores all those overrides in a prefix tree, which has a bit better performance than repeated .startsWith calls:

The old version (.startsWith(...)):

Benchmark                                                                              Mode  Cnt         Score       Error   Units
IgnoredTypesMatcherBenchmark.additionalLibraryMatcher_appType                         thrpt   10         9.744 ±     0.428  ops/us
IgnoredTypesMatcherBenchmark.additionalLibraryMatcher_appType:heap.total.after        thrpt   10  41943040.000 ±     0.001   bytes
IgnoredTypesMatcherBenchmark.additionalLibraryMatcher_appType:heap.total.before       thrpt   10  41943040.000 ±     0.001   bytes
IgnoredTypesMatcherBenchmark.additionalLibraryMatcher_appType:heap.used.after         thrpt   10  10787619.200 ± 72013.009   bytes
IgnoredTypesMatcherBenchmark.additionalLibraryMatcher_appType:heap.used.before        thrpt   10  10649194.400 ± 56761.205   bytes
IgnoredTypesMatcherBenchmark.additionalLibraryMatcher_appType:·gc.alloc.rate          thrpt   10        ≈ 10⁻⁴              MB/sec
IgnoredTypesMatcherBenchmark.additionalLibraryMatcher_appType:·gc.alloc.rate.norm     thrpt   10        ≈ 10⁻⁴                B/op
IgnoredTypesMatcherBenchmark.additionalLibraryMatcher_appType:·gc.count               thrpt   10           ≈ 0              counts
IgnoredTypesMatcherBenchmark.additionalLibraryMatcher_springType                      thrpt   10         3.172 ±     0.045  ops/us
IgnoredTypesMatcherBenchmark.additionalLibraryMatcher_springType:heap.total.after     thrpt   10  41943040.000 ±     0.001   bytes
IgnoredTypesMatcherBenchmark.additionalLibraryMatcher_springType:heap.total.before    thrpt   10  41943040.000 ±     0.001   bytes
IgnoredTypesMatcherBenchmark.additionalLibraryMatcher_springType:heap.used.after      thrpt   10  10748656.000 ± 77617.852   bytes
IgnoredTypesMatcherBenchmark.additionalLibraryMatcher_springType:heap.used.before     thrpt   10  10652167.200 ± 56637.563   bytes
IgnoredTypesMatcherBenchmark.additionalLibraryMatcher_springType:·gc.alloc.rate       thrpt   10        ≈ 10⁻⁴              MB/sec
IgnoredTypesMatcherBenchmark.additionalLibraryMatcher_springType:·gc.alloc.rate.norm  thrpt   10        ≈ 10⁻⁴                B/op
IgnoredTypesMatcherBenchmark.additionalLibraryMatcher_springType:·gc.count            thrpt   10           ≈ 0              counts

The new version (trie):

Benchmark                                                                              Mode  Cnt         Score       Error   Units
IgnoredTypesMatcherBenchmark.trieMatcher_appType                                      thrpt   10        38.168 ±     2.112  ops/us
IgnoredTypesMatcherBenchmark.trieMatcher_appType:heap.total.after                     thrpt   10  35651584.000 ±     0.001   bytes
IgnoredTypesMatcherBenchmark.trieMatcher_appType:heap.total.before                    thrpt   10  35651584.000 ±     0.001   bytes
IgnoredTypesMatcherBenchmark.trieMatcher_appType:heap.used.after                      thrpt   10  10688258.400 ± 59034.737   bytes
IgnoredTypesMatcherBenchmark.trieMatcher_appType:heap.used.before                     thrpt   10  10607850.400 ± 47090.969   bytes
IgnoredTypesMatcherBenchmark.trieMatcher_appType:·gc.alloc.rate                       thrpt   10        ≈ 10⁻⁴              MB/sec
IgnoredTypesMatcherBenchmark.trieMatcher_appType:·gc.alloc.rate.norm                  thrpt   10        ≈ 10⁻⁵                B/op
IgnoredTypesMatcherBenchmark.trieMatcher_appType:·gc.count                            thrpt   10           ≈ 0              counts
IgnoredTypesMatcherBenchmark.trieMatcher_springType                                   thrpt   10         9.597 ±     0.330  ops/us
IgnoredTypesMatcherBenchmark.trieMatcher_springType:heap.total.after                  thrpt   10  41943040.000 ±     0.001   bytes
IgnoredTypesMatcherBenchmark.trieMatcher_springType:heap.total.before                 thrpt   10  41943040.000 ±     0.001   bytes
IgnoredTypesMatcherBenchmark.trieMatcher_springType:heap.used.after                   thrpt   10  10749009.600 ± 71859.031   bytes
IgnoredTypesMatcherBenchmark.trieMatcher_springType:heap.used.before                  thrpt   10  10652520.800 ± 56659.667   bytes
IgnoredTypesMatcherBenchmark.trieMatcher_springType:·gc.alloc.rate                    thrpt   10        ≈ 10⁻⁴              MB/sec
IgnoredTypesMatcherBenchmark.trieMatcher_springType:·gc.alloc.rate.norm               thrpt   10        ≈ 10⁻⁴                B/op
IgnoredTypesMatcherBenchmark.trieMatcher_springType:·gc.count                         thrpt   10           ≈ 0              counts

I didn't really trust my algo skills, fortunately this benchmark proved that I didn't make matters worse with this change 😂

Copy link
Member

@trask trask left a comment

Choose a reason for hiding this comment

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

nice 👍

Comment on lines +23 to 24
@Deprecated
public interface IgnoreMatcherProvider {
Copy link
Member

Choose a reason for hiding this comment

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

always nice to remove something when adding something 😄👍

* <p>This is a service provider interface that requires implementations to be registered in a
* provider-configuration file stored in the {@code META-INF/services} resource directory.
*/
public interface IgnoredTypesConfigurer extends Ordered {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason for a separate interface instead of knob on InstrumentationModule?

Copy link
Member Author

Choose a reason for hiding this comment

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

I thought that it'd be useful to be able ignore some classes (e.g. task classes to prevent context leaking) even if you turn the instrumentation off.

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm - well we could choose to respet them even if it's disabled? Not sure if it's a great idea - IIRC, dd-trace-java has the knob on InstrumentationModule so it could keep us more consistent with them, though maybe that's a difficult goal at this point

Copy link
Member Author

Choose a reason for hiding this comment

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

As far as I understand, they have something similar just for concurrent/task classes: https://github.com/DataDog/dd-trace-java/blob/master/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/ExcludeFilterProvider.java
And they're doing a separate pass over Instrumenters and check with instanceof if this interface is implemented.

it could keep us more consistent with them, though maybe that's a difficult goal at this point

With all our changes to muzzle, the split to InstrumentationModule/TypeInstrumentation, and DD's custom things (like profiling) it's probably impossible 😅

Hmm - well we could choose to respet them even if it's disabled?

That's what seemed a bit confusing to me - you have the enabled flag but it only works for some InstrumentationModule methods.


import org.checkerframework.checker.nullness.qual.Nullable;

/** A prefix tree that maps from the longest matching prefix to a value {@code V}. */
Copy link
Contributor

Choose a reason for hiding this comment

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

Did you copy this class from anywhere?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, I wrote it from scratch.


@Nullable
Node<V> getNext(char c) {
int index = Arrays.binarySearch(chars, c);
Copy link
Contributor

Choose a reason for hiding this comment

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

If you feel like comparing some optimizations, some ideas are

  • Don't binary search, these arrays seem small enough that it would be slower than a normal loop
  • A single array with every other element Character and Node - single array means better cache performance
  • Copy in from Armeria (while simplifying it's funcionality for parameters) :P

https://github.com/line/armeria/blob/master/core/src/main/java/com/linecorp/armeria/server/RoutingTrieBuilder.java

The main difference is the nodes are subpaths rather than characters - it's quite unfortunate a boring path like org.springframework.blah has a node per character

Copy link
Member Author

Choose a reason for hiding this comment

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

Nice, thanks!
I'll note all your suggestions down and try them out later.

@trask trask merged commit 3b09d46 into open-telemetry:main Jun 11, 2021
@mateuszrzeszutek mateuszrzeszutek deleted the ignored-types branch June 12, 2021 08:38
robododge pushed a commit to robododge/opentelemetry-java-instrumentation that referenced this pull request Jun 17, 2021
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