Spring中如何通过自定义用户事件管理日志文件切换?
Posted
技术标签:
【中文标题】Spring中如何通过自定义用户事件管理日志文件切换?【英文标题】:How to manage log file switching through custom user event in Spring? 【发布时间】:2020-04-30 20:43:46 【问题描述】:假设我们使用 Logback 进行日志记录。
每次发生特定事件(即函数调用)时,都需要更改日志文件的路径。
例如,我们在某处调用函数。
startNewLogSegment("A")
在此事件之后,记录器应开始写入logs/mySegment_A.log
文件。
然后,再次调用:
startNewLogSegment("B")
在此事件之后,记录器应完成对前一个文件的写入并开始写入logs/mySegment_B.log
文件。
假设由startNewLogSegment
更改的状态应该在整个应用程序(所有线程)中可见。
我尝试将这种方法应用于 MDC:
logback.xml
...
<appender name="SIFTING_BY_ID" class="ch.qos.logback.classic.sift.SiftingAppender">
<discriminator>
<key>id</key>
<defaultValue>initial</defaultValue>
</discriminator>
<sift>
<appender name="FULL-$id" class="ch.qos.logback.core.FileAppender">
<file>logs/mySegment_$id.log</file>
<append>false</append>
<encoder >
<pattern>%ddd-MM-yyyy HH:mm:ss.SSS [%thread] [%-5level] %logger36.%M - %msg%n</pattern>
</encoder>
</appender>
</sift>
</appender>
...
并在自定义事件出现时调用MDC.put("id", "A")
。
但它的工作方式与我需要的不同。
已知MDC manages contextual information on a per thread basis,所以至少我们需要a control over threads creation 来实现上述目标。
我想知道这种方法是否可以用于 Spring,尤其是 Spring Reactor 执行的异步操作。我没有找到关于将自定义线程池用于内部 Spring 活动的信息。
我希望,有一种更简单的方法可以在不滥用 Spring 内部结构的情况下调整日志记录。
【问题讨论】:
【参考方案1】:我最终实现了鉴别器 AbstractDiscriminator<ILoggingEvent>
的自定义实现,允许 uasge 全局可见值。
GVC.java
/**
* Global values context.
* Allows to sift log files globally independent from a thread calling log operation.
* <p>
* Used API analogous to standard @link org.slf4j.MDC.
*/
public final class GVC
private static Map<String, String> STORED = new HashMap<>();
private GVC()
public static synchronized void put(String key, String value)
STORED.put(key, value);
public static synchronized String get(String key)
return STORED.get(key);
GVCBasedDiscriminator.java
/**
* Customized analogue of MDCBasedDiscriminator.
* <p>
* GVCBasedDiscriminator essentially returns the value mapped to an GVC key.
* If the value is null, then a default value is returned.
* <p>
* Both Key and the DefaultValue are user specified properties.
*/
public class GVCBasedDiscriminator extends AbstractDiscriminator<ILoggingEvent>
private String key;
private String defaultValue;
public String getDiscriminatingValue(ILoggingEvent event)
String value = GVC.get(key);
if (value == null)
return defaultValue;
else
return value;
@Override
public String getKey()
return key;
@Override
public void start()
int errors = 0;
if (OptionHelper.isEmpty(key))
errors++;
addError("The \"Key\" property must be set");
if (OptionHelper.isEmpty(defaultValue))
errors++;
addError("The \"DefaultValue\" property must be set");
if (errors == 0)
started = true;
/**
* Key for this discriminator instance
*
* @param key
*/
public void setKey(String key)
this.key = key;
/**
* The default GVC value in case the GVC is not set for
* @link #setKey(String) mdcKey.
* <p/>
* <p> For example, if @link #setKey(String) Key is set to the value
* "someKey", and the MDC is not set for "someKey", then this appender will
* use the default value, which you can set with the help of this method.
*
* @param defaultValue
*/
public void setDefaultValue(String defaultValue)
this.defaultValue = defaultValue;
logback.xml
<appender name="TRACES_PER_SESSION_FILE" class="ch.qos.logback.classic.sift.SiftingAppender">
<!-- here the custom discriminator implementation is applied -->
<discriminator class="internal.paxport.misc.logging.GVCBasedDiscriminator">
<key>id</key>
<defaultValue>initial</defaultValue>
</discriminator>
<sift>
<appender name="FULL-$id" class="ch.qos.logback.core.FileAppender">
<file>logs/mySegment_$id.log</file>
<append>false</append>
<encoder>
<pattern>%ddd-MM-yyyy HH:mm:ss.SSS [%thread] [%-5level] %logger36.%M - %msg%n</pattern>
</encoder>
</appender>
</sift>
</appender>
【讨论】:
以上是关于Spring中如何通过自定义用户事件管理日志文件切换?的主要内容,如果未能解决你的问题,请参考以下文章