Implementing std.log

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Sun May 15 17:05:24 PDT 2011


On 05/15/2011 02:54 PM, Jacob Carlborg wrote:
> On 2011-05-14 19:04, Andrei Alexandrescu wrote:
>> On 5/9/11 1:52 AM, Andrei Alexandrescu wrote:
>> [snip]
>>
>> I updated my std.log draft. Added a lot of features including formatted
>> writing, delayed logging, and a variety of configuration options.
>> Replaced the redundant log.xyz with logXyz. The implementation is
>> getting close to reviewable form.
>>
>> Documentation:
>>
>> http://d-programming-language.org/phobos-prerelease/std_log.html
>>
>> Source:
>>
>> https://github.com/andralex/phobos
>>
>> Feedback welcome.
>>
>>
>> Thanks,
>>
>> Andrei
>
> How about an API that looks something like this:
> http://pastebin.com/dLVp1GRr
>
> This API contains standard interfaces for a logger and a logging level.
> It contains a default logger implementation and a couple of logging
> levels. This API also allows you to implement custom loggers and custom
> logging levels. Multiple logger instances are possible with options set
> on each instance.
>
> Note this is just a suggestion for the API and doesn't contain any real
> implementation (just prints to stdout).

Thanks for your work.

I think there's an important distinction to be made. There are two 
"API"s being discussed. One is the client interface and the other is the 
extensibility interface.

Jose looked into both: he provided a client interface that has 
formatting, levels, enabling, and such, and an extensibility interface 
that essentially is a simple output stream.

My library explores the client interface and leaves the extensibility 
interface as an obvious piece of work that needs little agreement and 
minimal design effort.

Finally, your library keeps the client interface to a minimum and 
focuses almost exclusively on the extensibility interface. In doing so, 
it makes few choices that I disagree with. Allow me to share some 
specific feedback.

1. It "becomes dynamic" too early. First, in order to disable logging 
during compilation, a barrier of aliased types is needed. The alias 
would choose either a "null type" that does nothing (see 
StaticNullLogger at 
https://github.com/andralex/phobos/blob/master/std/log.d), or a log that 
actually does something. I think your design can be adjusted to do that 
with relative ease.

2. It "becomes dynamic" too early from a different perspective. The 
interface for extensibility is identical with the interface for use and 
as a consequence leaves too broad functionality unimplemented. A better 
design is to handle a bunch of decisions (is the log dynamically 
enabled? every N calls? every N seconds? before N seconds have passed? 
after N seconds have passed?) in a lightweight front end, i.e. _before_ 
arguments have been evaluated (this is crucial!). Also, the front end 
should take care of formatting minutiae, leaving the dynamic back-end 
the simple task of streaming text where it's supposed to be going. I 
think Jose's design did the right thing there by doing enabled checks 
and formatting in the front-end, leaving only transport to the back-end.

3. Another consequence is that extensibility points have the signature:

Logger log(string file, long line, ...);

which leaves the heavyweight formatting task to the antiquated "..." 
interface (no static types left, meaning e.g. no structs defining 
toString can be logged). Even assuming that's not a problem, 
implementors of this function are left with a fair amount of work to do.

4. The Logger class contains info, warning, and error Level objects. 
Each Level object in turn contains a reference to a Logger. This design 
leaves some odd shrapnel behind, e.g. one can get to the critical log 
from the info log.

5. I've seen the notion of a default logging level elsewhere but I think 
it's inadequate for the info/warning/error/critical/fatal approach. It 
is adequate for verbosity levels, i.e. vlog and friends. For 
info/warning/etc. the decision of the appropriate level belongs to the 
caller.

6. My initial design also contained a global "log battery" containing 
the info, warning, etc. objects as members. I found that design stilted 
because it provides absolutely no benefit besides a marginal "log.info" 
vs. "logInfo", has no encapsulation advantage, is adverse to 
extensibility, and worse of all perpetuates poor object oriented design. 
It's best to call a spade a spade, so there should be five global 
objects because that's in keep with reality.


Andrei


More information about the Digitalmars-d mailing list