August 22, 2013
On Thursday, 22 August 2013 at 17:09:17 UTC, Robert Schadek wrote:
> On 08/22/2013 05:59 PM, Jacob Carlborg wrote:
> But still, I like that very much, even though this is still in conflict
> with std.math.log.
We should avoid name conflicts as much as possible. So, I vote to the Craig Dillabaugh's idea:
logLog()  //OK, that is kind of ugly.
logInfo()
logWarning()
logError()

Note that we can use logDefault(), not logLog(). I think it will be better.
August 22, 2013
Am Thu, 22 Aug 2013 20:04:16 +0200
schrieb Robert Schadek <realburner@gmx.de>:

> On 08/22/2013 07:48 PM, Johannes Pfau wrote:
> > The problem is that format allocates using the GC. Functions like writefln can be much more efficient so if the backend is a FileLogger it could take advantage of that. But IIRC it's not simple to implement this 'forwarding' with classes / interfaces as you'll need templated functions...
> yes, but as you said it is not simple. If it where a template the
> assignable default logger concept would not work,
> as it would instantiate the template of the base class. I don't think
> that this is possible (plz proof me wrong).
> IMO the default logger concept is more important.

I've implemented a small logger some time ago and IIRC I couldn't come up with a satisfying solution.

The last std.log proposal made a compromise to deal with this: It accepted formatted log input but it did call sformat internally before passing it to the Logger implementation. The benefit of this was that it could reuse the same buffer.

In (pseudo)code:

void logf(Args...)(string fmt, Args args)
{
    ubyte[BUFSIZE] buffer;
    _logger.log(sformat(buffer, fmt, args));
}
August 22, 2013
On 08/22/2013 08:17 PM, Johannes Pfau wrote:
> Am Thu, 22 Aug 2013 20:04:16 +0200
> schrieb Robert Schadek <realburner@gmx.de>:
>
>> On 08/22/2013 07:48 PM, Johannes Pfau wrote:
>>> The problem is that format allocates using the GC. Functions like writefln can be much more efficient so if the backend is a FileLogger it could take advantage of that. But IIRC it's not simple to implement this 'forwarding' with classes / interfaces as you'll need templated functions...
>> yes, but as you said it is not simple. If it where a template the
>> assignable default logger concept would not work,
>> as it would instantiate the template of the base class. I don't think
>> that this is possible (plz proof me wrong).
>> IMO the default logger concept is more important.
> I've implemented a small logger some time ago and IIRC I couldn't come up with a satisfying solution.
>
> The last std.log proposal made a compromise to deal with this: It accepted formatted log input but it did call sformat internally before passing it to the Logger implementation. The benefit of this was that it could reuse the same buffer.
>
> In (pseudo)code:
>
> void logf(Args...)(string fmt, Args args)
> {
>     ubyte[BUFSIZE] buffer;
>     _logger.log(sformat(buffer, fmt, args));
> }
What happens if this throws because of an overflow and you're only
indirectly responsable for the call to logf?
I would rather pass my own static string buffer to log if I fear
performance problems, than to hope
that the buffer in logf is big enough.
August 22, 2013
On Thursday, 22 August 2013 at 15:51:53 UTC, Craig Dillabaugh wrote:
> Do you really find the three extra characters a big problem.

They are unnecessary. If you want to make clear you are dealing with logging, you can just write something along the lines of:

import log = std.logger;
log.error("123");

David
August 22, 2013
On Thursday, August 22, 2013 23:36:48 David Nadlinger wrote:
> On Thursday, 22 August 2013 at 15:51:53 UTC, Craig Dillabaugh
> 
> wrote:
> > Do you really find the three extra characters a big problem.
> 
> They are unnecessary. If you want to make clear you are dealing with logging, you can just write something along the lines of:
> 
> import log = std.logger;
> log.error("123");

