简体   繁体   中英

Changing logging levels localized name with jdk logging/slf4j

I see that logging levels using jdk logging are localized, running this example:

package com.stackoverflow.tests.logging;

import java.util.Locale;
import java.util.logging.Logger;

public class TestLogging
{

    public static void doLog(Locale l)
    {
        Locale.setDefault(l);

        Logger logger = Logger.getLogger(TestLogging.class.getName());

        final String msg = "Hello logging world";
        logger.severe(msg);
        logger.info(msg);
        logger.config(msg);
        logger.fine(msg);
        logger.finer(msg);
        logger.finest(msg);

    }

    public static void main(String args[])
    {

        doLog(Locale.ITALY);

    //  doLog(Locale.UK);

    //  doLog(Locale.FRANCE);

    }
}

Ouput for italian (using default logger configuration hence only severe and info levels are logged)

dic 15, 2014 10:48:43 AM com.stackoverflow.tests.logging.TestLogging doLog
Grave: Hello logging world
dic 15, 2014 10:48:43 AM com.stackoverflow.tests.logging.TestLogging doLog
Informazioni: Hello logging world

I would like to set up custom localized message for logging levels instead of the one provided by default.

How can I do that

  1. Using JDK logging directly (I see Logger.getLogger can take a ResourceBundle but I did not manage to make it work, and also I dont know what is expected to be in this file)
  2. Using SLF4 facade (I guess that would imply tweaking LoggerFactory.getLogger function of SLF4J which is the one I'm using to obtain the loggers)

Based on some testing, it doesn't seem possible to do this with JDK logging.

The resource bundle name passed to Logger doesn't influence the Level object that creates the localized name. Instead, it uses a default resource bundle ( sun.util.logging.resources.logging ) to obtain a text version of the level.

My test comprised of a file named logmessages.properties containing:

INFO="NEWINFO"
testmessage="fooballs"

and a simple class:

import java.util.logging.Logger;

public class LocaleLoggingTest {

  public static void main(String[] args) throws Exception {
    Logger logger = Logger.getLogger("name", "logmessages");
    logger.info("testmessage");
  }
}

Output:

Dec 15, 2014 10:23:39 AM LocaleLoggingTest main
INFO: "fooballs"

If you debug, by the time you get to java.util.logging.SimpleFormatter.format(LogRecord) , the log record has a Level object with a default resource bundle. Frustrating, eh?

In java.util.logging , you can define your own levels using a different bundle name or none at all. The way to do that is subclassing java.util.logging.Level and adding your own constants. For example, if you want non-localized names, you can create your levels as follows:

public class Level extends java.util.logging.Level {
    private static final long serialVersionUID = -1283674772992561191L;

    public static final Level OFF = new Level("OFF", Integer.MAX_VALUE);
    public static final Level SEVERE = new Level("SEVERE", 1000);
    public static final Level WARNING = new Level("WARNING", 900);
    public static final Level INFO = new Level("INFO", 800);
    public static final Level CONFIG = new Level("CONFIG", 700);
    public static final Level FINE = new Level("FINE", 500);
    public static final Level FINER = new Level("FINER", 400);
    public static final Level FINEST = new Level("FINEST", 300);
    public static final Level ALL = new Level("ALL", Integer.MIN_VALUE);

    protected Level(String name, int value) {
        super(name, value);
    }
}

If you want to use another bundle name, do the following:

public class Level extends java.util.logging.Level {
    private static final long serialVersionUID = -1283674772992561191L;

    static final String my_bundle_name = "my.bundle.name";

    public static final Level OFF = new Level("OFF", Integer.MAX_VALUE, my_bundle_name);
    public static final Level SEVERE = new Level("SEVERE", 1000, my_bundle_name);
    public static final Level WARNING = new Level("WARNING", 900, my_bundle_name);
    public static final Level INFO = new Level("INFO", 800, my_bundle_name);
    public static final Level CONFIG = new Level("CONFIG", 700, my_bundle_name);
    public static final Level FINE = new Level("FINE", 500, my_bundle_name);
    public static final Level FINER = new Level("FINER", 400, my_bundle_name);
    public static final Level FINEST = new Level("FINEST", 300, my_bundle_name);
    public static final Level ALL = new Level("ALL", Integer.MIN_VALUE, my_bundle_name);

    protected Level(String name, int value, String resourceBundleName) {
        super(name, value, resourceBundleName);
    }
}

Of course, you must use your custom levels instead of the default ones, so you must use calls like Logger.log(Level level, String msg) , where you specify the level explicitly, instead of Logger.info(String msg) , that always uses the default level.

EDIT: I got the idea from https://docs.oracle.com/javase/8/docs/api/java/util/logging/Level.html#Level-java.lang.String-int-

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM