如何为log4j设置单独的日志记录流?

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)

现在,在打印此信息时,我希望能够打开和关闭不同类型的信息(参数,结果,拍摄时间).

使用日志记录级别来区分的问题是,更精细的粒度级别也包含更粗略的级别.

我怎样才能轻松设置它?

Sør*_*sen 7

我认为 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 MarkerFilterlogback MarkerFilter全局切换参数、结果和持续时间的日志记录。

Log4j 2.0 中的配置

Log4j 2.0 在如何使用 MarkerFilter 方面为您提供了很大的灵活性:

  1. 例如,您可以将其用作上下文范围的过滤器,从而关闭所有持续时间记录。
  2. 您可以将其应用于 org.myproject.MyClass 记录器,以关闭该特定类的结果记录(例如)。
  3. 您可以将其应用于特定的 appender,从而将参数日志记录到结果日志记录或类似文件中的单独文件中。

logback中的配置

在 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)


dwj*_*ton 3

您可以通过创建自定义日志记录类来设置不同的日志记录行为。

这是我的解决方案:

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)