[Top] [Contents] [Index] [ ? ]

SimpleLogging

Version 3.0 – February 2024

The goal of this library is to be a small logging facade that backends to a number of standard logging packages and that can be copied into another project. This allows you to write your code and include log messages without having a fixed dependency on any one logging package. I include this code into my libraries and so they can stay agnostic. This logging code allows you to write messages with the slf4j-style {} argument support, handles arrays appropriately, and supports up to 4 arguments before forcing the caller to pass in an object array or calling a different logArgs(...) method for variable arguments.

This library is similar to other logging systems which separate the API from the logging implementation. SimpleLogging is better than the others because it calls directly to specific backend APIs which can be chosen through code or configuration. This direct calling allows for more control over the backend selection without addition additional dependencies to the classpath.

SimpleLogging is also designed to be copied into your open source project so you don’t have to add a maven dependency. Just copy the java files from src/main/java into your source tree and rename the packages as necessary. Please also copy the SIMPLELOGGING_LICENSE.txt file which is the very permissive ISC license. You may want to change the constants in LoggerConstants.java.

To get started quickly using SimpleLogging, see section Getting Started. There is also a PDF version of this documentation.

Gray Watson http://256stuff.com/gray/


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1. Getting Started

To use SimpleLogging in your code is similar to other logging libraries that you are used to.

 
// usually a logger will be per-class
// getLogger() also can take a String label
private static final Logger logger =
   LoggerFactory.getLogger(MyClass.class);
...

// log trace message with arguments
// toString() on the args only called if trace messages enabled
logger.trace("some trace information: {} and {}", arg1, arg2);
...

// NOTE: exception argument comes _before_ the
// message format to not confuse the arguments
logger.error(exception, "http client threw getting URL: {}", url);

For more extensive instructions, see section Using SimpleLogging.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2. Using SimpleLogging


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.1 Downloading Jar

To get started with SimpleLogging, you will need to download the jar file. The SimpleLogging release page is the default repository but the jars are also available from the central maven repository.

The code works with Java 8 or later.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.2 Depending on SimpleLogging in Your Library

To use the SimpleLogging code in your library, you can either depend on the jar or just copy the classes into a logging package in your code and rename the package as necessary. You may want to tune the order of discovery in the LogBackendType enumerated class or remove support for certain loggers that your library doesn’t need to support.

SimpleLogging is designed to be copied into your open source project so you don’t have to add a dependency. Just copy the java files from src/main/java into your source tree and rename the packages as necessary. Please also copy the SIMPLELOGGING_LICENSE.txt file which is the very permissive ISC license. You may want to change the constants in LoggerConstants.java.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.3 Logging Messages with {} Arguments

SimpleLogging supports "slf4j" type of arguments. Whenever the {} characters appear in your logging message, the library will look for arguments to substitute into the {}. For example:

 
String host = "server1";
logger.info("connected to host {}", host);

If info messages are being displayed then the following message will be logged:

 
connection to host server1 failed

This can be accomplished with a simple StringBuilder but the big difference is that no unnecessary objects will be created unless the log message is to be written. If the logger is limited to warning messages and above, no StringBuilder will be created and the toString() method for the arguments will never be called if the above info log call is made.

By default the various log methods (logger.trace(...), logger.debug(...), ...) take 0 to 4 arguments with no objects being created (aside from some possible auto-boxing of numbers). If you need more arguments you can use the argument-array with a explicit new Object[] { ... } pattern or use variable arguments with a call to logger.traceArgs(...), logger.debugArgs(...), etc.. The variable arguments also creates an Object[] regardless of whether or not the log message will be logged so SimpleLogging wants you to be explicit about creating it. It is recommended that you test for the log level with an if statement when you are logging with the Object[] or variable arguments.

 
if (logger.isLevelEnabled(Level.TRACE)) {
   // here's with an explicit object array
   logger.trace("Method args: {}, {}, {}, {}, {}",
       new Object[] { schema, host, port, path, query });
   // here's with a variable arguments with traceArgs()
   logger.traceArgs("Method args: {}, {}, {}, {}, {}",
       schema, host, port, path, query);
}

Here’s how the arguments are turned into strings in the log message:

  1. if you pass no arguments to the logger call, then any {} patterns will be displayed with no substitution
  2. if you have more {} patterns in the message than arguments, then any extras will output the empty string
  3. if you have more arguments than you have {} patterns in the message then they will be ignored
  4. null values will output the string null
  5. arrays will be displayed as [ele1, ele2, ...] with each element going through the same logic here
  6. if the argument implements LogArgumentCreator then the results of arg.createLogArg() will be displayed
  7. by default arg.toString() will be displayed

