Skip to content

Circular Dependency in Logger initialization between OTEL Log4j appender and JUL-Log4j bridge #16743

@Traderjoe95

Description

@Traderjoe95

Describe the bug

When using the JUL bridge of Log4j (org.apache.logging.log4j:log4j-jul) together with the io.opentelemetry.instrumentation:opentelemetry-log4j-appender-2.17 library, there is a circular dependency in the initialization of the logger context.

  1. Anything triggers the context initialization
  2. Log4j attempts to construct the OTEL appender
  3. The OTEL appender eagerly gets GlobalOpenTelemetry
  4. GlobalOpenTelemetry requests a JUL logger
  5. The JUL logging bridge finds a partially initialized context and fails to construct a logger

Steps to reproduce

  1. Use the following dependencies together:
  • io.opentelemetry.instrumentation:opentelemetry-log4j-appender-2.17:2.24.0-alpha or 2.25.0-alpha or 2.26.0-alpha
  • org.apache.logging.log4j:log4j-api:2.25.3
  • org.apache.logging.log4j:log4j-core:2.25.3
  • org.apache.logging.log4j:log4j-jul:2.25.3
  1. Configure log4j to use an OpenTelemetry appender, e.g. through log4j2.xml
  2. Write a minimal application that only creates a logger (LogManager.getLogger(MyClass.class))
  3. Run it while setting the system property java.util.logging.manager to org.apache.logging.log4j.jul.LogManager

Expected behavior

The logger is successfully initialized

Actual behavior

The initialization fails with

