Skip to content

Logging

Introduction

Logging refers to the recording of activity by an application and is a common issue for development teams:

  • Logging is producing messages that tell you what your program is doing
  • It’s not much different than using System.out.println(...)
  • Log messages can go to the console, to a file, or one of several other destinations
  • You can use logging to help you debug a program
  • You can use logging to produce a file when the user runs your program

Why Logging?

  • In reality the large programs always have bugs
    • JUnit testing can greatly be used for testing, but it’s impossible to see in advance all potentially useful tests
  • The program may go to the customers and then occures errors
  • A typical error report from customer is It doesn’t work and it does not tell anything about the problem.
  • It is very useful that a customer gives us a detailed scenario in which the program fails. in such cases we want to tell the typical customer: Send us the log; it’s in such-and-such a place.

Requirements

  • Logging should be easy for the developer to use
  • Logging should be flexible
  • Logging setup/config should be easy, especially for system administrators
  • Configuration should be done at runtime
  • Framework should free you up to concentrate on the business/application logic

Basic use

import java.util.logging.*;
private static Logger myLogger =  Logger.getLogger("myPackage");
myLogger.log(Level.SEVERE, "Bad news!");
Aug 15, 2020 10:51:09 AM myPackage.Sync main SEVERE: Bad news!

Key Concepts

the key concepts (entities) of a logging framework are:

Entity Description
Log Manager Access point to logging system
Log Message The log message
Severity Level A ranking of the log messages, also used as a filter criteria
Logger A processing unit for the log message
Appenders/Handlers A target to send the log message to
Filters Criteria used to filter message
Formatters/Renderers/Layouts Formatting of the log message for its handler/appender

Logging flow of control

  • You send your message to a Logger
  • The Logger checks a Filter to see whether to ignore the message
  • The Logger sends the message to a Handler to put the message somewhere
  • The Handler checks another Filter to see whether to ignore this kind of message sent to this destination
  • The Handler calls a Formatter to decide what kind of a text string to produce
  • The Handler sends the formatted message somewhere

Severity level

The severity level is used for the classification of log messages. Levels are organised in a hierarchy of severity where the lower level include the higher level messages. An example of level names from Apache Commons Logging is as follows:

Level Description
FATAL Severe errors that cause premature termination. Expect these to be immediately visible on a status console.
ERROR Other runtime errors or unexpected conditions. Expect these to be immediately visible on a status console.
WARNING Use of deprecated APIs, poor use of API, 'almost' errors, other runtime situations that are undesirable or unexpected, but not necessarily "wrong". Expect these to be immediately visible on a status console.
INFO Interesting runtime events (startup/shutdown). Expect these to be immediately visible on a console, so be conservative and keep to a minimum.
DEBUG detailed information on the flow through the system. Expect these to be written to logs only.
TRACE more detailed information. Expect these to be written to logs only.

Logging Frameworks

There are many logginf framework available. The following list shows some of the most used frameworks:

Framework Supported Log Levels
Log4J FATAL - ERROR - WARN - INFO - DEBUG - TRACE
Java Logging API SEVERE - WARNING - INFO - CONFIG - FINE - FINER - FINEST
tinylog ERROR - WARNING - INFO - DEBUG - TRACE
Logback ERROR - WARN - INFO - DEBUG - TRACE
SLF4J ERROR - WARN - INFO - DEBUG - TRACE

Logger

A Logger is an object that allows the application to log without regard to where the output is sent/stored.

  • A logger is conceptually like a message queue
  • A logger “processes” a log message
  • Every Logger has a parent
  • Root Logger is top of the logger hierarchy and always exists
  • Loggers are source of complexity as Log messages “bubble up” the hierarchy
  • Loggers can have severity levels to filter incoming log messages

Logger Name

A logger has a name. The name is usually structured hierarchically, with periods (.) separating the levels. A common scheme is to use the name of the class or package that is doing the logging. Both log4j and the Java logging API support defining handlers higher up the hierarchy.

For example, the logger might be named "com.sun.some.UsefulClass". The handler can be defined for any of the following:

  • com
  • com.sun
  • com.sun.some
  • com.sun.some.UsefulClass

Filter

Filters cause a log event to be ignored or logged. Logging frameworks such as Log4j 2 and SLF4J also provide Markers, which when attached to a log event can also be used for filtering. Filters can also be used to accept or deny log events based on exceptions being thrown, data within the log message, data in a ThreadLocal that is exposed through the logging API, or a variety of other methods.

  • Filter is an interface; it defines the single method boolean isLoggable(LogRecord record)
  • A filter is a criteria against which incoming log messages are compared to be processed or discarded
  • Filters can be on Loggers in some cases
  • Filters can be on appenders
  • A filter can be attached to more than one appender/logger

Appenders/Handlers

Appenders listen for messages at or above a specified minimum severity level. The Appender takes the message it is passed and posts it appropriately.

  • Loggers can have more than one appender
  • An appender can belong to more than one logger
  • Appenders can be anything
    • display on the console
    • write to a file or syslog
    • append to a database table
    • distribute via Java Messaging Services
    • send via email
    • write to a socket
    • discard to the "bit-bucket" (/dev/null)

Formatters/Layouts

A Formatter is an object that formats a given object. Mostly this consists of taking the binary object and converting it to a string representation. Each framework defines a default output format that can be overridden if desired.

Meta Loggers

  • Frameworks to abstract away Logging frameworks
  • Allow for run time changing of logging frameworks
  • Apache Commons Logging – not used due to architectural issues
  • Sl4j is one of the best meta logging framework
    • SL4J allows for code to be written without concern for underlying framework
      • Change deployed jars to target different frameworks
    • SL4J allows for bridging of disparate logging frameworks in 3rd party libraries used in your application

Logging Best Practices

  • Don’t Write Logs by Yourself (AKA Don’t Reinvent the Wheel)
  • Log at the Proper Level
  • Employ the Proper Log Category
  • Write Meaningful Log Messages
  • Write Log Messages in English
  • Add Context to Your Log Messages
  • Log in Machine Parseable Format
  • But Make the Logs Human-Readable as Well
  • Don’t Log Too Much or Too Little
  • Think of Your Audience
  • Don’t Log for Troubleshooting Purposes Only
  • Avoid Vendor Lock-In
  • Don’t Log Sensitive Information

SLF4J Example

To get started with SLF4J, you only need one library on the classpath, the slf4j-api dependency. If you are using a dependency management tool like Maven, then you would add the following dependency to your dependencies section:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.5</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.5</version>
</dependency>

Having the API on your classpath will allow you to write log statements like the following:

// SLF4J
org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(MyClass.class);
logger.info("This is an info message");
logger.error("This is an error message");
logger.debug("Here is a debug message"); 

Exercise

  • Exercise 1:
    • write a maven application
    • add SLF4J dependencies
    • log some messages from main method: inof, error and debug
    • customize log4j behind SLF4J using log4j.properties