📜 ⬆️ ⬇️

Java / quick start logging

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.

')
Example â„–1


Good


public class SomeClass { private static Logger log = Logger.getLogger(SomeClass.class.getName()); public void someMethod() { log.info("Some message"); } ... 


  1. 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).
  2. 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
  3. Here, to write to the log, I use the short method .info, and not the more general method .log, so much more concise
  4. 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()); } 


  1. If you need to log an exception, use the .log method (level, message, exception)
  2. 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.
  3. 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


Display the message log somewhere else


What is bad console output? The console is essentially a good old stderr . What does it mean:


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:
  1. From the command line launch application
  2. 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()); } ..... 





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:


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

Source: https://habr.com/ru/post/130195/


All Articles