October 14, 2013
On Mon, Oct 14, 2013 at 2:27 PM, Dicebot <public@dicebot.lv> wrote:

> I'd like to have module-specific logging _without_ creating local module
> instance. And without referring to specific logger at all. As I have
> mentioned, something like:
> ```
> import log = std.logger;
> log.local.info(...); // uses special default logger that inspects
> __MODULE__
> log.global.error(...); // uses normal default logger
>
> ```
>

This idea sounds great (esp. if paired with hierarchical loggers I have
been talking about).  If I'm importing std.logger, chances are I am going
to create a logger for the module.
Would eliminate a bunch of boilerplate 'logger log =
logfactory.getMeALog(modulename)'


October 14, 2013
On Monday, 14 October 2013 at 22:04:44 UTC, Jeremy Powers wrote:
> And the shed should be blue.

I vote that we paint it octarine: a nice color that's not too purple and yet not too green and can only be created with magic. So far nobody has painted a bike shed to my satisfaction and I can't understand why.

October 15, 2013
A few concerns:

There doesn't seem to be a debug or trace log level. This is quite a useful thing to have once your program is deployed.

I don't like the returning by ref for log methods. For example, it seems like you can do: log(5 < 4, "This is a test log") = new StdIOLogger();
It could potentially be useful to return the Logger so you can chain calls and such, but it should not be possible to set the logger by assigning the result of a log call.

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.


There's a lot of suggestions for things like network logging, but I think this is far beyond the scope of the module, and the sheer amount of different ways of doing it means people will likely write their own anyways. For example, synchronous vs asynchronous, what protocol to use, authentication, client data, encryption, etc.
October 15, 2013
On Monday, 14 October 2013 at 11:39:52 UTC, Dicebot wrote:
> Lets unleash the forces of constructive destruction.

So, not to be too heavy-handed with criticism on this library, but I think this should come up to par with solutions like log4j, log4cpp, or log4cxx, with respect to features and capabilities.  Libraries like these have enjoyed a lot of very serious use, and once you have something like that in your project, it's hard to not use most of what they have to offer.  There's really not a lot of fluff in those solutions.

Here's what I think is missing:
- System log support (as others have mentioned).  This would be syslog or WEL, depending on environment.

- Guarantees or options for working with log rotation (logrotate.d).  It's nice to either know that you must restart your daemon once logs are rotated, or can configure logging to re-open handles automatically or when it detects rotation has occurred.

- Guarantees about threading and thread safety, with concessions to help keep log event streams coherent from thread to thread.  Log formatting in particular could enjoy the ability to emit a thread id, so logs can be analyzed without confusing which thread is responsible for which chain of events.

Here's what I think would make this an amazing library:
- Nested Diagnostic Context (NDC) support.  This isn't heavily used in all projects, but it does a fantastic job of cutting down on the tendency to put tons of redundant information into every call to log().  In practice, this helps tremendously for debugging, as engineers stop pulling punches as adding rich contextual data to log lines becomes painless.

- Log "category" support.  Just some way to add an axis for filtering, so you can configure logging to block all log messages from one library, or just errors from another, at the same time. Under log4j, this is simply the module where the log event originates from - other libs let you use an arbitrary string.

- Filtering log events on another axis.  Loggers can already be configured with a log level.  But it would be nice to be able to set a global log level to dial in how much information comes out of the system across all logger instances.

That said, I do appreciate the compactness of this library.  It provides some very straightforward logging support and covers all the basic and important use cases.  But after using more feature-rich solutions, I can't help but think of all the places that I would feel inclined to go with a stronger solution, or extend this to do more of the kinds of things I'm used to doing elsewhere.  I think D has a chance to make an implementation of something on   par with log4j or log4cxx, easy to do, without needing anywhere near as much code.

- Eric
October 15, 2013
On 2013-10-14 23:22, Dicebot wrote:

> If we need to care about that, D module system is a failure.
> But I don't think it is a valid concern.

