1717package org .springframework .boot .context .logging ;
1818
1919import java .util .Collections ;
20+ import java .util .LinkedHashMap ;
2021import java .util .List ;
2122import java .util .Locale ;
2223import java .util .Map ;
4950import org .springframework .core .env .Environment ;
5051import org .springframework .util .LinkedMultiValueMap ;
5152import org .springframework .util .MultiValueMap ;
53+ import org .springframework .util .ObjectUtils ;
5254import org .springframework .util .ResourceUtils ;
5355import org .springframework .util .StringUtils ;
5456
5557/**
5658 * An {@link ApplicationListener} that configures the {@link LoggingSystem}. If the
5759 * environment contains a {@code logging.config} property it will be used to bootstrap the
5860 * logging system, otherwise a default configuration is used. Regardless, logging levels
59- * will be customized if the environment contains {@code logging.level.*} entries.
61+ * will be customized if the environment contains {@code logging.level.*} entries and
62+ * logging groups can be defined with {@code logging.group} .
6063 * <p>
6164 * Debug and trace logging for Spring, Tomcat, Jetty and Hibernate will be enabled when
6265 * the environment contains {@code debug} or {@code trace} properties that aren't set to
@@ -88,6 +91,9 @@ public class LoggingApplicationListener implements GenericApplicationListener {
8891 private static final Bindable <Map <String , String >> STRING_STRING_MAP = Bindable
8992 .mapOf (String .class , String .class );
9093
94+ private static final Bindable <Map <String , String []>> STRING_STRINGS_MAP = Bindable
95+ .mapOf (String .class , String [].class );
96+
9197 /**
9298 * The default order for the LoggingApplicationListener.
9399 */
@@ -111,19 +117,30 @@ public class LoggingApplicationListener implements GenericApplicationListener {
111117 */
112118 public static final String LOGGING_SYSTEM_BEAN_NAME = "springBootLoggingSystem" ;
113119
114- private static final MultiValueMap <LogLevel , String > LOG_LEVEL_LOGGERS ;
120+ private static final Map <String , List <String >> DEFAULT_GROUP_LOGGERS ;
121+ static {
122+ MultiValueMap <String , String > loggers = new LinkedMultiValueMap <>();
123+ loggers .add ("web" , "org.springframework.core.codec" );
124+ loggers .add ("web" , "org.springframework.http" );
125+ loggers .add ("web" , "org.springframework.web" );
126+ loggers .add ("sql" , "org.springframework.jdbc.core" );
127+ loggers .add ("sql" , "org.hibernate.SQL" );
128+ DEFAULT_GROUP_LOGGERS = Collections .unmodifiableMap (loggers );
129+ }
115130
116- private static AtomicBoolean shutdownHookRegistered = new AtomicBoolean ( false ) ;
131+ private static final Map < LogLevel , List < String >> LOG_LEVEL_LOGGERS ;
117132
118133 static {
119- LOG_LEVEL_LOGGERS = new LinkedMultiValueMap <>();
120- LOG_LEVEL_LOGGERS .add (LogLevel .DEBUG , "org.springframework.boot" );
121- LOG_LEVEL_LOGGERS .add (LogLevel .DEBUG , "org.hibernate.SQL" );
122- LOG_LEVEL_LOGGERS .add (LogLevel .TRACE , "org.springframework" );
123- LOG_LEVEL_LOGGERS .add (LogLevel .TRACE , "org.apache.tomcat" );
124- LOG_LEVEL_LOGGERS .add (LogLevel .TRACE , "org.apache.catalina" );
125- LOG_LEVEL_LOGGERS .add (LogLevel .TRACE , "org.eclipse.jetty" );
126- LOG_LEVEL_LOGGERS .add (LogLevel .TRACE , "org.hibernate.tool.hbm2ddl" );
134+ MultiValueMap <LogLevel , String > loggers = new LinkedMultiValueMap <>();
135+ loggers .add (LogLevel .DEBUG , "sql" );
136+ loggers .add (LogLevel .DEBUG , "web" );
137+ loggers .add (LogLevel .DEBUG , "org.springframework.boot" );
138+ loggers .add (LogLevel .TRACE , "org.springframework" );
139+ loggers .add (LogLevel .TRACE , "org.apache.tomcat" );
140+ loggers .add (LogLevel .TRACE , "org.apache.catalina" );
141+ loggers .add (LogLevel .TRACE , "org.eclipse.jetty" );
142+ loggers .add (LogLevel .TRACE , "org.hibernate.tool.hbm2ddl" );
143+ LOG_LEVEL_LOGGERS = Collections .unmodifiableMap (loggers );
127144 }
128145
129146 private static final Class <?>[] EVENT_TYPES = { ApplicationStartingEvent .class ,
@@ -133,6 +150,8 @@ public class LoggingApplicationListener implements GenericApplicationListener {
133150 private static final Class <?>[] SOURCE_TYPES = { SpringApplication .class ,
134151 ApplicationContext .class };
135152
153+ private static AtomicBoolean shutdownHookRegistered = new AtomicBoolean (false );
154+
136155 private final Log logger = LogFactory .getLog (getClass ());
137156
138157 private LoggingSystem loggingSystem ;
@@ -304,8 +323,32 @@ protected void setLogLevels(LoggingSystem system, Environment environment) {
304323 return ;
305324 }
306325 Binder binder = Binder .get (environment );
307- binder .bind ("logging.level" , STRING_STRING_MAP ).orElseGet (Collections ::emptyMap )
308- .forEach ((name , level ) -> setLogLevel (system , name , level ));
326+ Map <String , String []> groups = getGroups (binder );
327+ Map <String , String > levels = binder .bind ("logging.level" , STRING_STRING_MAP )
328+ .orElseGet (Collections ::emptyMap );
329+ levels .forEach ((name , level ) -> {
330+ String [] groupedNames = groups .get (name );
331+ if (ObjectUtils .isEmpty (groupedNames )) {
332+ setLogLevel (system , name , level );
333+ }
334+ else {
335+ setLogLevel (system , groupedNames , level );
336+ }
337+ });
338+ }
339+
340+ private Map <String , String []> getGroups (Binder binder ) {
341+ Map <String , String []> groups = new LinkedHashMap <>();
342+ DEFAULT_GROUP_LOGGERS .forEach (
343+ (name , loggers ) -> groups .put (name , StringUtils .toStringArray (loggers )));
344+ binder .bind ("logging.group" , STRING_STRINGS_MAP .withExistingValue (groups ));
345+ return groups ;
346+ }
347+
348+ private void setLogLevel (LoggingSystem system , String [] names , String level ) {
349+ for (String name : names ) {
350+ setLogLevel (system , name , level );
351+ }
309352 }
310353
311354 private void setLogLevel (LoggingSystem system , String name , String level ) {
@@ -360,8 +403,9 @@ public void setSpringBootLogging(LogLevel springBootLogging) {
360403 }
361404
362405 /**
363- * Sets if initialization arguments should be parsed for {@literal --debug} and
364- * {@literal --trace} options. Defaults to {@code true}.
406+ * Sets if initialization arguments should be parsed for {@literal debug} and
407+ * {@literal trace} properties (usually defined from {@literal --debug} or
408+ * {@literal --trace} command line args. Defaults to {@code true}.
365409 * @param parseArgs if arguments should be parsed
366410 */
367411 public void setParseArgs (boolean parseArgs ) {
0 commit comments