Skip to content

Commit ec926ad

Browse files
committed
Add Log4j2 rolling policy configuration support
Signed-off-by: hojooo <[email protected]> Log4j2: Introduce SpringBootTriggeringPolicy and wire plugin discovery - Add SpringBootTriggeringPolicy plugin supporting size, time, size-and-time, and cron strategies - Read rolling strategy parameters from LOG4J2_ROLLINGPOLICY_* system properties (fallback to attributes) - Register Boot plugin package in Log4J2LoggingSystem to ensure plugin discovery - Use SpringBootTriggeringPolicy under a top-level Policies wrapper in log4j2-file.xml Signed-off-by: hojooo <[email protected]> Log4j2: Add property-driven rolling strategy support and metadata - Introduce rolling policy properties: strategy, time-based.interval, time-based.modulate, cron.schedule - Extend Log4j2RollingPolicySystemProperty with STRATEGY, TIME_INTERVAL, TIME_MODULATE, CRON_SCHEDULE - Propagate new properties in Log4j2LoggingSystemProperties (with deprecated fallback guarded for null) - Document new properties in configuration metadata - Update Log4j2LoggingSystemPropertiesTests to assert new system properties mappingAdd Log4j2 rolling policy configuration support Signed-off-by: hojooo <[email protected]> Tests: Initialize with packaged file config and unwrap composite policy - Initialize with classpath:org/springframework/boot/logging/log4j2/log4j2-file.xml to validate file-based rolling - Unwrap CompositeTriggeringPolicy to locate nested SpringBootTriggeringPolicy and assert its delegate - Keep assertions for time, size-and-time, and cron strategies Signed-off-by: hojooo <[email protected]> Refactor Builder import path Signed-off-by: hojooo <[email protected]> add clean-history-on-start and total-size-cap property in log4j2-file.xml Signed-off-by: hojooo <[email protected]> refactor indent Signed-off-by: hojooo <[email protected]> Refactor Log4j2LoggingSystemPropertiesTests to verify System.setProperty path Signed-off-by: hojooo <[email protected]> Add Rolling Policy Signed-off-by: hojooo <[email protected]>
1 parent 811ddcd commit ec926ad

File tree

9 files changed

+796
-4
lines changed

9 files changed

+796
-4
lines changed

core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,10 @@
5858
import org.springframework.boot.logging.LoggingInitializationContext;
5959
import org.springframework.boot.logging.LoggingSystem;
6060
import org.springframework.boot.logging.LoggingSystemFactory;
61+
import org.springframework.boot.logging.LoggingSystemProperties;
6162
import org.springframework.core.Conventions;
6263
import org.springframework.core.annotation.Order;
64+
import org.springframework.core.env.ConfigurableEnvironment;
6365
import org.springframework.core.env.Environment;
6466
import org.springframework.core.io.Resource;
6567
import org.springframework.core.io.ResourceLoader;
@@ -128,6 +130,11 @@ public class Log4J2LoggingSystem extends AbstractLoggingSystem {
128130
this.loggerContext = loggerContext;
129131
}
130132

