How to use java.util.logging

Basic usage

First of all, the basic usage. The main appearances are the following three.

  1. Logger-An object that outputs logs.
  2. Handler --An object that controls the output destination of the log.
  3. Formatter-An object that controls the format of the log.

First, create a Logger instance.

Logger logger = Logger.getLogger("logger name")

Next, create a Handler instance and register it with logger. You can register multiple Handlers. This time, create a Handler with C: \ sample \ sample.log as the output destination. If you want to output to a file, use the Handler interface implementation class FileHandler.

Handler handler = new FileHandler("C:\\sample\\sample.log");
logger.addHandler(handler);

Finally, create a Formatter instance and register it with Handler. This time, we will use SimpleFormatter to format it in a human-readable format. SimpleFormatter is an implementation class of the Formatter interface.

Formatter formatter =  new SimpleFormatter();
handler.setFormatter(formatter);

Now you are ready to go. Pass the message to logger and output the log.

logger.log(Level.INFO, "message");

As mentioned above, when outputting the log, specify the log level of the message. The following 7 types of log levels are prepared by java.util.logging. The lower you go, the more serious the log becomes.

--FINE ST-- Very detailed trace message --FINER --A fairly detailed trace message --FINE --Detailed trace message --CONFIG --Static configuration message --INFO --Information message --WARNING --Warning message --SEVERE --Critical message

You can set the logger to output only messages above a certain log level. For example, if you want to output only messages of INFO level or higher, set as follows.

logger.setLevel(Level.INFO);

The sample program of basic usage is described below.

BasicLoggingSample


package sample;

import java.io.IOException;
import java.util.function.Supplier;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

public class BasicLoggingSample {

	public static void main(String[] arg) throws SecurityException, IOException {
		//Get the logger and set the log level to INFO
		Logger logger = Logger.getLogger(BasicLoggingSample.class.getName());
		logger.setLevel(Level.INFO);

		//Create a handler and register it with the logger
		Handler handler = new FileHandler("C:\\sample\\sample.log");
		logger.addHandler(handler);
		
		//Create a formatter and register it as a handler
		Formatter formatter =  new SimpleFormatter();
		handler.setFormatter(formatter);
		
		//Output INFO message
		logger.log(Level.INFO, "INFO message");

		//There is a simple method to output each log level message.
		logger.finest("FINEST message");
		logger.finer("FINER message");
		logger.fine("FINE message");
		logger.config("CONFIG message");
		logger.info("INFO message");
		logger.warning("WARNING message");
		logger.severe("SEVERE message");
		
		//In addition to the method of passing the message as a character string, Supplier<String>There is also a way to pass.
		Supplier<String> supplier = new Supplier<String>() {
			@Override
			public String get() {
				return "Supply message";
			}
		};
		logger.info(supplier);
		
		//The log output method when an Exception occurs is as follows. The Throwable stack trace passed as an argument is output.
		logger.log(Level.WARNING, "An error has occurred.", new RuntimeException("Runtime error"));
	}
}

Logger hierarchy

Loggers have a hierarchical structure based on namespaces. For example, if you create the following logger,

Logger logger = Logger.getLogger("com.sample.App");

The hierarchical structure is as follows. The parent logger for com.sample.App is com.sample, and the parent logger for com.sample is com. In addition, the parent logger for com will be the root logger.

Root
└─com
    └─sample
        └─App

If the logger prints a message, the output is propagated to the parent logger as well. In other words, in the above example, if you output a message to the com.sample.App logger, the message will also be output from com.sample, com, and the root logger, respectively.

I don't think it's easy to explain in words, so let's take a look at the sample program.

NameSpaceSample


package sample;

import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

public class NameSpaceSample {

	public static void main(String[] arg) throws SecurityException, IOException {
		//Get each logger. To get the root logger, specify an empty string in the logger name.
		Logger root = Logger.getLogger("");
		Logger com = Logger.getLogger("com");
		Logger sample = Logger.getLogger("com.sample");
		Logger app = Logger.getLogger("com.sample.App");
		
		// com.sample.App parents are com.sample、com.The parent of sample is com, and the parent of com is the root logger.
		System.out.println(app.getParent() == sample);
		System.out.println(app.getParent().getParent() == com);
		System.out.println(app.getParent().getParent().getParent() == root);
		
		//The parent of the root logger is null.
		System.out.println(root.getParent());
		
		//Set up a handler for each logger.
		Formatter formatter = new SimpleFormatter();
		Handler rootHandler = new FileHandler("C:\\sample\\root.log");
		root.addHandler(rootHandler);
		rootHandler.setFormatter(formatter);
		
		Handler comHandler = new FileHandler("C:\\sample\\com.log");
		com.addHandler(comHandler);
		comHandler.setFormatter(formatter);
		
		Handler sampleHandler = new FileHandler("C:\\sample\\sample.log");
		sample.addHandler(sampleHandler);
		sampleHandler.setFormatter(formatter);
		
		Handler appHandler = new FileHandler("C:\\sample\\App.log");
		app.addHandler(appHandler);
		appHandler.setFormatter(formatter);
		
		//When you output a message with the app, a message is also output from each parent logger.
		app.info("INFO message");
	}
}

