How to create a decent application log--10 tips

Source: Internet
Author: User
Tags garbage collection tidy log4j

Our JCP small partner, Tomasz Nurkiewicz recently posted about several application logging article, wrote very interesting, we decided that these posts tidy up, and everybody shares. Here are some of the tips he gives, hoping to make your logs neat and useful.

(Note: For you to read the catchy, we made a small change to the original post.) 1) 工欲善其事, its prerequisite many program apes seem to have forgotten the importance of logging program behavior and current activities. When someone writes the following paragraph into the code and has fun, he may not even realize the importance of log in code maintenance, program optimization, and troubleshooting. You are wrong to underestimate the value of logs.

Log.info ("Happy and carefree Logging");

In my opinion, SLF4J is the best loggingapi of the day because it supports pattern substitution (substitution), for example, in slf4j, you can write this:
Log.debug ("Found {} Records matching filter: ' {} '", records, filter);

But in log4j you have to write this:
Log.debug ("Found" + Records + "Records matching filter:" + filter + "");

Using log4j is not only a long statement, but also a poor readability, and more because of the heavy use of string links leading to performance degradation. Slf4j adds a very friendly substitution feature. Also, because the string link is not used, the ToString () function is not invoked when the logging statement is filtered, so there is no need to use isdebugenabled (). By the way, note the single quotes on either side of the filter string parameter.

SLF4J is just a cosmetic pattern, as far as implementing I recommend Logback Framework, not log4j. Logback has developed a number of more interesting features than log4j.

The final introduction of the PERF4J, their manifesto is (translator note: On the meaning of the Declaration, you can view the PERF4J official website detailed introduction, the general meaning is that programmers like println to find exceptions, using Currenttimemillis to calculate the program time consuming, therefore, The following means that the perf4j is used to measure the performance of the program, and log4j is used to detect the problem of the program:

PERF4J is to System.currenttimemillis () as log4j are to System.out.println ()

I have used perf4j in a high load application and have seen many other combat cases. Both administrators and users feel that the icons provided by PERF4J are stunning, allowing us to immediately discover performance flaws. About PERF4J We can write a separate article to discuss, now you just need to look at their developer manual.

In addition, Ceki Gulcu (LOG4J,SLF4J and founder of the Logback Project) gave a simple implementation of how to get rid of commons-logging dependencies. (Click to view) 2) Logging level always remember heart

Whenever you write down a logging statement in your code, you are always racking your brains to think about what level of logging you should use here. In fact, 90% of the program apes never care about the logging level, they simply use the same logging level, either info, or Debug. Why is that so? The logging framework has at least two advantages over System.out: classification, grading. This feature of the logging framework allows you to filter portions of the statements forever or selectively during debugging. If you really don't understand the difference, it's recommended that you print the following, and then type "Log" in the IDE. Take a good look at it before:

Error-A very serious error occurred, you must immediately check the cause of the error. No IT system can tolerate this level of error. For example: null pointer exception, database unavailable, critical task stopped.

WARN -Programs may continue to be implemented, but require special attention. In fact, I divide the warn into two levels: one is a common and obvious problem (for example, the current data does not exist, the cache value is used), and the other is a possible problem or suggestion. For example: "Application running in development mode" or "Administration console is isn't secured with a password". The program can tolerate these warning messages, but the information must be reasonable and checked.

INFO --the important business process is over. Ideally, an administrator or an advanced user should be able to read info and quickly find out what the program is doing. For example, if a program is used to order tickets, for each ticket, there should be an info statement to print the following message "who ordered where to fly to." As for info, it is also said that every action that can significantly change the state of the program should be printed using the info statement (such as database updates, peripheral system requests).

DEBUG -Used by developers. What information is mentioned in the following section should use debug for log.

TRACE --trace Prints very detailed information that will only be used when it is developed. You may notice trace information for a period of time after the product is online, but these log statements are only temporary and will gradually close. Debug and trace are difficult to distinguish, but if you just want to log the logs for a while and then remove the logs after the development test is complete, it's best to use trace.

These are just a few suggestions, you can also follow your own guidelines to design, as long as there is. My experience is that all information is not filtered to record, but must be able to quickly filter the log, and extract the appropriate level of information, the key time can be helpful.

The last thing to say is the famous "*enabled ()" condition in which someone likes to add a similar judgment before each logging statement:

if (log.isdebugenabled ())
    Log.debug ("Place for your commercial");

Personally, this habit should be avoided. This statement has minimal performance improvements (especially with the SLF4J replacement template mentioned earlier), and it looks more like an immature optimization. Besides, can you see where the repetition is? Only a few cases, under very specific conditions, can prove that the construction of logging information is very cost-intensive. In most other cases, you just have to finish your logging work, and the rest of the logging framework.

3 What are you logging. Whenever you write a logging statement, take a moment to see what's in the log file. After a while, look at the log file to see if there are any abnormal statements. First, avoid the null pointer in the logging statement:
Log.debug ("Processing request with ID: {}", Request.getid ());

Are you sure the request above is not NULL?
Another area that is prone to problems is the collection class. When reading a domain object from a database using Hibernate, and inadvertently writing down the following logging statement:
Log.debug ("Returning users: {}", users);

SLF4J It is good to invoke the ToString method of the collection class only when the statement does print. However, when invoked, memory overflows, n+1 selection exceptions, thread deadlocks, delayed initialization exceptions, log storage full, and so on can occur.

A better approach would be to logging only the ID of the domain object or the size of the collection class. However, it is difficult to imagine the complexity of generating a collection of IDs from a set of objects that have GetID methods, and Java is very difficult to handle. Groovy has great expansion operators, in Java we can use the Commons Beanutils class to achieve this function

Log.debug ("Returning user ids: {}", Collect (Users, "IDs"));

The Collect method in the code can be implemented like this:
public static Collection Collect (Collection Collection, String PropertyName) {return
    collectionutils.collect ( Collection, New Beantopropertyvaluetransformer (PropertyName));


The last point is the wrong use of ToString or unreasonable implementation. First, you create the ToString method for each class that appears in the logging statement, using Tostringbuilder preferentially. Second, beware of arrays and atypical collection classes. Arrays and some collection classes may not implement a method of ToString for all elements in the collection. For arrays, you can use the Deeptostring method of the Arrays tool class. To view logs frequently, you can find malformed log information.
4) Avoid side effects

Logging statements should have no impact or small impact on the behavior of the program. Recently, an old friend showed me a thing, this system only runs in certain environment to run out of Hibernate delay initialization exception. As you might have guessed, some logging statements can cause a delay in garbage collection when connecting to a session. In this system environment, the log level increases and garbage collection is not properly initialized. Imagine how long it would take to find bugs in a single environment without the experience of deploying in a different environment.

Another side effect is to reduce the speed of the program. If the log is too much information, or if the ToString method is not used properly, or if too many string connections are used, then log can affect performance. How big a impact it is. I have encountered a case where the server reboots every 15 minutes, and the culprit is that excessive logging causes the thread to die. This is another side effect. From my personal experience, hundreds of MIB per hour is probably the limit of log.

Of course, if the logging statement has an exception and causes the application to crash, it is also a very large side effect. I saw someone trying to avoid the crash by using the following statement:

try {
    log.trace ("id=" + request.getuser (). GetId () + "accesses" + manager.getpage (). GETURL (). toString ())
} catch (NullPointerException e) {}

It's real code, but for the better of the world, please don't do it, never.

5 Simplicity but not simple logging statements should contain both data and descriptions. For example:

Log.debug ("message processed");
Log.debug (Message.getjmsmessageid ());
 
Log.debug ("message with ID ' {} ' processed", Message.getjmsmessageid ());

When you are debugging in an unfamiliar program, you will use the above section of the code. Please believe that the above two actually not bad, are very general. Let's look at another one:
if (message instanceof TextMessage)
    //...
else
    log.warn ("Unknown message type");

It is difficult to add a message type, message ID, and so on in a warning statement. Seeing the above information, I only know that there is a problem, but I don't know what is wrong. What is the context?

There is also a "magic log." For example: Many programmers on a team know that "&&&!#" followed by some strings means "receive a message with ID XYZ". No one wants to change the way of log, he just randomly knocked on the keyboard a few, think "&&&!#" is not bad, so used, and, this character for him personally find it is easier.

As a result, the entire log file looks like a random string sequence. Even one might think that it is a Perl program and not necessarily. In fact, log files should be readable, tidy, and descriptive. Do not use magic numbers to record values, numbers, IDs, and contexts. Show the data being processed and the meaning of the data, and what the program is doing exactly. A good log can even be used as a document for program code.

Did I mention not to write down passwords or other privacy records? Please don't. 6) Optimizing pattern

Logging pattern is a great tool that explicitly adds a meaningful context to your Logging statement, but what you need to add to the pattern is carefully considered. For example, if the day is scrolled every hour, and the log document name already contains the date time, then the date doesn't make sense. Conversely, in multiple threads, if the name of the thread is not logging, it is difficult to trace through the log-because the log overlaps. It can be used normally in a single-threaded program, but a single-threaded program basically does not exist.

In my personal experience, the ideal logging pattern should include: current time (excluding date, accurate to millisecond), logging level, thread name, logger name, and logging information. In Logback, the code is probably like this.

<appender name= "STDOUT" class= "Ch.qos.logback.core.ConsoleAppender" >
    <encoder>
        <pattern >%d{hh:mm:ss. SSS}%-5level [%thread][%logger{0}]%m%n</pattern>
    </encoder>
</appender>

The pattern should not contain file names, class names, and line numbers, although these kinds of information are tempting. I have seen an empty log statement in my code:

Log.info ("");

The empty log statement occurs because the programmer who wrote this code assumes that logging pattern is bound to have a line number, and he knows "if the empty logging information appears in the 67th line of the file (in the Authenticate () method), means that user authentication is passed. In addition, the logging class name, method name, and line number have a significant effect on performance.

The logging framework has a more advanced feature: Mapping diagnostic contexts (mapped diagnostic context). This mapping is managed by the local thread. You can put a key-value pair into this map, and then each logging statement in that thread will contain this value, which becomes part of the pattern. 7 The method's entry and return values should log down

When looking for bugs in development, you usually go into the debugger and try to find the possible cause. However, consider the situation where you are not allowed to debug. For example, a bug occurred many days ago, and now you have only log to see what you can find out.

You don't even need a debugger if you can stick to the logging and the parameters of each method. Of course, there are some ways to consider whether to log, such as accessing the External System (database), thread block, thread waiting, and so on. You can simply use the following pattern:

Public String PrintDocument (Document doc, mode mode) {
    log.debug ("Entering PrintDocument (doc={}, mode={})", Doc, mode);
    String id =//lengthy printing operation
    Log.debug ("Leaving PrintDocument (): {}", id);
    return ID;
}

Because you've recorded the call to the method from cover to cover, you can find the less efficient code, or even the reason for the deadlock or the thread being mutually exclusive--just find the "go" statement. Also, if your method name is more semantically consistent, the log will be pleasing to the eye. In addition, it becomes easier to analyze where the problem is, because you know exactly what happened at each step. You can even use AOP to log a whole bunch of methods so that you can reduce repetitive code, but be careful when you use it because the log file can be very large.

It's best to consider using Debug or trace levels. If you feel that some method calls are too high to be detrimental to performance, simply lower the class's logging level or simply not log the class. However, it is better to have more logs than to log too little. You can make a comparison between a logging statement and a unit test--if the code has a unit test case, then it's best to have a logging statement. There is no part of a system that can be logged without logging. Remember, sometimes, flipping through the log is the only way to tell if a program is running properly or paralyzed. 8) attention to the peripheral system

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.