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