In the course of my work at DataArt, I, among other things, engage in mentoring activities. In particular, this includes checking the training tasks done by the trainees. Recently in tasks a tendency of “strange” use of loggers has been outlined. My colleagues and I decided to include a link to an article describing the java logging best practices in the text of the assignment, but it turned out that such an article in which would simply and without unnecessary details explain how to write to the log in Java, located.
This article does not contain any revelations, it does not consider the subtleties of any of the numerous java logging frameworks. Here I tell you how to write to the log so that it does not cause surprise to your colleagues, the main purpose of writing is to include it in the list of mandatory reading for trainees. If still interesting, read on.
A few explanations.
- All sample code uses the java.util.logging framework. The question “Which of the logging frameworks is kosher” I leave behind the scenes. I can only say that the easiest way to reach java.util.logging is because it already goes along with the JRE and in fact is told in this article with minimal cosmetic edits true for the vast majority of logging systems.
- In general, the recipes given in this article are not the only true ones, there are points about which can be argued, but in general these recipes have been used for many years, by many developers, in many projects and they are good enough to follow them if you don’t have any serious objections.
- The article does not consider such "advanced" topics as:
- Configuring levels for individual loggers
- Formatting Logs
- Asynchronous logging
- Creating your own logging levels in Log4J
- Contextual logging
- And much more
- The word logging I write in Russian as logging with a single letter “g” is mostly due to the fact that such a translation option is more common
- Tips that, with what level of logging, I probably also leave behind the scenes, because it all depends strongly on the application, operating conditions, customer relations, etc. fine things.
')
Example â„–1
Good
public class SomeClass { private static Logger log = Logger.getLogger(SomeClass.class.getName()); public void someMethod() { log.info("Some message"); } ...
- Logger is a static class field initialized when the class is loaded, has a simple, short name. It is important that all of your classes have the same variable name for the logger (this is dictated by the general rule, the same things in the program should be done in the same way).
- As a logger name, I use the class name, in fact, this is not the only way, you can try to organize some kind of logging hierarchy (for example, transport layer / app layer for subsystems dealing with data exchange), but as practice shows, invent and then the main thing It is extremely difficult to strictly follow this hierarchy, and the variant with the names of the loggers matching the class names is very good and is used in 99% of projects
- Here, to write to the log, I use the short method .info, and not the more general method .log, so much more concise
- The name of the logger is taken as SomeClass.class.getName (), and not as “com.dataart.demo.java.logging.SomeClass”, both methods are the same, but the first one protects you from surprises when refactoring a class name / package
poorly
public class SomeClass { public void someMethod() { Logger.getLogger("com.dataart.demo.java.logging.SomeClass").log(Level.INFO,"Some message"); } ...
In fact, the same thing but more letters and not read so easily.
Remark between examples
You probably noticed that all the messages in the examples in English. This is not by chance. The fact is that even if all-all who work and will work with your code speak Russian, there is a chance that you will have to view the log messages on a remote computer, for example, via ssh and in a large number of cases you will see something like this message "? ???, ???? ?????? " (I certainly know that Russian letters can be thrust through ssh, but for some reason, not always everything is set up properly).
Or even on the local machine in cmd you can see what is this:
INFO: ╨╨░╨║╨╛╨╡-╤╨╛ ╤╨╛╨╛╨▒╤╨╡╨╜╨╕╨╡ ╨▓ ╨╗╨╛╨│
You can certainly fight this too. But it is not always easy to explain to the customer at that end of the handset how to make Russian letters visible instead of cracks.
Tip: Write a log message in English, well, or at least in Latin letters.
Example 2
Good
try { throw new Exception("Some exception"); } catch (Exception ex) { log.log(Level.SEVERE, "Exception: ", ex); } // log.fine("some minor, debug message"); if (log.isLoggable(Level.FINE)) { log.fine("Some CPU consuming message: " + prepareCPUConsumingLogMessage()); }
- If you need to log an exception, use the .log method (level, message, exception)
- If you have not specifically configured the system log configuration, messages with a level below info, for example, fine will not be displayed. But writing them at least for important parts of the system is worth it. When something goes wrong, you will set up a more detailed logging level and you will see a lot of interesting things.
- Too many log messages, even if they are not physically written to the log file because of their too low level, can significantly slow down the execution of the program. Especially if you need to spend a lot of resources to prepare the message itself. For this there is a method .isLoggable (level) - it lets you know whether the current configuration of the logger will miss this message
poorly
try { throw new Exception("Some exception"); } catch (Exception ex) { log.severe("Exception: " + ex.toString() ); } log.fine("Some CPU consuming message: " + itTakes500MillisecondsToPrepageThisMessage());
If you log only ex.toString (), then you will not be able to understand in which string the exception initially worked.
Example 3
Logger need to be configured. There is a default configuration. It displays all messages with the INFO level and above to the console. It is good enough for development from the IDE, but for a real application it would usually be nice to correct it.
What options are there
Default: File logging.properties for INFO level, output to console
#Console handler
handlers= java.util.logging.ConsoleHandler
.level=INFO
Making the logging more detailed we also output the messages of the FINE level.
#Console handler
handlers= java.util.logging.ConsoleHandler
.level=FINE
java.util.logging.ConsoleHandler.level = FINE
What we did here
- Set the FINE level for the root logger, just so that the messages crawl through the system log.
- And they said that all that would get through the log system should be displayed on the console from the FINE level and above.
Display the message log somewhere else
What is bad console output? The console is essentially a good old
stderr . What does it mean:
- If the application is started using javaw, you will not see anything at all.
- If the output goes to the console and the message you need flashed 4 hours ago, the console's buffer has already eaten it, the information is gone.
- If the console output is sent to the java com.yourcompanyname.EntryClass 2 >> application_log.txt file and the application runs without stopping for several weeks - the file will be very, very large, risking to occupy the entire disk.
To solve these problems, java.util.logging.FileHandler was invented - a handler that outputs a log message to a file. At the same time, he can rotate files, i.e. after reaching the maximum allowable size, it adds a message to the current log file and opens a new file with an incremental prefix. And so in a circle. for example
handlers= java.util.logging.FileHandler java.util.logging.FileHandler.pattern = application_log.txt java.util.logging.FileHandler.limit = 50 java.util.logging.FileHandler.count = 7 java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
will create such files (the last column is the size in bytes)
application_log.txt.0 0
application_log.txt.1 │ 79
application_log.txt.2 │ 79
application_log.txt.3 │ 676
application_log.txt.4 │ 87
application_log.txt.5 114
We specified a maximum size of 50 bytes, in real life, you should rather specify at least a megabyte, for example like this (I know that 1,000,000 is a little less than a megabyte, but who wants to write 1048576 from memory, if that doesn’t change the essence of the matter)
java.util.logging.FileHandler.limit = 1,000,000
In the example, as we can see, the files turned out to be more than 50 bytes because the size is essentially rounded up to the last whole message log. Those. if you specify a size of 1 byte and write a log message with a size of 1000 bytes, the file size will become 1000 bytes and after that the message log will close and the next one will open.
copy & paste config for real life, it is enough for most service, console and desktop applications.
handlers = java.util.logging.FileHandler
java.util.logging.FileHandler.pattern = application_log.txt
java.util.logging.FileHandler.limit = 1,000,000
java.util.logging.FileHandler.count = 5
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
The last part of the magic
Well, the last thing left to tell is how to actually configure the logger from the properties file. There are two ways:
- From the command line launch application
- In the first lines of your application code
The first one is slightly more correct because it is declarative and works right before the code of your application starts working.
Like this
java Djava.util.logging.config.file=logging.properties com.dataart.application.ClassName
But unfortunately, changing the launch string is not always possible or not always convenient. The second method also works well.
public static void main(String[] args) { try { LogManager.getLogManager().readConfiguration( MainApplicationEntryClass.class.getResourceAsStream("/logging.properties")); } catch (IOException e) { System.err.println("Could not setup logger configuration: " + e.toString()); } .....
- Here MainApplicationEntryClass is a class - the entry point to your application, apparently you will have a different class name
- The logging.properties file itself is usually placed in the root of the class hierarchy in such cases and looks like this, for example

What's left overs
In real life, at least half of all Java applications are web applications. The logging technique itself does not differ at all from the above. Well, maybe with the exception that different application servers can use different logging libraries such as for example:
- Log4J
- JULI logger (strictly speaking, this is not a completely independent framework, but a kind of add-on over java.util.logging)
- SLF4J
- Commons logging
Accordingly, the configuration and method names differ somewhat. But the principle itself changes little. Specific features are usually well described in the documentation for the application server itself, for example