110 lines
6.7 KiB
Markdown
110 lines
6.7 KiB
Markdown
# Javaagent structure
|
|
|
|
The javaagent can be logically divided into several parts, based on the class loader that contains
|
|
particular classes (and resources) in the runtime:
|
|
|
|
- The main agent class living in the system class loader.
|
|
- Classes that live in the bootstrap class loader.
|
|
- Classes that live in the agent class loader.
|
|
- Javaagent extensions, and the extension class loader(s).
|
|
|
|
## System class loader
|
|
|
|
The only class that is loaded by the system class loader is the
|
|
`io.opentelemetry.javaagent.OpenTelemetryAgent` class. This is the main class of the javaagent, it
|
|
implements the
|
|
[Java instrumentation agent specification](https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html).
|
|
This class is loaded during application startup by the system class loader. Its sole
|
|
responsibility is to push the agent's classes into JVM's bootstrap class loader and immediately
|
|
delegate to the `io.opentelemetry.javaagent.bootstrap.AgentInitializer` class, living in the
|
|
bootstrap class loader.
|
|
|
|
Inside the javaagent jar, this class is located in the `io/opentelemetry/javaagent/` directory.
|
|
|
|
## Bootstrap class loader
|
|
|
|
The bootstrap class loader contains several modules:
|
|
|
|
- **The `javaagent-bootstrap` module**:
|
|
it contains classes that continue the initialization work started by `OpenTelemetryAgent`, as well
|
|
as some internal javaagent classes and interfaces that must be globally available to the whole
|
|
application. This module is internal and its APIs are considered unstable.
|
|
- **The `instrumentation-api` and `instrumentation-api-incubator` modules**:
|
|
these modules contain the [Instrumenter API](using-instrumenter-api.md) and other related
|
|
utilities. Because they are used by almost all instrumentations, they must be globally available
|
|
to all classloaders running within the instrumented application. The classes located in these
|
|
modules are used by both javaagent and library instrumentations - they all must be usable even
|
|
without the javaagent present.
|
|
- **The `instrumentation-annotations-support` module**:
|
|
it contains classes that provide support for annotation-based auto-instrumentation, e.g.
|
|
the `@WithSpan` annotation. This module is internal and its APIs are considered unstable.
|
|
- **The `io.opentelemetry.javaagent.bootstrap` package from the `javaagent-extension-api` module**:
|
|
this package contains several instrumentation utilities that are only usable when an application
|
|
is instrumented with the javaagent; for example, the `Java8BytecodeBridge` that should be used
|
|
inside advice classes.
|
|
- All modules using the `otel.javaagent-bootstrap` Gradle plugin:
|
|
these modules contain instrumentation-specific classes that must be globally available in the
|
|
bootstrap class loader. For example, classes that are used to coordinate
|
|
different `InstrumentationModule`s, like the common utilities for storing Servlet context path, or
|
|
the thread local switch used to coordinate different Kafka consumer instrumentations. By
|
|
convention, all these modules are named according to this
|
|
pattern: `:instrumentation:...:bootstrap`.
|
|
- The [OpenTelemetry API](https://github.com/open-telemetry/opentelemetry-java/tree/main/api/all).
|
|
|
|
Inside the javaagent jar, these classes are all located under the `io/opentelemetry/javaagent/`
|
|
directory. Aside from the javaagent-specific `javaagent-bootstrap` and `javaagent-extension-api`
|
|
modules, all other modules are relocated and placed under the `io/opentelemetry/javaagent/shaded/`
|
|
directory. This is done to avoid conflicts with the application code, which may contain different
|
|
versions of some of our APIs (`opentelemetry-api`, `instrumentation-api`).
|
|
|
|
## Agent class loader
|
|
|
|
The agent class loader contains almost everything else not mentioned before, including:
|
|
|
|
- **The `javaagent-tooling` module**:
|
|
this module picks up the initialization process started by `OpenTelemetryAgent`
|
|
and `javaagent-bootstrap` and actually finishes the work, starting up the OpenTelemetry SDK and
|
|
building and installing the `ClassFileTransformer` in the JVM. The javaagent
|
|
uses [ByteBuddy](https://bytebuddy.net) to configure and construct the `ClassFileTransformer`.
|
|
This module is internal and its APIs are considered unstable.
|
|
- **The `muzzle` module**:
|
|
it contains classes that are internally used by [muzzle](muzzle.md), our safety net feature. This
|
|
module is internal and its APIs are considered unstable.
|
|
- **The `io.opentelemetry.javaagent.extension` package from the `javaagent-extension-api` module**:
|
|
this package contains common extension points and SPIs that can be used to customize the agent
|
|
behavior.
|
|
- All modules using the `otel.javaagent-instrumentation` Gradle plugin:
|
|
these modules contain actual javaagent instrumentations. Almost all of them implement
|
|
the `InstrumentationModule`, some of them include a library instrumentation as an `implementation`
|
|
dependency. You can read more about writing instrumentations [here](writing-instrumentation.md).
|
|
By convention, all these modules are named according to this
|
|
pattern: `:instrumentation:...:javaagent`.
|
|
- The [OpenTelemetry SDK](https://github.com/open-telemetry/opentelemetry-java/tree/main/sdk/all),
|
|
along with various exporters and SDK extensions.
|
|
- [ByteBuddy](https://bytebuddy.net).
|
|
|
|
Inside the javaagent jar, all classes and resources that are meant to be loaded by
|
|
the `AgentClassLoader` are placed inside the `inst/` directory. All Java class files have
|
|
the `.classdata` extension (instead of just `.class`) - this ensures that they will not be loaded by
|
|
general class loaders included with the application, making the javaagent internals completely
|
|
isolated from the application code.
|
|
|
|
If a javaagent instrumentation includes a library instrumentation as an `implementation` dependency,
|
|
that dependency is shaded to prevent conflicts with application code (which may or may not include
|
|
the same library classes in different version).
|
|
|
|
## Extension class loader
|
|
|
|
The extension class loader(s) is used to load custom extensions, if they're used. Extensions can be
|
|
external jars (provided by the `otel.javaagent.extensions` configuration property), or can be
|
|
embedded into an OpenTelemetry javaagent distribution (by adding the extension jars into
|
|
the `extensions/` directory inside the javaagent jar). Each extension is loaded in isolation, in a
|
|
separate class loader - this is intended to reduce the possibility of conflicts between different
|
|
extensions. Extension jars can be compiled against unshaded versions of the OpenTelemetry APIs,
|
|
the javaagent will apply shading dynamically in the runtime, when the extension is loaded.
|
|
|
|
## Class loader hierarchy graph
|
|
|
|

|
|
[Image source](https://docs.google.com/drawings/d/1DOftemu_96_0RggzOV3hFXejqeZWTmPBgbkaUhHw--g)
|