2

Currently, all my INFO, SEVERE and FINE logs are printed with red colour. I want to change the INFO and FINE logs to be white colour.

I found many articles to change the colour by creaing a new Fommater. I am wondering how could I change the printing colour by modifying the logging.properties?

I am using Java default logging library Util.Logging.Logger

Environment:

  • Ecipse 2018-12 (4.10.0)
  • Windows 10
Spider
  • 1,380
  • 4
  • 22
  • 42

3 Answers3

3

The problem is that Eclipse always shows stderr output in the same color (in this case red). It's configurable in settings but it will always be the same for all stderr stream.

My solution is to use a custom formatter for the console handler and inject ANSI color codes before each message depending on its level. So I made that, based on the original SimpleFormatter.java in JDK8. Here's the code:

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;

public class CustomFormatter extends Formatter {

    public static final String ANSI_RESET = "\u001B[0m";
    public static final String ANSI_RED = "\u001B[31m";
    public static final String ANSI_YELLOW = "\u001B[33m";
    public static final String ANSI_CYAN = "\u001B[36m";

    private final Date dat = new Date();
    private static final String format = "%1$s %2$tb %2$td, %2$tY %2$tl:%2$tM:%2$tS %2$Tp %3$s%n%5$s: %6$s%7$s%n";

    @Override
    public String format(LogRecord record) {
        dat.setTime(record.getMillis());
        String source;
        if (record.getSourceClassName() != null) {
            source = record.getSourceClassName();
            if (record.getSourceMethodName() != null) {
                source += " " + record.getSourceMethodName();
            }
        } else {
            source = record.getLoggerName();
        }
        String message = formatMessage(record);
        String throwable = "";
        if (record.getThrown() != null) {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            pw.println();
            record.getThrown().printStackTrace(pw);
            pw.close();
            throwable = sw.toString();
        }

        switch (record.getLevel().toString()) {
            case "INFO":
                return String.format(format, ANSI_CYAN, dat, source, record.getLoggerName(),
                        record.getLevel().getLocalizedName(), message + ANSI_RESET, throwable);
            case "WARNING":
                return String.format(format, ANSI_YELLOW, dat, source, record.getLoggerName(),
                        record.getLevel().getLocalizedName(), message + ANSI_RESET, throwable);
            case "SEVERE":
                return String.format(format, ANSI_RED, dat, source, record.getLoggerName(),
                        record.getLevel().getLocalizedName(), message + ANSI_RESET, throwable);
            default:
                return String.format(format, dat, source, record.getLoggerName(),
                        record.getLevel().getLocalizedName(), message, throwable);
        }
    }
}

Prerequisites

  • ANSI Escape in Console plugin for Eclipse. You'll need this so the Eclipse console can interpret ANSI Escape codes. Install it and restart Eclipse.

  • The code above compiled and zipped into a .jar file:

    1. Save the code above as CustomFormatter.java
    2. Compile it with javac CustomFormatter.java
    3. Create a JAR File Containing the Class File with jar cfv CustomFormatter.jar CustomFormatter.class and save it in whatever folder you want (for example, in C:\java\CustomFormatter)

