56

In plain Java SE 6 environment:

Logger l = Logger.getLogger("nameless");
l.setLevel(Level.ALL);
l.fine("somemessage");

Nothing shows up in Eclipse console. l.info("") and above works just fine, but anything below fine just doesn't seem to work. What's could be wrong? TIA.

4
  • 7
    Yet another reason to use Log4J instead of java.util.logging, IMHO. Commented Oct 28, 2009 at 1:57
  • 6
    or better yet, slf4j/logback. But either one kicks J.U.L ass many times over. Commented Jul 24, 2012 at 19:17
  • 2
    Ive never found these 3rd party logging libraries to offer much. Commented Aug 22, 2012 at 11:00
  • 5
    I can't help but think most people (like I was) are unaware of the logging.properties file and the fact that you can point to any logging.properties file when you run your process. If you want to change your logging levels based on your activity (debugging, testing, production, etc.) then you should have a logging.properties file for each purpose. See this answer and this example. Commented Sep 11, 2012 at 13:56

6 Answers 6

61

Even though the Logger level is set to ALL, the ConsoleHandler (the default Handler on the logger) still has a default level of INFO. This comes from the default logging.properties in JAVA_HOME/jre/lib

Sign up to request clarification or add additional context in comments.

4 Comments

+1 Add this to your project's logger setting to override ConsoleHandler defaults: java.util.logging.ConsoleHandler.level = FINE
And java.util.logging.ConsoleHandler.level is not possible to set/override from the UI in eclipse ?
You can set System properties from the Run Configuration window in Eclipse.
@Maine: this must be done with the console handler of the root logger, not to "your project's logger" which has no handler by default after being created. michel.iamit has provided the way to adjust the root logger console handler.
37

Instead of looping through all handlers and set the logging level, I prefer to set only the level of the console handler:

//get the top Logger
Logger topLogger = java.util.logging.Logger.getLogger("");

// Handler for console (reuse it if it already exists)
Handler consoleHandler = null;
//see if there is already a console handler
for (Handler handler : topLogger.getHandlers()) {
    if (handler instanceof ConsoleHandler) {
        //found the console handler
        consoleHandler = handler;
        break;
    }
}


if (consoleHandler == null) {
    //there was no console handler found, create a new one
    consoleHandler = new ConsoleHandler();
    topLogger.addHandler(consoleHandler);
}
//set the console handler to fine:
consoleHandler.setLevel(java.util.logging.Level.FINEST);

4 Comments

