Sök…


Använda standardloggaren

Det här exemplet visar hur man använder standardloggnings-api.

import java.util.logging.Level;
import java.util.logging.Logger;

public class MyClass {
    
    // retrieve the logger for the current class
    private static final Logger LOG = Logger.getLogger(MyClass.class.getName());
    
    public void foo() {
        LOG.info("A log message");
        LOG.log(Level.INFO, "Another log message");

        LOG.fine("A fine message");
    
        // logging an exception
        try {
            // code might throw an exception
        } catch (SomeException ex) {
            // log a warning printing "Something went wrong"
            // together with the exception message and stacktrace
            LOG.log(Level.WARNING, "Something went wrong", ex);
        }

        String s = "Hello World!";

        // logging an object
        LOG.log(Level.FINER, "String s: {0}", s);

        // logging several objects
        LOG.log(Level.FINEST, "String s: {0} has length {1}", new Object[]{s, s.length()});
    }

}

Loggningsnivåer

Java Logging Api har 7 nivåer . Nivåerna i fallande ordning är:

  • SEVERE (högsta värde)
  • WARNING
  • INFO
  • CONFIG
  • FINE
  • FINER
  • FINEST (lägsta värde)

Standardnivån är INFO (men detta beror på systemet och en virtuell maskin).

Obs : Det finns också nivåer OFF (kan användas för att stänga av loggning) och ALL (påsidan av OFF ).

Kodsexempel för detta:

import java.util.logging.Logger;

public class Levels {
    private static final Logger logger = Logger.getLogger(Levels.class.getName());

    public static void main(String[] args) {

        logger.severe("Message logged by SEVERE");
        logger.warning("Message logged by WARNING");
        logger.info("Message logged by INFO");
        logger.config("Message logged by CONFIG");
        logger.fine("Message logged by FINE");
        logger.finer("Message logged by FINER");
        logger.finest("Message logged by FINEST");

        // All of above methods are really just shortcut for
        // public void log(Level level, String msg):
        logger.log(Level.FINEST, "Message logged by FINEST");
    }
}

Som standard körs denna klass endast meddelanden med en nivå högre än CONFIG :

Jul 23, 2016 9:16:11 PM LevelsExample main
SEVERE: Message logged by SEVERE
Jul 23, 2016 9:16:11 PM LevelsExample main
WARNING: Message logged by WARNING
Jul 23, 2016 9:16:11 PM LevelsExample main
INFO: Message logged by INFO

Logga in komplexa meddelanden (effektivt)

Låt oss titta på ett urval av loggning som du kan se i många program:

public class LoggingComplex {
    
    private static final Logger logger = 
        Logger.getLogger(LoggingComplex.class.getName());

    private int total = 50, orders = 20;
    private String username = "Bob";

    public void takeOrder() {
        // (...) making some stuff
        logger.fine(String.format("User %s ordered %d things (%d in total)", 
                                  username, orders, total));
        // (...) some other stuff
    }

    // some other methods and calculations
}

Exemplet ovan ser helt bra ut, men många programmerare glömmer att Java VM är en stackmaskin. Detta innebär att alla metodens parametrar beräknas innan metoden körs.

Detta faktum är avgörande för att logga in i Java, särskilt för att logga in något i låga nivåer som FINE , FINER , FINEST som är inaktiverade som standard. Låt oss titta på Java-bytekod för takeOrder() .

Resultatet för javap -c LoggingComplex.class är något liknande:

public void takeOrder();
    Code:
       0: getstatic     #27 // Field logger:Ljava/util/logging/Logger;
       3: ldc           #45 // String User %s ordered %d things (%d in total)
       5: iconst_3
       6: anewarray     #3  // class java/lang/Object
       9: dup
      10: iconst_0
      11: aload_0
      12: getfield      #40 // Field username:Ljava/lang/String;
      15: aastore
      16: dup
      17: iconst_1
      18: aload_0
      19: getfield      #36 // Field orders:I
      22: invokestatic  #47 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      25: aastore
      26: dup
      27: iconst_2
      28: aload_0
      29: getfield      #34 // Field total:I
      32: invokestatic  #47 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      35: aastore
      36: invokestatic  #53 // Method java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
      39: invokevirtual #59 // Method java/util/logging/Logger.fine:(Ljava/lang/String;)V
      42: return

Rad 39 kör den faktiska loggningen. Allt tidigare arbete (laddar variabler, skapar nya objekt, sammanlänker strängar i format ) kan vara för ingenting om loggningsnivån är högre än FINE (och är som standard). Sådan loggning kan vara mycket ineffektiv och kräva onödiga minnes- och processorresurser.

Det är därför du bör fråga om nivån du vill använda är aktiverad.

Rätt sätt ska vara:

public void takeOrder() {
    // making some stuff
    if (logger.isLoggable(Level.FINE)) {
        // no action taken when there's no need for it
        logger.fine(String.format("User %s ordered %d things (%d in total)",
                                  username, orders, total));
    }
    // some other stuff
}

Sedan Java 8:

Logger-klassen har ytterligare metoder som tar en Supplier<String> som parameter, som helt enkelt kan tillhandahållas av en lambda:

public void takeOrder() {
    // making some stuff
    logger.fine(() -> String.format("User %s ordered %d things (%d in total)",
            username, orders, total));
    // some other stuff
}

Metoden Leverantörer get() - i detta fall lambda - kallas bara när motsvarande nivå är aktiverad och så if konstruktion inte behövs längre.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow