Early review of std.logger

Sönke Ludwig sludwig at outerproduct.org
Tue Oct 15 07:12:20 PDT 2013


Am 15.10.2013 15:52, schrieb Robert Schadek:
> On 10/15/2013 03:21 PM, Sönke Ludwig wrote:
>> Am 15.10.2013 10:41, schrieb Robert Schadek:
>>> On 10/15/2013 02:44 AM, Kapps wrote:
>>>> The simple act of logging a message is very verbose right now:
>>>> log(LogLevel.trace, "Creating new pool") is a lot of boiler plate. I'd
>>>> prefer something like log.trace("Creating new pool") and log("Creating
>>>> new pool") where the latter would use opCall to forward to the default
>>>> log level. If it's intentional that you can assign the result of log,
>>>> this also helps that because log = new StdIOLogger would be possible
>>>> (log being a property that returns a Logger, and so a setter could be
>>>> made), but log("Creating new pool") = new StdIOLogger() would not be.
>>> The LogLevel is optional. And always writing log.trace might become more
>>> typing work and assigning a LogLevel and than calling log("..."). Both
>>> have pros and cons
>>
>> What happens when a called function alters the default log level?
> The default log level is altered.

Believe it or not, for some reason I suspected as much.

>>
>> ---
>> void func1() {
>>      log.logLevel = LogLevel.debug;
>>      log("This is a debug message");
>>      func2();
>>      log("This is supposed to be a debug message");
>> }
>>
>> void func2() {
>>      log.logLevel = LogLevel.warning;
>>      log("This is a warning");
>> }
>> ---
> If you don't specify a logger nor a LogLevel the currently set default
> logger will log the message with its currently set LogLevel.

Yes, but the point is that when looking only at func1, you might expect 
that all messages are logged as debug messages, but the last one will be 
logged as a warning instead. func2 may be hidden in library where the 
function body is not readily available.

>>
>>
>> I don't think it's a good idea to use such kind of global state,
>> especially for a logging framework that is supposed to be shared
>> between libraries, so that it is difficult to predict what a
>> particular function does. With a logger that is shared between
>> threads, things get worse of course.
> I think this is good, as it gives you a way to quite libraries down. The
> idea behind the free standing "log" function is to provide an ultra easy
> way to log. It is not meant to be used for the 2<<31 line program. In
> that case you will properly have very specific needs on how to log.
> Hence implement the abstract Logger class to your needs.

But if it's available people _will_ use it in complex contexts. Also if 
the writer of a 2<<8 loc library uses it and the library is used by a 
large piece of software, that will also be affected. The point is that 
it is unhygienic and requires non-trivial extra work when using a logger 
in a multi-threaded environment. Some kind of scoped stack of default 
log levels would get around this issue, but that smells like over 
engineering.

>>
>> A related question: It seems like Logger.logLevel at the same time
>> means the minimum log level that is output and the default log level,
>> is that right?
> Yes. The LogLevel of each logger is the LogLevel used if non is
> specified and only messages are logged by this logger if their LogLevel
> is greater equal to that Level. Additionally the LogLevel must be >= to
> the global LogLevel.

But these are two different concepts and it's hard for me to imagine why 
they should be conflated. But I guess it's time to stop complaining 
about the whole log("message") complex.


More information about the Digitalmars-d mailing list