Better logging with TinyLog 2

tiny-log-logging-framework

Most, if not all, Java and Android developers have come across logging requirements in their application. Most commonly known Java logging frameworks are Log4j2, Logback, and JUL (Java Util Logging), and most people have probably used SLF4J, the abstraction on top of these logging frameworks.

A lesser know logging framework is TinyLog 2. This blog post will dive into TinyLog 2, hereafter referred to as TinyLog, and in this post, we’ll dive into what sets TinyLog apart, and how to use it.

What is TinyLog

TinyLog is a logging framework for Java and Android-based applications with a relative small file size (around 120kb for the current version of TinyLog 2), which is particularly handy for Android applications. While the file size of TinyLog is quite small, TinyLog still manages to pack quite a lot of features in their library, which we’ll dive in soon.

Different to most logging frameworks, TinyLog uses a static logging interface, so there’s no need to use a LogFactory in every class to get access to the Logger interface. This makes using TinyLog a little easier to use than the more established logging frameworks.

How to use TinyLog

To get started with TinyLog, we’ll need to import a few dependencies. When using Java, we’ll need to add the following dependencies to our build.gradle:

implementation 'org.tinylog:tinylog-api:2.0.0'
implementation 'org.tinylog:tinylog-impl:2.0.0'

Alternatively, when using Kotlin, there’s a specific API binary, which can be included as follows:

implementation 'org.tinylog:tinylog-api-kotlin:2.0.0'
implementation 'org.tinylog:tinylog-impl:2.0.0'

TinyLog provides specific interfaces for Java, Kotlin and Scala, but all languages use the same implementation.

After the dependencies have been added, a trivial example of the logging looks like this:

import org.junit.Test
import org.tinylog.kotlin.Logger

class LogTest {
    @Test fun basic() {
        Logger.info("This is an info message")
    }
}

Note: for the Java version, replace the org.tinylog.kotlin.Logger with org.tinylog.Logger.

Running the above test will use the default log format, which will result in the following output:

2019-06-15 00:17:14 [Test worker] LogTest.basic()
INFO: This is an info message

Even without creating the logger from the LogFactory TinyLog knows which class and in which method logging takes place.

So much for the basics, let’s dive into some more advanced features.

Features

As stated before, TinyLog has quite some features, making it a very flexible logging framework and a potentially good replacement for Logback or SL4J (you’re not really using JUL right?).

Lazy logging

In Kotlin, lazy logging can be used for String templates or possible expensive computations. For example, the following will use Kotlin String templates:

@Test
fun lazy() {
    val user = "Anonymous"

    Logger.trace { "User $user logged in" }
}

For expensive computations, the same approach can be used:

Java

Logger.warn(() -> expensiveComputation());

Kotlin

Logger.warn { expensiveComputation() }

Log patterns

By creating a tinylog.properties on the classpath, it’s easy to change the log pattern. An example log pattern could look like this:

writer        = console
writer.format = {date: HH:mm:ss.SSS} {level}: {message}

Combining that with the previous example, the following output will be created:

00:34:54.639 TRACE: User Anonymous logged in

If for some reason you’d like to use a pipe separate in the logs, that is possible since the latest version by using the {pipe} macro:

writer.format = {level|min-size=5} {pipe} {thread|min-size=8} {pipe} {message}

Message formatting

Another interesting feature is inline log formatting, such as DecimalFormat or ChoiceFormat patterns. For example, with TinyLog it’s possible to do:

val balance = 200.155
Logger.info("Current balance: {0.00} AUD", balance)

Which will automatically format the balance to 200.16, or ChoiceFormat can be used:

Logger.debug("Search result: {0#no results|1#one result found|1<{} results found}", results.size()

Extending TinyLog

For a lot of projects, an aggregated log is used, and while TinyLog provides a few options out of the box, such a as JDBC writer or a shared file writer, other people (such as us) using ELK or similar aggregation frameworks. By implementing your own Custom Writer, it’s relatively easy to incorporate any log aggregation framework into TinyLog.

SLF4J for TinyLog

Besides listing all the nice features of TinyLog, it might be worthwhile to note that the performance of TinyLog is outstanding. Have a look at their benchmarks for more information.

Also, for those using SLF4J, it’s not necessary to drop SLF4J; TinyLog provides an SLF4J bridge to seamlessly work together.

Conclusion

I hope the above gave a bit of insight into TinyLog, what it does, how you can use it, and what some of the options are, and maybe for the next project you embark on it’s possible to evaluate TinyLog as an option.

Leave a Reply

Your email address will not be published. Required fields are marked *