Source: author: GeekerLou jianshu.com/p/546e9aace657

I. Introduction to logs

1.1 WHAT is a Log (WHAT)

Log: Record the running track of the program, which is convenient to find key information and quickly locate and solve problems.

Usually, Java programmers rely on Eclipse/IDEA and other integrated development tools to track and resolve bugs when developing projects. But what if the project is released to a test or production environment? You may say you can use remote debugging, but you are not allowed to do so.

Therefore, logs are a means for developers and testers to locate problems when there is no Debug tool in the test or production environment. A good log can quickly locate and solve online problems according to the track of the log. Otherwise, a bad log output cannot assist in locating problems but may affect the running performance and stability of the program.

Logging is used in many places to introduce AOP, and in fact logging is extremely unscientific when it comes to cutting aspects! It is never enough for logs to simply output something at the start, end, or exception of a method, and such logs have no meaning for log analysis. What if you start and end the entire log in a method? If there is no logging in a method, then logging is meaningless! If there is a problem with your application, it is useless to look up the cause. Such a log may as well not be used!

1.2 What Are Logs For? (WHY)

Logging is almost everywhere, no matter what programming language you use. To sum up, logs can be used in the following ways:

  • “Problem Tracking” : assist in troubleshooting and locating online problems to optimize program performance.
  • Status Monitoring: You can monitor the running status of the system by analyzing logs.
  • Security audit: Security audit is mainly concerned with security. Unauthorized operations can be discovered.

1.3 summarize

Logging is very, very important in an application. Good logging information can help us quickly locate bugs in the application and find out the cause.

As a cultured programmer, the log should be paid enough attention to.

2. Logging Framework (HOW)

2.1 Common Log frameworks

Log4j, Logging, Commons-logging, slf4J, logback, slf4J, slF4J, logback, slf4J, logback, slf4J, logback, slF4J, logback Look at the breakdown below:

2.1.1 Logging

This is a Java logging utility class that has been available since JDK 1.5, under the java.util.logging package. Usually, it’s not used anymore, so just take a look.

2.1.2 commons-logging

Commons-logging is a logging facade interface. It is also the first logging facade interface provided by Apache. Users can choose different logging implementation frameworks according to their preferences without changing the log definition. It’s not very popular anymore, so just find out.

2.1.3 Slf4j

Slf4j, short for “Simple Logging Facade for Java”, provides a Simple Logging Facade for Java. The Facade, the lower level is the interface. It allows users to access different logging systems through SLF4J in their projects to their liking.

The SLF4J entry is therefore a collection of interfaces that are not responsible for the specific logging implementation, but for finding the appropriate logging system to bind to at compile time. The specific interfaces are defined in SLF4J-API. Slf4j-api: Public Final Class LoggerFactory slF4J-API: Public Final Class LoggerFactory So SLF4J-API is essentially an interface definition.

2.1.4 Log4j

Log4j is an open source logging framework for Apache and is the most popular.

Note: Log4j was discontinued by Apache on 08.05, 2015, and users need to switch to Log4j2.

Here is the official announcement:

On August 5, 2015 the Logging Services Project Management Committee announced that Log4j 1.x had reached end of life. For complete text of the announcement please see the Apache Blog. Users of Log4j 1 are recommended to upgrade to Apache Log4j 2.

2.1.5 Log4j2

Log4j 2 Apache Log4j 2 is an upgrade product of Log4j developed by Apache.

Log4j2 is very different from Log4j1, Log4j2 is not compatible with Log4j1.

2.1.6 Logback

Slf4j Logback is the native implementation framework of Slf4j, which is also written by Log4j itself, but has more advantages, features and better performance than Log4j, and is now basically used to replace Log4j as the mainstream.

Logback has a much faster execution speed than Log4j. Based on our previous work on Log4J, LogBack rewrites the internal implementation to be up to 10 times faster for certain scenarios. The components of Logback are faster and require less memory.

2.2 How to Choose a Logging Framework

