Java >> Java tutorial >  >> Tag >> Log4j

Hvordan kan jeg konfigurere separate strømme af logning til log4j?

Jeg tror, ​​hvad John Ament mente, er, at loggernavnet (eller kategorien, som det også nogle gange kaldes) frit kan vælges. Opkaldet

LoggerFactory.getLogger(MyClass.class)

er for det meste kun en bekvemmelighed for at ringe

LoggerFactory.getLogger(MyClass.class.getName())

Der er ikke noget krav fra logningsrammen, at du navngiver dine loggere efter klassens fulde navn. Dette er blot en konvention, der understøttes af den første getLogger-overbelastning ovenfor.

Så i stedet for at have tre forskellige Logger-implementeringer med samme navn som i dit eksempel:

 private AbstractLogger l1= new LoggerOne(this.getClass());
 private AbstractLogger l2= new LoggerTwo(this.getClass());
 private AbstractLogger l3= new LoggerThree(this.getClass());

Du kan nemt bruge standard Logger-implementeringen med 3 forskellige navne:

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); 
    }
}

Da log4j-loggere er hierarkiske, kan du styre dem sammen eller individuelt efter behov. Så hvis du vil aktivere dem alle:

log4j.logger.org.myproject.MyClass=DEBUG, stdout

Hvis du senere skal slå resultater fra:

log4j.logger.org.myproject.MyClass=DEBUG, stdout
log4j.logger.org.myproject.MyClass.results=OFF

På samme måde kan du sende output til forskellige destinationer, hvis det er nødvendigt.

Brug af markører

Alt ovenstående blev skrevet ved kun at bruge den grundlæggende funktionalitet, der er tilgængelig i enhver SLF4J-implementering. Hvis du bruger Log4j 2 eller er villig til at skifte til logback, kan du i stedet bruge markører til at opnå det samme, men på globalt plan. I stedet for at have flere loggere i klassen kan du således have flere markører, som sådan:

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); 
    }
}

Dette giver dig mulighed for at skifte logning af parametre, resultater og varigheder globalt ved at bruge Log4j 2.0 MarkerFilter eller logback MarkerFilter.

Konfiguration i Log4j 2.0

Log4j 2.0 giver dig en masse fleksibilitet i, hvordan du bruger MarkerFilter:

  1. Du kan anvende det som et kontekstdækkende filter og dermed slå alle fra logning af f.eks. varigheder.
  2. Du kan anvende det på org.myproject.MyClass-loggeren for at deaktivere logning af resultater (f.eks.) for den specifikke klasse.
  3. Du kan anvende det på en specifik appender og dermed foretage parameterlogning til en separat fil fra resultatlogning eller lignende.

Konfiguration i logback

I logback er historien mere kompleks, afhængig af hvad du ønsker at opnå. For at deaktivere al logning af en given markør globalt, skal du blot bruge MarkerFilter. Dette er et TurboFilter, så det gælder for hele logningskonteksten. Hvis du vil logge forskellige markører til separate kilder, kan du bruge SiftingAppender og skrive en markørbaseret diskriminator ved at udvide AbstractDiscriminator. Da logback ikke understøtter filtre direkte på loggere, bør du bruge klassespecifikke markører i stedet for globale, hvis du har brug for at konfigurere output pr. klasse pr. markør, f.eks. .

Her er et eksempel på implementering af en markørbaseret diskriminator til brug med 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();
    }
}

Denne implementering er stærkt inspireret af standarden ContextBased Discriminator. Du ville bruge MarkerBased Discriminator sådan her:

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

Du indstiller forskellig logføringsadfærd ved at oprette brugerdefinerede logningsklasser.

Her er min løsning:

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);           
    }    
}

Opsætning i 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

Når du bruger disse loggere:

Sådan bruger du disse loggere:

 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();

    }

}

Log output:

12:27:29 DEBUG LoggerTwo:18 - class maventestspace.MyMain :log 2
12:27:29 DEBUG LoggerThree:18 - class maventestspace.MyMain :Foo time taken:1

Bemærk, at LoggerOne ikke udskriver, fordi den er indstillet til FEJL i egenskabsfilen.

For at omdirigere disse separate logfiler skal du opsætte nye appenders og loggere.

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

Det lyder som om den mest ligetil løsning er at udnytte forskellige kategorier til det, du logger. Bruger dette som eksempel

String baseCategory = MyClass.class.getName();
String params = baseCategory+".params";
String duration = baseCategory+".duration";

Du ville blot sende disse navne ind som loggerfabrikskategorier.


Java tag