Thanx, but I agree the real answer is in setting the logging level, like in the answer above. This solution is more like a workaround. I don't get why you cannot set the logging level in the console settings in Eclise. I used to work with JBuilder, and there this was an option.
..hi 2009, this is 2012 calling. For anyone who now has to use libraries/jars that do stuff like this example (which we thought was a good idea at the time), you can continue to use your new, preferred slf4j+logback config by adding jul-to-slf4j bridge (jul-to-slf4j.jar) to the classpath, and code like this might work. Lessons learned: keep all low-level log manipulation out of your code, and configure logging levels in the config files (in this case, -Djava.util.logging.config.file={file}, where {file} is a customized version of logging.properties with ".level" set appropriately).
indeed ConsoleHandler might not be present at all, so it needs to be created like above :(
I found this useful also to set the logging level for console logger programmatically, via a menu item in my application. Thank you! I could not figure out why the ConsoleHandler was not getting its level set when I set my logger to a level.
20

An indivual at my workplace found the following to work:

public class Foo {
    private final static Logger logger = Logger.getLogger(Foo.class.getName());
    public static final void main(String[] args) {
        ConsoleHandler ch = new ConsoleHandler();
        ch.setLevel(Level.FINEST);
        Foo.logger.addHandler(ch);
        Foo.logger.setLevel(Level.FINEST);
        Foo.logger.finest("test");
    }
}

If you just set the root or the handler to finest (exclusively) then it didn't work. When I set both to FINEST then it works. His explanation was:

Both the logger and its handlers have Log Levels… The order of filtering is Logger then Handlers. That means it checks to see if the log message passes the loggers filter first, then sends the message on to the individual handlers for filtering.

He further explained it using the following examples:

  • Logger myLogger has a level of FINEST and a single ConsoleHandler myHandler which has a level of INFO

  • myLogger.fine("foo") à message makes it past the logger’s filter, but gets stopper by the handler’s filter… Nothing output.

  • myLogger.info("foo") à passes both filters and foo is output.

Now…

  • Logger myLogger has a level of INFO and a single ConsoleHandler myHandler which has a level of FINEST

  • myLogger.fine("foo") à message gets stopped by the logger’s filter and never makes it to the handler... Nothing output.

  • myLogger.info("foo") à passes both filters and foo is output.

Now…

  • Logger myLogger has a level of FINEST and a single ConsoleHandler myHandler which has a level of FINEST

  • myLogger.fine("foo") à passes both filters and "foo" is output.

  • myLogger.info("foo") à passes both filters and foo is output.

2 Comments

Should be the correct answer. I just set level for console handler but nothing work. Luckily I read your answer.
This might be recommended if you want to just pass all the logging output to the OS (executing environment) so that the log data can be better stored and analyzed by a third party. Your application should just make it part of stdout according to The Twelve-Factor App (12factor.net/logs)
3

You need to set the log level on both the handlers in the logger, and the logger itself. Logging is only performed at the "coarsest" of the two levels. Here is a logging class that does the job.

import java.io.PrintWriter;
import java.io.StringWriter;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.logging.ConsoleHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

public class Log {

    private static final Logger logger = Logger.getGlobal();

    private static Level logLevel = Level.INFO;
    static {
        // Remove all the default handlers (usually just one console handler)
        Logger rootLogger = Logger.getLogger("");
        Handler[] rootHandlers = rootLogger.getHandlers();
        for (Handler handler : rootHandlers) {
            rootLogger.removeHandler(handler);
        }

        // Add our own handler
        ConsoleHandler handler = new ConsoleHandler();
        handler.setLevel(logLevel);
        handler.setFormatter(new LogFormatter());
        logger.addHandler(handler);
        logger.setLevel(logLevel);
    }

    public static class LogFormatter extends Formatter {
        @Override
        public String format(LogRecord record) {
            String stackTrace = "";
            Throwable thrown = record.getThrown();
            if (thrown != null) {
                StringWriter stacktraceWriter = new StringWriter();
                try (PrintWriter writer = new PrintWriter(stacktraceWriter)) {
                    thrown.printStackTrace(writer);
                }
                stackTrace = stacktraceWriter.toString();
            }
            return ZonedDateTime.ofInstant(Instant.ofEpochMilli(record.getMillis()), ZoneId.of("UTC")).format(DateTimeFormatter.ISO_ZONED_DATE_TIME) + "\t" + record.getLevel()
                    + "\t" + record.getMessage() + "\n" + stackTrace;
        }
    }

    private static final String classname = Log.class.getName();

    private static String callerRef() {
        StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
        if (stackTraceElements.length < 4) {
            return "";
        } else {
            int i = 1;
            for (; i < stackTraceElements.length; i++) {
                if (stackTraceElements[i].getClassName().equals(classname)) {
                    break;
                }
            }
            for (; i < stackTraceElements.length; i++) {
                if (!stackTraceElements[i].getClassName().equals(classname)) {
                    break;
                }
            }
            if (i < stackTraceElements.length) {
                return stackTraceElements[i].toString();
            } else {
                return "[in unknown method]";
            }
        }
    }

    public static void setLogLevel(Level newLogLevel) {
        logLevel = newLogLevel;
        for (Handler handler : logger.getHandlers()) {
            handler.setLevel(newLogLevel);
        }
        Log.logger.setLevel(newLogLevel);
    }

    public static int getLevelNum() {
        return logLevel.intValue();
    }

    public static int getLevelNum(Level level) {
        return level.intValue();
    }

    public static void fine(String msg) {
        logger.log(Level.FINE, msg);
    }

    public static void info(String msg) {
        logger.log(Level.INFO, msg);
    }

    public static void warning(String msg) {
        logger.log(Level.WARNING, msg + "\t " + callerRef());
    }

    public static void error(String msg) {
        logger.log(Level.SEVERE, msg + "\t " + callerRef());
    }

    public static void exception(String msg, Throwable cause) {
        logger.log(Level.SEVERE, msg + "\t " + callerRef(), cause);
    }

}

1 Comment

+1 for actually including the import lines. Anyone asking this question might not know which bits import from where.
2

Other users have already given good answer why it happened (ConsoleHandler has a separate level variable). I reuse my application logger's level and copy it up to the parent hiearchy. Also provides easy way to refresh levels at runtime anytime I want.

// Set same level all loggers and handlers up to the parent level
// OFF,SEVERE,WARNING,INFO,CONFIG,FINE,FINER,FINEST,ALL
Logger logger = Logger.getLogger(this.getClass().getPackage().getName());
//Level level = Level.parse("FINEST");
Level level = logger.getLevel();
Logger tempLogger = logger;
while(tempLogger != null) {
   tempLogger.setLevel(level);
   for(Handler handler : tempLogger.getHandlers())
      handler.setLevel(level);
   tempLogger = tempLogger.getParent();
}

Comments

1
private final static Logger LOGGER = Logger.getLogger(WoTServer.class.getName());
for(Handler h : LOGGER.getParent().getHandlers()){
    if(h instanceof ConsoleHandler){
        h.setLevel(Level.ALL);
    }
} 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.