2026-03-19T09:28:35.765558700Z main ERROR Unable to create Lookup for ctx
java.lang.NullPointerException: Cannot invoke "java.util.List.size()" because "org.apache.logging.log4j.core.impl.ThreadContextDataInjector.SERVICE_PROVIDERS" is null
	at org.apache.logging.log4j.core.impl.ThreadContextDataInjector.getProviders(ThreadContextDataInjector.java:284)
	at org.apache.logging.log4j.core.impl.ThreadContextDataInjector.access$000(ThreadContextDataInjector.java:60)
	at org.apache.logging.log4j.core.impl.ThreadContextDataInjector$AbstractContextDataInjector.<init>(ThreadContextDataInjector.java:95)
	at org.apache.logging.log4j.core.impl.ThreadContextDataInjector$ForDefaultThreadContextMap.<init>(ThreadContextDataInjector.java:116)
	at org.apache.logging.log4j.core.impl.ContextDataInjectorFactory.createDefaultInjector(ContextDataInjectorFactory.java:86)
	at org.apache.logging.log4j.util.LoaderUtil.newCheckedInstanceOfProperty(LoaderUtil.java:365)
	at org.apache.logging.log4j.core.impl.ContextDataInjectorFactory.createInjector(ContextDataInjectorFactory.java:71)
	at org.apache.logging.log4j.core.lookup.ContextMapLookup.<init>(ContextMapLookup.java:34)
	at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486)
	at org.apache.logging.log4j.core.util.ReflectionUtil.instantiate(ReflectionUtil.java:188)
	at org.apache.logging.log4j.core.lookup.Interpolator.<init>(Interpolator.java:90)
	at org.apache.logging.log4j.core.lookup.Interpolator.<init>(Interpolator.java:109)
	at org.apache.logging.log4j.core.config.AbstractConfiguration.<init>(AbstractConfiguration.java:138)
	at org.apache.logging.log4j.core.config.DefaultConfiguration.<init>(DefaultConfiguration.java:46)
	at org.apache.logging.log4j.core.LoggerContext.<init>(LoggerContext.java:132)
	at org.apache.logging.log4j.core.selector.ClassLoaderContextSelector.createContext(ClassLoaderContextSelector.java:265)
	at org.apache.logging.log4j.core.selector.ClassLoaderContextSelector.locateContext(ClassLoaderContextSelector.java:224)
	at org.apache.logging.log4j.core.selector.ClassLoaderContextSelector.getContext(ClassLoaderContextSelector.java:142)
	at org.apache.logging.log4j.core.selector.ClassLoaderContextSelector.getContext(ClassLoaderContextSelector.java:125)
	at org.apache.logging.log4j.core.selector.ClassLoaderContextSelector.getContext(ClassLoaderContextSelector.java:119)
	at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:155)
	at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:48)
	at org.apache.logging.log4j.LogManager.getContext(LogManager.java:139)
	at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getContext(AbstractLoggerAdapter.java:138)
	at org.apache.logging.log4j.jul.AbstractLoggerAdapter.getContext(AbstractLoggerAdapter.java:34)
	at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getLogger(AbstractLoggerAdapter.java:46)
	at org.apache.logging.log4j.jul.LogManager.getLogger(LogManager.java:81)
	at java.logging/java.util.logging.LogManager.demandLogger(LogManager.java:521)
	at java.logging/java.util.logging.LogManager.demandLogger(LogManager.java:517)
	at java.logging/java.util.logging.Logger.demandLogger(Logger.java:656)
	at java.logging/java.util.logging.Logger.getLogger(Logger.java:720)
	at java.logging/java.util.logging.Logger.getLogger(Logger.java:703)
	at io.opentelemetry.api.GlobalOpenTelemetry.<clinit>(GlobalOpenTelemetry.java:69)
	at io.opentelemetry.instrumentation.log4j.contextdata.v2_17.OpenTelemetryContextDataProvider.<clinit>(OpenTelemetryContextDataProvider.java:31)
	at java.base/jdk.internal.misc.Unsafe.ensureClassInitialized0(Native Method)
	at java.base/jdk.internal.misc.Unsafe.ensureClassInitialized(Unsafe.java:1160)
	at java.base/jdk.internal.reflect.MethodHandleAccessorFactory.ensureClassInitialized(MethodHandleAccessorFactory.java:300)
	at java.base/jdk.internal.reflect.MethodHandleAccessorFactory.newConstructorAccessor(MethodHandleAccessorFactory.java:103)
	at java.base/jdk.internal.reflect.ReflectionFactory.newConstructorAccessor(ReflectionFactory.java:200)
	at java.base/java.lang.reflect.Constructor.acquireConstructorAccessor(Constructor.java:549)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486)
	at java.base/java.util.ServiceLoader$ProviderImpl.newInstance(ServiceLoader.java:789)
	at java.base/java.util.ServiceLoader$ProviderImpl.get(ServiceLoader.java:729)
	at java.base/java.util.ServiceLoader$3.next(ServiceLoader.java:1403)
	at org.apache.logging.log4j.util.ServiceLoaderUtil$ServiceLoaderSpliterator.tryAdvance(ServiceLoaderUtil.java:106)
	at java.base/java.util.Spliterator.forEachRemaining(Spliterator.java:332)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
	at org.apache.logging.log4j.core.impl.ThreadContextDataInjector.getServiceProviders(ThreadContextDataInjector.java:86)
	at org.apache.logging.log4j.core.impl.ThreadContextDataInjector.<clinit>(ThreadContextDataInjector.java:69)
	at org.apache.logging.log4j.core.impl.ThreadContextDataInjector$AbstractContextDataInjector.<init>(ThreadContextDataInjector.java:95)
	at org.apache.logging.log4j.core.impl.ThreadContextDataInjector$ForDefaultThreadContextMap.<init>(ThreadContextDataInjector.java:116)
	at org.apache.logging.log4j.core.impl.ContextDataInjectorFactory.createDefaultInjector(ContextDataInjectorFactory.java:86)
	at org.apache.logging.log4j.util.LoaderUtil.newCheckedInstanceOfProperty(LoaderUtil.java:365)
	at org.apache.logging.log4j.core.impl.ContextDataInjectorFactory.createInjector(ContextDataInjectorFactory.java:71)
	at org.apache.logging.log4j.core.lookup.ContextMapLookup.<init>(ContextMapLookup.java:34)
	at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486)
	at org.apache.logging.log4j.core.util.ReflectionUtil.instantiate(ReflectionUtil.java:188)
	at org.apache.logging.log4j.core.lookup.Interpolator.<init>(Interpolator.java:90)
	at org.apache.logging.log4j.core.lookup.Interpolator.<init>(Interpolator.java:109)
	at org.apache.logging.log4j.core.config.AbstractConfiguration.<init>(AbstractConfiguration.java:138)
	at org.apache.logging.log4j.core.config.NullConfiguration.<init>(NullConfiguration.java:32)
	at org.apache.logging.log4j.core.LoggerContext.<clinit>(LoggerContext.java:111)
	at org.apache.logging.log4j.core.selector.ClassLoaderContextSelector.createContext(ClassLoaderContextSelector.java:265)
	at org.apache.logging.log4j.core.selector.ClassLoaderContextSelector.locateContext(ClassLoaderContextSelector.java:224)
	at org.apache.logging.log4j.core.selector.ClassLoaderContextSelector.getContext(ClassLoaderContextSelector.java:142)
	at org.apache.logging.log4j.core.selector.ClassLoaderContextSelector.getContext(ClassLoaderContextSelector.java:125)
	at org.apache.logging.log4j.core.selector.ClassLoaderContextSelector.getContext(ClassLoaderContextSelector.java:119)
	at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:155)
	at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:48)
	at org.apache.logging.log4j.LogManager.getContext(LogManager.java:139)
	at org.apache.logging.log4j.LogManager.getLogger(LogManager.java:557)
	at io.vertx.core.logging.Log4j2LogDelegateFactory.isAvailable(Log4j2LogDelegateFactory.java:27)
	at io.vertx.core.internal.logging.LoggerFactory.configureWith(LoggerFactory.java:59)
	at io.vertx.core.internal.logging.LoggerFactory.initialise(LoggerFactory.java:42)
	at io.vertx.core.internal.logging.LoggerFactory.<clinit>(LoggerFactory.java:28)

The stack trace clearly shows the circular dependency

Javaagent or library instrumentation version

2.24.0-alpha through 2.26.0-alpha

Environment

JDK: Temurin 21
OS: Windows

Additional context

No response

Tip

React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1 or me too, to help us triage it. Learn more here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingneeds triageNew issue that requires triage

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions