19

I would like to format my log message before being printed out on the console Logger.fine

e.g. How do I format "{0} has {1} apples with him", so the inputs are John and 10

I would prefer a logging framework which provides a solution to this and I don't want to format these messages separately. JDK6 specific logging classes don't seem to have these granularity.

Matthew Gilliard
  • 9,298
  • 3
  • 33
  • 48
Jason
  • 12,229
  • 20
  • 51
  • 66
  • 6
    If you use [SLF4J](http://www.slf4j.org), you can write: `log.debug("{} has {} apples with him", "John", 10);` SLF4J has a binding that redirects back to `java.util.logging`. – Tomasz Nurkiewicz Aug 12 '11 at 07:17
  • 1
    Please rephrase the question. Tokeninzation is about breaking up a string into constituent pieces and generates outputs not inputs. Your example suggests you are asking how to format, not tokenize. – Ray Toal Aug 12 '11 at 07:19

4 Answers4

25

Use MessageFormat:

String s = MessageFormat.format("{0} has {1} apples with him", "John", 10);

or String.format:

String s = String.format("%1$s has %2$d apples with him", "John", 10);
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • 2
    For simple cases like this you can just leave out the `1$` and `2$` and use `"%s has %d apples with him"` for `String.format()`. – Joachim Sauer Aug 12 '11 at 07:29
  • +1 for MessageFormat - i was able to convert all my log statements to use MessageFormat will very little effort – Julie Dec 01 '16 at 17:18
  • For me this immediately led to this related question: https://stackoverflow.com/questions/2809633/what-is-the-difference-between-messageformat-format-and-string-format-in-jdk-1-5 – Jaap Mar 21 '22 at 09:17
  • This is not necessary, see answer by David Groomes below. – John Mikic Jul 27 '23 at 16:04
5

Even with just JDK logging, you can use a custom Formatter to handle formatting of log messages with parameters.

For (a simplistic) example:

public class MyFormatter extends Formatter {

    /**
     * @see java.util.logging.Formatter#format(java.util.logging.LogRecord)
     */
    @Override
    public String format(final LogRecord record) {
        return MessageFormat.format(record.getMessage(), record.getParameters());
    }
}

Then to use it, you can configure a logging.properties file with:

java.util.logging.ConsoleHandler.formatter = com.example.MyFormatter
Ben
  • 60,438
  • 111
  • 314
  • 488
Alistair A. Israel
  • 6,417
  • 1
  • 31
  • 40
4

Just use String.format:

String.format
   ("%s has %s apples with him", "John", "10");
Oskar Kjellin
  • 21,280
  • 10
  • 54
  • 93
2

JUL (java.util.logging) supports curly-brace style parameters out-of-the-box. You do not need a third-party logging framework. See below for a single-class working example (spoiler, I still recommend using SLF4J instead of JUL).

import java.time.LocalDateTime;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

class JavaUtilLoggingExample {

    private static final Logger log = Logger.getLogger(JavaUtilLoggingExample.class.getName());

    /**
     * A java.util.logging (JUL) example adapted from the JavaDoc for java.text.MessageFormat.
     * See https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/text/MessageFormat.html
     *
     * Written for the StackOverflow question: https://stackoverflow.com/q/7036765
     */
    public static void main(String[] args) {
        int planet = 7;
        String event = "a disturbance in the Force";

        log.log(Level.INFO, "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.", new Object[]{planet, new Date(), event});

        // The following is printed (pretty good!):
        //
        //        Jan 02, 2022 8:06:59 PM JavaUtilLoggingExample main
        //        INFO: At 8:06:59 PM on Jan 2, 2022, there was a disturbance in the Force on planet 7

        // However, try to modernize your code and use java.time.LocalDateTime instead of java.util.Date and you will be
        // met with a surprise. Given this log statement:
        log.log(Level.INFO, "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.", new Object[]{planet, LocalDateTime.now(), event});

        // The following is printed (not good!):
        //
        //        Jan 02, 2022 8:06:59 PM JavaUtilLoggingExample main
        //        INFO: At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.

        // Why? See this discussion. https://stackoverflow.com/a/66870717

        // By contrast, a similar (but less feature-ful) version of the above log statement written using the
        // SLF4J 'org.slf4j.Logger' class is below. It is much more succinct but it doesn't offer as many formatting
        // features.
        //
        // log.info("At {}, there was {} on planet {}.", new Date(), event, planet);

        // In conclusion, I continually wind back up with SLF4J in even my trivial Java programs despite my
        // once-yearly well-intentioned "Hey, why don't I reduce external dependencies as much as feasible. Can I just use JUL?"
        // efforts. The SLF4J API fits well in practice.
    }
}
David Groomes
  • 2,303
  • 1
  • 21
  • 23