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

Remove generated InstrumentationModule#getMuzzleReferences() method from the source code #4087

Merged
merged 4 commits into from
Sep 13, 2021

Conversation

iNikem
Copy link
Contributor

@iNikem iNikem commented Sep 10, 2021

It bothered me for a long time that we have a bunch of public classes in io.opentelemetry.javaagent.extension.muzzle package that in fact should never ever be used directly by the users of javaagent-extension-api module. They are there and public only because InstrumentationModule#getMuzzleReferences() exposes them. But that method is also should never be used by end-users. It is auto-generated and is used by muzzle and tooling modules.

This PR does the following:

  • removes InstrumentationModule#getMuzzleReferences() method from the source code
  • introduces MuzzleReferencesAccessor class into muzzle module to access the generated version of getMuzzleReferences method via MethodHandle
  • Moves all usages of getMuzzleReferences method inside ReferenceMatcher class (and ReferencesPrinter)

All of the above would allow us to move io.opentelemetry.javaagent.extension.muzzle.ClassRef class (and all related classes from that package) from javaagent-extension-api module into muzzle, but unfortunately they are used by gradle-plugins. So as preparation for the future, I created a verbatim copies of all classes from io.opentelemetry.javaagent.extension.muzzle package in io.opentelemetry.javaagent.tooling.muzzle.references. Next PR can change gradle plugins to use these new classes. Old copies of them can be removed then from javaagent-extension-api.

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

@@ -36,7 +37,14 @@
private final Set<String> helperClassNames;
private final InstrumentationClassPredicate instrumentationClassPredicate;

public ReferenceMatcher(
public static ReferenceMatcher of(InstrumentationModule instrumentationModule) {
Copy link
Member

Choose a reason for hiding this comment

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

👍

@iNikem iNikem marked this pull request as ready for review September 11, 2021 09:07
Copy link
Member

@mateuszrzeszutek mateuszrzeszutek left a comment

Choose a reason for hiding this comment

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

Nice 👍
I think we can do the same thing for the new registerMuzzleContextStoreClasses() method that I introduced recently.

*/
class MuzzleReferencesAccessor {
private static final ClassValue<MethodHandle> getMuzzleReferences =
new ClassValue<MethodHandle>() {
Copy link
Member

Choose a reason for hiding this comment

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

Now that I think of it we don't really need to use ClassValues and MethodHandles - the getMuzzleReferences() will be called exactly once per InstrumentationModule implementation, so there's no need to cache the result here (it's already cached in the MuzzleMatcher).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Are you sure? Will be happy to remove this cache!

Copy link
Member

Choose a reason for hiding this comment

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

Yep -- the only place (MuzzleMatcher) that constructs ReferenceMatcher in the agent uses an AtomicBoolean initialized field to make sure it only does it once (building a giant map of references can get expensive).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What about io.opentelemetry.javaagent.tooling.muzzle.ClassLoaderMatcher#matchesAll?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also, I will try Lauri idea from #4087 (comment) anyway later on. That will probably remove this whole class.

Copy link
Member

Choose a reason for hiding this comment

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

That one is only used in the gradle muzzle-check plugin, it doesn't affect the agent at all.

* generated automatically during compilation by the {@code
* io.opentelemetry.instrumentation.javaagent-codegen} Gradle plugin.
*/
class MuzzleReferencesAccessor {
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps javaagent-codegen should add an interface that has getMuzzleReferences to instrumentation module so you wouldn't need to use reflection.

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 assume that MethodHandle has no performance overhead on invocation. But I will think about this idea, it may be more elegant indeed.

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 will try this idea as a follow-up optimisation. I like it, but prefer to finish current iteration of removing ClassRef and friends from public API.

Copy link
Member

Choose a reason for hiding this comment

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

This will also be easier to extend with other muzzle-generated methods.

Copy link
Contributor

Choose a reason for hiding this comment

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

If it is possible to build extension jars that contain instrumentation modules then all of the muzzle and codegen stuff has become part of our api. Have you thought about how to version it and how to handle cases where agent is incompatible with codegen version used?

Copy link
Contributor Author

@iNikem iNikem Sep 13, 2021

Choose a reason for hiding this comment

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

Ohhh, good question... The only vague thought I have atm is "javaagent must support all previous stable versions of codegen within any given major version." Which assumes "in sync" versioning of the agent and gradle plugins.

Copy link
Member

Choose a reason for hiding this comment

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

If it is possible to build extension jars that contain instrumentation modules then all of the muzzle and codegen stuff has become part of our api

oh no, this is a great point, so maybe we shouldn't get rid of these classes from our public API? 😭

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These classes should be part of the contract between muzzle generation and muzzle verification. But no end-user, including extension authors, should see them.

@iNikem iNikem merged commit 17d9c6f into open-telemetry:main Sep 13, 2021
@iNikem iNikem deleted the hide-muzzle-refs branch September 13, 2021 10:55
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.

5 participants