Instructions

  • Go to Window --> Preferences --> Ansi Console and check Try using the standard error color setting for stderr output, then Apply and Close.
  • Edit logging.properties file, which is located in the lib folder of your JRE. You may have multiple ones in your computer, you should edit the one corresponding to the JRE version that Eclipse is using. You can know which one is using by reading below the "Console" tab in Eclipse: JRE folder

    1. Open logging.properties with a text editor. In my case, I'll edit C:\Program Files\Java\jre1.8.0_231\lib\logging.properties.
    2. You should change java.util.logging.ConsoleHandler.formatter value (in my case it's the 44th line) so it's equal to CustomFormatter, exactly like this: java.util.logging.ConsoleHandler.formatter = CustomFormatter. Make sure you save the changes.
  • Add CustomFormatter.jar as a JRE system library in Eclipse.

    1. Go to Window --> Preferences --> Java --> Installed JREs
    2. Select the JRE that you're using, click Edit and Add External JARs...
    3. Go to the folder in which you saved CustomFormatter.jar and select it.
    4. Make sure it's on the list of system libraries and click Finish and Apply and Close
    5. That's it. You should have different colors for each Logger level now. It's cyan for INFO, yellow for WARNING and red for SEVERE. You can change it to whatever color you want by modifying the code above with the corresponding ANSI Color code. It's working for me with java 8 and Eclipse 2019-12:

      Result

NOTE: If normal stdout text appears blue, red or yellow try to disable Limit console output in Window --> Preferences --> Run/Debug --> Console

jajube
  • 319
  • 2
  • 5
1

Currently, all my INFO, SEVERE and FINE logs are printed with red colour.

That depends on what process is consuming System.err. Since the output is red I assume you are using an IDE. Which IDE are you using? Perhaps it has settings to modify how the console output is rendered. For eclipse, you can:

  1. Change the Standard Out/Standard Error text color so that Standard Out is white and Standard Error is red.
  2. Create a regular ConsoleHandler that is set to level WARNING. This will direct all warnings and above to the ERR stream which will be red.
  3. Create a special Handler to print to Standard OUT and set the level to ALL.
  4. Create a java.util.logging.Filter to filter out messages that are greater than INFO for the Standard OUT handler and install it on that handler.
  5. Attach both the console handler (ERR) and handler for OUT to the root logger.

I am wondering how could I change the printing colour by modifying the logging.properties?

Only thing you can do from the logging.properties is install a new type of Formatter or a 3rd party Handler that may be able to change the output color but, it depends on how the consumed console output stream is rendered (E.G HTML vs. BASH terminal).

jmehrens
  • 10,580
  • 1
  • 38
  • 47
  • I am using Eclipse. Ok, maybe I have to create a custom formatter. – Spider Feb 28 '19 at 17:25
  • Thank you for your solution! But I will move to other logging framework, as Java detault logging framework has so many problems. – Spider Mar 01 '19 at 16:05
  • @Spider if you want to create a custom formatter, check my answer. I did it based on the original `SimpleFormatter.java` and it works! I used ANSI Color Codes so INFO level is cyan, WARNING level is yellow and SEVERE level is red – jajube Mar 02 '20 at 09:42
0

Great answer from jajube. I use netbeans 8.2. Its console has default red text but handles ANSI codes. I modified his answer to the formatter below

package net.sf.jaer.util;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;

/**
 * Based on
 * https://stackoverflow.com/questions/54909752/how-to-change-the-util-logging-logger-printing-colour-in-logging-properties
 * with ANSI codes from
 * https://stackoverflow.com/questions/5762491/how-to-print-color-in-console-using-system-out-println
 *
 * @author tobid Jan 2021
 */
public class LoggingAnsiColorConsoleFormatter extends Formatter {

    public static final String ANSI_RESET = "\u001B[0m";
    public static final String ANSI_BLACK = "\u001B[30m";
    public static final String ANSI_RED = "\u001B[31m";
    public static final String ANSI_GREEN = "\u001B[32m";
    public static final String ANSI_YELLOW = "\u001B[33m";
    public static final String ANSI_BLUE = "\u001B[34m";
    public static final String ANSI_PURPLE = "\u001B[35m";
    public static final String ANSI_CYAN = "\u001B[36m";
    public static final String ANSI_WHITE = "\u001B[37m";
    public static final String ANSI_BLACK_BACKGROUND = "\u001B[40m";
    public static final String ANSI_RED_BACKGROUND = "\u001B[41m";
    public static final String ANSI_GREEN_BACKGROUND = "\u001B[42m";
    public static final String ANSI_YELLOW_BACKGROUND = "\u001B[43m";
    public static final String ANSI_BLUE_BACKGROUND = "\u001B[44m";
    public static final String ANSI_PURPLE_BACKGROUND = "\u001B[45m";
    public static final String ANSI_CYAN_BACKGROUND = "\u001B[46m";
    public static final String ANSI_WHITE_BACKGROUND = "\u001B[47m";

    private final Date date = new Date();
    // FORMAT uses e.g. 2$ which refers to 2nd argument of String.format
    // It has two lines: Line 1 is the date and class/method. Line 2 is the LEVEL and message
    // Lines are separated by the format spec %n which makes newline
    // This format puts date and class/method in CYAN, followed by newline with level colored, followed by default message color
    private static final String FORMAT = ANSI_CYAN+"%2$tb %2$td, %2$tY %2$tl:%2$tM:%2$tS %2$Tp %3$s%n%1$s%5$s:" + ANSI_RESET + " %6$s%7$s%n";
    // args to String.format
    // 1 ansi code
    // 2 date 
    // 3 source (class/method) 
    // 4 logger name 
    // 5 level 
    // 6 message, 
    // 7 throwable
    // output example
    // Jan 05, 2021 7:09:55 AM net.sf.jaer.eventprocessing.filter.BackgroundActivityFilter resetFilter
    //INFO: resetting BackgroundActivityFilter

    @Override
    public String format(LogRecord record) {
        date.setTime(record.getMillis());
        String source;
        if (record.getSourceClassName() != null) {
            source = record.getSourceClassName();
            if (record.getSourceMethodName() != null) {
                source += " " + record.getSourceMethodName();
            }
        } else {
            source = record.getLoggerName();
        }
        String message = formatMessage(record);
        String throwable = "";
        if (record.getThrown() != null) {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            pw.println();
            record.getThrown().printStackTrace(pw);
            pw.close();
            throwable = sw.toString();
        }

        switch (record.getLevel().toString()) {
            case "INFO":
                return String.format(FORMAT, ANSI_GREEN_BACKGROUND+ANSI_BLACK, date, source, record.getLoggerName(),
                        record.getLevel().getLocalizedName(), message + ANSI_RESET, throwable);
            case "WARNING":
                return String.format(FORMAT, ANSI_YELLOW_BACKGROUND+ANSI_BLACK, date, source, record.getLoggerName(),
                        record.getLevel().getLocalizedName(), message + ANSI_RESET, throwable);
            case "SEVERE":
                return String.format(FORMAT, ANSI_RED_BACKGROUND + ANSI_WHITE, date, source, record.getLoggerName(),
                        record.getLevel().getLocalizedName(), message + ANSI_RESET, throwable);
            default:
                return String.format(FORMAT, date, source, record.getLoggerName(),
                        record.getLevel().getLocalizedName(), message, throwable);
        }
    }
}

It is instantiated in my Logging.properties that I specify in startup by

-Djava.util.logging.config.file=conf/Logging.properties

The Logging.properties has this line

java.util.logging.ConsoleHandler.formatter = net.sf.jaer.util.LoggingAnsiColorConsoleFormatter

Output appears like this

console logger sample

tobi delbruck
  • 301
  • 2
  • 9