When you run the sample program, the logs will be output to root.log, com.log, sample.log, and ʻApp.log under the C: \ sample` directory.

How to use the filter

I introduced how to set the log level in the logger and control it so that only messages above a certain log level are output, but if you want more detailed control, use the Filter class.

Filter filter = new Filter() {
	@Override
	public boolean isLoggable(LogRecord record) {
		return record.getMessage().contains("Number of cases processed=");
	}
};
logger.setFilter(filter);

If Filter is set as above, only logs that include " number of processes = " in the message will be output.

Set log level and filter in handler

The above explanation showed how to set a log level filter on the logger. In fact, log levels and filters can also be set in Handler.

The sample program is described below.

FiltringSample


package sample;

import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Filter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

public class FiltringSample {
	
	public static void main(String[] arg) throws SecurityException, IOException {
		//Create a logger and set handlers and formatters
		Logger logger = Logger.getLogger("sample1");
		Handler handler = new FileHandler("C:\\sample\\sample.log");
		logger.addHandler(handler);
		handler.setFormatter(new SimpleFormatter());
		
		//Set logger log level to INFO
		logger.setLevel(Level.INFO);
		logger.info("Sample message");                          //Output
		
		//Set a filter on the logger
		Filter filter1 = new Filter() {
			@Override
			public boolean isLoggable(LogRecord record) {
				return record.getMessage().contains("Number of cases processed=");
			}
		};
		logger.setFilter(filter1);
		logger.info("Sample message");                          //Not output
		logger.info("Sample message,Number of cases processed=1");               //Output
		
		//Set a filter on the handler
		Filter filter2 = (record) -> record.getMessage().contains("Number of updates=");
		handler.setFilter(filter2);
		logger.info("Sample message");                          //Not output
		logger.info("Sample message,Number of cases processed=1");               //Not output
		logger.info("Sample message,Number of cases processed=1,Number of updates=1");    //Output
		
		//Set log level in handler
		handler.setLevel(Level.WARNING);
		logger.info("Sample message");                          //Not output
		logger.info("Sample message,Number of cases processed=1");               //Not output
		logger.info("Sample message,Number of cases processed=1,Number of updates=1");    //Not output
		logger.warning("Warning message,Number of cases processed=1,Number of updates=1");   //Output
	}
}

If you execute the above, you can see that the log output is limited by the log level and filter set for the logger and handler.

Log output control in logger hierarchy

We have introduced above that the logger has a hierarchical structure, and that when a message is output to the logger, it propagates to the parent logger. Actually, there is a trap in this propagation mechanism, and if you do not understand the mechanism properly, you may get stuck in a pot. (I fit in ...) It may be difficult to understand even if you explain it in words, but once you explain it in words, the specifications for propagation to the parent logger are as follows.

--The log level filter set for the logger is checked only by the directly called logger. --The log level filter check set in the handler is checked by all handlers including the handler of the parent logger.

Yes, I think it's hard to understand. I think you can understand this faster by looking directly at the logic. Roughly speaking, the log output logic is as shown in the figure below.

フローチャート.png

Did you understand? The log level filter set on the logger is checked only on the first logger that receives the call, whereas it is checked. The log level filter set in the handler is checked by all handlers.

Two samples to confirm this are described below.

NameSpaceSample2


package sample;

import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

public class NameSpaceSample2 {

	public static void main(String[] arg) throws SecurityException, IOException {
		//Get 3 loggers. Set the handler and formatter.
		Logger root = Logger.getLogger("");
		Logger sample = Logger.getLogger("sample");
		Logger loggerTreeSample = Logger.getLogger("sample.NameSpaceSample2");
		Handler rootHandler = new FileHandler("C:\\sample\\root.log");
		Handler sampleHandler = new FileHandler("C:\\sample\\sample.log");
		Handler NameSpaceSample2Handler = new FileHandler("C:\\sample\\NameSpaceSample2.log");
		Formatter formatter = new SimpleFormatter();
		rootHandler.setFormatter(formatter);
		sampleHandler.setFormatter(formatter);
		NameSpaceSample2Handler.setFormatter(formatter);
		root.addHandler(rootHandler);
		sample.addHandler(sampleHandler);
		loggerTreeSample.addHandler(NameSpaceSample2Handler);
		
		//Set the log level to the logger.
		root.setLevel(Level.WARNING);
		sample.setLevel(Level.INFO);
		loggerTreeSample.setLevel(Level.FINE);

		//The handler is set to allow all log levels. (Level.Setting ALL allows the output of all log-level messages. )
		rootHandler.setLevel(Level.ALL);
		sampleHandler.setLevel(Level.ALL);
		NameSpaceSample2Handler.setLevel(Level.ALL);
		
		//Output log
		root.fine("Call from root.FINE message");
		root.info("Call from root.INFO message");
		root.warning("Call from root.WARNING message");
		sample.fine("Send from sample.FINE message");
		sample.info("Send from sample.INFO message");
		sample.warning("Send from sample.WARNING message");
		loggerTreeSample.fine("Called from NameSpaceSample2Handler.FINE message");
		loggerTreeSample.info("Called from NameSpaceSample2Handler.INFO message");
		loggerTreeSample.warning("Called from NameSpaceSample2Handler.WARNING message");
	}
}

When the above is executed, the message output by loggerTreeSample.fine (...) is C: \\ sample \\ root even though it is set as root.setLevel (Level.WARNING); . You can see that it is output to .log.

Here is another sample. The only difference from the sample above is the log level setting.

NameSpaceSample3


package sample;

import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

public class NameSpaceSample3 {

	public static void main(String[] arg) throws SecurityException, IOException {
		//Get 3 loggers. Set the handler and formatter.
		Logger root = Logger.getLogger("");
		Logger sample = Logger.getLogger("sample");
		Logger loggerTreeSample = Logger.getLogger("sample.NameSpaceSample2");
		Handler rootHandler = new FileHandler("C:\\sample\\root.log");
		Handler sampleHandler = new FileHandler("C:\\sample\\sample.log");
		Handler NameSpaceSample3Handler = new FileHandler("C:\\sample\\NameSpaceSample3.log");
		Formatter formatter = new SimpleFormatter();
		rootHandler.setFormatter(formatter);
		sampleHandler.setFormatter(formatter);
		NameSpaceSample3Handler.setFormatter(formatter);
		root.addHandler(rootHandler);
		sample.addHandler(sampleHandler);
		loggerTreeSample.addHandler(NameSpaceSample3Handler);
		
		//The logger is set to allow all log levels. (Level.Setting ALL allows the output of all log-level messages. )
		root.setLevel(Level.ALL);
		sample.setLevel(Level.ALL);
		loggerTreeSample.setLevel(Level.ALL);

		//Set the log level in the handler.
		rootHandler.setLevel(Level.WARNING);
		sampleHandler.setLevel(Level.INFO);
		NameSpaceSample3Handler.setLevel(Level.FINE);
		
		//Output log
		root.fine("Call from root.FINE message");
		root.info("Call from root.INFO message");
		root.warning("Call from root.WARNING message");
		sample.fine("Send from sample.FINE message");
		sample.info("Send from sample.INFO message");
		sample.warning("Send from sample.WARNING message");
		loggerTreeSample.fine("Called from NameSpaceSample3Handler.FINE message");
		loggerTreeSample.info("Called from NameSpaceSample3Handler.INFO message");
		loggerTreeSample.warning("Called from NameSpaceSample3Handler.WARNING message");
	}
}

If you execute the above, you can see that only WARNING level logs are output to C: \\ sample \\ root.log.

Read configuration file

As you may have seen in the sample programs so far, writing a lot of code to set up loggers and handlers can be tedious. After all, I want to push the setting part out of the program and write it in the setting file. Therefore, the next method is to read the configuration file from the outside.

The method to read the configuration file from the program is as follows. This time, I tried to read logging.properties located in the same classpath of the sample program. The configuration file should be read in the java.util.Properties format.

LogManager.getLogManager().readConfiguration(SettingFileSample.class.getResourceAsStream("logging.properties"));

The sample configuration file is as follows. Please refer to {java.home} \ lib \ logging.properties for a detailed explanation.

logging.properties


#Root logger handler log level setting ConsoleHandler has a standard error(System.err)Output the log to.
handlers=java.util.logging.ConsoleHandler
.level=INFO

#Logger used in the sample program"sample.SettingFileSample"settings of
sample.SettingFileSample.level=FINE
sample.SettingFileSample.handlers=java.util.logging.FileHandler

#ConsoleHandler settings
java.util.logging.ConsoleHandler.level=INFO
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter

#FileHandler settings
java.util.logging.FileHandler.pattern=C:/sample/sample.log
java.util.logging.FileHandler.limit=1000
java.util.logging.FileHandler.count=1
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter

The sample program using the above configuration file is described below.

SettingFileSample


package sample;

import java.io.IOException;
import java.util.logging.LogManager;
import java.util.logging.Logger;

public class SettingFileSample {

	public static void main(String[] arg) throws SecurityException, IOException {
		LogManager.getLogManager().readConfiguration(SettingFileSample.class.getResourceAsStream("logging.properties"));

		Logger logger = Logger.getLogger("sample.SettingFileSample");
		logger.finer("FINER message");
		logger.fine("FINE message");
		logger.info("INFO message");
	}
}

It's neat because there are no logger or handler settings.

How to use ResourceBundle with logger

java.util.logging can also support internationalization using ResourceBundle. The sample program is described below. The sample uses resource_ja.properties and resource_en.properties in the same classpath as the Java class.

ResourceBundleSample


package sample;

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

public class ResourceBundleSample {

	public static void main(String[] arg) {
		Logger lggr = Logger.getLogger(ResourceBundleSample.class.getName());
		lggr.setResourceBundle(ResourceBundle.getBundle("sample.resource", Locale.JAPANESE));
		lggr.info("ID1");
		
		lggr.setResourceBundle(ResourceBundle.getBundle("sample.resource", Locale.ENGLISH));
		lggr.info("ID1");
	}
}

resource_ja.properties


ID1=Japanese message

resource_en.properties


ID1=english message

When the sample program is executed, the first log is output as Japanese message and the second log is output as ʻenglish message`.

