On Logging

Posted on November 15, 2014 by Alex Sassmannshausen

Glean's logging originates in the dark whirl of ad-hoc debug statements, end-user messages that might be useful and attempts to make sense of monads as they unfold at run-time. You can probably imagine that this primordial ooze does not make for a very systematic or easy to use foundation.

From the next pre-release logging will be available in an improved framework:

Parameterize This

A new parameter is introduced called ’logger’. It starts it's humble life as a procedure that simply returns #f. Thus, by default, Glean does not perform any logging. I will get back to this point below.

The parameter itself actually returns the result of applying the ‘make-logger’ procedure. As implied above, this returns a constant #f if invoked with the default combination of arguments. It can also return a procedure that logs to stdout or a procedure that logs to a file.

The ‘logger’ parameter is set after the general boot routines, just prior to each actual server's launch, so the code is at ‘glean/$server/boot.scm‘.

Using The Logger

When writing code we don't have to concern our pretty little heads with ‘logger’ or ’make-logger’. We can simply use our logging procedures: ‘inform‘, ‘insist‘, ‘caution‘, and ‘exclaim‘. You may have noticed the list ascending in urgency — that's exactly how they should be used. There is a second parameter, ‘log-level‘, which can be set in the configuration files. This is used by the logger to decide which messages should be logged, if logging is enabled in the first place.

Monadic Logging... Maybe

Glean uses some inexpertly produced monads, which currently carry out logging in the ’bind’ stage. This is problematic, and we will need to implement proper monadic logging at a later stage. For now I am chuffed that we have organized the actual logging in ‘bind‘.

‘bind‘ uses a procedure called ‘mlogger’, which in turn uses the underlying logging procedures mentioned in the section above.

The neat thing about ‘mlogger‘ is that it is configurable by the monad that uses it: it takes a predicate and a dictionary procedure, and returns the actual logger, which can then be applied to every value encountered by ’bind’.

The logger will only log if the value passed to it passes predicate — and it will then be analysed by dictionary which ensures sensible messages are output by the monad, rather than just raw intermediate values.

No Logging?

The reason for this is primarily that logging, as it stands, involves side-effects. Glean is supposed to be written in a functional paradigm, and in the absence of a proper I/O or logging monad, there is no way, as far as I know, to retain referential transparency with logging switched on.

Having said this, a) I'm not sure what effect parameterization has on referential transparency; b) it may well be that when reasoning about procedures, one can ignore logging output, as it's side-effect seems immaterial to the computation — for the purposes of reasoning, a procedure may be referentially transparent, even though for the purposes of optimization it may not be. If either of the above are true then disabling logging by default is a mere point of principle: an insistence that I know that logging is not as it should be yet, and hence is not ready to be a default value.

Where To Next?

The primary changes that I can foresee to the logging mechanism concern themselves with making the entire logging process referentially transparent. This will inevitably require me to revisit monads and to implement logging through them.

This will have to wait until a later version — for now: friendly logging FTW!

Creative Commons Licence
This work by Alex Sassmannshausen is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License .