133+
@Override
134+
public LoggingSystemProperties getSystemProperties(ConfigurableEnvironment environment) {
135+
return new Log4j2LoggingSystemProperties(environment, getDefaultValueResolver(environment), null);
136+
}
137+
131138
@Override
132139
protected String[] getStandardConfigLocations() {
133140
// With Log4J2 we use the ConfigurationFactory
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Copyright 2012-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.logging.log4j2;
18+
19+
import java.util.function.BiConsumer;
20+
import java.util.function.Function;
21+
22+
import org.jspecify.annotations.Nullable;
23+
24+
import org.springframework.boot.logging.LogFile;
25+
import org.springframework.boot.logging.LoggingSystemProperties;
26+
import org.springframework.core.convert.ConversionFailedException;
27+
import org.springframework.core.convert.ConverterNotFoundException;
28+
import org.springframework.core.env.Environment;
29+
import org.springframework.core.env.PropertyResolver;
30+
import org.springframework.util.unit.DataSize;
31+
32+
/**
33+
* {@link LoggingSystemProperties} for Log4j2.
34+
*
35+
* @author hojooo
36+
* @see Log4j2RollingPolicySystemProperty
37+
*/
38+
public class Log4j2LoggingSystemProperties extends LoggingSystemProperties {
39+
40+
public Log4j2LoggingSystemProperties(Environment environment) {
41+
super(environment);
42+
}
43+
44+
/**
45+
* Create a new {@link Log4j2LoggingSystemProperties} instance.
46+
* @param environment the source environment
47+
* @param setter setter used to apply the property
48+
*/
49+
public Log4j2LoggingSystemProperties(Environment environment,
50+
@Nullable BiConsumer<String, @Nullable String> setter) {
51+
super(environment, setter);
52+
}
53+
54+
/**
55+
* Create a new {@link Log4j2LoggingSystemProperties} instance.
56+
* @param environment the source environment
57+
* @param defaultValueResolver function used to resolve default values or {@code null}
58+
* @param setter setter used to apply the property or {@code null} for system
59+
* properties
60+
*/
61+
public Log4j2LoggingSystemProperties(Environment environment,
62+
Function<@Nullable String, @Nullable String> defaultValueResolver,
63+
@Nullable BiConsumer<String, @Nullable String> setter) {
64+
super(environment, defaultValueResolver, setter);
65+
}
66+
67+
@Override
68+
protected void apply(@Nullable LogFile logFile, PropertyResolver resolver) {
69+
super.apply(logFile, resolver);
70+
applyRollingPolicyProperties(resolver);
71+
}
72+
73+
private void applyRollingPolicyProperties(PropertyResolver resolver) {
74+
applyRollingPolicy(Log4j2RollingPolicySystemProperty.STRATEGY, resolver);
75+
applyRollingPolicy(Log4j2RollingPolicySystemProperty.TIME_INTERVAL, resolver, Integer.class);
76+
applyRollingPolicy(Log4j2RollingPolicySystemProperty.TIME_MODULATE, resolver, Boolean.class);
77+
applyRollingPolicy(Log4j2RollingPolicySystemProperty.CRON_SCHEDULE, resolver);
78+
applyRollingPolicy(Log4j2RollingPolicySystemProperty.FILE_NAME_PATTERN, resolver);
79+
applyRollingPolicy(Log4j2RollingPolicySystemProperty.CLEAN_HISTORY_ON_START, resolver);
80+
applyRollingPolicy(Log4j2RollingPolicySystemProperty.MAX_FILE_SIZE, resolver, DataSize.class);
81+
applyRollingPolicy(Log4j2RollingPolicySystemProperty.TOTAL_SIZE_CAP, resolver, DataSize.class);
82+
applyRollingPolicy(Log4j2RollingPolicySystemProperty.MAX_HISTORY, resolver);
83+
}
84+
85+
private void applyRollingPolicy(Log4j2RollingPolicySystemProperty property, PropertyResolver resolver) {
86+
applyRollingPolicy(property, resolver, String.class);
87+
}
88+
89+
private <T> void applyRollingPolicy(Log4j2RollingPolicySystemProperty property, PropertyResolver resolver,
90+
Class<T> type) {
91+
T value = getProperty(resolver, property.getApplicationPropertyName(), type);
92+
if (value == null && property.getDeprecatedApplicationPropertyName() != null) {
93+
value = getProperty(resolver, property.getDeprecatedApplicationPropertyName(), type);
94+
}
95+
if (value != null) {
96+
String stringValue = String.valueOf((value instanceof DataSize dataSize) ? dataSize.toBytes() : value);
97+
setSystemProperty(property.getEnvironmentVariableName(), stringValue);
98+
}
99+
}
100+
101+
@SuppressWarnings("unchecked")
102+
private <T> @Nullable T getProperty(PropertyResolver resolver, String key, Class<T> type) {
103+
try {
104+
return resolver.getProperty(key, type);
105+
}
106+
catch (ConversionFailedException | ConverterNotFoundException ex) {
107+
if (type != DataSize.class) {
108+
throw ex;
109+
}
110+
// Fallback for Log4j2 compatibility - try parsing as string if DataSize conversion fails
111+
String value = resolver.getProperty(key);
112+
if (value != null) {
113+
try {
114+
return (T) DataSize.parse(value);
115+
}
116+
catch (Exception parseEx) {
117+
ex.addSuppressed(parseEx);
118+
throw ex;
119+
}
120+
}
121+
return null;
122+
}
123+
}
124+
125+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Copyright 2012-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.logging.log4j2;
18+
19+
import org.jspecify.annotations.Nullable;
20+
21+
/**
22+
* Log4j2 rolling policy system properties that can later be used by log configuration
23+
* files.
24+
*
25+
* @author hojooo
26+
* @see Log4j2LoggingSystemProperties
27+
*/
28+
public enum Log4j2RollingPolicySystemProperty {
29+
30+
/**
31+
* Logging system property for the rolled-over log file name pattern.
32+
*/
33+
FILE_NAME_PATTERN("file-name-pattern", "logging.pattern.rolling-file-name"),
34+
35+
/**
36+
* Logging system property for the clean history on start flag.
37+
*/
38+
CLEAN_HISTORY_ON_START("clean-history-on-start", "logging.file.clean-history-on-start"),
39+
40+
/**
41+
* Logging system property for the file log max size.
42+
*/
43+
MAX_FILE_SIZE("max-file-size", "logging.file.max-size"),
44+
45+
/**
46+
* Logging system property for the file total size cap.
47+
*/
48+
TOTAL_SIZE_CAP("total-size-cap", "logging.file.total-size-cap"),
49+
50+
/**
51+
* Logging system property for the file log max history.
52+
*/
53+
MAX_HISTORY("max-history", "logging.file.max-history"),
54+
55+
/**
56+
* Logging system property for the rolling policy strategy.
57+
*/
58+
STRATEGY("strategy", null),
59+
60+
/**
61+
* Logging system property for the rolling policy time interval.
62+
*/
63+
TIME_INTERVAL("time-based.interval", null),
64+
65+
/**
66+
* Logging system property for the rolling policy time modulate flag.
67+
*/
68+
TIME_MODULATE("time-based.modulate", null),
69+
70+
/**
71+
* Logging system property for the cron based schedule.
72+
*/
73+
CRON_SCHEDULE("cron.schedule", null);
74+
75+
private final String environmentVariableName;
76+
77+
private final String applicationPropertyName;
78+
79+
private final @Nullable String deprecatedApplicationPropertyName;
80+
81+
Log4j2RollingPolicySystemProperty(String applicationPropertyName, @Nullable String deprecatedApplicationPropertyName) {
82+
this.environmentVariableName = "LOG4J2_ROLLINGPOLICY_" + name();
83+
this.applicationPropertyName = "logging.log4j2.rollingpolicy." + applicationPropertyName;
84+
this.deprecatedApplicationPropertyName = deprecatedApplicationPropertyName;
85+
}
86+
87+
/**
88+
* Return the name of environment variable that can be used to access this property.
89+
* @return the environment variable name
90+
*/
91+
public String getEnvironmentVariableName() {
92+
return this.environmentVariableName;
93+
}
94+
95+
String getApplicationPropertyName() {
96+
return this.applicationPropertyName;
97+
}
98+
99+
@Nullable String getDeprecatedApplicationPropertyName() {
100+
return this.deprecatedApplicationPropertyName;
101+
}
102+
103+
}

0 commit comments

Comments
 (0)