Implementing std.log

Jacob Carlborg doob at me.com
Tue May 17 02:02:29 PDT 2011


On 2011-05-16 02:05, Andrei Alexandrescu wrote:
> 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.

Note that my suggestion was just a simple and incomplete suggestion on 
how the API could look like. I only provided "info", "warning" and 
"error" methods as examples, I'm not saying the API should only have 
these three levels.

> 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.

I didn't consider disabling logging during compilation at all. If people 
like the basic idea with my API then, of course, I would flesh it out 
and add support compile time disabling of the logging.

> 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.

The problem with variadic template methods are that they're not virtual.

> 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.

I thought it was a good idea that you could chain calls like this:

log.info("foo").error("bar");

> 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.

Ok. Just a note, nobody is forcing you to use the default logging level.

> 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

I got the impression that you change "log.info" to "logInfo" just 
because you wanted user defined loggers to look the same. My suggestion 
shows that's not necessary. Also I tried to minimize the use of global 
variables.

-- 
/Jacob Carlborg


More information about the Digitalmars-d mailing list