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 ;
5055import java .util .HashMap ;
5156import java .util .List ;
5257import java .util .Map ;
58+ import java .util .Objects ;
5359import java .util .logging .LogManager ;
5460import java .util .logging .Logger ;
5561import java .util .stream .Stream ;
@@ -85,6 +91,8 @@ public class AgentInstaller {
8591
8692 private static final Map <String , List <Runnable >> CLASS_LOAD_CALLBACKS = new HashMap <>();
8793
94+ private static volatile boolean instrumentationInstalled ;
95+
8896 public static void installBytebuddyAgent (
8997 Instrumentation inst , ClassLoader extensionClassLoader , EarlyInitAgentConfig earlyConfig ) {
9098 addByteBuddyRawSetting ();
@@ -99,7 +107,7 @@ public static void installBytebuddyAgent(
99107 if (earlyConfig .getBoolean (JAVAAGENT_ENABLED_CONFIG , true )) {
100108 setupUnsafe (inst );
101109 List <AgentListener > agentListeners = loadOrdered (AgentListener .class , extensionClassLoader );
102- installBytebuddyAgent (inst , extensionClassLoader , agentListeners );
110+ installBytebuddyAgent (inst , extensionClassLoader , agentListeners , earlyConfig );
103111 } else {
104112 logger .fine ("Tracing is disabled, not installing instrumentations." );
105113 }
@@ -108,31 +116,13 @@ public static void installBytebuddyAgent(
108116 private static void installBytebuddyAgent (
109117 Instrumentation inst ,
110118 ClassLoader extensionClassLoader ,
111- Iterable <AgentListener > agentListeners ) {
119+ Iterable <AgentListener > agentListeners ,
120+ EarlyInitAgentConfig earlyConfig ) {
112121
113122 WeakRefAsyncOperationEndStrategies .initialize ();
114-
115123 EmbeddedInstrumentationProperties .setPropertiesLoader (extensionClassLoader );
116-
117124 setDefineClassHandler ();
118-
119- // If noop OpenTelemetry is enabled, autoConfiguredSdk will be null and AgentListeners are not
120- // called
121- AutoConfiguredOpenTelemetrySdk autoConfiguredSdk =
122- installOpenTelemetrySdk (extensionClassLoader );
123-
124- ConfigProperties sdkConfig = AutoConfigureUtil .getConfig (autoConfiguredSdk );
125- AgentInstrumentationConfig .internalInitializeConfig (new ConfigPropertiesBridge (sdkConfig ));
126- copyNecessaryConfigToSystemProperties (sdkConfig );
127-
128- setBootstrapPackages (sdkConfig , extensionClassLoader );
129- ConfiguredResourceAttributesHolder .initialize (
130- SdkAutoconfigureAccess .getResourceAttributes (autoConfiguredSdk ));
131-
132- for (BeforeAgentListener agentListener :
133- loadOrdered (BeforeAgentListener .class , extensionClassLoader )) {
134- agentListener .beforeAgent (autoConfiguredSdk );
135- }
125+ FieldBackedImplementationConfiguration .configure (earlyConfig );
136126
137127 AgentBuilder agentBuilder =
138128 new AgentBuilder .Default (
@@ -154,9 +144,6 @@ private static void installBytebuddyAgent(
154144 if (JavaModule .isSupported ()) {
155145 agentBuilder = agentBuilder .with (new ExposeAgentBootstrapListener (inst ));
156146 }
157-
158- agentBuilder = configureIgnoredTypes (sdkConfig , extensionClassLoader , agentBuilder );
159-
160147 if (logger .isLoggable (FINE )) {
161148 agentBuilder =
162149 agentBuilder
@@ -166,6 +153,28 @@ private static void installBytebuddyAgent(
166153 .with (new TransformLoggingListener ());
167154 }
168155
156+ installEarlyInstrumentation (agentBuilder , inst );
157+
158+ // If noop OpenTelemetry is enabled, autoConfiguredSdk will be null and AgentListeners are not
159+ // called
160+ AutoConfiguredOpenTelemetrySdk autoConfiguredSdk =
161+ installOpenTelemetrySdk (extensionClassLoader );
162+
163+ ConfigProperties sdkConfig = AutoConfigureUtil .getConfig (autoConfiguredSdk );
164+ AgentInstrumentationConfig .internalInitializeConfig (new ConfigPropertiesBridge (sdkConfig ));
165+ copyNecessaryConfigToSystemProperties (sdkConfig );
166+
167+ setBootstrapPackages (sdkConfig , extensionClassLoader );
168+ ConfiguredResourceAttributesHolder .initialize (
169+ SdkAutoconfigureAccess .getResourceAttributes (autoConfiguredSdk ));
170+
171+ for (BeforeAgentListener agentListener :
172+ loadOrdered (BeforeAgentListener .class , extensionClassLoader )) {
173+ agentListener .beforeAgent (autoConfiguredSdk );
174+ }
175+
176+ agentBuilder = configureIgnoredTypes (sdkConfig , extensionClassLoader , agentBuilder );
177+
169178 int numberOfLoadedExtensions = 0 ;
170179 for (AgentExtension agentExtension : loadOrdered (AgentExtension .class , extensionClassLoader )) {
171180 if (logger .isLoggable (FINE )) {
@@ -192,13 +201,44 @@ private static void installBytebuddyAgent(
192201
193202 agentBuilder = AgentBuilderUtil .optimize (agentBuilder );
194203 ResettableClassFileTransformer resettableClassFileTransformer = agentBuilder .installOn (inst );
204+ instrumentationInstalled = true ;
195205 ClassFileTransformerHolder .setClassFileTransformer (resettableClassFileTransformer );
196206
197207 addHttpServerResponseCustomizers (extensionClassLoader );
198208
199209 runAfterAgentListeners (agentListeners , autoConfiguredSdk );
200210 }
201211
212+ private static void installEarlyInstrumentation (
213+ AgentBuilder agentBuilder , Instrumentation instrumentation ) {
214+ // We are only going to install the virtual fields here. Installing virtual field changes class
215+ // structure and can not be applied to already loaded classes.
216+ agentBuilder = agentBuilder .with (AgentBuilder .RedefinitionStrategy .DISABLED );
217+
218+ AgentBuilder .Identified .Extendable extendableAgentBuilder =
219+ agentBuilder
220+ .ignore (
221+ target -> instrumentationInstalled , // turn off after instrumentation is installed
222+ Objects ::nonNull )
223+ .type (none ())
224+ .transform (
225+ (builder , typeDescription , classLoader , module , protectionDomain ) -> builder );
226+
227+ VirtualFieldImplementationInstallerFactory virtualFieldInstallerFactory =
228+ new VirtualFieldImplementationInstallerFactory ();
229+ for (EarlyInstrumentationModule earlyInstrumentationModule :
230+ loadOrdered (EarlyInstrumentationModule .class , Utils .getExtensionsClassLoader ())) {
231+
232+ VirtualFieldImplementationInstaller contextProvider =
233+ virtualFieldInstallerFactory .create (
234+ earlyInstrumentationModule .getInstrumentationModule ());
235+ extendableAgentBuilder = contextProvider .injectFields (extendableAgentBuilder );
236+ }
237+
238+ agentBuilder = AgentBuilderUtil .optimize (extendableAgentBuilder );
239+ agentBuilder .installOn (instrumentation );
240+ }
241+
202242 private static void copyNecessaryConfigToSystemProperties (ConfigProperties config ) {
203243 for (String property : asList ("otel.instrumentation.experimental.span-suppression-strategy" )) {
204244 String value = config .getString (property );
0 commit comments