I'd oppose warning, critical, error, etc. because they're not verbs like functions are supposed to be. It's variables or properties which are nouns. So, while I agree that the module system makes it so that the name clashes shouldn't be a big deal, I disagree with the names anyway and would still prefer logWarning to warning.

- Jonathan M Davis
August 22, 2013
On Thursday, 22 August 2013 at 21:36:50 UTC, David Nadlinger
wrote:
> On Thursday, 22 August 2013 at 15:51:53 UTC, Craig Dillabaugh wrote:
>> Do you really find the three extra characters a big problem.
>
> They are unnecessary. If you want to make clear you are dealing with logging, you can just write something along the lines of:
>
> import log = std.logger;
> log.error("123");
>
> David

I think the two solutions are pretty close in terms of
readability.  Of course the solution here uses convention to
ensure clarity in what the log functions are doing, while
logError() enforces clarity.  I could do:

import px482374203 = std.logger;

....

//much later
px482374203.error("What the heck is this!");

Not that I would ever do that ...

Also just to be nit-picky you are typing 4 extra characters which
is 25% worse than my suggestion :o)
[ In fairness having to use the shift key to type logError()
likely makes log.error() just a bit easier to type.]
August 22, 2013
I hope this gets up, I've been waiting for a std.logger for a while.

My custom one works fine but it's extra sideline code to compile, maintain and lug around.

As for naming, I like the following

log.whisper("low priority log message")
log.say("default log level");
log.shout("Warning level");
log.scream("**ERROR**");

:D

To be honest I don't really care about the naming, but if pressed I'd go for

log("default")
log.warn("a warning")
log.error("an error")

...or something similar. I just find it easier to read than logWarning, logError etc.


/BS

August 23, 2013
W dniu 22.08.2013 16:00, Robert Schadek pisze:
> Docu:
> http://burner.github.io/phobos/phobos-prerelease/std_logger.html

What about specifying log level at runtime, e.g.:

// set by the user at runtime
LogLevel userLogLevelForX;

log(userLogLevelForX, "X");

?
August 23, 2013
On 08/23/2013 02:07 AM, Piotr Szturmaj wrote:
> W dniu 22.08.2013 16:00, Robert Schadek pisze:
>> Docu: http://burner.github.io/phobos/phobos-prerelease/std_logger.html
>
> What about specifying log level at runtime, e.g.:
>
> // set by the user at runtime
> LogLevel userLogLevelForX;
>
> log(userLogLevelForX, "X");
>
> ?
Any other Logger:
auto myCoolLogger = new XXXXLogger();
myCoolLogger.logLevel = LogLevel.Critical;


For the default Logger:
log.logLevel = LogLevel.Info;
August 23, 2013
W dniu 23.08.2013 09:44, Robert Schadek pisze:
> On 08/23/2013 02:07 AM, Piotr Szturmaj wrote:
>> W dniu 22.08.2013 16:00, Robert Schadek pisze:
>>> Docu:
>>> http://burner.github.io/phobos/phobos-prerelease/std_logger.html
>>
>> What about specifying log level at runtime, e.g.:
>>
>> // set by the user at runtime
>> LogLevel userLogLevelForX;
>>
>> log(userLogLevelForX, "X");
>>
>> ?
> Any other Logger:
> auto myCoolLogger = new XXXXLogger();
> myCoolLogger.logLevel = LogLevel.Critical;
>
>
> For the default Logger:
> log.logLevel = LogLevel.Info;

I see, but isn't separate class instance for every log level a bit too much? Setting log level before calling log() isn't (IMHO) good either (think of multi-threaded logging).

My opinion is that LogLevel should not be encapsulated within Logger class.

Instead function overloading should be used (again IMO):

void log(string message);
void log(LogLevel level, string message);

So having separate classes for different loggers (sinks) is very nice, but LogLevel should be specifiable for each message, no matter which Logger class is used.

Then, each _compile-time_ specifiers like .Warning() or .Error() should be just a syntactic sugar over log().