Reader small image

You're reading from  Clojure Web Development Essentials

Product typeBook
Published inFeb 2015
Reading LevelIntermediate
Publisher
ISBN-139781784392222
Edition1st Edition
Languages
Right arrow
Author (1)
Ryan Baldwin
Ryan Baldwin
author image
Ryan Baldwin

Ryan Baldwin is a theatre major turned computer science geek. Hailing from the prairies of Western Canada, Ryan has been developing software on a wide array of platforms and technologies since 2001. Once, he wrote a crazy system application that compiled XSD Schema Docs into XAML forms that performed two-way binding with underlying XML documents in .NET WPF. Why? Because it had to be done. Another time, he worked on a project that would mash multiple social networks together, allowing users to find out who they were indirectly "connected" to (something akin to 6 Degrees of Kevin Bacon). It was eventually shelved. In 2012, he relocated to Toronto, where he works with the University Health Network, developing systems and tools that facilitate patient information exchange. You can often find him wearing headphones and jittering in coffee shops.
Read more about Ryan Baldwin

Right arrow

Chapter 3. Logging

We've read patiently and slugged our way through Chapter 2, Ring and the Ring Server, learning the technicalities about request and response maps, handlers, middleware, and adapters. The time has come for us to start getting our hands dirty.

Logging is a wonderful tool in development, and is essential for successfully debugging a system that's gone completely haywire. Logging is the eyes, ears, and mouth of our system. It is our saving grace. However, logging traditionally has a dark side. If you've ever used Java or .NET, you'll be well versed in log4j and log4net, and all the excruciatingly painful configurations that go along with it. While logging is extremely useful, setting it up correctly is nothing short of a clinic in patience.

In this chapter, you will learn:

  • How to configure Timbre for logging

  • How to reconfigure one of the appenders configured by Luminus

  • How to configure a new appender from scratch

  • How to emit logging statements

What is Timbre?


Timbre is a full Clojure library for logging. It's fast, has low overhead, and has many interesting appenders out of the box. Most importantly, setting it up is relatively easy and straightforward compared to other logging libraries.

What is an appender?

An appender is the term used for anything that emits a logging statement to a destination. For example, a logger that writes logging statements to a file is referred to as a file appender, and a logger that writes to a MongoDB database is a MongoDB appender (which natively exists in Timbre). Basically, appender is a fancy pants term for "writer". In the world of Timbre, an appender is, technically, just a map of options, one of which is the appender function responsible for performing the actual logging.

Configuring a Timbre appender


An appender's configuration is managed by a single function, timbre/set-config!, which accepts a list of keys identifying the type of appender, and the appender map, which is the actual configuration for the appender.

Taking a look at the init function in hipstr.handler, the first thing we see is a call to configure Timbre:

(timbre/set-config!
  [:appenders :rotor]
  {:min-level :info
    :enabled? true
    :async? false ; should be always false for rotor
    :max-message-per-msecs nil
    :fn rotor/appender-fn})

The preceding snippet configures the rotor appender, a type of file appender that creates a new log file after the current log file exceeds a specific size. Timbre's set-config! has a similar signature and behavior to Clojure's assoc-in (https://clojuredocs.org/clojure.core/assoc-in) function, but without having to define the target map to mutate.

Note

To see all the different appenders that Timbre ships with and to see how to configure each of them, take...

Logging with Timbre


We can emit a log statement using Timbre's log function, which accepts—at a minimum—the log level and a message to emit. The following code shows an example of an log function.

(require '[taoensso.timbre :as timbre])
(timbre/log :info "This is an info message.")
>> 2014-Nov-24 14:35:24 -0500 computer.local INFO [hipstr.handler] - This is an info message.

Alternatively, Timbre makes available a function for each logging level, thus relieving us from having to specify the log level with each call, as shown in the following code:

(timbre/info "This is an info message.")

Timbre's log functions are similar to Clojure's str and println functions, as we can pass multiple strings to produce a single long string:

(timbre/info "This" "is" "an" "info" "message.")

No logging framework would be complete without the ability to log exceptions. Here is an example of appending an Exception:

(timbre/error (Exception. "Aw snap!") "Something bad happened." "It's really awful.")

Appenders will...

Adding an appender


Luminus generates our application to use the rotor appender. I prefer using a rolling appender instead of a rotor appender. A rolling appender is a file appender, like the rotor appender, however, it doesn't create a new log file when a predetermined maximum size is hit. Instead, a new log file is created either daily, weekly, or monthly. I find rolling appenders more useful in production environments because they help when diagnosing problems that have happened sometime in the past (you have a better idea which log files to check).

In this section, we're going to configure a rolling appender for our hipstr application.

Adding the rolling appender

We can put our rolling logs in their own directory, called logs. Unfortunately, Timbre doesn't create directories for us, so we'll have to create the directory first. From the terminal, add a logs directory in the hipstr source root:

# mkdir logs

Next, in our hipstr.handler namespace, we'll want to refer to the taoensso.timbre.appenders...

Summary


It is always confounding to configure logging libraries. In this chapter, you learned that it doesn't have to be impossible when using Timbre. You learned how to configure existing appenders, as well as adding new ones, and you learned the value of always reading the friendly manual… even if the manual is docstrings in the source code. You can use your new found knowledge and love for Timbre if you need to debug anything in the next chapter, wherein we will discuss Compojure route handlers, Selmer templates, and we'll finally create our first page.

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Clojure Web Development Essentials
Published in: Feb 2015Publisher: ISBN-13: 9781784392222
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Ryan Baldwin

Ryan Baldwin is a theatre major turned computer science geek. Hailing from the prairies of Western Canada, Ryan has been developing software on a wide array of platforms and technologies since 2001. Once, he wrote a crazy system application that compiled XSD Schema Docs into XAML forms that performed two-way binding with underlying XML documents in .NET WPF. Why? Because it had to be done. Another time, he worked on a project that would mash multiple social networks together, allowing users to find out who they were indirectly "connected" to (something akin to 6 Degrees of Kevin Bacon). It was eventually shelved. In 2012, he relocated to Toronto, where he works with the University Health Network, developing systems and tools that facilitate patient information exchange. You can often find him wearing headphones and jittering in coffee shops.
Read more about Ryan Baldwin