Here are examples of these rules.

 
// no arguments but a {} pattern
logger.info("connected to host '{}'");
// outputs: connected to host '{}'

// missing argument to second {} displays as empty string
String host = "host1";
logger.info("connected to host '{}' port '{}'", host);
// outputs: connected to host 'host1' port ''

// extra argument (port) is ignored
String host = "host1";
int port = 443;
logger.info("connected to host '{}'", host, port);
// outputs: connected to host 'host1'

// null argument
String host = null;
logger.info("connected to host '{}' failed", host);
// outputs: connected to host 'null'

// arguments that are arrays
String[] hosts = new String[] { "srv1", "srv2" };
logger.info("connected to hosts {} failed", hosts);
// outputs: connected to hosts [srv1, srv2]

// logging of Host which implements LogArgumentCreator where
// host.createLogArg() method returns the string: host4
Host host = new Host();
logger.info("connected to host '{}'", host);
// outputs: connected to host 'host4'

// logging of Server where server.toString() returns: srv3
Server server = new Server();
logger.info("connected to host '{}'", server);
// outputs: connected to host 'srv3'


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.4 Setting Log Level or Disabling Logging

By default the choice of whether or not to log, for example, a trace log message is up to the specific log backend. For example. if you are using LOG4J2, your LOG4J2 config file determines whether or not trace logging is enabled for a particular package. That said, there are some ways that you can impact in code which messages will get logged with calls to the SimpleLogging methods regardless of the log backend.

 
// have all INFO or above messages to be logged
// regardless of the backend configurations
Logger.setGlobalLogLevel(Level.INFO);

You can also disable all log messages by using the OFF level:

 
// force all messages to be disabled
Logger.setGlobalLogLevel(Level.OFF);

Another way to not have any log messages show would be use use the NULL log backend.

 
// set the backend type to be the null logger
LoggerFactory.setLogBackendType(LogBackendType.NULL);

To set the global log level via properties see section Configuring Logging with the SimpleLogging Properties File.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.5 Using "Fluent" Logging Method Chaining

Another pattern supported by SimpleLogging is the "fluent" logging which uses method chaining to build up a log message. The benefit of this method are that no objects are created by the log call unless the log level is enabled. Typically, primitives are auto-boxed into their object equivalents in a standard SimpleLogging logger before it can check to see if the log level is enabled but fluent logging handles those without creating objects as well.

For example, even with port being an int primitive below, there are no objects generated by thus call unless TRACE log level is enabled.

 
// create a fluent logger instead of a logger
private static final FluentLogger fluentLogger =
   LoggerFactory.getFluentLogger(MyClass.class);
...
// this generates no additional objects even due to auto-boxing
// of port unless trace logging is enabled
fluentLogger.atTrace()
    .msg("connected to host '{}' port '{}'")
    .arg(host)
    .arg(port)
    .log();

Logging of arrays in fluent logging can be done one of two ways. You can use the flientLogger.args(...) method to add an array of object arguments to the log message, each element of which will match a {} from the message. If you want an array to be associated with a single {} and displayed as [arg1, arg2, ...] then you need to use the method fluentLogger.arg(Object) which will interpret the array as a single object.

For example, the following code which calls this args(...) method will output: "1 + 2 = 3"

 
fluentLogger.msg("{} + {} = {}").args(new Object[] { 1, 2, 3 }).log();

While the following code which calls arg(...) will output: "port numbers: [1, 2, 3]" which interprets the array as an Object and will match a single {} from the message.

 
fluentLogger.msg("port numbers: {}").arg(new Object[] { 1, 2, 3 }).log();

You can also append to a previous log message set with msg(String) in case you want to do something like the following logic:

 
FluentContext context = fluentLogger.atTrace().msg("connection from: ");
if (host != null) {
    context.appendMsg("host {}, ").arg(host);
}
context.appendMsg("port {}").arg(port);
context.log();

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.6 How SimpleLogging Discovers the Logging Backend

Built into the LoggerFactory class is a LogBackendType enumerated type which SimpleLogging uses to try to locate what logging packages are on the classpath and therefore should be used.

The following logging implementations will be discovered on the classpath in this order.

  1. ANDROID – Android native Log
  2. LOGBACK – Logback direct without SLF4J
  3. LOG4J2 – version 2+
  4. LOG4J – older, only used via reflection if available on the classpath
  5. LAMBDA – AWS Lambda systems logging
  6. SLF4J – (often paired with logback)
  7. COMMONS_LOGGING – Apache Commons Logging
  8. LOCAL – log implementation that can write to a simple file
  9. CONSOLE – log writing to System.out or System.err
  10. JAVA_UTIL – Java util logging which is usually available in the JRE but never chosen directly
  11. NULL – null logger to log no messages

