I'm working on a network-layer library. I'd like to build this
library with ubiquitous logging that applications can turn on at
will. I don't want to tie the application to a particular choice of
logging libraries.
I can easily set up something like:
(defvar *logger* nil)
(defun set-logger (fn) (setf *logger* fn))
(defmacro log (category &rest args)
`(when *logger* (funcall *logger* ,category ,@args))
The problem with this approach is that most logging libraries have
their main logging routine set up as a macro like this:
(defmacro log (category &rest args)
`(when (category-is-turned-on-p ,category)
(really-log ,category ,@args)))
In this way, they avoid having to evaluate the arguments when no-one
cares about the particular category:
(log :excruciating-detail (stringify-all-of-memory *gc* :pretty
t))
I can't think of a way to have the application load my network
library, then call something in my library to activate logging, and
not have my library unconditionally evaluating the arguments.
I pretty much want the user to be able to provide a function for me to
call to log things. I want this function to take two arguments, a
category and a form. I want the form to be evaluated in my library's
context if it gets evaluated at all, but I don't want it to get
evaluated before I pass it into the lambda. I don't know how to do
this.
Some trick with `&environment` and `eval`? What am I missing?
Thanks,
Patrick