Explain the correct use posture of Java log in detail

  • 2021-07-22 09:37:25
  • OfStack

Preface

As for the log, it is relatively simple in everyone's impression, only the related dependency package is introduced, and the rest is to print the information we need to "enjoy" in the project. However, the simpler things are, the easier it is for us to ignore them, which leads to some bug that should not happen. As a rigorous programmer, how can this happen? So let's take a look at the correct gestures for logging.

Text

Log specification

Naming

The first is the naming of log files. Try to see the name and know the meaning. The team must also use the naming convention of Unified 1, otherwise the "dirty and messy" log files will affect the efficiency of troubleshooting problems. It is recommended to name it with "projectName_logName_logType. log", so that you can clearly know which project, what type and what function the log file belongs to. For example, in our MessageServer project, the log file name related to monitoring Rabbitmq consumers can be defined as "messageserver_rabbitmqconsumer_monitor. log".

Preservation time

As for the time of log saving, it is recommended to keep ordinary log files for 15 days. If it is more important, it can be extended according to the actual situation. Please refer to the disk space of each server and the size of log files to make the best choice.

Log level

Common logging levels are as follows:

DEBUG level: Logs information about the debugger. INFO level: Record meaningful information about the normal operation of the program. WARN level: Logs information that potential errors may occur. ERROR level: Record current program error information, need to be concerned about processing. Fatal level: Indicates that a serious error has occurred and the program will be interrupted.

It is recommended to use these four levels in the project, ERROR, WARN, INFO, DEBUG.

Correct posture

1. Judge the log level in advance


// Conditional judgment 
if(logger.isDebugEnabled){
  logger.debug("server info , id : " + id + ", user : " + user);
}

// Use placeholders 
logger.debug("server info , id : {}, user : {}",id,user);

For DEBUG and INFO level logs, there are relatively high frequencies in our programs. When our projects are large, there are more logs. At this time, in order to run the program efficiently, we must print logs in the form of conditional judgment or placeholders. Why? If the log level configured in our project is WARN, then for our following log output statement 'logger. debug ("server info, id:" + id + ", user:" + user);', although the log will not be printed, it will perform string splicing operation. Here, our user is an instance object, so it will also execute toString method, which wastes a lot of system resources.

2. Avoid redundant log output

In our production environment, the output of DEBUG log is generally prohibited, and its printing frequency is very high, which can easily cause serious impact on the normal running program. In our recent project, we encountered a similar situation.

Then it's time to learn to use the additivity attribute


<logger name="xx" additivity="true">

If it is configured as true here, that is, the default situation. At this time, the current Logger will inherit the Appender of the parent Logger. To put it bluntly, the output of the current log will be output to the parent file besides the current log file. Therefore, in general cases, in order to avoid repeated printing, we will set this parameter to false to reduce unnecessary output.

3. Ensure the integrity of log records

In our code, the content of the log record should include the stack of exceptions. Please do not output simple logs such as "XX Error" at will, which is of no help to debug errors. Therefore, when we record exceptions, we must bring stack information, such as


logger.error("rabbitmq consumer error,cause : "+e.getMessage(),e);

Remember that when you output an object instance, make sure that the object overrides the toString method, otherwise only its hashCode value will be output.

4. Define the logger variable as static


private static final Logger logger = LoggerFactory.getLogger(XX.class);

Make sure that only one Logger object is used for one object, and avoid recreating it every time, otherwise it may lead to OOM.

5. Use log levels correctly


try{
  //..
}catch(xx){
  logger.info(..);
}

In this way, the original information of ERROR is all printed in the log file of INFO. Unsuspecting colleagues will still stare at the error log, and they can't find any problems, which will affect the work efficiency, right?

6. The combination of slf4j+logback is recommended

The logback library already implements the interface of slf4j, so there is no need to introduce redundant adapters. Moreover, logback has more advantages, so it is recommended that new projects can use this combination.
There is another point to note. After introducing slf4j, we should pay attention to whether the log library actually used is introduced by us, and it may also use the log library brought by our third-party dependency package, which may lead to the invalidation of our log.

7. Aggregation analysis of logs

The aggregation of logs can integrate logs located between different servers for analysis and processing. Nowadays, ELK technology stack or EFG (fluentd+elasticsearch+grafana) are all mature open source solutions.

Take ELK as an example, we can read the log file printed by the application directly through logstash on our server, or we can configure the relevant socket information in the log configuration file in our project, and output the log information directly to logstash when printing. Then it is stored by elasticsearch and displayed by kibana.

Conclusion

Ok, talk about the log first so much ~ if you need to add or communicate, you can leave a message below.


Related articles: