dwj*_*ton 5 java logging log4j
说我有这样一个类:
public class MyClass
{
private Logger log = LoggerFactory.getLogger(MyClass.class); //org.slf4j.LoggerFactory
public void foo(Params p)
{
log.info("Foo params: " + p);
long t1 = System.currentTimeMillis();
Result r = someMethod(p);
long t2 = System.currentTimeMillis();
log.info("Foo result: " + r)
log.info("Foo time taken: + (t2-t1)/1000);
}
}
Run Code Online (Sandbox Code Playgroud)
现在,在打印此信息时,我希望能够打开和关闭不同类型的信息(参数,结果,拍摄时间).
使用日志记录级别来区分的问题是,更精细的粒度级别也包含更粗略的级别.
我怎样才能轻松设置它?
我认为 John Ament 的意思是可以自由选择记录器名称(或类别,有时也称为类别)。电话
LoggerFactory.getLogger(MyClass.class)
Run Code Online (Sandbox Code Playgroud)
主要是为了方便打电话
LoggerFactory.getLogger(MyClass.class.getName())
Run Code Online (Sandbox Code Playgroud)
日志框架不要求您根据类的全名命名记录器。这只是上面第一个 getLogger 重载支持的约定。
因此,不要使用与示例中相同名称的三个不同的 Logger 实现:
private AbstractLogger l1= new LoggerOne(this.getClass());
private AbstractLogger l2= new LoggerTwo(this.getClass());
private AbstractLogger l3= new LoggerThree(this.getClass());
Run Code Online (Sandbox Code Playgroud)
您可以简单地使用具有 3 个不同名称的标准 Logger 实现:
public class MyClass
{
private static final String loggerBaseName = MyClass.class.getName();
private final Logger paramsLogger = LoggerFactory.getLogger(loggerBaseName + ".params");
private final Logger resultsLogger = LoggerFactory.getLogger(loggerBaseName + ".results");
private final Logger durationLogger = LoggerFactory.getLogger(loggerBaseName + ".duration");
public void foo(Params p)
{
paramsLogger.info("Foo params: {}", p);
long t1 = System.currentTimeMillis();
Result r = someMethod(p);
long t2 = System.currentTimeMillis();
resultsLogger.info("Foo result: {}", r)
durationLogger.info("Foo time taken: {}", (t2-t1)/1000);
}
}
Run Code Online (Sandbox Code Playgroud)
由于 log4j 记录器是分层的,您可以根据需要一起或单独控制它们。因此,如果您想启用所有这些:
log4j.logger.org.myproject.MyClass=DEBUG, stdout
Run Code Online (Sandbox Code Playgroud)
如果您以后需要关闭结果:
log4j.logger.org.myproject.MyClass=DEBUG, stdout
log4j.logger.org.myproject.MyClass.results=OFF
Run Code Online (Sandbox Code Playgroud)
如果需要,您可以以同样的方式将输出发送到不同的目的地。
以上所有内容都是仅使用任何 SLF4J 实现中可用的基本功能编写的。如果您正在使用 Log4j 2 或愿意切换到 logback,您可以使用标记来实现相同的目的,但在全局级别上。因此,您可以拥有多个标记,而不是在类中有多个记录器,如下所示:
public class GlobalMarkers
{
public static final Marker PARAMS = MarkerFactory.getMarker("PARAMS");
public static final Marker RESULTS = MarkerFactory.getMarker("RESULTS");
public static final Marker DURATION = MarkerFactory.getMarker("DURATION");
}
public class MyClass
{
private Logger logger = LoggerFactory.getLogger(MyClass.class);
public void foo(Params p)
{
logger.info(GlobalMarkers.PARAMS, "Foo params: {}", p);
long t1 = System.currentTimeMillis();
Result r = someMethod(p);
long t2 = System.currentTimeMillis();
logger.info(GlobalMarkers.RESULTS, "Foo result: {}", r)
logger.info(GlobalMarkers.DURATION, "Foo time taken: {}", (t2-t1)/1000);
}
}
Run Code Online (Sandbox Code Playgroud)
这将允许您使用Log4j 2.0 MarkerFilter或logback MarkerFilter全局切换参数、结果和持续时间的日志记录。
Log4j 2.0 在如何使用 MarkerFilter 方面为您提供了很大的灵活性:
在 logback 中,故事更复杂,具体取决于您希望实现的目标。要全局关闭给定标记的所有日志记录,只需使用 MarkerFilter。这是一个 TurboFilter,所以它适用于整个日志上下文。如果你想记录不同的标记来分离源,你可以使用SiftingAppender并通过扩展 AbstractDiscriminator 编写一个基于标记的鉴别器。由于 logback 不直接支持记录器上的过滤器,如果您需要为每个类每个标记配置输出,例如关闭 MyClass 的结果记录但为其他类保持它,您应该使用特定于类的标记而不是全局标记.
这是与 SiftingAppender 一起使用的基于标记的鉴别器的示例实现:
public class MarkerBasedDiscriminator extends AbstractDiscriminator<ILoggingEvent> {
private static final String KEY = "markerName";
private String defaultValue;
public String getDefaultValue() {
return defaultValue;
}
public void setDefaultValue(String defaultValue) {
this.defaultValue = defaultValue;
}
public String getKey() {
return KEY;
}
public void setKey() {
throw new UnsupportedOperationException("Key not settable. Using " + KEY);
}
public String getDiscriminatingValue(ILoggingEvent e) {
Marker eventMarker = e.getMarker();
if (eventMarker == null)
return defaultValue;
return eventMarker.getName();
}
}
Run Code Online (Sandbox Code Playgroud)
这个实现很大程度上受到标准ContextBasedDiscriminator 的启发。您可以像这样使用 MarkerBasedDiscriminator:
<configuration>
<appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">
<discriminator class="org.myproject.MarkerBasedDiscriminator">
<defaultValue>general</defaultValue>
</discriminator>
<sift>
<appender name="FILE-${markerName}" class="ch.qos.logback.core.FileAppender">
<file>${markerName}.log</file>
<append>false</append>
<encoder>
<pattern>%d [%thread] %level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
</sift>
</appender>
<root level="DEBUG">
<appender-ref ref="SIFT" />
</root>
</configuration>
Run Code Online (Sandbox Code Playgroud)
您可以通过创建自定义日志记录类来设置不同的日志记录行为。
这是我的解决方案:
public abstract class AbstractLogger {
protected Logger log;
protected Class callingClass;
public AbstractLogger(Class c)
{
this.log = LoggerFactory.getLogger(this.getClass());
this.callingClass = c;
}
public void log(String s)
{
log.debug(this.callingClass + " :" + s);
}
}
public class LoggerOne extends AbstractLogger {
public LoggerOne(Class c) {
super(c);
}
}
public class LoggerTwo extends AbstractLogger {
public LoggerTwo(Class c) {
super(c);
}
}
public class LoggerThree extends AbstractLogger {
public LoggerThree(Class c) {
super(c);
}
}
Run Code Online (Sandbox Code Playgroud)
在 Log4j.properties 中设置
#Define custom levels by package
#set to ERROR to turn them off
log4j.logger.org.myproject.loggers.LoggerOne=ERROR
log4j.logger.org.myproject.loggers.LoggerTwo=DEBUG
log4j.logger.org.myproject.loggers.LoggerThree=DEBUG
Run Code Online (Sandbox Code Playgroud)
使用这些记录器时:
要使用这些记录器:
public class MyMain {
// private Logger log = LoggerFactory.getLogger(MyMain.class);
private AbstractLogger l1= new LoggerOne(this.getClass());
private AbstractLogger l2= new LoggerTwo(this.getClass());
private AbstractLogger l3= new LoggerThree(this.getClass());
public void run()
{
l1.log("log 1");
long t1 = System.currentTimeMillis();
try {
Thread.sleep(1000); //1000 milliseconds is one second.
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
long t2 = System.currentTimeMillis();
l2.log("log 2");
l3.log("Foo time taken:" + (t2-t1)/1000);
}
public static void main(String[] args) {
MyMain me = new MyMain();
me.run();
}
}
Run Code Online (Sandbox Code Playgroud)
日志输出:
12:27:29 DEBUG LoggerTwo:18 - class maventestspace.MyMain :log 2
12:27:29 DEBUG LoggerThree:18 - class maventestspace.MyMain :Foo time taken:1
Run Code Online (Sandbox Code Playgroud)
请注意,LoggerOne 不会打印,因为它在属性文件中设置为 ERROR。
要重定向这些单独的日志文件,您需要设置新的附加程序和记录器。
log4j.logger.org.myproject.loggers.LoggerOne=DEBUG, file1, stdout
log4j.logger.org.myproject.loggers.LoggerTwo=DEBUG, file2, stdout
log4j.logger.org.myproject.loggers.LoggerThree=DEBUG, file3, stdout
# Direct log messages to a log file
log4j.appender.file1=org.apache.log4j.RollingFileAppender
#log4j.appender.TextProcessor.Threshold=debug
log4j.appender.file1.File=E:\\logs\\log1.txt
log4j.appender.file1.MaxFileSize=10MB
log4j.appender.file1.MaxBackupIndex=1
log4j.appender.file1.layout=org.apache.log4j.PatternLayout
log4j.appender.file1.layout.ConversionPattern=%d{HH:mm:ss} %-5p %c{1}:%L - %m%n
# Direct log messages to a log file
log4j.appender.file2=org.apache.log4j.RollingFileAppender
#log4j.appender.TextProcessor.Threshold=debug
log4j.appender.file2.File=E:\\logs\\log2.txt
log4j.appender.file2.MaxFileSize=10MB
log4j.appender.file2.MaxBackupIndex=1
log4j.appender.file2.layout=org.apache.log4j.PatternLayout
log4j.appender.file2.layout.ConversionPattern=%d{HH:mm:ss} %-5p %c{1}:%L - %m%n
# Direct log messages to a log file
log4j.appender.file3=org.apache.log4j.RollingFileAppender
#log4j.appender.TextProcessor.Threshold=debug
log4j.appender.file3.File=E:\\logs\\log3.txt
log4j.appender.file3.MaxFileSize=10MB
log4j.appender.file3.MaxBackupIndex=1
log4j.appender.file3.layout=org.apache.log4j.PatternLayout
log4j.appender.file3.layout.ConversionPattern=%d{HH:mm:ss} %-5p %c{1}:%L - %m%n
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
799 次 |
| 最近记录: |