If you need to force the logging type, you can use the following static methods.

 
// used to set a specific LoggerFactory.LogBackendType
LoggerFactory.setLogBackendType(LogBackendType.LOGBACK);

Or to specify a specifically factory class including custom ones:

 
// used to set a specific LoggerFactory or custom
LoggerFactory.setLogBackendFactory(new LogbackLogBackendFactory());

You can also set the com.j256.simplelogger.backend Java system property to one of the LogBackendType values in the above list.

 
java -Dcom.j256.simplelogger.backend=LOGBACK ...

You can also set the property to be a class name that implements LogBackendFactory.

 
java -Dcom.j256.simplelogger.backend=com.j256.simplelogging.backend.LogbackLogBackend$LogbackLogBackendFactory ...

To set the backend via properties see section Configuring Logging with the SimpleLogging Properties File.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.7 Configuring Logging with the SimpleLogging Properties File

By default the library will look for the simplelogging.properties properties file at the top of the classpath which will help to configure the logging backend, the global log-level, and local-log level for classes. It handles comments on lines that start with # and lines in the format of name = value.

You can set the backend directly to one of the LogBackendType enum names:

 
backend = LOG4J2

You can also set the backend to a class that implements LogBackendFactory:

 
backend = com.mysite.MyLoggingLogBackend.Factory

You can also set the order to check for the various backend implementations:

 
dicovery.order = LOGBACK, LOG4J2, COMMONS_LOGGING, NULL

You can also set the global log level which affects all loggers regardless of the backend log level configuration.

 
global.level = INFO

You can set the level to the string OFF to disable all logs.

 
global.level = OFF

You can also disable the default global log level and let the backends determine the level by setting the global level property to NULL:

 
global.level = NULL

If you are using the LocalLog backend, you can also use the configuration file to define the log level of your various logger classes. Lines for this should look like locallog.class-regex-pattern = level. You should escape any period characters with a single backslash unless they are part of a regex match.

 
locallog.com\.j256\.simplelogging.* = DEBUG

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.8 More Usage Examples

Usually the logger is defined per-class as a static field.

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

The logger handles trace, debug, info, warn, error, and fatal messages. Not all of these message types are supported by all of the logger backends so SimpleLogging tries to map where appropriate.

 
logger.trace("read '{}' bytes", readCount);
logger.debug("host '{}', port-number {}", host, port);
logger.info("connecting to: {}:{}", host, port);
logger.warn("retry connect to host '{}', port {}", host, port);
logger.error("connect failed to host '{}', port {}", host, port);
logger.fatal(exception, "host '{}' threw exception", host);

If you want to use more than 4 arguments, you will either need to pass in an Object[] or call the methods with the Args suffix. This is a specific design decision because in either case, an Object[] is created even if the message is never logged.

 
logger.debug("schema '{}', host '{}', port {}, path {}, query {}",
     new Object[] { schema, host, port, path, query });

Or with variable arguments with methods that have an Args suffix such as debugArgs(...).

 
logger.debugArgs("scheme '{}', host '{}', port {}, path: {}",
     schema, host, port, path);

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.9 Using With Maven

To use SimpleLogging with maven, include the following dependency in your ‘pom.xml’ file:

 
<dependency>
   <groupId>com.j256.simplelogging</groupId>
   <artifactId>simplelogging</artifactId>
   <version>3.0</version>
</dependency>

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3. Open Source License

ISC License. This document is part of the SimpleLogging project.

Copyright 2024, Gray Watson

Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

Index of Concepts