People already complain about conflict function names in Phobos.

-- 
/Jacob Carlborg
October 15, 2013
Am 15.10.2013 09:08, schrieb Jacob Carlborg:
> On 2013-10-14 23:22, Dicebot wrote:
>
>> If we need to care about that, D module system is a failure.
>> But I don't think it is a valid concern.
>
> People already complain about conflict function names in Phobos.
>

And I'd agree with them. At least inside of a library, care IMO should be taken to minimize overlap (of course functionally equivalent ones in different overload sets are fine, though). But in case of "logXXX" this seems to be very unlikely, much in contrast to "log" (std.math.log).
October 15, 2013
Am 14.10.2013 20:24, schrieb Robert Schadek:
> On 10/14/2013 04:44 PM, Sönke Ludwig wrote:
>> Am 14.10.2013 15:12, schrieb Robert Schadek:
>>> On 10/14/2013 02:39 PM, Sönke Ludwig wrote:
>>>>   - The static methods in LogManager should be made global and the class
>>>>     be removed. It's not for objects so it shouldn't be a class.
>>> LogManager also stores the global log level. Sure I can make another
>>> static global function storing this log level, but I would like to keep
>>> them together as they belong together IMO.
>> The same could be said about the global "log" functions, which are
>> tightly coupled to that state. I think this is already nicely grouped
>> together by the logger module itself, since there is not much else in it.
>>
>> Basically, I just wouldn't consider this style to be particularly
>> idiomatic D code, but of course that's just personal
>> perception/preference (there is also some precedence using "struct"
>> instead of "class" in Druntime). However, if it ends up like this in the
>> final version, it should get a "@disable this();" to prevent misuse.
> It is for ment for phobos not druntime. Anyway structs would mean all
> templates and people will scream template bloat. And this would break
> the design, which I find to be a valid use of classes and
> polymorphisms.  The StdIOLogger can have its default constructor called IMO.

No no, I was talking about the JobManager, not the Logger classes. No templates involved.

>>
>>>>   - For me this logger is completely worthless without any debug log
>>>>     levels. The last std.log entry had at least anonymous verbosity
>>>>     levels, but I'd prefer something like I did in vibe.d [1], where
>>>>     each level has a defined role. This should especially improve the
>>>>     situation when multiple libraries are involved.
>>> Logger.log(LogLevel.(d|D)ebug, "Your message");
>> That would be my idea. Having at least two (diagnostic output for the
>> user and debug output for the developer), but better all four debug
>> levels can be very useful, though.
> Maybe I miscommunicated what I want to show by that example. The (d|D)
> part is the rename to enum lower case.
> The debug log level is given through the LogLevel.Debug, which will be
> renamed to LogLevel.debug. I would call the developer the user of the
> logger. Maybe log messages can be communicated to the user of the
> applicaiton and the developer of the application through a MultiLogger
> class.

But the statement of mine that you quoted was about debug levels (the case issue is clear)... Also right now there is no "(D|d)ebug" level, so I'm actually not sure about the statement that you want to make. But my example of having different levels for the application user and the developer is mostly important when the application user enables verbose log output to see where things go wrong. In that case things like system error codes and the like would make sense, but a repeated printout of some kind of internal buffer state would hardly help the user - it could, however, help the developer.

>> Thanks for bringing this forward!
>
> To whom is this directed?

To you for attempting to revive the logger topic.

October 15, 2013
On Monday, 14 October 2013 at 12:48:14 UTC, Martin Drasar wrote:
> 1) MultiLogger class that takes references to other loggers and just
> forwards the call to the log function.

+1
Also, we should support a few loggers whith same type. For example, I can use 2 file loggers: the 1-st only for debug messages and the 2-nd for all other messages. It can help for message sorting.

Also, we should support a reserve loggers. For example, I can use a file logger as a default and a syslog as a reserve logger (it will be used if the file logger fails). It increases logger reliability.

