• Stars
    star
    103
  • Rank 333,046 (Top 7 %)
  • Language
    Clojure
  • License
    Eclipse Public Li...
  • Created over 9 years ago
  • Updated about 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Clojurescript logging library

Klang - A Clojurescript logging libary/viewer

Simple logging library for clojurescript.

Example Example

Demo

(Old) Demo is here: Demo.

Features

  • Central hub to push all log messages in your client app
  • Zero overhead and removal of all log function calls for production by eliding all calls with macros. No Klang code goes into your app.
  • Enter a search term to quickly find log messages
  • Pausing the UI in case of many logs arriving. This will not discard the logs but buffer them.
  • Click on any log message and dump the object to your javascript console (as an object). This allows you to inspect the object and even log functions and invoke them in your javascript console. See the demo. Also works great with Devtools
  • Attach a full stacktrace to every log call (dumped to the console and clickable in Chrome!).

Motivation

By now (2015) the javascript and clojurescript community seems to have arrived at the fact that javascript applications need to be asynchronous throughout. React's Flux architecture, core.async, re-frame (which uses core.async), RxJS, CSP etc etc. are all examples of such design decisions.

Asyncronous systems have many advantages but also make reasoning about the system harder. One very simple and effective way to cope (or rather: "help") with understanding behavior is extensive logging from the start of the development. This projects the concurrent nature of the control flow into a single, easy to understand linear trace of events. The javascript console is not powerful enough, hence this library.

Clojars

Clojars Project

Usage

The following is the simplest usage, using no macros (see below for advanced usage):

(ns your.app.somens
  (:require [klang.core :refer-macros [info! warn! erro! crit! fata! trac!]]))

;; You can pass any arguments to the log macros:

(info! "Sending transit request" {:url "foo"})
(erro! "Failed to connect" {:reason http-status})

;; To show/hide the logs just press the `m` key OR:
(k/show!)

Note that if you use this in production facing code then you'll want to use this library somewhat differently in order to elide any logging for production (see below).

Production eliding of log calls

In most use cases for web app development you'll want to remove logging data and the overhead of Klang from your JS code for deployment. For this you have to do two things:

  1. Configure Klang to elide log calls you don't want.
  2. Create your own CLJS function that get's called for the severe errors/warnings. There you can log them or send them to the server etc.

Klang offers:

  • Setup of whitelist and blacklist (similar to timbre) to elide specific log calls. For instance: whitelist a namspace. Whitelist a specific :type of logs (only :FATAL). This means you specify which log macro calls generate cljs function calls.
  • Optionally add line number and file name in your cljs file to every log call
  • Optionally add local bindings that exist when you make a log call (by default enabled)
  • Change the actual log function being called (for instance your own function instead of klang for production)

Ways to configure

Klang gets configures by a single map. The default map is the following:

{:logger-fn 'klang.core/log!
;; Hold the keywords of which metadata of &form should be added to a log! call
;; Usually :file & :line are available
:form-meta #{}
;; Allow shortening namespaces:
:compact-ns? false
;; True if every macro call also attaches the environment (local bindings) to a
;; log call.
:meta-env? true
:default-emit? true
:whitelist ""
:blacklist ""}

You can change the behaviour of the macroexpansion of Klang by configuring it in two ways. All involve setting a Java system property. Which you can set in leiningen like so:

{:jvm-opts ["-Dklang.config-file=klang-prod.edn"]}
  1. Set klang.config-file=klang-prod.edn. It should be on the classpath since the file will be called with io/resource

  2. Set the Java defines:

    • klang.logger-fn=klang.core/log!
    • klang.form-meta=\"#{:line :file}\"
    • klang.compact-ns=false
    • klang.meta-env=false
    • klang.trace=false
    • klang.default-emit=true
    • klang.whitelist=\"(ERRO|FATA|WARN)\"
    • klang.blaclist=\"TRAC\"

The options are all read-stringed except the whitelist and blacklist.

The options mean:

:logger-fn: A symbol. This the CLJS function that gets called for the log calls. The macro emit the proper call (or not if it's elided). The arguments of the logger-fn are:

  1. ns, the namespace string, possibly shortened.
  2. severity, the serverity as a string (like "INFO", "WARN")
  3. & args, the rest of the message.
  • :form-meta: A set. Can be set to #{:file, :line} to include file and line location of the log call.

  • :trace: If true, will include the stacktrace in the meta data of every log call. You can then click on it in the JS console and jump to the sources of the stacktrace.

  • :compact-ns?: If true the namespace will be shortend. Foo.Barr.Bazzz.Wuzz will be F.B.B.W. Useful for production builds.

  • :meta-env?: If true will include the local bindings in a map as the first argument to the log function. These bindings can be inspected by clicking on the log message in the overlay.

  • :default-emit?: If neither whitelist nor blacklist kicks in, then this decides if the log call should be emitted.

  • :whitelist/:blacklist: A regular expression that can whitelist/blacklist log calls. It gets matched to the string: the-namespace/the-severity.

Example production config:

Put this somewhere in resources/config/klang.edn for example:

{:logger-fn your.ns/production-logger
 :form-meta #{}
 :compact-ns? true
 :meta-env? false
 :default-emit? false
 :whitelist "*/(ERRO|FATA|WARN|CRIT)"
 :trace? false}

And set:

"-Dklang.config-file=config/klang.edn"

NOTE: In order to use the production logger you have to require your CLJS namespace in every namespace where you log. This avoids the Clojurescript warnings "WARNING: Use of undeclared Var our.logger/prod-logger". One simple hack is to:

  • Create a new folder like env/prod/src
  • Add the above folder to the src directory only for production builds (EG. leiningen {:profiles {:cljs-prod {:sources-paths ["env/prod/src", "src/cljs"]}}} Then compile with lein with-profile cljs-prod .....
  • Create a file env/prod/src/klang/core.cljs in which you define your production logger:
(defn log! [ns severity & msg] ...)

This will avoid the warning. However, even with the warnings your program should run just fine (and compile fine by Google Closure compiler).

Contribute

Depending on your workflow you can choose to start just figwheel or to first start a REPL and start figwheel from there.

Just figwheel

$ lein figheel

REPL then figwheel

You will want to do it this way if you want to jack in with Emacs CIDER or connect to the REPL from other tools/editors.

$ lein repl

Then at the REPL prompt:

klang.dev=> (start)

License

Copyright Β© 2015-2017 Andre Rauh. Distributed under the Eclipse Public License, the same as Clojure.