How to use security manager with logger

If you enable Security Manager, you will not be able to programmatically change the logger settings. When the following sample program is executed with Security Manager enabled, ʻAccessControlException` is executed.

LoggingPermissionSample


package sample;

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

public class LoggingPermissionSample {
	
	public static void main(String[] arg) {
		Logger lg = Logger.getLogger("");
		lg.setLevel(Level.FINE);
		lg.fine("fine message");
		lg.info("info message");
	}
}

To allow logger changes when Security Manager is enabled, write the following in the policy file: For details, refer to the Javadoc of LoggerPermission.

java.policy


grant {
        permission java.util.logging.LoggingPermission "control", "";
}

To enable the security manager, specify java.security.manager in the VM argument as shown below. To specify the policy file explicitly, specify java.security.policy in the VM argument as shown below.

java -Djava.security.manager -Djava.security.policy=policy file path sample.LoggingPermissionSample

Recommended Posts

How to use java.util.logging
How to use Map
How to use rbenv
How to use letter_opener_web
How to use with_option
How to use fields_for
How to use map
How to use collection_select
How to use Twitter4J
How to use active_hash! !!
How to use MapStruct
How to use hidden_field_tag
How to use TreeSet
[How to use label]
How to use identity
How to use hashes
How to use JUnit 5
How to use Dozer.mapper
How to use Gradle
How to use org.immutables
How to use java.util.stream.Collector
How to use VisualVM
How to use Map
[Java] How to use Map
How to use Chain API
[Java] How to use Map
How to use Priority Queuing
[Rails] How to use enum
How to use java Optional
How to use JUnit (beginner)
How to use Ruby return
[Rails] How to use enum
How to use @Builder (Lombok)
[Swift] How to use UserDefaults
How to use java class
How to use Swift UIScrollView
How to use Big Decimal
[Java] How to use Optional ②
[Java] How to use removeAll ()
How to use String [] args
[Java] How to use string.format
How to use rails join
How to use Java Map
Ruby: How to use cookies
How to use dependent :: destroy
How to use Eclipse Debug_Shell
How to use Apache POI
[Rails] How to use validation
How to use Java variables
[Rails] How to use authenticate_user!
[Rails] How to use "kaminari"
How to use GC Viewer
[Java] How to use Optional ①
How to use Lombok now
[Creating] How to use JUnit
[Rails] How to use Scope
How to use the link_to method
[Rails] How to use gem "devise"
How to use Lombok in Spring
How to use StringBurrer and Arrays.toString.
How to use arrays (personal memorandum)