The consequence of too many options is the difficulty of choosing. In my opinion, there is no best, only the most suitable:

  • Commons-loggin, SLF4J is a logging abstraction facade, not a concrete logging framework. Log4j and LogBack are specific logging implementation frameworks.
  • Where performance is a concern, choosing Logback or implementing your own high-performance Logging API may be more appropriate. Recommendation:slf4j + logback.
  • In projects that already use Log4j, if no problems are found, it may be more appropriate to continue: the recommended combination is:slf4j + log4j2.
  • If you don’t want dependencies, use java.util.logging or the logging interface already provided by the framework container.

Third, the timing of logging

Do we ever get bogged down in our online journals? There are no logs, a lot of useless logs, or the information needed is scattered in all corners, especially in the case of urgent online bugs, effective logs are flooded by a large number of meaningless log information, anxious and helpless to waste a lot of energy to query logs. So when is the right time to log?

To summarize a few points for logging:

  • “Programming language prompts exceptions” : All major programming languages today include exception mechanisms, and popular business-related frameworks have complete exception modules. This type of catch is what the system tells developers to be concerned about and is a very high quality error. Logs should be logged appropriately, using warn or error levels depending on the business situation.
  • “Business process not expected” : In addition to platform and programming language exceptions, the project code is one of the logging scenarios where the results are not expected. Simply put, all process branches can be considered. It is up to the developer to decide whether to tolerate the situation. Common suitable scenarios include incorrect external parameters, data processing problems that result in return codes that are not within a reasonable range, and so on.
  • System core roles and key actions of components: The service actions triggered by the core roles in the system need to be paid attention to and are important indicators to measure the normal running of the system. It is recommended to record info-level logs, for example, the entire process of an e-commerce system user from login to placing an order. Interaction between microservices and service nodes; Core data table addition and deletion; Core component operation, etc. If the log frequency is high or the printing volume is very large, you can refine the key point INFO record, and consider DEBUG level as appropriate.
  • System initialization: startup parameters of a system or service. The initialization of core modules or components depends on some key configurations and provides different services according to different parameters. Be sure to log INFO here, print out the parameters, and start the finished service statement.

Best practices for log printing

4.1 Log variable Definition

Log variables are always constant and are best defined as final static with uppercase variable names.

private static final Logger log = LoggerFactory.getLogger({SimpleClassName}.getClass());
Copy the code

Usually a class has only one log object, and you can define a log in a parent class if you have one.

The log variable type is defined as a facade interface (such as SLF4J Logger), and the implementation class can be Log4j, Logback and other log implementation frameworks. Do not define the implementation class as a variable type, otherwise it is inconvenient to switch the log and does not meet the abstract programming thought.

In addition, it is recommended to introduce lombok’s dependency and annotate the class header with @slf4J so that the log variable can be used to print logs anywhere in the program. It is much simpler to use and does not need to change the original code when refactoring, especially when changing the class name.

4.2 Parameter placeholder format

Use the parameterized form {} placeholder, [] for parameter isolation

Log.debug ("Save order with order no: [{}], and order Amount: [{}]"); Log.debug ("Save order with order no: [{}], and order Amount: [{}]");Copy the code

[] is the output dynamic parameter, {} is used as a placeholder similar to binding variables, and only when it is ready to print the parameters will be processed, easy to locate problems.

If the log framework does not support parameterization and log output does not support this log level, redundant objects will be created and memory will be wasted. In this case, you need to use isXXEnabled to check whether:

