Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
S
spring-boot
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DEMO
spring-boot
Commits
b9047c22
Commit
b9047c22
authored
Jul 20, 2019
by
HaiTao Zhang
Committed by
Madhura Bhave
Jul 30, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add support for configuring logging groups via endpoint
See gh-17515
parent
8197feac
Changes
8
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
482 additions
and
29 deletions
+482
-29
LoggersEndpointAutoConfiguration.java
...toconfigure/logging/LoggersEndpointAutoConfiguration.java
+5
-2
LoggersEndpointDocumentationTests.java
.../web/documentation/LoggersEndpointDocumentationTests.java
+52
-4
LoggersEndpoint.java
...springframework/boot/actuate/logging/LoggersEndpoint.java
+62
-8
LoggersEndpointTests.java
...gframework/boot/actuate/logging/LoggersEndpointTests.java
+73
-6
LoggersEndpointWebIntegrationTests.java
...t/actuate/logging/LoggersEndpointWebIntegrationTests.java
+111
-4
LoggingApplicationListener.java
...work/boot/context/logging/LoggingApplicationListener.java
+23
-5
LoggingGroups.java
.../java/org/springframework/boot/logging/LoggingGroups.java
+112
-0
LoggingGroupsTests.java
.../org/springframework/boot/logging/LoggingGroupsTests.java
+44
-0
No files found.
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/LoggersEndpointAutoConfiguration.java
View file @
b9047c22
...
...
@@ -16,6 +16,7 @@
package
org
.
springframework
.
boot
.
actuate
.
autoconfigure
.
logging
;
import
org.springframework.beans.factory.ObjectProvider
;
import
org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint
;
import
org.springframework.boot.actuate.logging.LoggersEndpoint
;
import
org.springframework.boot.autoconfigure.EnableAutoConfiguration
;
...
...
@@ -24,6 +25,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
;
import
org.springframework.boot.autoconfigure.condition.SpringBootCondition
;
import
org.springframework.boot.logging.LoggingGroups
;
import
org.springframework.boot.logging.LoggingSystem
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.ConditionContext
;
...
...
@@ -45,8 +47,9 @@ public class LoggersEndpointAutoConfiguration {
@ConditionalOnBean
(
LoggingSystem
.
class
)
@Conditional
(
OnEnabledLoggingSystemCondition
.
class
)
@ConditionalOnMissingBean
public
LoggersEndpoint
loggersEndpoint
(
LoggingSystem
loggingSystem
)
{
return
new
LoggersEndpoint
(
loggingSystem
);
public
LoggersEndpoint
loggersEndpoint
(
LoggingSystem
loggingSystem
,
ObjectProvider
<
LoggingGroups
>
loggingGroupsObjectProvider
)
{
return
new
LoggersEndpoint
(
loggingSystem
,
loggingGroupsObjectProvider
.
getIfAvailable
());
}
static
class
OnEnabledLoggingSystemCondition
extends
SpringBootCondition
{
...
...
spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/LoggersEndpointDocumentationTests.java
View file @
b9047c22
...
...
@@ -17,14 +17,17 @@
package
org
.
springframework
.
boot
.
actuate
.
autoconfigure
.
endpoint
.
web
.
documentation
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.EnumSet
;
import
java.util.List
;
import
org.junit.jupiter.api.Test
;
import
org.springframework.beans.factory.ObjectProvider
;
import
org.springframework.boot.actuate.logging.LoggersEndpoint
;
import
org.springframework.boot.logging.LogLevel
;
import
org.springframework.boot.logging.LoggerConfiguration
;
import
org.springframework.boot.logging.LoggingGroups
;
import
org.springframework.boot.logging.LoggingSystem
;
import
org.springframework.boot.test.mock.mockito.MockBean
;
import
org.springframework.context.annotation.Bean
;
...
...
@@ -54,32 +57,60 @@ class LoggersEndpointDocumentationTests extends MockMvcEndpointDocumentationTest
fieldWithPath
(
"configuredLevel"
).
description
(
"Configured level of the logger, if any."
).
optional
(),
fieldWithPath
(
"effectiveLevel"
).
description
(
"Effective level of the logger."
));
private
static
final
List
<
FieldDescriptor
>
groupLevelFields
=
Arrays
.
asList
(
fieldWithPath
(
"configuredLevel"
).
description
(
"Configured level of the logger group"
),
fieldWithPath
(
"members"
).
description
(
"Loggers that are part of this group"
).
optional
());
@MockBean
private
LoggingSystem
loggingSystem
;
@MockBean
private
ObjectProvider
<
LoggingGroups
>
loggingGroupsObjectProvider
;
@MockBean
LoggingGroups
loggingGroups
;
@Test
void
allLoggers
()
throws
Exception
{
given
(
this
.
loggingSystem
.
getSupportedLogLevels
()).
willReturn
(
EnumSet
.
allOf
(
LogLevel
.
class
));
given
(
this
.
loggingSystem
.
getLoggerConfigurations
())
.
willReturn
(
Arrays
.
asList
(
new
LoggerConfiguration
(
"ROOT"
,
LogLevel
.
INFO
,
LogLevel
.
INFO
),
new
LoggerConfiguration
(
"com.example"
,
LogLevel
.
DEBUG
,
LogLevel
.
DEBUG
)));
given
(
this
.
loggingGroupsObjectProvider
.
getIfAvailable
()).
willReturn
(
this
.
loggingGroups
);
given
(
this
.
loggingGroups
.
getLoggerGroupNames
()).
willReturn
(
Collections
.
singleton
(
"test"
));
given
(
this
.
loggingGroups
.
getLoggerGroup
(
"test"
)).
willReturn
(
Arrays
.
asList
(
"test.member"
));
given
(
this
.
loggingGroups
.
getLoggerGroupConfiguredLevel
(
"test"
)).
willReturn
(
LogLevel
.
INFO
);
this
.
mockMvc
.
perform
(
get
(
"/actuator/loggers"
)).
andExpect
(
status
().
isOk
())
.
andDo
(
MockMvcRestDocumentation
.
document
(
"loggers/all"
,
responseFields
(
fieldWithPath
(
"levels"
).
description
(
"Levels support by the logging system."
),
fieldWithPath
(
"loggers"
).
description
(
"Loggers keyed by name."
))
.
andWithPrefix
(
"loggers.*."
,
levelFields
)));
fieldWithPath
(
"loggers"
).
description
(
"Loggers keyed by name."
),
fieldWithPath
(
"groups"
).
description
(
"Logger groups keyed by name"
))
.
andWithPrefix
(
"loggers.*."
,
levelFields
)
.
andWithPrefix
(
"groups.*."
,
groupLevelFields
)));
}
@Test
void
logger
()
throws
Exception
{
given
(
this
.
loggingGroupsObjectProvider
.
getIfAvailable
()).
willReturn
(
this
.
loggingGroups
);
given
(
this
.
loggingSystem
.
getLoggerConfiguration
(
"com.example"
))
.
willReturn
(
new
LoggerConfiguration
(
"com.example"
,
LogLevel
.
INFO
,
LogLevel
.
INFO
));
this
.
mockMvc
.
perform
(
get
(
"/actuator/loggers/com.example"
)).
andExpect
(
status
().
isOk
())
.
andDo
(
MockMvcRestDocumentation
.
document
(
"loggers/single"
,
responseFields
(
levelFields
)));
}
@Test
void
loggerGroups
()
throws
Exception
{
given
(
this
.
loggingGroupsObjectProvider
.
getIfAvailable
()).
willReturn
(
this
.
loggingGroups
);
given
(
this
.
loggingGroups
.
isGroup
(
"com.example"
)).
willReturn
(
true
);
given
(
this
.
loggingGroups
.
getLoggerGroup
(
"com.example"
)).
willReturn
(
Arrays
.
asList
(
"com.member"
,
"com.member2"
));
given
(
this
.
loggingGroups
.
getLoggerGroupConfiguredLevel
(
"com.example"
)).
willReturn
(
LogLevel
.
INFO
);
this
.
mockMvc
.
perform
(
get
(
"/actuator/loggers/com.example"
)).
andExpect
(
status
().
isOk
())
.
andDo
(
MockMvcRestDocumentation
.
document
(
"loggers/group"
,
responseFields
(
groupLevelFields
)));
}
@Test
void
setLogLevel
()
throws
Exception
{
given
(
this
.
loggingGroupsObjectProvider
.
getIfAvailable
()).
willReturn
(
this
.
loggingGroups
);
this
.
mockMvc
.
perform
(
post
(
"/actuator/loggers/com.example"
).
content
(
"{\"configuredLevel\":\"debug\"}"
)
.
contentType
(
MediaType
.
APPLICATION_JSON
))
...
...
@@ -89,8 +120,24 @@ class LoggersEndpointDocumentationTests extends MockMvcEndpointDocumentationTest
verify
(
this
.
loggingSystem
).
setLogLevel
(
"com.example"
,
LogLevel
.
DEBUG
);
}
@Test
void
setLogLevelOfLoggerGroup
()
throws
Exception
{
given
(
this
.
loggingGroupsObjectProvider
.
getIfAvailable
()).
willReturn
(
this
.
loggingGroups
);
given
(
this
.
loggingGroups
.
isGroup
(
"com.example"
)).
willReturn
(
true
);
this
.
mockMvc
.
perform
(
post
(
"/actuator/loggers/com.example"
)
.
content
(
"{\"configuredLevel\":\"debug\"}"
).
contentType
(
MediaType
.
APPLICATION_JSON
))
.
andExpect
(
status
().
isNoContent
()).
andDo
(
MockMvcRestDocumentation
.
document
(
"loggers/setGroup"
,
requestFields
(
fieldWithPath
(
"configuredLevel"
).
description
(
"Level for the logger group. May be omitted to clear the level of the loggers."
)
.
optional
())));
verify
(
this
.
loggingGroups
).
setLoggerGroupLevel
(
"com.example"
,
LogLevel
.
DEBUG
);
}
@Test
void
clearLogLevel
()
throws
Exception
{
given
(
this
.
loggingGroupsObjectProvider
.
getIfAvailable
()).
willReturn
(
this
.
loggingGroups
);
this
.
mockMvc
.
perform
(
post
(
"/actuator/loggers/com.example"
).
content
(
"{}"
).
contentType
(
MediaType
.
APPLICATION_JSON
))
.
andExpect
(
status
().
isNoContent
()).
andDo
(
MockMvcRestDocumentation
.
document
(
"loggers/clear"
));
...
...
@@ -102,8 +149,9 @@ class LoggersEndpointDocumentationTests extends MockMvcEndpointDocumentationTest
static
class
TestConfiguration
{
@Bean
LoggersEndpoint
endpoint
(
LoggingSystem
loggingSystem
)
{
return
new
LoggersEndpoint
(
loggingSystem
);
LoggersEndpoint
endpoint
(
LoggingSystem
loggingSystem
,
ObjectProvider
<
LoggingGroups
>
loggingGroupsObjectProvider
)
{
return
new
LoggersEndpoint
(
loggingSystem
,
loggingGroupsObjectProvider
.
getIfAvailable
());
}
}
...
...
spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/logging/LoggersEndpoint.java
View file @
b9047c22
...
...
@@ -19,6 +19,7 @@ package org.springframework.boot.actuate.logging;
import
java.util.Collection
;
import
java.util.Collections
;
import
java.util.LinkedHashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.NavigableSet
;
import
java.util.Set
;
...
...
@@ -30,6 +31,7 @@ import org.springframework.boot.actuate.endpoint.annotation.Selector;
import
org.springframework.boot.actuate.endpoint.annotation.WriteOperation
;
import
org.springframework.boot.logging.LogLevel
;
import
org.springframework.boot.logging.LoggerConfiguration
;
import
org.springframework.boot.logging.LoggingGroups
;
import
org.springframework.boot.logging.LoggingSystem
;
import
org.springframework.lang.Nullable
;
import
org.springframework.util.Assert
;
...
...
@@ -39,6 +41,7 @@ import org.springframework.util.Assert;
*
* @author Ben Hale
* @author Phillip Webb
* @author HaiTao Zhang
* @since 2.0.0
*/
@Endpoint
(
id
=
"loggers"
)
...
...
@@ -46,13 +49,17 @@ public class LoggersEndpoint {
private
final
LoggingSystem
loggingSystem
;
private
final
LoggingGroups
loggingGroups
;
/**
* Create a new {@link LoggersEndpoint} instance.
* @param loggingSystem the logging system to expose
* @param loggingGroups the logging group to expose if it exists
*/
public
LoggersEndpoint
(
LoggingSystem
loggingSystem
)
{
public
LoggersEndpoint
(
LoggingSystem
loggingSystem
,
LoggingGroups
loggingGroups
)
{
Assert
.
notNull
(
loggingSystem
,
"LoggingSystem must not be null"
);
this
.
loggingSystem
=
loggingSystem
;
this
.
loggingGroups
=
loggingGroups
;
}
@ReadOperation
...
...
@@ -64,19 +71,32 @@ public class LoggersEndpoint {
Map
<
String
,
Object
>
result
=
new
LinkedHashMap
<>();
result
.
put
(
"levels"
,
getLevels
());
result
.
put
(
"loggers"
,
getLoggers
(
configurations
));
if
(
this
.
loggingGroups
!=
null
&&
this
.
loggingGroups
.
getLoggerGroupNames
()
!=
null
)
{
Set
<
String
>
groups
=
this
.
loggingGroups
.
getLoggerGroupNames
();
result
.
put
(
"groups"
,
getLoggerGroups
(
groups
));
}
return
result
;
}
@ReadOperation
public
LoggerLevels
loggerLevels
(
@Selector
String
name
)
{
Assert
.
notNull
(
name
,
"Name must not be null"
);
if
(
this
.
loggingGroups
!=
null
&&
this
.
loggingGroups
.
isGroup
(
name
))
{
List
<
String
>
members
=
this
.
loggingGroups
.
getLoggerGroup
(
name
);
LogLevel
groupConfiguredLevel
=
this
.
loggingGroups
.
getLoggerGroupConfiguredLevel
(
name
);
return
new
GroupLoggerLevels
(
groupConfiguredLevel
,
members
);
}
LoggerConfiguration
configuration
=
this
.
loggingSystem
.
getLoggerConfiguration
(
name
);
return
(
configuration
!=
null
)
?
new
LoggerLevels
(
configuration
)
:
null
;
return
(
configuration
!=
null
)
?
new
Single
LoggerLevels
(
configuration
)
:
null
;
}
@WriteOperation
public
void
configureLogLevel
(
@Selector
String
name
,
@Nullable
LogLevel
configuredLevel
)
{
Assert
.
notNull
(
name
,
"Name must not be empty"
);
if
(
this
.
loggingGroups
!=
null
&&
this
.
loggingGroups
.
isGroup
(
name
))
{
this
.
loggingGroups
.
setLoggerGroupLevel
(
name
,
configuredLevel
);
return
;
}
this
.
loggingSystem
.
setLogLevel
(
name
,
configuredLevel
);
}
...
...
@@ -88,11 +108,21 @@ public class LoggersEndpoint {
private
Map
<
String
,
LoggerLevels
>
getLoggers
(
Collection
<
LoggerConfiguration
>
configurations
)
{
Map
<
String
,
LoggerLevels
>
loggers
=
new
LinkedHashMap
<>(
configurations
.
size
());
for
(
LoggerConfiguration
configuration
:
configurations
)
{
loggers
.
put
(
configuration
.
getName
(),
new
LoggerLevels
(
configuration
));
loggers
.
put
(
configuration
.
getName
(),
new
Single
LoggerLevels
(
configuration
));
}
return
loggers
;
}
private
Map
<
String
,
LoggerLevels
>
getLoggerGroups
(
Set
<
String
>
groups
)
{
Map
<
String
,
LoggerLevels
>
loggerGroups
=
new
LinkedHashMap
<>(
groups
.
size
());
for
(
String
name
:
groups
)
{
List
<
String
>
members
=
this
.
loggingGroups
.
getLoggerGroup
(
name
);
LogLevel
groupConfiguredLevel
=
this
.
loggingGroups
.
getLoggerGroupConfiguredLevel
(
name
);
loggerGroups
.
put
(
name
,
new
GroupLoggerLevels
(
groupConfiguredLevel
,
members
));
}
return
loggerGroups
;
}
/**
* Levels configured for a given logger exposed in a JSON friendly way.
*/
...
...
@@ -100,11 +130,8 @@ public class LoggersEndpoint {
private
String
configuredLevel
;
private
String
effectiveLevel
;
public
LoggerLevels
(
LoggerConfiguration
configuration
)
{
this
.
configuredLevel
=
getName
(
configuration
.
getConfiguredLevel
());
this
.
effectiveLevel
=
getName
(
configuration
.
getEffectiveLevel
());
public
LoggerLevels
(
LogLevel
configuredLevel
)
{
this
.
configuredLevel
=
getName
(
configuredLevel
);
}
private
String
getName
(
LogLevel
level
)
{
...
...
@@ -113,6 +140,33 @@ public class LoggersEndpoint {
public
String
getConfiguredLevel
()
{
return
this
.
configuredLevel
;
}
}
public
static
class
GroupLoggerLevels
extends
LoggerLevels
{
private
List
<
String
>
members
;
public
GroupLoggerLevels
(
LogLevel
configuredLevel
,
List
<
String
>
members
)
{
super
(
configuredLevel
);
this
.
members
=
members
;
}
public
List
<
String
>
getMembers
()
{
return
this
.
members
;
}
}
public
static
class
SingleLoggerLevels
extends
LoggerLevels
{
private
String
effectiveLevel
;
public
SingleLoggerLevels
(
LoggerConfiguration
configuration
)
{
super
(
configuration
.
getConfiguredLevel
());
this
.
effectiveLevel
=
super
.
getName
(
configuration
.
getEffectiveLevel
());
}
public
String
getEffectiveLevel
()
{
...
...
spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/logging/LoggersEndpointTests.java
View file @
b9047c22
...
...
@@ -23,9 +23,12 @@ import java.util.Set;
import
org.junit.jupiter.api.Test
;
import
org.springframework.boot.actuate.logging.LoggersEndpoint.GroupLoggerLevels
;
import
org.springframework.boot.actuate.logging.LoggersEndpoint.LoggerLevels
;
import
org.springframework.boot.actuate.logging.LoggersEndpoint.SingleLoggerLevels
;
import
org.springframework.boot.logging.LogLevel
;
import
org.springframework.boot.logging.LoggerConfiguration
;
import
org.springframework.boot.logging.LoggingGroups
;
import
org.springframework.boot.logging.LoggingSystem
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
...
...
@@ -38,46 +41,110 @@ import static org.mockito.Mockito.verify;
*
* @author Ben Hale
* @author Andy Wilkinson
* @author HaiTao Zhang
*/
class
LoggersEndpointTests
{
private
final
LoggingSystem
loggingSystem
=
mock
(
LoggingSystem
.
class
);
private
final
LoggingGroups
loggingGroups
=
mock
(
LoggingGroups
.
class
);
@Test
@SuppressWarnings
(
"unchecked"
)
void
loggersShouldReturnLoggerConfigurationsWithNoLoggerGroups
()
{
given
(
this
.
loggingSystem
.
getLoggerConfigurations
())
.
willReturn
(
Collections
.
singletonList
(
new
LoggerConfiguration
(
"ROOT"
,
null
,
LogLevel
.
DEBUG
)));
given
(
this
.
loggingSystem
.
getSupportedLogLevels
()).
willReturn
(
EnumSet
.
allOf
(
LogLevel
.
class
));
given
(
this
.
loggingGroups
.
getLoggerGroupNames
()).
willReturn
(
null
);
Map
<
String
,
Object
>
result
=
new
LoggersEndpoint
(
this
.
loggingSystem
,
this
.
loggingGroups
).
loggers
();
Map
<
String
,
LoggerLevels
>
loggers
=
(
Map
<
String
,
LoggerLevels
>)
result
.
get
(
"loggers"
);
Set
<
LogLevel
>
levels
=
(
Set
<
LogLevel
>)
result
.
get
(
"levels"
);
SingleLoggerLevels
rootLevels
=
(
SingleLoggerLevels
)
loggers
.
get
(
"ROOT"
);
assertThat
(
rootLevels
.
getConfiguredLevel
()).
isNull
();
assertThat
(
rootLevels
.
getEffectiveLevel
()).
isEqualTo
(
"DEBUG"
);
assertThat
(
levels
).
containsExactly
(
LogLevel
.
OFF
,
LogLevel
.
FATAL
,
LogLevel
.
ERROR
,
LogLevel
.
WARN
,
LogLevel
.
INFO
,
LogLevel
.
DEBUG
,
LogLevel
.
TRACE
);
assertThat
(
result
.
get
(
"groups"
)).
isNull
();
}
@Test
@SuppressWarnings
(
"unchecked"
)
void
loggersShouldReturnLoggerConfigurations
()
{
void
loggersShouldReturnLoggerConfigurations
WithLoggerGroups
()
{
given
(
this
.
loggingSystem
.
getLoggerConfigurations
())
.
willReturn
(
Collections
.
singletonList
(
new
LoggerConfiguration
(
"ROOT"
,
null
,
LogLevel
.
DEBUG
)));
given
(
this
.
loggingSystem
.
getSupportedLogLevels
()).
willReturn
(
EnumSet
.
allOf
(
LogLevel
.
class
));
Map
<
String
,
Object
>
result
=
new
LoggersEndpoint
(
this
.
loggingSystem
).
loggers
();
given
(
this
.
loggingGroups
.
getLoggerGroup
(
"test"
)).
willReturn
(
Collections
.
singletonList
(
"test.member"
));
given
(
this
.
loggingGroups
.
getLoggerGroupNames
()).
willReturn
(
Collections
.
singleton
(
"test"
));
given
(
this
.
loggingGroups
.
getLoggerGroupConfiguredLevel
(
"test"
)).
willReturn
(
LogLevel
.
DEBUG
);
Map
<
String
,
Object
>
result
=
new
LoggersEndpoint
(
this
.
loggingSystem
,
this
.
loggingGroups
).
loggers
();
Map
<
String
,
LoggerLevels
>
loggerGroups
=
(
Map
<
String
,
LoggerLevels
>)
result
.
get
(
"groups"
);
GroupLoggerLevels
testLoggerLevel
=
(
GroupLoggerLevels
)
loggerGroups
.
get
(
"test"
);
Map
<
String
,
LoggerLevels
>
loggers
=
(
Map
<
String
,
LoggerLevels
>)
result
.
get
(
"loggers"
);
Set
<
LogLevel
>
levels
=
(
Set
<
LogLevel
>)
result
.
get
(
"levels"
);
LoggerLevels
rootLevels
=
loggers
.
get
(
"ROOT"
);
SingleLoggerLevels
rootLevels
=
(
SingleLoggerLevels
)
loggers
.
get
(
"ROOT"
);
assertThat
(
rootLevels
.
getConfiguredLevel
()).
isNull
();
assertThat
(
rootLevels
.
getEffectiveLevel
()).
isEqualTo
(
"DEBUG"
);
assertThat
(
levels
).
containsExactly
(
LogLevel
.
OFF
,
LogLevel
.
FATAL
,
LogLevel
.
ERROR
,
LogLevel
.
WARN
,
LogLevel
.
INFO
,
LogLevel
.
DEBUG
,
LogLevel
.
TRACE
);
assertThat
(
loggerGroups
).
isNotNull
();
assertThat
(
testLoggerLevel
).
isNotNull
();
assertThat
(
testLoggerLevel
.
getConfiguredLevel
()).
isEqualTo
(
"DEBUG"
);
assertThat
(
testLoggerLevel
.
getMembers
()).
isEqualTo
(
Collections
.
singletonList
(
"test.member"
));
}
@Test
void
loggerLevelsWhenNameSpecifiedShouldReturnLevels
()
{
given
(
this
.
loggingGroups
.
isGroup
(
"ROOT"
)).
willReturn
(
false
);
given
(
this
.
loggingSystem
.
getLoggerConfiguration
(
"ROOT"
))
.
willReturn
(
new
LoggerConfiguration
(
"ROOT"
,
null
,
LogLevel
.
DEBUG
));
LoggerLevels
levels
=
new
LoggersEndpoint
(
this
.
loggingSystem
).
loggerLevels
(
"ROOT"
);
SingleLoggerLevels
levels
=
(
SingleLoggerLevels
)
new
LoggersEndpoint
(
this
.
loggingSystem
,
this
.
loggingGroups
)
.
loggerLevels
(
"ROOT"
);
assertThat
(
levels
.
getConfiguredLevel
()).
isNull
();
assertThat
(
levels
.
getEffectiveLevel
()).
isEqualTo
(
"DEBUG"
);
}
@Test
void
groupNameSpecifiedShouldReturnConfiguredLevelAndMembers
()
{
given
(
this
.
loggingGroups
.
isGroup
(
"test"
)).
willReturn
(
true
);
given
(
this
.
loggingGroups
.
getLoggerGroup
(
"test"
)).
willReturn
(
Collections
.
singletonList
(
"test.member"
));
given
(
this
.
loggingGroups
.
getLoggerGroupConfiguredLevel
(
"test"
)).
willReturn
(
LogLevel
.
DEBUG
);
GroupLoggerLevels
levels
=
(
GroupLoggerLevels
)
new
LoggersEndpoint
(
this
.
loggingSystem
,
this
.
loggingGroups
)
.
loggerLevels
(
"test"
);
assertThat
(
levels
.
getConfiguredLevel
()).
isEqualTo
(
"DEBUG"
);
assertThat
(
levels
.
getMembers
()).
isEqualTo
(
Collections
.
singletonList
(
"test.member"
));
}
@Test
void
configureLogLevelShouldSetLevelOnLoggingSystem
()
{
new
LoggersEndpoint
(
this
.
loggingSystem
).
configureLogLevel
(
"ROOT"
,
LogLevel
.
DEBUG
);
given
(
this
.
loggingGroups
.
getLoggerGroup
(
"ROOT"
)).
willReturn
(
null
);
new
LoggersEndpoint
(
this
.
loggingSystem
,
this
.
loggingGroups
).
configureLogLevel
(
"ROOT"
,
LogLevel
.
DEBUG
);
verify
(
this
.
loggingSystem
).
setLogLevel
(
"ROOT"
,
LogLevel
.
DEBUG
);
}
@Test
void
configureLogLevelWithNullSetsLevelOnLoggingSystemToNull
()
{
new
LoggersEndpoint
(
this
.
loggingSystem
).
configureLogLevel
(
"ROOT"
,
null
);
given
(
this
.
loggingGroups
.
getLoggerGroup
(
"ROOT"
)).
willReturn
(
null
);
new
LoggersEndpoint
(
this
.
loggingSystem
,
this
.
loggingGroups
).
configureLogLevel
(
"ROOT"
,
null
);
verify
(
this
.
loggingSystem
).
setLogLevel
(
"ROOT"
,
null
);
}
@Test
void
configureLogLevelInLoggerGroupShouldSetLevelOnLoggingSystem
()
{
given
(
this
.
loggingGroups
.
isGroup
(
"test"
)).
willReturn
(
true
);
given
(
this
.
loggingGroups
.
getLoggerGroup
(
"test"
)).
willReturn
(
Collections
.
singletonList
(
"test.member"
));
new
LoggersEndpoint
(
this
.
loggingSystem
,
this
.
loggingGroups
).
configureLogLevel
(
"test"
,
LogLevel
.
DEBUG
);
verify
(
this
.
loggingGroups
).
setLoggerGroupLevel
(
"test"
,
LogLevel
.
DEBUG
);
}
@Test
void
configureLogLevelWithNullInLoggerGroupShouldSetLevelOnLoggingSystem
()
{
given
(
this
.
loggingGroups
.
isGroup
(
"test"
)).
willReturn
(
true
);
given
(
this
.
loggingGroups
.
getLoggerGroup
(
"test"
)).
willReturn
(
Collections
.
singletonList
(
"test.member"
));
new
LoggersEndpoint
(
this
.
loggingSystem
,
this
.
loggingGroups
).
configureLogLevel
(
"test"
,
null
);
verify
(
this
.
loggingGroups
).
setLoggerGroupLevel
(
"test"
,
null
);
}
// @Test
// void
}
spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/logging/LoggersEndpointWebIntegrationTests.java
View file @
b9047c22
This diff is collapsed.
Click to expand it.
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/logging/LoggingApplicationListener.java
View file @
b9047c22
...
...
@@ -16,6 +16,7 @@
package
org
.
springframework
.
boot
.
context
.
logging
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.LinkedHashMap
;
import
java.util.List
;
...
...
@@ -36,6 +37,7 @@ import org.springframework.boot.context.properties.bind.Binder;
import
org.springframework.boot.context.properties.source.ConfigurationPropertyName
;
import
org.springframework.boot.logging.LogFile
;
import
org.springframework.boot.logging.LogLevel
;
import
org.springframework.boot.logging.LoggingGroups
;
import
org.springframework.boot.logging.LoggingInitializationContext
;
import
org.springframework.boot.logging.LoggingSystem
;
import
org.springframework.boot.logging.LoggingSystemProperties
;
...
...
@@ -126,6 +128,11 @@ public class LoggingApplicationListener implements GenericApplicationListener {
*/
public
static
final
String
LOGFILE_BEAN_NAME
=
"springBootLogFile"
;
/**
* The name of the{@link LoggingGroups} bean.
*/
public
static
final
String
LOGGING_GROUPS_BEAN_NAME
=
"springBootLoggingGroups"
;
private
static
final
Map
<
String
,
List
<
String
>>
DEFAULT_GROUP_LOGGERS
;
static
{
MultiValueMap
<
String
,
String
>
loggers
=
new
LinkedMultiValueMap
<>();
...
...
@@ -166,6 +173,8 @@ public class LoggingApplicationListener implements GenericApplicationListener {
private
LoggingSystem
loggingSystem
;
private
LoggingGroups
loggingGroups
;
private
LogFile
logFile
;
private
int
order
=
DEFAULT_ORDER
;
...
...
@@ -235,6 +244,9 @@ public class LoggingApplicationListener implements GenericApplicationListener {
if
(
this
.
logFile
!=
null
&&
!
beanFactory
.
containsBean
(
LOGFILE_BEAN_NAME
))
{
beanFactory
.
registerSingleton
(
LOGFILE_BEAN_NAME
,
this
.
logFile
);
}
if
(
this
.
loggingGroups
!=
null
&&
!
beanFactory
.
containsBean
(
LOGGING_GROUPS_BEAN_NAME
))
{
beanFactory
.
registerSingleton
(
LOGGING_GROUPS_BEAN_NAME
,
this
.
loggingGroups
);
}
}
private
void
onContextClosedEvent
()
{
...
...
@@ -257,6 +269,7 @@ public class LoggingApplicationListener implements GenericApplicationListener {
*/
protected
void
initialize
(
ConfigurableEnvironment
environment
,
ClassLoader
classLoader
)
{
new
LoggingSystemProperties
(
environment
).
apply
();
this
.
loggingGroups
=
new
LoggingGroups
(
this
.
loggingSystem
);
this
.
logFile
=
LogFile
.
get
(
environment
);
if
(
this
.
logFile
!=
null
)
{
this
.
logFile
.
applyToSystemProperties
();
...
...
@@ -325,7 +338,8 @@ public class LoggingApplicationListener implements GenericApplicationListener {
system
.
setLogLevel
(
logger
,
level
);
return
;
}
groupLoggers
.
forEach
((
groupLogger
)
->
system
.
setLogLevel
(
groupLogger
,
level
));
this
.
loggingGroups
.
setLoggerGroup
(
logger
,
groupLoggers
);
this
.
loggingGroups
.
setLoggerGroupLevel
(
logger
,
level
);
}
protected
void
setLogLevels
(
LoggingSystem
system
,
Environment
environment
)
{
...
...
@@ -342,7 +356,7 @@ public class LoggingApplicationListener implements GenericApplicationListener {
setLogLevel
(
system
,
name
,
level
);
}
else
{
setLogLevel
(
system
,
groupedNames
,
level
);
setLogLevel
(
groupedNames
,
level
,
name
);
}
});
}
...
...
@@ -353,9 +367,13 @@ public class LoggingApplicationListener implements GenericApplicationListener {
return
groups
;
}
private
void
setLogLevel
(
LoggingSystem
system
,
String
[]
names
,
LogLevel
level
)
{
for
(
String
name
:
names
)
{
setLogLevel
(
system
,
name
,
level
);
private
void
setLogLevel
(
String
[]
names
,
LogLevel
level
,
String
groupName
)
{
try
{
this
.
loggingGroups
.
setLoggerGroup
(
groupName
,
Arrays
.
asList
(
names
));
this
.
loggingGroups
.
setLoggerGroupLevel
(
groupName
,
level
);
}
catch
(
RuntimeException
ex
)
{
this
.
logger
.
error
(
"Cannot set level '"
+
level
+
"' for '"
+
groupName
+
"'"
);
}
}
...
...
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/LoggingGroups.java
0 → 100644
View file @
b9047c22
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
logging
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.concurrent.ConcurrentHashMap
;
import
org.springframework.util.Assert
;
/**
* Manage logger groups.
*
* @author HaiTao Zhang
* @since 2.2.0
*/
public
class
LoggingGroups
{
private
Map
<
String
,
LogLevel
>
loggerGroupConfigurations
;
private
Map
<
String
,
List
<
String
>>
loggerGroups
;
private
LoggingSystem
loggingSystem
;
public
LoggingGroups
(
LoggingSystem
loggingSystem
)
{
this
.
loggerGroupConfigurations
=
new
ConcurrentHashMap
<>();
this
.
loggerGroups
=
new
ConcurrentHashMap
<>();
this
.
loggingSystem
=
loggingSystem
;
}
/**
* Associate a name to a list of logger's name to create a logger group.
* @param groupName name of the logger group
* @param members list of the members names
*/
public
void
setLoggerGroup
(
String
groupName
,
List
<
String
>
members
)
{
Assert
.
notNull
(
groupName
,
"Group name can not be null"
);
Assert
.
notNull
(
members
,
"Members can not be null"
);
this
.
loggerGroups
.
put
(
groupName
,
members
);
}
/**
* Set the logging level for a given logger group.
* @param groupName the name of the group to set
* @param level the log level ({@code null}) can be used to remove any custom level
* for the logger group and use the default configuration instead.
*/
public
void
setLoggerGroupLevel
(
String
groupName
,
LogLevel
level
)
{
Assert
.
notNull
(
groupName
,
"Group name can not be null"
);
List
<
String
>
members
=
this
.
loggerGroups
.
get
(
groupName
);
members
.
forEach
((
member
)
->
this
.
loggingSystem
.
setLogLevel
(
member
.
equalsIgnoreCase
(
LoggingSystem
.
ROOT_LOGGER_NAME
)
?
null
:
member
,
level
));
this
.
loggerGroupConfigurations
.
put
(
groupName
,
level
);
}
/**
* Checks whether a groupName is associated to a logger group.
* @param groupName name of the logger group
* @return a boolean stating true when groupName is associated with a group of loggers
*/
public
boolean
isGroup
(
String
groupName
)
{
Assert
.
notNull
(
groupName
,
"Group name can not be null"
);
return
this
.
loggerGroups
.
containsKey
(
groupName
);
}
/**
* Get the all registered logger groups.
* @return a Set of the names of the logger groups
*/
public
Set
<
String
>
getLoggerGroupNames
()
{
synchronized
(
this
)
{
return
this
.
loggerGroups
.
isEmpty
()
?
null
:
Collections
.
unmodifiableSet
(
this
.
loggerGroups
.
keySet
());
}
}
/**
* Get a logger group's members.
* @param groupName name of the logger group
* @return list of the members names associated with this group
*/
public
List
<
String
>
getLoggerGroup
(
String
groupName
)
{
Assert
.
notNull
(
groupName
,
"Group name can not be null"
);
return
Collections
.
unmodifiableList
(
this
.
loggerGroups
.
get
(
groupName
));
}
/**
* Get a logger group's configured level.
* @param groupName name of the logger group
* @return the logger groups configured level
*/
public
LogLevel
getLoggerGroupConfiguredLevel
(
String
groupName
)
{
Assert
.
notNull
(
groupName
,
"Group name can not be null"
);
return
this
.
loggerGroupConfigurations
.
get
(
groupName
);
}
}
spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/LoggingGroupsTests.java
0 → 100644
View file @
b9047c22
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
logging
;
import
java.util.Arrays
;
import
org.junit.jupiter.api.Test
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
verify
;
/**
* Tests for {@link LoggingGroups}
*
* @author HaiTao Zhang
*/
public
class
LoggingGroupsTests
{
private
LoggingSystem
loggingSystem
=
mock
(
LoggingSystem
.
class
);
@Test
void
setLoggerGroupWithTheConfiguredLevelToAllMembers
()
{
LoggingGroups
loggingGroups
=
new
LoggingGroups
(
this
.
loggingSystem
);
loggingGroups
.
setLoggerGroup
(
"test"
,
Arrays
.
asList
(
"test.member"
,
"test.member2"
));
loggingGroups
.
setLoggerGroupLevel
(
"test"
,
LogLevel
.
DEBUG
);
verify
(
this
.
loggingSystem
).
setLogLevel
(
"test.member2"
,
LogLevel
.
DEBUG
);
verify
(
this
.
loggingSystem
).
setLogLevel
(
"test.member"
,
LogLevel
.
DEBUG
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment