• <cite id="pswqr"></cite>
    <cite id="pswqr"><noscript id="pswqr"><samp id="pswqr"></samp></noscript></cite>
    <rt id="pswqr"></rt>

    <source id="pswqr"><menuitem id="pswqr"><strike id="pswqr"></strike></menuitem></source><cite id="pswqr"><noscript id="pswqr"><samp id="pswqr"></samp></noscript></cite>
  • <source id="pswqr"><menuitem id="pswqr"></menuitem></source>
  • <cite id="pswqr"><noscript id="pswqr"><label id="pswqr"></label></noscript></cite>
  • <rp id="pswqr"></rp>

    LoggingThe Ultimate Guide

    your open-source resource for understanding, analyzing, and troubleshooting system logs

    curated byloggly


    Java Logging Basics

    Java takes a customizable and extensible approach to logging. While Java provides a basic logging API through the java.util.logging package, you can easily use one or more alternative logging solutions instead. These solutions provide different methods for creating log data, but share the ultimate goal of delivering logs from your application to a destination.
    This section explores the basics behind logging in Java and how logging can help you become a better Java developer.

    Java Logging Components

    The Java logging API consists of three core components:

    • Loggers: Loggers are responsible for capturing events and passing them to the appropriate Appender.
    • Appenders: Also known as Handlers, Appenders are responsible for recording log events to a destination. Appenders use Layouts to format events before sending them to an output.
    • Layouts: Also known as Formatters, Layouts are responsible for converting and formatting the data in a log event. Layouts determine how the data looks when it appears in a log entry.

    When a Logger?records an event, it forwards it to the appropriate?Appender. The Appender?then formats the log entry using a?Layout before sending it to the console, a file, or another destination. Additionally,?Filters let you further specify whether an Appender should be used for a specific log entry.?Filters aren’t required in a logging configuration, but they give you greater control over the flow of your log messages.

    Logging Frameworks

    Logging in Java requires the use of one or more logging frameworks. These frameworks provide the objects, methods, and configuration necessary to transmit log messages. Java provides a default framework in the java.util.logging package. There are also many third-party frameworks including?Log4j,?Logback, and tinylog. Other packages, such as?SLF4J and?Apache Commons Logging, provide abstraction layers which decouple your code from the underlying logging framework, allowing you to switch between logging frameworks.
    Choosing a logging solution depends on the complexity of your logging needs, compatibility with other logging solutions, ease of use, and personal choice. Logback is based on the previous version (version 1) of Log4j, so its feature sets are very similar. However, the latest version of Log4j (version 2) introduces several improvements, such as support for multiple APIs and improved performance when using the?Disruptor?library. tinylog, while lacking in features, is extremely fast and well-suited for small projects.
    Another factor to consider is the framework’s support in various Java-based projects. For example, Android programs can only log using Log4j and Logback, or using third-party packages. Apache Tomcat can use Log4j to log internal messages, but only with Log4j version 1.

    Abstraction Layers

    Abstraction layers such as SLF4J decouple your application from its logging framework. An application can choose to bind a specific logging framework (such as java.util.logging, Log4j, or Logback) at run time by including that framework on the application’s classpath. If a logging framework is not available on the classpath, the abstraction layer effectively disables log calls. Abstraction layers make it easier to change a project’s existing framework and to integrate projects that use different frameworks.


    While all Java logging frameworks can be configured through code, most configuration is performed through external configuration files. These files determine when and how log messages are processed, and are loaded by the logging framework during run time. Most of the configuration examples provided in this guide use these configuration files.


    The default Java logging framework stores its configuration in a file called logging.properties. Settings are stored per line using a dot notation format. Java installs a global configuration file in the lib folder of the Java installation directory, although you can use a separate configuration file by specifying the java.util.logging.config.file property when starting a Java program. logging.properties files can also be created and stored with individual projects.
    The example below shows an Appender being defined in a global logging.properties file:


    Version 1 of Log4j uses a syntax similar to java.util.logging. Programs that use Log4j will search for a log4j.properties file in the project directory. By default, Log4j contains a default configuration that outputs all log messages to the console. Log4j also supports an XML configuration syntax, which is defined in a log4j.xml file.
    Version 2 of Log4j supports XML, JSON, and YAML configuration through the log4j2.xml, log4j2.json, and log4j2.yaml files. Similar to version 1, version 2 will search for these files in the project directory. You can find configuration examples in each version’s documentation.


    Most Logback configuration is done through the logback.xml file, which uses an XML syntax similar to Log4j. Logback also supports configuration through the Groovy programming language using a logback.groovy file. You can find configuration examples for each file type through their respective links.


    Loggers are objects that trigger log events. Loggers are created and called in the code of your Java application, where they generate events before passing them to an Appender. A class can have multiple independent Loggers responding to different events, and you can nest Loggers under other Loggers to create a hierarchy.

    Creating a New Logger

    The process of creating a new Logger is similar across logging frameworks, although the exact method names may be different. With java.util.logging, you create a new Logger using Logger.getLogger(). getLogger() takes a string parameter that identifies the name of a Logger. If a Logger with that name already exists, then that Logger is returned; otherwise, a new Logger is created. It’s generally good practice to name a new Logger after the current class using class.getName():

    Logging Events

    Loggers provide several methods for triggering log events. However, before you can log an event, you need to assign a level. Log levels determine the severity of the log and can be used to filter the event or send it to a different Appender (for more information, see the Log Levels section). The Logger.log() method requires a level in addition to a message:

    Most logging frameworks provide shorthand methods for logging at a particular level. For example, the following statement produces the same output as the previous statement:

    You can also prevent a Logger from logging messages below a certain level. In this case, the Logger logs only events that are at or above a WARNING level. Events generated at other levels are dropped:

    There are more methods available for recording additional information. logp() (log precise) lets you specify the source class and method for each log entry, while logrb() (log with resource bundle) lets you specify a resource bundle to extract logs from. The entering() and exiting() methods let you log method calls for tracing the execution flow of your program.


    Appenders forward log messages to the desired output. Appenders are responsible for accepting log events, formatting them using a Layout, and delivering them to their destination. Multiple Appenders can be combined to write the same log event to multiple destinations. For instance, a single event can be simultaneously displayed in a console and emailed to a recipient.
    Note that java.util.logging refers to Appenders as Handlers.

    Adding Appenders

    Most logging frameworks have Appenders that perform similar functions, but vary in their implementation. With java.util.logging, you can add an Appender to a Logger using the Logger.addHandler() method. For example, the following command adds a new ConsoleHandler, which outputs log events to the console:

    A more common approach to adding Appenders is through the use of a configuration file. With java.util.logging, Appenders are defined in a comma-separated list. This example exports log events to a console and to a file:

    With XML-based configurations, Appenders are added as an element underneath the element. With Log4j, we can easily add a new ConsoleAppender that sends log messages to System.out:

    Types of Appenders

    This section describes some of the more common Appenders and how they’re implemented in various logging frameworks.


    One of the most common Appenders is the ConsoleAppender, which simply displays log entries in the console. The ConsoleAppender is used as the default Appender for many logging frameworks and often comes preconfigured with basic settings. ConsoleAppenders in Log4j, for instance, are configured using the following parameters:

    Parameter Description
    filter This determines whether the log event is handled by the Appender.
    layout This determines how the log entry is formatted. This defaults to a PatternLayout of “%m%n”, which displays log messages on separate lines.
    follow This determines whether the Appender acknowledges any changes to the underlying output (System.out or System.err). By default, changes aren’t followed.
    name This sets the name of the Appender.
    ignoreExceptions This determines whether the Appender logs exceptions that occur while log events are being appended.
    target This specifies the output destination. The default is SYSTEM_OUT, but this can be changed to SYSTEM_ERR.

    A complete Log4j2 configuration file looks something like this:

    This configuration creates a ConsoleAppender named MyAppender that uses a PatternLayout to format the details of the event before writing it to System.out. The <> element provides configuration for the Loggers defined in your code. The single LoggerConfig in this configuration is the Root Logger, which accepts messages that are at or above an ERROR level. If we use logger.error() to record a message, it appears on the console like so:

    You can achieve the same output using Logback:


    FileAppenders write log entries to files. FileAppenders are responsible for opening and closing files, appending entries to files, and locking files to prevent data corruption or overwriting.
    To create a FileAppender in Log4j, specify the name of the destination file, whether to append or overwrite, and whether to lock the file while recording entries:

    This creates a FileAppender named MyFileAppender that locks myLog.log while appending new entries.
    With Logback, you can ensure file integrity by enabling prudent mode. Prudent mode increases the cost of writing to files, but safely manages file writes from multiple FileAppenders and even from multiple Java programs.


    SyslogAppenders send log entries to a logging service on a local or remote system. syslog is a service that accepts logging events from the operating system, processes, other services, and other devices. Events can range from diagnostic information to user logins to hardware failures. syslog events are categorized by facility, which specifies the type of event that’s being logged. For instance, the auth facility tells syslog that an event is related to security and authentication.
    SyslogAppenders are natively supported in Log4j and Logback. To create a SyslogAppender in Log4j, specify the host number, port number, and protocol that the syslog is listening on. The example below also specifies a facility:

    You can do the same with Logback:

    Other Appenders

    We’ve covered some of the more commonly used Appenders. There are dozens of additional Appenders that add new capabilities and build on the capabilities of other Appenders. For instance, the RollingFileAppender in Log4j extends FileAppender by automatically rolling over log files when a certain condition is met. The SMTPAppender sends an email containing the contents of the log. The FailoverAppender automatically switches to a different Appender in case one or more Appenders fails during the logging process.
    For more information on other Appenders, see the?Log4j Appenders reference and the?Logback Appenders reference.


    Layouts convert the contents of a log entry from one data type into another. Logging frameworks provide Layouts for plain text, HTML, syslog, XML, JSON, serialized, and other logs.
    Note that java.util.logging refers to Layouts as Formatters.
    For example, java.util.logging provides two Layouts: the SimpleFormatter and the XMLFormatter. SimpleFormatter, the default Layout for ConsoleHandlers, outputs plain text log entries similar to this:

    XMLFormatter, the default Layout for FileHandlers, outputs log entries similar to this:

    Configuring a Layout

    Layouts are typically configured using a configuration file, although starting with Java 7, SimpleFormatters can be configured using a?system property.
    For example, one of the most common Layouts in Log4j and Logback is the PatternLayout. PatternLayout lets you determine which parts of a log event are exported based on a conversion pattern. Conversion patterns act as placeholders for data that appears in each log event. For example, the default PatternLayout in Log4J uses the following pattern:

    %d{HH:mm:ss.SSS} formats the date in terms of hours, minutes, seconds, and milliseconds. %level displays the severity of the log event. %C displays the name of the class that the log event originated from. %t displays the Logger’s current thread. %m displays the event’s message. Finally, %n adds a new line for the next event.

    Changing Layouts

    To use a different Layout with java.util.logging, set the Appender’s formatter property to the Layout of your choice. To do this in code, you can create a new Handler and use its setFormatter method, then assign the Handler to the Logger using logger.AddHandler(). The following example creates a ConsoleHandler that formats logs using an XMLFormatter instead of the default SimpleFormatter:

    This causes the Logger to print the following output to the console:

    For more information on Layouts in Log4j and Logback, see the Log4j Layouts reference and the Logback Layouts reference.

    Using Custom Layouts

    Custom Layouts let you specify how Appenders output log entries. While it’s possible to tweak the SimpleLogger output?starting with Java SE 7, you’re restricted to simple plain text messages. More advanced formats, such as HTML or JSON, require either a custom Layout or a separate framework.
    For more details on creating custom Layouts for java.util.logging, see the?Java Logging: Formatters section of Jakob Jenkov’s Java logging guide.

    Log Levels

    Log levels provide a way to categorize and identify logs based on their severity. java.util.logging provides the following levels, which are listed by decreasing severity:

    • SEVERE (highest level)
    • INFO
    • CONFIG
    • FINE
    • FINER
    • FINEST (lowest level)

    In addition, there are two extra levels: ALL and OFF. ALL causes the Logger to log all messages, while OFF disables logging.

    Setting a Log Level

    Setting a level will cause a Logger to ignore messages below that level. For example, the following statement causes the Logger to ignore messages below the WARNING level:
    However, any messages that have a level of WARNING or SEVERE will be logged by the Logger. This can also be set in the configuration file by changing the Logger’s LoggerConfig:

    Conversion Patterns

    The PatternLayout class from Log4j and Logback supports conversion patterns, which determine how information is pulled from each log event and how it’s formatted. A subset of those patterns is shown below. While these particular fields are the same in both Log4j and Logback, not all fields use identical patterns. See the PatternLayout documentation for Log4j and for Logback for more information.

    Field Name Log4j/Logback pattern
    message %m
    level/severity %p
    exception %ex
    thread %t
    logger %c
    method %M

    For example, the following PatternLayout displays the log level in brackets, followed by the thread name and the event’s message:

    This is an example of log data using this conversion pattern:

    Logging Stack Traces

    If you’ve ever experienced an exception in a Java program, then chances are you’ve come across a stack trace. Stack traces provide a snapshot of the program’s active method calls, allowing you to pinpoint your place in the program’s execution. For example, the following stack trace was generated after the program tried to open a file that didn’t exist:

    This example uses a class called FooClass with a main method. At line 47, a FileReader tried to open a file called foo.file. There was no file called foo.file in the program’s directory, so the Java Virtual Machine threw a FileNotFoundException. Since this call was embedded in a try-catch block, we were able to catch the exception and log it, or at the very least, prevent the program from crashing.

    Logging Stack Traces with PatternLayout

    As of this writing, the latest versions of Log4j and Logback automatically append %xEx (stacktrace with packaging information for each call in the stack) to a PatternLayout unless another throwable-related pattern is already in the Layout. The pattern for a normal log message:

    Effectively becomes:

    This results in not only the error message being logged, but also the full-stack trace:

    The packaging lookup for %xEx is a relatively expensive operation that could result in a performance hit if your application frequently logs exceptions such as:

    One workaround is to explicitly include %ex in the pattern to request only the stack trace for exceptions:

    Another option is to exclude all exception information by appending %xEx{none} (in Log4j):

    or %nopex (in Logback):

    Logging Stack Traces with Structured Layouts

    Structured Layouts such as JSON and XML are ideal for stack traces, as you’ll see in the Parsing Multiline Stack Traces section.These Layouts will automatically break down stack traces into their core components, making them easy to export to other programs or to a logging service. The same stack trace as above is partially shown below in JSON format:

    Logging Uncaught Exceptions

    Typically, exceptions are handled by catching them. If an exception is not caught, it could lead to termination of the program. It’s a good idea to capture any logs that will help you debug why the exception happened, so you can fix the root cause. Here is how you can set up a default exception handler that will log the error.
    The Thread class contains two methods that provide the ability to specify an ExceptionHandler for an uncaught exception:
    setDefaultUncaughtExceptionHandler for handling any exceptions in your program on any thread, and the setUncaughtExceptionHandler, which allows you specify a different handler for a specific thread. The ThreadGroup also allows you to specify a handler. Most people will use the default exception handler.
    The following is an example of setting up a default exception handler to create a log event. It requires you to pass in an UncaughtExceptionHandler.

    Here is a sample log showing what an uncaught exception looks like:


    JavaScript Object Notation (JSON) is a format for storing structured data. JSON stores data as a collection of name/value pairs similar to a?HashMap or?Hashtable. JSON is portable and versatile, with most modern languages supporting it natively or through readily-available libraries.
    JSON supports many basic data types including strings, numbers, booleans, arrays, and null values. For example, you could represent a computer using the following JSON notation:

    JSON’s portability makes it ideal for storing log entries. With JSON, a Java log can be read by any number of JSON interpreters. Because the data is already structured, parsing a JSON log is far easier than parsing a plain text log.

    JSON in Java

    There are a number of JSON implementations for Java, one of which is?JSON.simple. JSON.simple is lightweight, easy to use, and fully compliant with the JSON specification.
    To turn the computer object above into a usable Java object, we’ll read it from a file and pass it to JSON.simple, which returns an Object. We can then cast the Object to a JSONObject:

    In addition to retrieving name/value pairs, you can log a JSONObject using any logging framework. The JSONObject includes a toString() method that formats the JSON as text.

    While this makes the JSONObject easy to print, it can lead to unexpected results when using structured Layouts such as JSONLayout or XMLLayout. Because the JSONObject is treated as a string, it gets embedded into the message field rather than as a separate object.

    Log4j’s JSONLayout doesn’t natively support embedded JSON objects, but it may be possible to add a JSONObject field by creating a custom Layout that extends or replaces JSONLayout. However, if you use a log management system, keep in mind that many log management systems use pre-determined data types for certain fields. If you create a Layout that stores a JSONObject type in the message field, it might conflict with the String data type used by the log management system. One way around this is to store JSON data in one field, and string log messages in another field.

    Other JSON Libraries

    There are many other libraries besides JSON.simple.?JSON-java is a reference implementation by the creator of JSON with additional functionality for converting to other data formats, including web elements. However, JSON-java is currently unmaintained and unsupported.
    For mapping JSON objects to and from Java objects, Google provides the?Gson library. Parsing JSON with Gson is as simple as using the toJson() and fromJson() methods, which respectively convert Java objects to and from a JSON string. Gson even works on objects that exist in memory, allowing you to map objects that you don’t have the source code for.


    Jackson is a powerful, popular, and feature-rich library for managing JSON objects in Java. Some frameworks even use Jackson for their JSON Layouts. Despite its size and complexity, Jackson is easy for beginners and advanced users alike.
    Logback provides Jackson integration through the logback-jackson and logback-json-classic libraries, which are part of the logback-contrib project. With Jackson integration, you can export logs in JSON format to any Appender.
    The Logback Wiki provides a detailed explanation on adding JSON to Logback. While the example in the link uses a LogglyAppender, the same configuration works for other Appenders. The following example shows how to write JSON-formatted log entries to a file called myLog.json:

    You can find a more in-depth introduction to Jackson in the?FasterXML Wiki.

    Learning More About JSON

    You can learn more about JSON through the JSON home page, or by following an interactive hands-on tutorial through CodeAcademy (note that this lesson is based on JavaScript, not Java). Online tools such as?JSONLint and?JSON Editor Online can help with parsing, validating, and formatting JSON code.

    NDC, MDC, and ThreadContext

    When dealing with multithreaded applications, especially web services, tracking events can be difficult. When entries are being generated for multiple simultaneous users, how can you tell which actions are associated with which events? What if two users failed to open the same file, or failed to log in at the same time? You would need a way to associate each entry with a unique identifier such as a user ID, session ID, or device ID. This is where NDC, MDC, and ThreadContext come in handy.
    NDC, MDC, and ThreadContext create log trails by adding unique data stamps to individual log entries. Known as fish tagging, these stamps let you distinguish logs using one or more unique values. These stamps are managed on a per-thread basis and last for the lifetime of the thread, or until otherwise removed. For instance, if your web application generates a new thread for each user, you can tag log entries created by that thread with that particular user’s user ID. This can be useful when you want to trace particular requests, transactions, or users through a complex system.

    Nested Diagnostic Context (NDC)

    NDC, or Nested Diagnostic Context, is based on the idea of a stack. Information can be placed (pushed) onto and removed (popped) from the stack. The values in the stack can then be accessed by a Logger without having to explicitly pass a value to the logging method.
    The following code example uses NDC and Log4j to associate a username with a log entry. NDC is a static class, so we can access its methods without having to initialize an NDC object. In this example, NDC.push(username) and NDC.push(sessionID) store the current values of username (“admin”) and sessionID (“1234”) in the stack. NDC.pop() removes individual items from the stack while NDC.remove() lets Java reclaim the memory used by the stack, preventing memory leaks:

    Log4j’s PatternLayout class extracts values from NDC through the %x conversion character. If a log event is triggered, the full NDC stack is passed to Log4j:

    Running the program results in the following output:

    Mapped Diagnostic Context (MDC)

    Similar to NDC is MDC, or Mapped Diagnostic Context. MDC differs from NDC in that it stores data as key-value pairs rather than as a stack. This allows you to easily reference individual keys in a Layout. MDC.put(key, value) adds a new key-value pair to the Context, while MDC.remove(key) removes the pair.
    To display the same username and session ID in our logs, we’ll store both variables as key-value pairs using MDC.put():

    Once again, it’s important to free the Context once it’s no longer in use. MDC.clear() removes all values from the MDC. This reduces memory usage and prevents future MDC calls from accessing stale data.
    Accessing MDC values in the logging framework is slightly different. Values are accessed using the %X{key} conversion character, where key is any key currently stored in the Context. In this case, we can use %X{username} and %X{sessionID} to retrieve their respective values.

    If no key is specified, then the contents of the MDC are sent to the Appender using the format {{key, value}, {key, value}}.

    NDC and MDC in Logback

    Unlike Log4j, Logback doesn’t provide a native implementation of NDC. However, the slf4j-ext package provides an NDC implementation that uses MDC as its base. You can access and manage MDC values natively in Logback using MDC.put(), MDC.remove(), and MDC.clear():

    Adding the following pattern to an Appender in Logback.xml results in the same output as Log4j:

    MDC access isn’t limited to PatternLayouts. When using the JSONFormatter, for instance, all of the values in the MDC are exported:


    Version 2 of Log4j merged MDC and NDC into a single concept known as the Thread Context. The Thread Context is an evolution of MDC and NDC, presenting them respectively as the Thread Context Map and Thread Context Stack. The Thread Context is managed through the static ThreadContext class, which is implemented similar to Log4j 1’s MDC and NDC classes.
    When using the Thread Context Stack, data is pushed to and popped from a stack just like with NDC:

    With the Thread Context Map, values are associated with keys just like with MDC:

    ThreadContext provides methods for clearing the stack, clearing the MDC, and clearing all values stored in the Context. Respectively, these methods are ThreadContext.clearAll(), ThreadContext.clearMap(), and ThreadContext.clearStack().
    As with MDC and NDC, you can access values in the Thread Context using Layouts. With PatternLayout, the %x conversion pattern retrieves values from the stack while %X and %X{key} retrieves values from the map.

    Filtering on ThreadContext

    Some frameworks allow you to filter logs based on an attribute. For instance, Log4j’s DynamicThresholdFilter automatically adjusts the log level if a key matches a certain value. For instance, if we wanted to toggle logging messages with the TRACE level, we can create a key called trace-logging-enabled and add a filter to our Log4j configuration:

    If the ThreadContext contains a key called trace-logging-enabled, onMatch and onMismatch determine how to proceed. There are three options available to onMatch and onMismatch: ACCEPT, which processes the filter’s rules; DENY, which ignores the filter’s rules; or NEUTRAL, which defers to the next filter. Below that, we define a KeyValuePair that enables TRACE-level logging when the key is set to true.
    Now, the Appenders will log TRACE-level messages when trace-logging-enabled is true, even if the root Logger is set to a higher level.
    You might also want to filter certain logs to certain Appenders. In this case, Log4j provides the ThreadContextMapFilter. If we wanted to limit a certain Appender to only log TRACE messages for a certain user, we could add a ThreadContextMapFilter based on the username key:

    For more information, see the Log4j and Logback documentation on DynamicThresholdFilter.


    Markers allow you to stamp individual log entries with unique data. Markers can be used to group entries, trigger actions, or filter entries to certain Appenders. You can even combine Markers with ThreadContext to improve your ability to search and filter log data.
    For example, imagine we have a class that connects to a database. If an exception occurs while opening the database, we’ll log the exception as a fatal error. We can create a Marker named DB_ERROR and apply it to the log event:

    To display the Marker in the log output, add the %marker conversion pattern to your PatternLayout.

    Alternative Layouts such as JSON and XML automatically include Markers in their output.

    Centralized logging services make it easy to search by Marker by automatically parsing and storing Marker data.

    Filtering Markers

    Marker filters let you determine which Markers are handled by which Loggers. The marker field is compared against the name of the Marker included in the log event. The Logger will then perform an action if the values match. For example, with Log4j, we can configure an Appender to display only messages that use the DB_ERROR Marker by adding the following configuration to an Appender in log4j2.xml:

    If the log entry has a Marker that matches the marker field, onMatch determines what to do with the entry. If the Markers don’t match, or if the log entry has no Marker, then onMismatch determines what to do with the entry. There are three options available for onMatch and onMismatch: ACCEPT, which allows the event; DENY, which blocks the event; or NEUTRAL, which does nothing with the event.
    With Logback, there’s a bit more setup. First, add a new EvaluatorFilter to the Appender. Specify the onMatch and onMismatch actions as above. Then, add an OnMarkerEvaluator and pass the name of the Marker to the Evaluator.

    Combining Markers with NDC, MDC, and Thread Context

    Markers provide a similar function as ThreadContext by stamping log entries with unique data, which can then be accessed by Appenders. Combining them can make your logs easier to index and search, but it helps to know when to use one or the other.
    NDC, MDC, and ThreadContext are used to associate related log entries. If your application handles multiple simultaneous users, ThreadContext lets you associate a set of log entries with a particular user. Because the ThreadContext is unique for each thread, you can use the same logging methods to automatically group related log entries.
    Markers, on the other hand, are commonly used to tag or highlight special events. In the above example, we used the DB_ERROR Marker to tag a SQL-related exception that occurred in the method. We could use the DB_ERROR Marker to process the event separately from other events, such as using an SMTPAppender to email the database administrator.

    Additional Resources

    Guides and Tutorials

    Java Logging (Jakob Jenkov) – Tutorial on logging with the Java Logging API
    Java Logging Overview (Oracle) – Oracle’s guide to logging in Java
    Log4J Tutorial (Tutorials Point) – Guide to logging with Log4j 1

    Logging Abstraction Layers

    Apache Commons Logging (Apache) – Abstraction layer for Log4j, Avalon LogKit, and java.util.logging
    SLF4J (QOS.ch) – Popular abstraction layer for multiple logging frameworks including Log4j, Logback, and java.util.logging

    Logging Frameworks

    Java Logging API (Oracle) – Java’s default logging framework
    Log4j (Apache) – Open-source logging framework
    Logback (Logback Project) – Open-source project designed as a successor to Log4j version 1
    tinylog (tinylog) – Lightweight open-source logger

    Written & Contributed by



    #Java takes a customizable and extensible approach to logging: http://bit.ly/1kJQ4Ji @loggly

    One of the most common Appenders is the ConsoleAppender, which simply displays log entries in the console: http://bit.ly/1kJQ4Ji #Java @loggly

    Log levels provide a way to categorize and identify logs based on their severity: http://bit.ly/1kJQ4Ji #java #howto @loggly

    Markers allow you to stamp individual log entries with unique #data http://bit.ly/1kJQ4Ji #java @loggly

    This guide will help software developers and system administrators become experts at using logs to better run their systems. This is a vendor-neutral, community effort featuring examples from a variety of solutions

    Meet Our Contributors Become a contributor