Creating logging abstraction based on macros

Viewed 56

My project is a framework. It does itself do logging with its own implementation but should also be able to use a logging library the user chooses for his application. Since logging libraries like log4cl are very much based on macros I'm not quite sure how to accomplish this because as I understand macros must be loaded first, before functions, etc.

What I came up with is asdf based. I provide a simple package that exports symbols like: lerror, lwarn, ldebug, etc. which should be implemented as macros allowing to make special implementation for log4cl or other log libraries.

I.e. a simple logging implementation that comes with my framework is just using FORMAT and dumping to *standard-output*.

The asdf approach them requires to make systems. One for the lisp file that just defines the package with exported symbols. Then other systems, based on the last, that provide the specific implementations as macros. The user would then have to define a sequence of systems that must be specified before the actual framework system in order to have the framework 'use' a specific logging library (that is available for the macro-expansion phase).

While this works, I'm not sure this is the right approach. It seems quite complicated. Wouldn't we deal with macros the approach would simply be to define generic functions and provide specific implementation, but they wouldn't require to be defined first.

1 Answers

If you want to use a function or macro to log something, it is generally better to have that defined/loaded before the using code is defined/loaded. That way the names of the logging functionality is already known (the compiler can warn about argument errors, the compiler might not warn about undefined functionality, ...). Additionally this would be required if the logging functionality resides in its own namespace (-> package).

One remaining question: why would a logging operator be a macro?

There might be a reason for it: the macro runs at macro-expansion time and sees the source code and might see additional information at compile time from the compile time environment.

As a macro we can write:

(log-write (call-some-functionality) "calling ~a")

above would be able to log the code, too.

As a function we would need to write:

(log-write (call-some-functionality)
           "calling (call-some-functionality)")

Since the function does not see the code of its arguments.

Related