Skip to content

Commit be55b2a

Browse files
author
Mateusz Rzeszutek
authored
Update muzzle and InstrumentationModule docs after latest changes (#4412)
* Update muzzle and InstrumentationModule docs after latest changes * additional comment
1 parent 2e97a4d commit be55b2a

File tree

2 files changed

+55
-31
lines changed

2 files changed

+55
-31
lines changed

docs/contributing/muzzle.md

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,24 @@ Muzzle has two phases:
1717

1818
### Compile-time reference collection
1919

20-
The compile-time reference collection and code generation process is implemented using a ByteBuddy
21-
plugin (called `MuzzleCodeGenerationPlugin`).
22-
23-
For each instrumentation module the ByteBuddy plugin first applies `InstrumentationModuleMuzzle`
24-
interface to it and then proceeds to implement all methods from that interface by generating the
25-
required bytecode.
26-
It collects symbols referring to both internal and third party APIs used by the currently processed module's type
27-
instrumentations (`InstrumentationModule#typeInstrumentations()`). The reference collection process
28-
starts from advice classes (values of the map returned by the
29-
`TypeInstrumentation#transformers()` method) and traverses the class graph until it encounters a
30-
reference to a non-instrumentation class (determined by `InstrumentationClassPredicate` and
31-
the `InstrumentationModule#isHelperClass(String)` predicate). Aside from references,
32-
the collection process also builds a graph of dependencies between internal instrumentation helper
20+
The compile-time reference collection and code generation process is implemented using a Gradle
21+
plugin ([`io.opentelemetry.instrumentation.muzzle-generation`](https://plugins.gradle.org/plugin/io.opentelemetry.instrumentation.muzzle-generation)).
22+
23+
For each instrumentation module the code generation plugin first applies
24+
the `InstrumentationModuleMuzzle` interface to it and then proceeds to implement all methods from
25+
that interface by generating the required bytecode.
26+
It collects symbols referring to both internal and third party APIs used by the currently processed
27+
module's type instrumentations (`InstrumentationModule#typeInstrumentations()`). The reference
28+
collection process starts from advice classes (collected by calling the
29+
`TypeInstrumentation#transform(TypeTransformer)` method) and traverses the class graph until it
30+
encounters a reference to a non-instrumentation class (determined by `InstrumentationClassPredicate`
31+
and the `InstrumentationModule#isHelperClass(String)` predicate). Aside from references, the
32+
collection process also builds a graph of dependencies between internal instrumentation helper
3333
classes - this dependency graph is later used to construct a list of helper classes that will be
3434
injected to the application classloader (`InstrumentationModuleMuzzle#getMuzzleHelperClassNames()`).
3535
Muzzle also automatically generates the `InstrumentationModuleMuzzle#registerMuzzleVirtualFields()`
36-
method. All collected references are then used to generate an `InstrumentationModuleMuzzle#getMuzzleReferences` method.
36+
method. All collected references are then used to generate
37+
an `InstrumentationModuleMuzzle#getMuzzleReferences` method.
3738

3839
If your `InstrumentationModule` subclass defines a method with exact same signature as a method
3940
from `InstrumentationModuleMuzzle`, the muzzle compile plugin will not override your code:
@@ -57,12 +58,13 @@ once for the whole instrumentation module.
5758

5859
The source code of the runtime muzzle matcher is located in the `muzzle` module.
5960

60-
## Muzzle gradle plugin
61+
## `muzzle-check` gradle plugin
6162

62-
The muzzle gradle plugin allows to perform the runtime reference matching process against different
63-
third party library versions, when the project is built.
63+
The [`muzzle-check`](https://plugins.gradle.org/plugin/io.opentelemetry.instrumentation.muzzle-check)
64+
gradle plugin allows to perform the runtime reference matching process against different third party
65+
library versions, when the project is built.
6466

65-
Muzzle gradle plugin is just an additional utility for enhanced build-time checking
67+
The `muzzle-check` gradle plugin is just an additional utility for enhanced build-time checking
6668
to alert us when there are breaking changes in the underlying third party library
6769
that will cause the instrumentation not to get applied.
6870
**Even without using it muzzle reference matching is _always_ active in runtime**,
@@ -88,25 +90,25 @@ Example:
8890
muzzle {
8991
// it is expected that muzzle fails the runtime check for this component
9092
fail {
91-
group = "commons-httpclient"
92-
module = "commons-httpclient"
93+
group.set("commons-httpclient")
94+
module.set("commons-httpclient")
9395
// versions from this range are checked
94-
versions = "[,4.0)"
96+
versions.set("[,4.0)")
9597
// this version is not checked by muzzle
96-
skip('3.1-jenkins-1')
98+
skip("3.1-jenkins-1")
9799
}
98100
// it is expected that muzzle passes the runtime check for this component
99101
pass {
100-
group = 'org.springframework'
101-
module = 'spring-webmvc'
102-
versions = "[3.1.0.RELEASE,]"
102+
group.set("org.springframework")
103+
module.set("spring-webmvc")
104+
versions.set("[3.1.0.RELEASE,]")
103105
// except these versions
104-
skip('1.2.1', '1.2.2', '1.2.3', '1.2.4')
105-
skip('3.2.1.RELEASE')
106+
skip("1.2.1", "1.2.2", "1.2.3", "1.2.4")
107+
skip("3.2.1.RELEASE")
106108
// this dependency will be added to the classpath when muzzle check is run
107-
extraDependency "javax.servlet:javax.servlet-api:3.0.1"
109+
extraDependency("javax.servlet:javax.servlet-api:3.0.1")
108110
// verify that all other versions - [,3.1.0.RELEASE) in this case - fail the muzzle runtime check
109-
assertInverse = true
111+
assertInverse.set(true)
110112
}
111113
}
112114
```
@@ -131,10 +133,10 @@ library. Expecting muzzle check failures from some library versions is a way to
131133
instrumentation will not be applied to them in the runtime - and won't break anything in the
132134
instrumented application.
133135

134-
The easiest way it can be done is by adding `assertInverse = true` to the `pass` muzzle
136+
The easiest way it can be done is by adding `assertInverse.set(true)` to the `pass` muzzle
135137
directive. The plugin will add an implicit `fail` directive that contains all other versions of the
136138
instrumented library.
137-
It is worth using `assertInverse = true` by default when writing instrumentation modules, even for
139+
It is worth using `assertInverse.set(true)` by default when writing instrumentation modules, even for
138140
very old library versions. The muzzle plugin will ensure that those old versions won't be
139141
accidentally instrumented when we know that the instrumentation will not work properly for them.
140142
Having a `fail` directive forces the authors of the instrumentation module to properly specify

docs/contributing/writing-instrumentation-module.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,28 @@ All classes referenced by service providers defined in the `helperResourceNames(
9191
treated as helper classes: they'll be checked for invalid references and automatically injected into
9292
the application classloader.
9393

94+
### `getAdditionalHelperClassNames()`
95+
96+
If you don't use the [muzzle gradle plugins](muzzle.md), or have a specific scenario that requires
97+
providing the helper classes by hand (e.g. an unusual SPI implementation), you can override
98+
the `getAdditionalHelperClassNames()` method to provide a list of additional helper classes that
99+
should be injected to the application classloader when the instrumentation is applied.
100+
101+
```java
102+
public List<String> getAdditionalHelperClassNames() {
103+
return Arrays.asList(
104+
"org.my.library.instrumentation.SomeHelper",
105+
"org.my.library.instrumentation.AnotherHelper");
106+
}
107+
```
108+
109+
The order of the class names returned by this method matters - if you have several helper classes
110+
extending one another then you'll want to return the base class first. For example, if you have a
111+
`B extends A` class the list should contain `A` first and `B` second.
112+
113+
These helper classes will be injected into the application classloader after those provided by the
114+
muzzle codegen plugin.
115+
94116
### `classLoaderMatcher()`
95117

96118
Different versions of the same library often need completely different instrumentations:

0 commit comments

Comments
 (0)