Also, it will be perfect to have logger failed notifications. For example, the file logger failed can indicate that we haven't got free disc space, a file system problems or hard disk problems. So, we should inform admin about this problems. We can do it via stderr (for local computer only), via syslog network logger or via e-mail logger.
October 15, 2013
On 10/15/2013 04:06 AM, Eric Anderton wrote:
> On Monday, 14 October 2013 at 11:39:52 UTC, Dicebot wrote:
>> Lets unleash the forces of constructive destruction.
>
> So, not to be too heavy-handed with criticism on this library, but I think this should come up to par with solutions like log4j, log4cpp, or log4cxx, with respect to features and capabilities.  Libraries like these have enjoyed a lot of very serious use, and once you have something like that in your project, it's hard to not use most of what they have to offer.  There's really not a lot of fluff in those solutions.
IMO these libraries are to heavy. Especially with phobos inclusion in mind.
>
> Here's what I think is missing:
> - System log support (as others have mentioned).  This would be syslog
> or WEL, depending on environment.
This is sort of the idea of the design, I can't anticipate your needs therefor I should not try. I should try to give you guidelines or a framework to work against.
>
> - Guarantees or options for working with log rotation (logrotate.d). It's nice to either know that you must restart your daemon once logs are rotated, or can configure logging to re-open handles automatically or when it detects rotation has occurred.
See previous point
>
> - Guarantees about threading and thread safety, with concessions to help keep log event streams coherent from thread to thread.  Log formatting in particular could enjoy the ability to emit a thread id, so logs can be analyzed without confusing which thread is responsible for which chain of events.
>
Passing a thread id with a log message, ok! shared!?
> Here's what I think would make this an amazing library:
> - Nested Diagnostic Context (NDC) support.  This isn't heavily used in
> all projects, but it does a fantastic job of cutting down on the
> tendency to put tons of redundant information into every call to
> log().  In practice, this helps tremendously for debugging, as
> engineers stop pulling punches as adding rich contextual data to log
> lines becomes painless.
See previous point
>
> - Log "category" support.  Just some way to add an axis for filtering, so you can configure logging to block all log messages from one library, or just errors from another, at the same time. Under log4j, this is simply the module where the log event originates from - other libs let you use an arbitrary string.
at one point the logger had names, but I thought on how to get the
correct names to them. This lead to some config file and I don't want that.
>
> - Filtering log events on another axis.  Loggers can already be configured with a log level.  But it would be nice to be able to set a global log level to dial in how much information comes out of the system across all logger instances.
there already is a global log level
>
> That said, I do appreciate the compactness of this library.  It provides some very straightforward logging support and covers all the basic and important use cases.  But after using more feature-rich solutions, I can't help but think of all the places that I would feel inclined to go with a stronger solution, or extend this to do more of the kinds of things I'm used to doing elsewhere.  I think D has a chance to make an implementation of something on   par with log4j or log4cxx, easy to do, without needing anywhere near as much code.
>
> - Eric

October 15, 2013
On 10/15/2013 02:44 AM, Kapps wrote:
> A few concerns:
>
> There doesn't seem to be a debug or trace log level. This is quite a useful thing to have once your program is deployed.
there is a LogLevel.debug and a LogLevel.info
>
> I don't like the returning by ref for log methods. For example, it
> seems like you can do: log(5 < 4, "This is a test log") = new
> StdIOLogger();
> It could potentially be useful to return the Logger so you can chain
> calls and such, but it should not be possible to set the logger by
> assigning the result of a log call.
I saw this, but this comes from the way you get the default logger. I don't think that this is that bad, but I bet somebody will disagree.
>
> 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
>
>
> There's a lot of suggestions for things like network logging, but I think this is far beyond the scope of the module, and the sheer amount of different ways of doing it means people will likely write their own anyways. For example, synchronous vs asynchronous, what protocol to use, authentication, client data, encryption, etc.
my point exactly