1818
1919import  java .io .FileNotFoundException ;
2020import  java .io .IOException ;
21- import  java .io .InputStream ;
22- import  java .net .URL ;
23- import  java .net .URLConnection ;
2421import  java .util .ArrayList ;
2522import  java .util .Collections ;
2623import  java .util .LinkedHashMap ;
3734import  org .apache .logging .log4j .core .LoggerContext ;
3835import  org .apache .logging .log4j .core .config .AbstractConfiguration ;
3936import  org .apache .logging .log4j .core .config .Configuration ;
37+ import  org .apache .logging .log4j .core .config .ConfigurationException ;
4038import  org .apache .logging .log4j .core .config .ConfigurationFactory ;
41- import  org .apache .logging .log4j .core .config .ConfigurationSource ;
4239import  org .apache .logging .log4j .core .config .LoggerConfig ;
4340import  org .apache .logging .log4j .core .config .composite .CompositeConfiguration ;
4441import  org .apache .logging .log4j .core .filter .DenyAllFilter ;
45- import  org .apache .logging .log4j .core .net .UrlConnectionFactory ;
46- import  org .apache .logging .log4j .core .net .ssl .SslConfiguration ;
47- import  org .apache .logging .log4j .core .net .ssl .SslConfigurationFactory ;
48- import  org .apache .logging .log4j .core .util .AuthorizationProvider ;
4942import  org .apache .logging .log4j .core .util .NameUtil ;
5043import  org .apache .logging .log4j .jul .Log4jBridgeHandler ;
5144import  org .apache .logging .log4j .status .StatusConsoleListener ;
7265import  org .springframework .core .io .ResourceLoader ;
7366import  org .springframework .util .Assert ;
7467import  org .springframework .util .ClassUtils ;
75- import  org .springframework .util .CollectionUtils ;
7668import  org .springframework .util .StringUtils ;
7769
7870/** 
@@ -100,43 +92,6 @@ public class Log4J2LoggingSystem extends AbstractLoggingSystem {
10092	 */ 
10193	static  final  String  LOG4J_LOG_MANAGER  = "org.apache.logging.log4j.jul.LogManager" ;
10294
103- 	/** 
104- 	 * JSON tree parser used by Log4j 2 (optional dependency). 
105- 	 */ 
106- 	static  final  String  JSON_TREE_PARSER_V2  = "com.fasterxml.jackson.databind.ObjectMapper" ;
107- 
108- 	/** 
109- 	 * JSON tree parser embedded in Log4j 3. 
110- 	 */ 
111- 	static  final  String  JSON_TREE_PARSER_V3  = "org.apache.logging.log4j.kit.json.JsonReader" ;
112- 
113- 	/** 
114- 	 * Configuration factory for properties files (Log4j 2). 
115- 	 */ 
116- 	static  final  String  PROPS_CONFIGURATION_FACTORY_V2  = "org.apache.logging.log4j.core.config.properties.PropertiesConfigurationFactory" ;
117- 
118- 	/** 
119- 	 * Configuration factory for properties files (Log4j 3, optional dependency). 
120- 	 */ 
121- 	static  final  String  PROPS_CONFIGURATION_FACTORY_V3  = "org.apache.logging.log4j.config.properties.JavaPropsConfigurationFactory" ;
122- 
123- 	/** 
124- 	 * YAML tree parser used by Log4j 2 (optional dependency). 
125- 	 */ 
126- 	static  final  String  YAML_TREE_PARSER_V2  = "com.fasterxml.jackson.dataformat.yaml.YAMLMapper" ;
127- 
128- 	/** 
129- 	 * Configuration factory for YAML files (Log4j 2, embedded). 
130- 	 */ 
131- 	static  final  String  YAML_CONFIGURATION_FACTORY_V2  = "org.apache.logging.log4j.core.config.yaml.YamlConfigurationFactory" ;
132- 
133- 	/** 
134- 	 * Configuration factory for YAML files (Log4j 3, optional dependency). 
135- 	 */ 
136- 	static  final  String  YAML_CONFIGURATION_FACTORY_V3  = "org.apache.logging.log4j.config.yaml.YamlConfigurationFactory" ;
137- 
138- 	private  static  final  SpringEnvironmentPropertySource  propertySource  = new  SpringEnvironmentPropertySource ();
139- 
14095	static  final  String  ENVIRONMENT_KEY  = Conventions .getQualifiedAttributeName (Log4J2LoggingSystem .class ,
14196			"environment" );
14297
@@ -157,78 +112,60 @@ public class Log4J2LoggingSystem extends AbstractLoggingSystem {
157112
158113	private  static  final  Filter  FILTER  = DenyAllFilter .newBuilder ().build ();
159114
160- 	public  Log4J2LoggingSystem (ClassLoader  classLoader ) {
115+ 	private  static  final  SpringEnvironmentPropertySource  propertySource  = new  SpringEnvironmentPropertySource ();
116+ 
117+ 	private  static  final  org .apache .logging .log4j .Logger  statusLogger  = StatusLogger .getLogger ();
118+ 
119+ 	private  final  LoggerContext  loggerContext ;
120+ 
121+ 	/** 
122+ 	 * Create a new {@link Log4J2LoggingSystem} instance. 
123+ 	 * @param classLoader the class loader to use. 
124+ 	 * @param loggerContext the {@link LoggerContext} to use. 
125+ 	 */ 
126+ 	Log4J2LoggingSystem (ClassLoader  classLoader , LoggerContext  loggerContext ) {
161127		super (classLoader );
128+ 		this .loggerContext  = loggerContext ;
162129	}
163130
164131	@ Override 
165132	protected  String [] getStandardConfigLocations () {
166- 		List <String > locations  = new  ArrayList <>();
167- 		addLocationsFromProperties (locations );
168- 		addStandardLocations (locations );
169- 		return  StringUtils .toStringArray (locations );
170- 	}
171- 
172- 	private  void  addLocationsFromProperties (List <String > locations ) {
173- 		for  (String  property  : List .of ("log4j2.configurationFile" , "log4j.configuration.location" )) {
174- 			String  propertyDefinedLocation  = PropertiesUtil .getProperties ().getStringProperty (property );
175- 			if  (propertyDefinedLocation  != null ) {
176- 				locations .add (propertyDefinedLocation );
177- 			}
178- 		}
133+ 		// With Log4J2 we use the ConfigurationFactory 
134+ 		throw  new  IllegalStateException ("Standard config locations cannot be used with Log4J2" );
179135	}
180136
181- 	private  void  addStandardLocations (List <String > locations ) {
182- 		LoggerContext  loggerContext  = getLoggerContext ();
183- 		String  contextName  = loggerContext .getName ();
184- 		List <String > extensions  = getStandardConfigExtensions ();
185- 		addLocation (locations , "log4j2-test"  + contextName , extensions );
186- 		addLocation (locations , "log4j2-test" , extensions );
187- 		addLocation (locations , "log4j2"  + contextName , extensions );
188- 		addLocation (locations , "log4j2" , extensions );
137+ 	@ Override 
138+ 	protected  @ Nullable  String  getSelfInitializationConfig () {
139+ 		return  getConfigLocation (getLoggerContext ().getConfiguration ());
189140	}
190141
191- 	private  List <String > getStandardConfigExtensions () {
192- 		List <String > extensions  = new  ArrayList <>();
193- 		// These classes need to be visible by the classloader that loads Log4j Core. 
194- 		ClassLoader  classLoader  = LoggerContext .class .getClassLoader ();
195- 		// The order of the extensions corresponds to the order in which Log4j Core 2 and 
196- 		// 3 will try to load them, in decreasing value of @Order. 
197- 		if  (isPresent (classLoader , PROPS_CONFIGURATION_FACTORY_V2 )
198- 				|| isPresent (classLoader , PROPS_CONFIGURATION_FACTORY_V3 )) {
199- 			extensions .add (".properties" );
200- 		}
201- 		if  (isPresent (classLoader , YAML_CONFIGURATION_FACTORY_V2 , YAML_TREE_PARSER_V2 )
202- 				|| isPresent (classLoader , YAML_CONFIGURATION_FACTORY_V3 )) {
203- 			Collections .addAll (extensions , ".yaml" , ".yml" );
204- 		}
205- 		if  (isPresent (classLoader , JSON_TREE_PARSER_V2 ) || isPresent (classLoader , JSON_TREE_PARSER_V3 )) {
206- 			Collections .addAll (extensions , ".json" , ".jsn" );
142+ 	@ Override 
143+ 	protected  @ Nullable  String  getSpringInitializationConfig () {
144+ 		ConfigurationFactory  configurationFactory  = ConfigurationFactory .getInstance ();
145+ 		try  {
146+ 			Configuration  springConfiguration  = configurationFactory .getConfiguration (getLoggerContext (), "-spring" ,
147+ 					null , getClassLoader ());
148+ 			String  configLocation  = getConfigLocation (springConfiguration );
149+ 			return  (configLocation  != null  && configLocation .contains ("-spring" )) ? configLocation  : null ;
207150		}
208- 		extensions .add (".xml" );
209- 		return  extensions ;
210- 	}
211- 
212- 	private  void  addLocation (List <String > locations , String  location , List <String > extensions ) {
213- 		extensions .forEach ((extension ) -> locations .add (location  + extension ));
214- 	}
215- 
216- 	private  boolean  isPresent (ClassLoader  classLoader , String ... classNames ) {
217- 		for  (String  className  : classNames ) {
218- 			if  (!isClassAvailable (classLoader , className )) {
219- 				return  false ;
220- 			}
151+ 		catch  (ConfigurationException  ex ) {
152+ 			statusLogger .warn ("Could not load Spring-specific Log4j Core configuration" , ex );
153+ 			return  null ;
221154		}
222- 		return  true ;
223- 	}
224- 
225- 	protected  boolean  isClassAvailable (ClassLoader  classLoader , String  className ) {
226- 		return  ClassUtils .isPresent (className , classLoader );
227155	}
228156
229- 	@ Deprecated (since  = "4.0.0" , forRemoval  = true )
230- 	protected  boolean  isClassAvailable (String  className ) {
231- 		return  ClassUtils .isPresent (className , getClassLoader ());
157+ 	/** 
158+ 	 * Return the configuration location. The result may be: 
159+ 	 * <ul> 
160+ 	 * <li>{@code null}: if DefaultConfiguration is used (no explicit config loaded)</li> 
161+ 	 * <li>A file path: if provided explicitly by the user</li> 
162+ 	 * <li>A URI: if loaded from the classpath default or a custom location</li> 
163+ 	 * </ul> 
164+ 	 * @param configuration the source configuration 
165+ 	 * @return the config location or {@code null} 
166+ 	 */ 
167+ 	private  @ Nullable  String  getConfigLocation (Configuration  configuration ) {
168+ 		return  configuration .getConfigurationSource ().getLocation ();
232169	}
233170
234171	@ Override 
@@ -335,7 +272,7 @@ private void load(LoggingInitializationContext initializationContext, String loc
335272		Environment  environment  = initializationContext .getEnvironment ();
336273		Assert .state (environment  != null , "'environment' must not be null" );
337274		applySystemProperties (environment , logFile );
338- 		loadConfiguration (location ,  logFile , overrides );
275+ 		reconfigure (location , overrides );
339276	}
340277
341278	private  List <String > getOverrides (LoggingInitializationContext  initializationContext ) {
@@ -346,66 +283,51 @@ private List<String> getOverrides(LoggingInitializationContext initializationCon
346283		return  overrides .orElse (Collections .emptyList ());
347284	}
348285
349- 	/** 
350- 	 * Load the configuration from the given {@code location}, creating a composite using 
351- 	 * the configuration from the given {@code overrides}. 
352- 	 * @param location the location 
353- 	 * @param logFile log file configuration 
354- 	 * @param overrides the overriding locations 
355- 	 * @since 2.6.0 
356- 	 */ 
357- 	protected  void  loadConfiguration (String  location , @ Nullable  LogFile  logFile , List <String > overrides ) {
286+ 	private  void  reconfigure (String  location , List <String > overrides ) {
358287		Assert .notNull (location , "'location' must not be null" );
359288		try  {
360289			List <Configuration > configurations  = new  ArrayList <>();
361- 			LoggerContext  context  = getLoggerContext ();
362- 			ResourceLoader  resourceLoader  = ApplicationResourceLoader .get ();
363- 			configurations .add (load (resourceLoader .getResource (location ), context ));
290+ 			ResourceLoader  resourceLoader  = ApplicationResourceLoader .get (getClassLoader ());
291+ 			configurations .add (load (resourceLoader , location ));
364292			for  (String  override  : overrides ) {
365- 				Configuration  overrideConfiguration  = loadOverride (resourceLoader , override ,  context );
293+ 				Configuration  overrideConfiguration  = loadOverride (resourceLoader , override );
366294				if  (overrideConfiguration  != null ) {
367295					configurations .add (overrideConfiguration );
368296				}
369297			}
370- 			context .reconfigure (mergeConfigurations (configurations ));
298+ 			this . loggerContext .reconfigure (mergeConfigurations (configurations ));
371299		}
372300		catch  (Exception  ex ) {
373- 			throw  new  IllegalStateException ("Could not initialize Log4J2 logging from "  + location , ex );
301+ 			throw  new  IllegalStateException ("Could not initialize Log4J2 logging from %s%s" .formatted (location ,
302+ 					(overrides .isEmpty () ? ""  : " with overrides "  + overrides )), ex );
374303		}
375304	}
376305
377- 	private  Configuration  load (Resource  resource , LoggerContext  context ) throws  IOException  {
378- 		ConfigurationFactory  factory  = ConfigurationFactory .getInstance ();
379- 		if  (resource .isFile ()) {
380- 			try  (InputStream  inputStream  = resource .getInputStream ()) {
381- 				return  factory .getConfiguration (context , new  ConfigurationSource (inputStream , resource .getFile ()));
382- 			}
383- 		}
384- 		URL  url  = resource .getURL ();
385- 		AuthorizationProvider  authorizationProvider  = ConfigurationFactory 
386- 			.authorizationProvider (PropertiesUtil .getProperties ());
387- 		SslConfiguration  sslConfiguration  = url .getProtocol ().equals ("https" )
388- 				? SslConfigurationFactory .getSslConfiguration () : null ;
389- 		URLConnection  connection  = UrlConnectionFactory .createConnection (url , 0 , sslConfiguration ,
390- 				authorizationProvider );
391- 		try  (InputStream  inputStream  = connection .getInputStream ()) {
392- 			return  factory .getConfiguration (context ,
393- 					new  ConfigurationSource (inputStream , url , connection .getLastModified ()));
306+ 	private  Configuration  load (ResourceLoader  resourceLoader , String  location ) throws  IOException  {
307+ 		ConfigurationFactory  configurationFactory  = ConfigurationFactory .getInstance ();
308+ 		Resource  resource  = resourceLoader .getResource (location );
309+ 		Configuration  configuration  = configurationFactory .getConfiguration (getLoggerContext (), null , resource .getURI (),
310+ 				getClassLoader ());
311+ 		// The error handling in Log4j Core 2.25.x is not consistent, some loading and 
312+ 		// parsing errors result in a null configuration, others in an exception. 
313+ 		if  (configuration  == null ) {
314+ 			throw  new  ConfigurationException ("Could not load Log4j Core configuration from "  + location );
394315		}
316+ 		return  configuration ;
395317	}
396318
397- 	private  @ Nullable  Configuration  loadOverride (ResourceLoader  resourceLoader , String  location , LoggerContext  context )
398- 			throws  IOException  {
319+ 	private  @ Nullable  Configuration  loadOverride (ResourceLoader  resourceLoader , String  location ) throws  IOException  {
399320		if  (location .startsWith (OPTIONAL_PREFIX )) {
400- 			Resource  resource  = resourceLoader .getResource (location .substring (OPTIONAL_PREFIX .length ()));
321+ 			String  actualLocation  = location .substring (OPTIONAL_PREFIX .length ());
322+ 			Resource  resource  = resourceLoader .getResource (actualLocation );
401323			try  {
402- 				return  (resource .exists ()) ? load (resource ,  context ) : null ;
324+ 				return  (resource .exists ()) ? load (resourceLoader ,  actualLocation ) : null ;
403325			}
404326			catch  (FileNotFoundException  ex ) {
405327				return  null ;
406328			}
407329		}
408- 		return  load (resourceLoader . getResource ( location ),  context );
330+ 		return  load (resourceLoader ,  location );
409331	}
410332
411333	private  Configuration  mergeConfigurations (List <Configuration > configurations ) {
@@ -417,33 +339,9 @@ private Configuration mergeConfigurations(List<Configuration> configurations) {
417339
418340	@ Override 
419341	protected  void  reinitialize (LoggingInitializationContext  initializationContext ) {
420- 		List <String > overrides  = getOverrides (initializationContext );
421- 		if  (!CollectionUtils .isEmpty (overrides )) {
422- 			reinitializeWithOverrides (overrides );
423- 		}
424- 		else  {
425- 			LoggerContext  context  = getLoggerContext ();
426- 			context .reconfigure ();
427- 		}
428- 	}
429- 
430- 	private  void  reinitializeWithOverrides (List <String > overrides ) {
431- 		LoggerContext  context  = getLoggerContext ();
432- 		List <Configuration > configurations  = new  ArrayList <>();
433- 		configurations .add (context .getConfiguration ());
434- 		ResourceLoader  resourceLoader  = ApplicationResourceLoader .get ();
435- 		for  (String  override  : overrides ) {
436- 			try  {
437- 				Configuration  overrideConfiguration  = loadOverride (resourceLoader , override , context );
438- 				if  (overrideConfiguration  != null ) {
439- 					configurations .add (overrideConfiguration );
440- 				}
441- 			}
442- 			catch  (IOException  ex ) {
443- 				throw  new  RuntimeException ("Failed to load overriding configuration from '"  + override  + "'" , ex );
444- 			}
445- 		}
446- 		context .reconfigure (mergeConfigurations (configurations ));
342+ 		String  currentLocation  = getSelfInitializationConfig ();
343+ 		Assert .notNull (currentLocation , "'currentLocation' must not be null" );
344+ 		load (initializationContext , currentLocation , null );
447345	}
448346
449347	@ Override 
@@ -584,8 +482,8 @@ public void cleanUp() {
584482		return  configuration .getLoggers ().get (name );
585483	}
586484
587- 	private   LoggerContext  getLoggerContext () {
588- 		return  ( LoggerContext )  LogManager . getContext ( false ) ;
485+ 	LoggerContext  getLoggerContext () {
486+ 		return  this . loggerContext ;
589487	}
590488
591489	private  boolean  isAlreadyInitialized (LoggerContext  loggerContext ) {
@@ -630,7 +528,11 @@ public static class Factory implements LoggingSystemFactory {
630528		@ Override 
631529		public  @ Nullable  LoggingSystem  getLoggingSystem (ClassLoader  classLoader ) {
632530			if  (PRESENT ) {
633- 				return  new  Log4J2LoggingSystem (classLoader );
531+ 				org .apache .logging .log4j .spi .LoggerContext  spiLoggerContext  = LogManager .getContext (classLoader , false );
532+ 				Assert .state (spiLoggerContext  instanceof  LoggerContext , "" );
533+ 				if  (spiLoggerContext  instanceof  LoggerContext  coreLoggerContext ) {
534+ 					return  new  Log4J2LoggingSystem (classLoader , coreLoggerContext );
535+ 				}
634536			}
635537			return  null ;
636538		}
0 commit comments