1313import static java .util .logging .Level .FINE ;
1414import static java .util .logging .Level .SEVERE ;
1515import static net .bytebuddy .matcher .ElementMatchers .any ;
16+ import static net .bytebuddy .matcher .ElementMatchers .none ;
1617
1718import io .opentelemetry .context .Context ;
1819import io .opentelemetry .context .ContextStorage ;
3031import io .opentelemetry .javaagent .bootstrap .internal .ConfiguredResourceAttributesHolder ;
3132import io .opentelemetry .javaagent .extension .AgentListener ;
3233import io .opentelemetry .javaagent .extension .ignore .IgnoredTypesConfigurer ;
34+ import io .opentelemetry .javaagent .extension .instrumentation .internal .EarlyInstrumentationModule ;
3335import io .opentelemetry .javaagent .tooling .asyncannotationsupport .WeakRefAsyncOperationEndStrategies ;
3436import io .opentelemetry .javaagent .tooling .bootstrap .BootstrapPackagesBuilderImpl ;
3537import io .opentelemetry .javaagent .tooling .bootstrap .BootstrapPackagesConfigurer ;
3638import io .opentelemetry .javaagent .tooling .config .ConfigPropertiesBridge ;
3739import io .opentelemetry .javaagent .tooling .config .EarlyInitAgentConfig ;
40+ import io .opentelemetry .javaagent .tooling .field .FieldBackedImplementationConfiguration ;
41+ import io .opentelemetry .javaagent .tooling .field .VirtualFieldImplementationInstaller ;
42+ import io .opentelemetry .javaagent .tooling .field .VirtualFieldImplementationInstallerFactory ;
3843import io .opentelemetry .javaagent .tooling .ignore .IgnoredClassLoadersMatcher ;
3944import io .opentelemetry .javaagent .tooling .ignore .IgnoredTypesBuilderImpl ;
4045import io .opentelemetry .javaagent .tooling .ignore .IgnoredTypesMatcher ;
4954import java .util .HashMap ;
5055import java .util .List ;
5156import java .util .Map ;
57+ import java .util .Objects ;
5258import java .util .logging .LogManager ;
5359import java .util .logging .Logger ;
5460import java .util .stream .Stream ;
@@ -84,6 +90,8 @@ public class AgentInstaller {
8490
8591 private static final Map <String , List <Runnable >> CLASS_LOAD_CALLBACKS = new HashMap <>();
8692
93+ private static volatile boolean instrumentationInstalled ;
94+
8795 public static void installBytebuddyAgent (
8896 Instrumentation inst , ClassLoader extensionClassLoader , EarlyInitAgentConfig earlyConfig ) {
8997 addByteBuddyRawSetting ();
@@ -98,7 +106,7 @@ public static void installBytebuddyAgent(
98106 if (earlyConfig .getBoolean (JAVAAGENT_ENABLED_CONFIG , true )) {
99107 setupUnsafe (inst );
100108 List <AgentListener > agentListeners = loadOrdered (AgentListener .class , extensionClassLoader );
101- installBytebuddyAgent (inst , extensionClassLoader , agentListeners );
109+ installBytebuddyAgent (inst , extensionClassLoader , agentListeners , earlyConfig );
102110 } else {
103111 logger .fine ("Tracing is disabled, not installing instrumentations." );
104112 }
@@ -107,31 +115,13 @@ public static void installBytebuddyAgent(
107115 private static void installBytebuddyAgent (
108116 Instrumentation inst ,
109117 ClassLoader extensionClassLoader ,
110- Iterable <AgentListener > agentListeners ) {
118+ Iterable <AgentListener > agentListeners ,
119+ EarlyInitAgentConfig earlyConfig ) {
111120
112121 WeakRefAsyncOperationEndStrategies .initialize ();
113-
114122 EmbeddedInstrumentationProperties .setPropertiesLoader (extensionClassLoader );
115-
116123 setDefineClassHandler ();
117-
118- // If noop OpenTelemetry is enabled, autoConfiguredSdk will be null and AgentListeners are not
119- // called
120- AutoConfiguredOpenTelemetrySdk autoConfiguredSdk =
121- installOpenTelemetrySdk (extensionClassLoader );
122-
123- ConfigProperties sdkConfig = AgentListener .resolveConfigProperties (autoConfiguredSdk );
124- AgentInstrumentationConfig .internalInitializeConfig (new ConfigPropertiesBridge (sdkConfig ));
125- copyNecessaryConfigToSystemProperties (sdkConfig );
126-
127- setBootstrapPackages (sdkConfig , extensionClassLoader );
128- ConfiguredResourceAttributesHolder .initialize (
129- SdkAutoconfigureAccess .getResourceAttributes (autoConfiguredSdk ));
130-
131- for (BeforeAgentListener agentListener :
132- loadOrdered (BeforeAgentListener .class , extensionClassLoader )) {
133- agentListener .beforeAgent (autoConfiguredSdk );
134- }
124+ FieldBackedImplementationConfiguration .configure (earlyConfig );
135125
136126 AgentBuilder agentBuilder =
137127 new AgentBuilder .Default (
@@ -153,9 +143,6 @@ private static void installBytebuddyAgent(
153143 if (JavaModule .isSupported ()) {
154144 agentBuilder = agentBuilder .with (new ExposeAgentBootstrapListener (inst ));
155145 }
156-
157- agentBuilder = configureIgnoredTypes (sdkConfig , extensionClassLoader , agentBuilder );
158-
159146 if (logger .isLoggable (FINE )) {
160147 agentBuilder =
161148 agentBuilder
@@ -165,6 +152,28 @@ private static void installBytebuddyAgent(
165152 .with (new TransformLoggingListener ());
166153 }
167154
155+ installEarlyInstrumentation (agentBuilder , inst );
156+
157+ // If noop OpenTelemetry is enabled, autoConfiguredSdk will be null and AgentListeners are not
158+ // called
159+ AutoConfiguredOpenTelemetrySdk autoConfiguredSdk =
160+ installOpenTelemetrySdk (extensionClassLoader );
161+
162+ ConfigProperties sdkConfig = AgentListener .resolveConfigProperties (autoConfiguredSdk );
163+ AgentInstrumentationConfig .internalInitializeConfig (new ConfigPropertiesBridge (sdkConfig ));
164+ copyNecessaryConfigToSystemProperties (sdkConfig );
165+
166+ setBootstrapPackages (sdkConfig , extensionClassLoader );
167+ ConfiguredResourceAttributesHolder .initialize (
168+ SdkAutoconfigureAccess .getResourceAttributes (autoConfiguredSdk ));
169+
170+ for (BeforeAgentListener agentListener :
171+ loadOrdered (BeforeAgentListener .class , extensionClassLoader )) {
172+ agentListener .beforeAgent (autoConfiguredSdk );
173+ }
174+
175+ agentBuilder = configureIgnoredTypes (sdkConfig , extensionClassLoader , agentBuilder );
176+
168177 int numberOfLoadedExtensions = 0 ;
169178 for (AgentExtension agentExtension : loadOrdered (AgentExtension .class , extensionClassLoader )) {
170179 if (logger .isLoggable (FINE )) {
@@ -191,13 +200,44 @@ private static void installBytebuddyAgent(
191200
192201 agentBuilder = AgentBuilderUtil .optimize (agentBuilder );
193202 ResettableClassFileTransformer resettableClassFileTransformer = agentBuilder .installOn (inst );
203+ instrumentationInstalled = true ;
194204 ClassFileTransformerHolder .setClassFileTransformer (resettableClassFileTransformer );
195205
196206 addHttpServerResponseCustomizers (extensionClassLoader );
197207
198208 runAfterAgentListeners (agentListeners , autoConfiguredSdk , sdkConfig );
199209 }
200210
211+ private static void installEarlyInstrumentation (
212+ AgentBuilder agentBuilder , Instrumentation instrumentation ) {
213+ // We are only going to install the virtual fields here. Installing virtual field changes class
214+ // structure and can not be applied to already loaded classes.
215+ agentBuilder = agentBuilder .with (AgentBuilder .RedefinitionStrategy .DISABLED );
216+
217+ AgentBuilder .Identified .Extendable extendableAgentBuilder =
218+ agentBuilder
219+ .ignore (
220+ target -> instrumentationInstalled , // turn off after instrumentation is installed
221+ Objects ::nonNull )
222+ .type (none ())
223+ .transform (
224+ (builder , typeDescription , classLoader , module , protectionDomain ) -> builder );
225+
226+ VirtualFieldImplementationInstallerFactory virtualFieldInstallerFactory =
227+ new VirtualFieldImplementationInstallerFactory ();
228+ for (EarlyInstrumentationModule earlyInstrumentationModule :
229+ loadOrdered (EarlyInstrumentationModule .class , Utils .getExtensionsClassLoader ())) {
230+
231+ VirtualFieldImplementationInstaller contextProvider =
232+ virtualFieldInstallerFactory .create (
233+ earlyInstrumentationModule .getInstrumentationModule ());
234+ extendableAgentBuilder = contextProvider .injectFields (extendableAgentBuilder );
235+ }
236+
237+ agentBuilder = AgentBuilderUtil .optimize (extendableAgentBuilder );
238+ agentBuilder .installOn (instrumentation );
239+ }
240+
201241 private static void copyNecessaryConfigToSystemProperties (ConfigProperties config ) {
202242 for (String property : asList ("otel.instrumentation.experimental.span-suppression-strategy" )) {
203243 String value = config .getString (property );
0 commit comments