Log.isdebugenabled () {if(log.isdebugenabled ()){// If (log.isdebugenabled ()){// If (log.isdebugenabled ()){// If (log.isdebugenabled ()){log.debug("Save order with order no: "+ orderNo + ", and order amount:" + orderAmount); }Copy the code

At least the debug level must be enabled, and the online log level must be higher than INFO.

It is recommended that you use SLF4J’s facade interface, which can output logs in parameterized form, and debug level does not need to use if judgment, simplifying the code.

4.3 Log Format

Log output is mainly in files, including the following contents:

  • Log time
  • Log level This parameter is mainly used
  • Call chain identity (optional)
  • Name of the thread
  • Logger name
  • Log contents
  • Exception stack (not necessarily)
11:44:44. 827 WARN ef3e0120160803114444 [93] [the main] [ClassPathXmlApplicationContext] Exception encountered during the context initialization - cancelling refresh attemptCopy the code

4.3.1 Log Time

As the date and time the log was generated, this data is very important, usually to the millisecond. Because the online log file is generally configured to scroll by day, the date is marked on the file name. Therefore, you can use HH:mm:ss.SSS format instead of the time. Yyyy-mm-dd HH: MM: ss.sss

4.3.2 Log Level

The output of logs is hierarchical. Different logs are generated for different Settings and occasions. The most commonly used logging framework, Log4j, provides a complete description of the logging level. Other logging frameworks are similar.

The following four levels are used:

  • DEBUG: Logs at the DEUBG level are generated during development and testing. Logs of this level should be as detailed as possible. Developers can record detailed information in the DEBUG for debugging, including parameter information, debugging details, and returned value information. In this way, they can analyze problems or exceptions during development or testing.
  • INFO: the INFO log main key information recording system, designed to keep system work normally during the key operation index, the developer can initialize the system configuration, state of business change information, or the user in the core business process handling records to the INFO in the log, convenient daily operations and repetition error back context scenarios. After the project is completed, you are advised to set the log level to INFO in the test environment. Then, you are advised to use the INFO level to check whether you can learn about the application usage and whether the logs provide useful information for troubleshooting when problems occur.
  • WARN: The WARN level mainly outputs warning content that is predictable and planned, for example, when a method entry parameter is empty or the value of the parameter does not meet the conditions for running the method. More detailed information should be output at the WARN level for later log analysis
  • ERROR: Logs of THE ERROR level are generated for unpredictable information, such as errors and exceptions. For example, network communication and database connection exceptions caught in the Catch block have little impact on the entire system process. Logs of the WARN level can be generated. When generating error-level logs, output as much data as possible, such as method input parameters and objects generated during method execution. If the data contains ERROR or exception objects, output these objects together

4.3.2.1 Selecting INFO and DEBUG

DEBUG logs are lower than INFO and contain more detailed information about the system running status during debugging, such as the values of variables. INFO is the default output level of online logs and provides information about the current system status to end users. The output should be meaningful to the end user. From a functional point of view, the output of Info can be regarded as part of the software product, and therefore should be treated with caution. Simulate running online in your head when trying to log INFO. If the log is going to be printed frequently or is not useful for error correction most of the time, you should consider downsizing to DEBUG.

  • The number of info and DEBUG logs printed is much larger than that of ERROR logs. For the sake of the log performance, if the code is core code and the log execution frequency is very high, you must check whether the log design is reasonable and whether you need to downgrade the log to debug logs.
  • Pay attention to the readability of the log and review the log after writing the code to see if it runs smoothly and provides real meaningful information.
  • Log output is common to multiple threads, and if another thread is writing log output, the log output will be interrupted, and the output will not match the expected output.

4.3.2.2 WARN,ERROR selection

It can be used when the expected results are not generated in the process of method or function processing or an error is reported in the framework. Common troubleshooting methods include:

  • Add judgment processing logic, try local solution: add logic judgment swallow alarm is always the best choice.
  • Throw an exception and hand it over to higher-level logic
  • Log and alert
  • Wrap an error with a return code

Generally speaking, logs of the WARN level will not send SMS alarms, while logs of the ERROR level will send SMS alarms or even phone alarms. Logs of the ERROR level indicate that serious problems occur in the system and must be handled immediately, for example, the database is unavailable or key business processes cannot go down. In fact, it is very irresponsible to record the error as long as there is a problem without discriminating the importance of the problem. For mature systems, there will be a complete error reporting mechanism, so when should the error message be sent? Many are based on the number of ERROR logs per unit of time. Therefore, if we treat errors without regard to priorities, we will increase the frequency of false alarms, and over time, our firefighters will not care so much about false alarms, and the alarm will lose its original meaning.

WARN represents recoverable exceptions. This failure does not affect the execution of the next service. Developers may worry that several failures can be tolerated in some scenarios and need to be reminded when the frequency is high. However, if the ERROR log is not recorded, there will be no real-time alarm and the best processing time will be missed.

Emphasize ERROR alarm

  • ERROR level log printing is usually accompanied by an alarm notification. The ERROR should be accompanied by a business function impairment, that is, a very serious problem has occurred in the system mentioned above and someone must take care of it immediately.

ERROR log target

  • Direct and accurate information to the handler: the error message forms its own closed loop.

Problem location:

  • What went wrong and what functions were affected
  • Obtaining help information: Direct help information or storage location of help information
  • Call the police to know the solution or who to call

Log template

Log.error (" [interface name or operation name] [Some error Msg] happens. [Probably Because]. [Probably need to do] [params]." ); Log.error (" [interface name or operation name] [Some error Msg] happens. [Probably Because]. [please contact xxx@xxx] [params]." );Copy the code

4.3.3 Calling the chain identifier

In distributed applications, a user’s request will invoke several services to complete, and these services may be nested. Therefore, the log to complete a request is not in the log file of an application, but scattered in the log file of different application nodes on different servers. This identifier is used to concatenate the invocation log of a request across the system.

Call chain identification format:

  • Unique string (Trace ID)
  • Call hierarchy (SPAN ID)

The call chain identifier is optional. If there is no such data, just print [].

4.3.4 Thread Name

Generally, a synchronous request is completed by the same thread in an application. The output thread name can be classified in the logs generated by each request to distinguish the current request context.

4.3.5 Logger Name

The logger name is usually the class name, and you can simply print the class name in the log file, depending on whether the package name and line number are needed. It is used to find the log output in the class to locate the fault.

4.3.6 Log Content

  • Println and System.err. Println are disabled
  • Parameter change replaces log splicing
  • The object that outputs the log should implement a fast toString method in its class so that only the object class name and hashCode are printed when the log is output
  • Null pointer prevention: Do not call an object’s method in the log to get a value, unless you ensure that the object is not null, it is very likely that the application will generate null pointer exceptions due to logging problems.
Log.debug ("Load student(id={}), name: {}", id, student.getName()); Log.debug ("Load student(id={}), student: {}", id, student);Copy the code

For some log contents that need to be concatenated or that need time or memory to be generated, use log.isxxxxxenable () to judge and then concatenate them. For example:

if (log.isDebugEnable()) {
    StringBuilder builder = new StringBuilder();
    for (Student student : students) {
        builder.append("student: ").append(student);
    }
    builder.append("value: ").append(JSON.toJSONString(object));
    log.debug( "debug log example, detail: {}" , builder );
}
Copy the code

4.3.7 Exception stack

The exception stack, which typically appears in logs at the ERROR or WARN level, contains the system of the method call chain and the source of the exception. The exception stack logs belong to the previous line and must be placed in the previous line during log collection.

4.4 Log Files

Log files are stored in a fixed directory and named according to a template. Recommended log file names are as follows:

Log File name that has been rolled to history: < Application name >[-< Function name >].log.< YYYY-MM-DD >Copy the code

4.5 Log Configuration

Configure different log output modes based on different environments:

  • Local debugging can output logs to the console
  • In the test environment or production environment, a log file is generated every day. If a large number of logs are generated, a log file can be generated every hour
  • Files output in a production environment, consider using asynchronous file output, this kind of way to log will not be refreshed in the file, creates a log time delay, when to stop the application may result in some log failed to refresh in memory to a file to create a loss, but if it is not very high to the requirement of application, can temporarily don’t consider asynchronous log

The logback log tool compresses the previous log file after the log file is rolled to reduce disk space usage. You are advised to enable this function for applications with a large number of logs.

4.6 Log Usage Specifications

  1. In general, only one Logger object is used in an object. Loggers should be static final, and private final is used only in rare cases where you need to pass a Logger ina constructor.
private static final Logger log = LoggerFactory.getLogger(Main.class);
Copy the code
  1. Do not use concrete logging implementation classes
InterfaceImpl interface = new InterfaceImpl();
Copy the code

Everybody understand this code? It is a principle of the software design pattern that object programming should be interface oriented, not implementation-oriented.

Interface interface = new InterfaceImpl();
Copy the code

The same is true in the logging framework. As mentioned above, logging has a facade interface and an implementation framework, so don’t program for implementation.

  1. Print all Throwable information for Exceptions. becauselog.error(msg)andlog.error(msg,e.getMessage())This log export method loses the most important StackTrace information.
void foo(){ try{ //do somehing }catch(Exception e){ log.error(e.getMessage()); Log.erroe ("Bad Things", LLDB etMessage()); Log. error("Bad Things",e); }}Copy the code
  1. Exceptions thrown after logging are not allowed. If a custom service exception is thrown after an exception is caught, no error log is required. The catcher handles the exception. Do not throw exceptions and print error logs at the same time. Otherwise, repeated logs will be generated.
void foo() throws LogException{ try{ //do somehing }catch(Exception e){ log.error("Bad Things",e); // throw new LogException("Bad Things",e); }}Copy the code
  1. Standard output is not allowed

Includes system.out.println () and system.error.println () statements. Because this is only printed to the console and not to a log file, it is not easy to manage logs. In addition, the standard output does not show the class name and line number information, once the code in the code for a large number of standard output, and log in to print the content of the standard output, it is difficult to locate the position of the journal content and print, can’t screen problem, want to delete the useless log output can’t change, this is the author personally when reconstructing antiques code across a pit.

void foo(){ try{ //do somehing }catch(Exception e){ Syste.out.println(e.getMessage()); / / error System. Error. Println (um participant etMessage ()); // error log.error("Bad Things",e); // Correct}}Copy the code
  1. PrintStackTrace is not allowed
void foo(){ try{ //do somehing }catch(Exception e){ e.printStacktrace(); // error log.error("Bad Things",e); // Correct}}Copy the code

Take a look at its source code:

public void printStackTrace() {
    printStackTrace(System.err);
}
Copy the code

It also prints to the Tomcat console using System.err.

  1. Disable debugging log output in the online environment

For the sake of log performance, if the code is core code and the execution frequency is very high, you are advised to add judgment to log output, especially the low-level output < DEBUG, INFO, and WARN >.

One reason is that there are too many DEBUG logs in the project. The other reason is that a large number of DEBUG logs are also used in various frameworks. After debugging is enabled online, disks are flooded, affecting the normal running of the service system.

  1. Do not print logs in large loops

If your framework uses a low-performing Log4j framework, do not print logs in thousands of for loops. This may drag down your application, and if your application’s response time is slow, consider whether you are printing too many logs.

for(int i=0; i<2000; i++){
    log.info("XX");
}
Copy the code

The best way to do this is to record the main points in the loop and print them out of the loop.

  1. Print a meaningful log

It is common to record some meaningful status data in the program log: when the program started and quit; Program running time consumption; The execution progress of time-consuming programs; State changes of important variables.

5. Reference materials

  1. How do Java programs log correctly
  2. Logging in Java applications
  3. Good Journaling practices
  4. This section describes common Java logging frameworks

Recent hot articles recommended:

1.1,000+ Java Interview Questions and Answers (2021)

2. Don’t use if/ else on full screen again, try strategy mode, it smells good!!

3. Oh, my gosh! What new syntax is xx ≠ null in Java?

4.Spring Boot 2.5 is a blockbuster release, and dark mode is exploding!

5. “Java Development Manual (Songshan version)” the latest release, quick download!

Feel good, don’t forget to click on + forward oh!