Jump to:   {  
A   B   C   D   F   G   H   I   J   L   M   N   O   P   Q   R   S   T   U   V   W  
Index Entry Section

{
{} arguments2.3 Logging Messages with {} Arguments

A
android logging, use with2.6 How SimpleLogging Discovers the Logging Backend
arguments in the message2.3 Logging Messages with {} Arguments
array argument logging2.3 Logging Messages with {} Arguments
arrays, fluent logging2.5 Using "Fluent" Logging Method Chaining
authorSimpleLogging
autoboxing, avoiding2.5 Using "Fluent" Logging Method Chaining
avoiding objects2.5 Using "Fluent" Logging Method Chaining
aws lambda logging, use with2.6 How SimpleLogging Discovers the Logging Backend

B
backend discovery order2.7 Configuring Logging with the SimpleLogging Properties File
backend, discovering2.6 How SimpleLogging Discovers the Logging Backend
backend, discovering2.7 Configuring Logging with the SimpleLogging Properties File

C
chaining methods2.5 Using "Fluent" Logging Method Chaining
com.j256.simplelogger.backend property2.6 How SimpleLogging Discovers the Logging Backend
commons logging, use with2.6 How SimpleLogging Discovers the Logging Backend
configuration properties2.7 Configuring Logging with the SimpleLogging Properties File
console logging2.6 How SimpleLogging Discovers the Logging Backend
copying code2.2 Depending on SimpleLogging in Your Library

D
disable all messages2.4 Setting Log Level or Disabling Logging
disable logging2.6 How SimpleLogging Discovers the Logging Backend
discovering backend2.6 How SimpleLogging Discovers the Logging Backend
discovering backend2.7 Configuring Logging with the SimpleLogging Properties File
downloading the jars2.1 Downloading Jar

F
fluent logging2.5 Using "Fluent" Logging Method Chaining

G
getting started1. Getting Started

H
how to download the jars2.1 Downloading Jar
how to get started1. Getting Started
how to use2. Using SimpleLogging

I
introductionSimpleLogging
isc license3. Open Source License

J
java property2.6 How SimpleLogging Discovers the Logging Backend
java util logging, use with2.6 How SimpleLogging Discovers the Logging Backend

L
lambda logging, use with2.6 How SimpleLogging Discovers the Logging Backend
license3. Open Source License
log backend discovery2.6 How SimpleLogging Discovers the Logging Backend
log backend discovery2.7 Configuring Logging with the SimpleLogging Properties File
log level, setting2.4 Setting Log Level or Disabling Logging
log type of backends2.2 Depending on SimpleLogging in Your Library
log4j, use with2.6 How SimpleLogging Discovers the Logging Backend
log4j2, use with2.6 How SimpleLogging Discovers the Logging Backend
logback direct, use with2.6 How SimpleLogging Discovers the Logging Backend
Logger1. Getting Started
logging facadeSimpleLogging
logging properties2.7 Configuring Logging with the SimpleLogging Properties File
LogMessageCreator2.3 Logging Messages with {} Arguments

M
Maven, use with2.9 Using With Maven
message arguments2.3 Logging Messages with {} Arguments
method chaining2.5 Using "Fluent" Logging Method Chaining

N
null argument logging2.3 Logging Messages with {} Arguments
null logger2.6 How SimpleLogging Discovers the Logging Backend

O
objects, avoiding2.5 Using "Fluent" Logging Method Chaining
open source license3. Open Source License

P
pom.xml dependency2.9 Using With Maven
properties file2.7 Configuring Logging with the SimpleLogging Properties File
property, system2.6 How SimpleLogging Discovers the Logging Backend

Q
quick start1. Getting Started

R
remove all messages2.4 Setting Log Level or Disabling Logging

S
setting log level2.4 Setting Log Level or Disabling Logging
simple loggingSimpleLogging
simplelogging properties2.7 Configuring Logging with the SimpleLogging Properties File
slf4j, use with2.6 How SimpleLogging Discovers the Logging Backend
system property2.6 How SimpleLogging Discovers the Logging Backend

T
toString, don’t use2.3 Logging Messages with {} Arguments
turn off all messages2.4 Setting Log Level or Disabling Logging

U
using in your library2.2 Depending on SimpleLogging in Your Library
using SimpleLogging2. Using SimpleLogging

V
varargs, use with2.8 More Usage Examples
variable arguments, use with2.8 More Usage Examples

W
where to get new jars2.1 Downloading Jar

Jump to:   {  
A   B   C   D   F   G   H   I   J   L   M   N   O   P   Q   R   S   T   U   V   W  

[Top] [Contents] [Index] [ ? ]

Table of Contents


[Top] [Contents] [Index] [ ? ]

About This Document

This document was generated by Gray Watson on March 2, 2024 using texi2html 1.82.

The buttons in the navigation panels have the following meaning:

Button Name Go to From 1.2.3 go to
[ < ] Back Previous section in reading order 1.2.2
[ > ] Forward Next section in reading order 1.2.4
[ << ] FastBack Beginning of this chapter or previous chapter 1
[ Up ] Up Up section 1.2
[ >> ] FastForward Next chapter 2
[Top] Top Cover (top) of document  
[Contents] Contents Table of contents  
[Index] Index Index  
[ ? ] About About (help)  

where the Example assumes that the current position is at Subsubsection One-Two-Three of a document of the following structure:


This document was generated by Gray Watson on March 2, 2024 using texi2html 1.82.