{"id":116115,"date":"2015-05-11T08:39:42","date_gmt":"2015-05-11T12:39:42","guid":{"rendered":"https:\/\/spin.aa8q45el-liquidwebsites.com\/?p=116115"},"modified":"2022-06-15T20:44:02","modified_gmt":"2022-06-16T00:44:02","slug":"clojure-logging","status":"publish","type":"post","link":"https:\/\/spin.atomicobject.com\/clojure-logging\/","title":{"rendered":"Taking Control of Logging in Clojure"},"content":{"rendered":"<p>Clojure inherits some interesting tradeoffs as a result of being built atop the Java Virtual Machine. One upside is the availability of many full-featured and mature Java libraries. But one downside is the need to survey the historical as well as technical landscape of your available choices.<\/p>\n<p>Unsurprisingly, when it came time to add proper logging to my project, I had to make sense of the several available Java logging libraries. Here\u2019s what I found.<!--more--><\/p>\n<h2>Use clojure.tools.logging<\/h2>\n<p>You should absolutely use Clojure\u2019s tools.logging library. Like most Clojure libraries, it provides the right balance of simplicity with just the complexity you really need. Unfortunately, one of those needed complexities is a dependency on an underlying Java logging library. It uses, in order of preference:<\/p>\n<ul>\n<li>slf4j<\/li>\n<li>commons-logging<\/li>\n<li>log4j<\/li>\n<li>java.util.logging<\/li>\n<\/ul>\n<p>So now you must make a choice, or (through inaction) choose Java\u2019s built in util.logging. (Thankfully, that\u2019s probably a pretty reasonable choice as long as you\u2019re not logging a ton of information and don\u2019t need finer control over what gets logged.)<\/p>\n<h3>log4j?<\/h3>\n<p>If you\u2019re like me, your attention might first gravitate toward log4j, simply because it\u2019s one you recognize as widely used. Nevertheless, it\u2019s likely not your best choice for a new project. It\u2019s not maintained, and it absolutely won\u2019t function without you first spending your time giving it some configuration that it should have just used by default anyway. Worse, it depends on some packages that appear not to be in maven, so you have to explicitly exclude those in your project.clj dependencies.<\/p>\n<h3>slf4j?<\/h3>\n<p>Given that tools.logging selects slf4j as its first preference, I made this my next area of investigation. I discovered that slf4j is not a logging library; it\u2019s actually an API meant to wrap a variety of other logging libraries. At this point, I was left feeling mildly disgusted at the idea of using a logging library that wraps another logging library that wraps other logging libraries. Worse, most of the Clojure examples I found in my searching were actually using slf4j to wrap log4j.<\/p>\n<h3>The solution: logback<\/h3>\n<p>With some more digging, I found out that the folks that made slf4 also made log4j, and that they have also made a new logging library meant to replace log4j. This library is logback. Naturally, logback natively supports the slf4j API. It also appears to provide all the flexibility I could want, while still providing entirely sane defaults. No need to spend my time up front configuring it, before I have any actual problems to solve.<\/p>\n<h2>Conclusion<\/h2>\n<p>Use clojure.tools.logging with logback. Just add these two dependencies to your project.clj:<\/p>\n<pre lang=\"clojure\">\r\n  :dependencies [...\r\n                 [org.clojure\/tools.logging \"0.3.1\"]\r\n                 ; No need to specify slf4j-api, it\u2019s required by logback\r\n                 [ch.qos.logback\/logback-classic \"1.1.3\"]\r\n                 ...]\r\n<\/pre>\n<p>It\u2019s not thrilling or enjoyable to spend your time hunting down the best way to add a glorified <code>println<\/code> to your project instead of actually getting real work done. I hope this will help others who find themselves in this situation in the future.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Clojure inherits some interesting tradeoffs as a result of being built atop the Java Virtual Machine. One upside is the availability of many full-featured and mature Java libraries. But one downside is the need to survey the historical as well as technical landscape of your available choices. Unsurprisingly, when it came time to add proper [&hellip;]<\/p>\n","protected":false},"author":455,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1764],"tags":[],"series":[],"class_list":["post-116115","post","type-post","status-publish","format-standard","hentry","category-java-dev"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Quickly Set up Clojure Logging with the Right Library<\/title>\n<meta name=\"description\" content=\"When it came time to add proper logging to my project, I had to make sense of the several available Java logging libraries. Here\u2019s what I found.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/spin.atomicobject.com\/clojure-logging\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Quickly Set up Clojure Logging with the Right Library\" \/>\n<meta property=\"og:description\" content=\"When it came time to add proper logging to my project, I had to make sense of the several available Java logging libraries. Here\u2019s what I found.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/spin.atomicobject.com\/clojure-logging\/\" \/>\n<meta property=\"og:site_name\" content=\"Atomic Spin\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/atomicobject\" \/>\n<meta property=\"article:published_time\" content=\"2015-05-11T12:39:42+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-06-16T00:44:02+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/spin.atomicobject.com\/wp-content\/uploads\/Atomic-Object-Spin.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2300\" \/>\n\t<meta property=\"og:image:height\" content=\"1534\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Chris Farber\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@atomicobject\" \/>\n<meta name=\"twitter:site\" content=\"@atomicobject\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Chris Farber\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"3 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/clojure-logging\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/clojure-logging\\\/\"},\"author\":{\"name\":\"Chris Farber\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/#\\\/schema\\\/person\\\/3c7d1972f93a6f4d2b21f597f94f4cac\"},\"headline\":\"Taking Control of Logging in Clojure\",\"datePublished\":\"2015-05-11T12:39:42+00:00\",\"dateModified\":\"2022-06-16T00:44:02+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/clojure-logging\\\/\"},\"wordCount\":513,\"publisher\":{\"@id\":\"https:\\\/\\\/atomicobject.com\\\/\"},\"articleSection\":[\"Java\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/clojure-logging\\\/\",\"url\":\"https:\\\/\\\/spin.atomicobject.com\\\/clojure-logging\\\/\",\"name\":\"Quickly Set up Clojure Logging with the Right Library\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/#website\"},\"datePublished\":\"2015-05-11T12:39:42+00:00\",\"dateModified\":\"2022-06-16T00:44:02+00:00\",\"description\":\"When it came time to add proper logging to my project, I had to make sense of the several available Java logging libraries. Here\u2019s what I found.\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/spin.atomicobject.com\\\/clojure-logging\\\/\"]}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/#website\",\"url\":\"https:\\\/\\\/spin.atomicobject.com\\\/\",\"name\":\"Atomic Spin\",\"description\":\"Atomic Object\u2019s blog on everything we find fascinating.\",\"publisher\":{\"@id\":\"https:\\\/\\\/atomicobject.com\\\/\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/spin.atomicobject.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/#organization\",\"name\":\"Atomic Object\",\"url\":\"https:\\\/\\\/spin.atomicobject.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/spin.atomicobject.com\\\/wp-content\\\/uploads\\\/AO-Logo-Emblem-Color.png\",\"contentUrl\":\"https:\\\/\\\/spin.atomicobject.com\\\/wp-content\\\/uploads\\\/AO-Logo-Emblem-Color.png\",\"width\":258,\"height\":244,\"caption\":\"Atomic Object\"},\"image\":{\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/atomicobject\",\"https:\\\/\\\/x.com\\\/atomicobject\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/#\\\/schema\\\/person\\\/3c7d1972f93a6f4d2b21f597f94f4cac\",\"name\":\"Chris Farber\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/217895b63a9f8ae1b67495e104c8f31f678405d712f69fee875f37b6d4658314?s=96&d=blank&r=pg\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/217895b63a9f8ae1b67495e104c8f31f678405d712f69fee875f37b6d4658314?s=96&d=blank&r=pg\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/217895b63a9f8ae1b67495e104c8f31f678405d712f69fee875f37b6d4658314?s=96&d=blank&r=pg\",\"caption\":\"Chris Farber\"},\"url\":\"https:\\\/\\\/spin.atomicobject.com\\\/author\\\/farber\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Quickly Set up Clojure Logging with the Right Library","description":"When it came time to add proper logging to my project, I had to make sense of the several available Java logging libraries. Here\u2019s what I found.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/spin.atomicobject.com\/clojure-logging\/","og_locale":"en_US","og_type":"article","og_title":"Quickly Set up Clojure Logging with the Right Library","og_description":"When it came time to add proper logging to my project, I had to make sense of the several available Java logging libraries. Here\u2019s what I found.","og_url":"https:\/\/spin.atomicobject.com\/clojure-logging\/","og_site_name":"Atomic Spin","article_publisher":"https:\/\/www.facebook.com\/atomicobject","article_published_time":"2015-05-11T12:39:42+00:00","article_modified_time":"2022-06-16T00:44:02+00:00","og_image":[{"width":2300,"height":1534,"url":"https:\/\/spin.atomicobject.com\/wp-content\/uploads\/Atomic-Object-Spin.jpg","type":"image\/jpeg"}],"author":"Chris Farber","twitter_card":"summary_large_image","twitter_creator":"@atomicobject","twitter_site":"@atomicobject","twitter_misc":{"Written by":"Chris Farber","Est. reading time":"3 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/spin.atomicobject.com\/clojure-logging\/#article","isPartOf":{"@id":"https:\/\/spin.atomicobject.com\/clojure-logging\/"},"author":{"name":"Chris Farber","@id":"https:\/\/spin.atomicobject.com\/#\/schema\/person\/3c7d1972f93a6f4d2b21f597f94f4cac"},"headline":"Taking Control of Logging in Clojure","datePublished":"2015-05-11T12:39:42+00:00","dateModified":"2022-06-16T00:44:02+00:00","mainEntityOfPage":{"@id":"https:\/\/spin.atomicobject.com\/clojure-logging\/"},"wordCount":513,"publisher":{"@id":"https:\/\/atomicobject.com\/"},"articleSection":["Java"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/spin.atomicobject.com\/clojure-logging\/","url":"https:\/\/spin.atomicobject.com\/clojure-logging\/","name":"Quickly Set up Clojure Logging with the Right Library","isPartOf":{"@id":"https:\/\/spin.atomicobject.com\/#website"},"datePublished":"2015-05-11T12:39:42+00:00","dateModified":"2022-06-16T00:44:02+00:00","description":"When it came time to add proper logging to my project, I had to make sense of the several available Java logging libraries. Here\u2019s what I found.","inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/spin.atomicobject.com\/clojure-logging\/"]}]},{"@type":"WebSite","@id":"https:\/\/spin.atomicobject.com\/#website","url":"https:\/\/spin.atomicobject.com\/","name":"Atomic Spin","description":"Atomic Object\u2019s blog on everything we find fascinating.","publisher":{"@id":"https:\/\/atomicobject.com\/"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/spin.atomicobject.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/spin.atomicobject.com\/#organization","name":"Atomic Object","url":"https:\/\/spin.atomicobject.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/spin.atomicobject.com\/#\/schema\/logo\/image\/","url":"https:\/\/spin.atomicobject.com\/wp-content\/uploads\/AO-Logo-Emblem-Color.png","contentUrl":"https:\/\/spin.atomicobject.com\/wp-content\/uploads\/AO-Logo-Emblem-Color.png","width":258,"height":244,"caption":"Atomic Object"},"image":{"@id":"https:\/\/spin.atomicobject.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/atomicobject","https:\/\/x.com\/atomicobject"]},{"@type":"Person","@id":"https:\/\/spin.atomicobject.com\/#\/schema\/person\/3c7d1972f93a6f4d2b21f597f94f4cac","name":"Chris Farber","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/217895b63a9f8ae1b67495e104c8f31f678405d712f69fee875f37b6d4658314?s=96&d=blank&r=pg","url":"https:\/\/secure.gravatar.com\/avatar\/217895b63a9f8ae1b67495e104c8f31f678405d712f69fee875f37b6d4658314?s=96&d=blank&r=pg","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/217895b63a9f8ae1b67495e104c8f31f678405d712f69fee875f37b6d4658314?s=96&d=blank&r=pg","caption":"Chris Farber"},"url":"https:\/\/spin.atomicobject.com\/author\/farber\/"}]}},"_links":{"self":[{"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/posts\/116115","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/users\/455"}],"replies":[{"embeddable":true,"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/comments?post=116115"}],"version-history":[{"count":0,"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/posts\/116115\/revisions"}],"wp:attachment":[{"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/media?parent=116115"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/categories?post=116115"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/tags?post=116115"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/series?post=116115"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}