On Tue, 06 Mar 2012 14:19:27 -0500, Jose Armando Garcia <jsan...@gmail.com> wrote:

On Mon, Mar 5, 2012 at 1:55 PM, Steven Schveighoffer
<schvei...@yahoo.com> wrote:
On Mon, 13 Feb 2012 10:50:04 -0500, David Nadlinger <s...@klickverbot.at>
wrote:

There are several modules in the review queue right now, and to get things going, I have volunteered to manage the review of Jose's std.log proposal.
Barring any objections, the review period starts now and ends in three
weeks, on March 6th, followed by a week of voting.



Some notes:

I dislike that logging affects function execution. In particular, I don't think the logging library should have any business throwing exceptions or errors. It should be invisible to the application. The equivalent function can be had by giving a wrapper function (i.e. log this message at the fatal level, and then throw an error). A use case I can see is printing several
fatal log messages before exiting.

Then don't use std.log.fatal. It is not like you are forced to use it.
You can implement the above by using std.log.error

Then I can't access the fatal level.

When I used Log4Net to log application errors, I only logged fatal errors to the event log (using an event log backend). In fact, in that case, I was *catching* uncaught exceptions. There was no need to throw another exception at that point. My point is, whether to throw an exception or not should be up to the application, and having a fatal level can be utilized in other ways than "this is just like error but throws an exception".

Again, the logging library should not be in the business of dictating application design.

If fatal and critical logged an error at the "Error" logging level, and threw an appropriate exception, that would be a different story, because then it's just a convenience function. But you have made two levels of logging unavailable without throwing exceptions.

As I brought up in another part of this thread, I envision the following pattern emerging:

try
{
   fatal("connection aborted!");
}
catch(LoggingError)
{
}

... // graceful shutdown of rest of the application
throw new LoggingError("connection aborted!");

The log aliases use names that are too common. I think log.info is a better symbol for logging than just 'info', which could be a symbol in a myriad of
places.  Given that D's symbol lookup rules allow shadowing of global
symbols, this does not work out very well.

This is a tough one. Should we be relying on D's module abstraction.
It is not scalable as a module designer and implementer to think about
other modules. This is why a lot of programming languages implement
the concept of namespaces.

The problem is that by default D pulls in a module's symbols into the current scope. You have to go out of your way to *avoid* this. By default you should be able to just import std.log and not have your local symbols shadow std.log's.

There are many solutions to this, as I have brought up elsewhere.

import log = std.log;
log.info("hello world");

I like this better:

import std.log;
// alias log.info info // if you desire
log.info("hello world");

Like others have stated, I think vlog is a) confusing, and b) unnecessary. Even reading the docs, I can't understand what it's used for, and why it
has such different syntax than the normal logging stuff.

I have tried to explain this before but it looks like I have failed. I
find it useful. If you are interested on a different explaination:
http://google-glog.googlecode.com/svn/trunk/doc/glog.html

Someone else pointed that out. I think the documentation explanation there is much more complete than your version, and I think vlog is fine, it just needs a lot more documentation.

Do we have to make the logger a singleton? I'd like to see cases where I
can have different log instances.  For example, an instance I can
enable/disable per class type, or an instance that logs to a diffferent
backend. Or a non-shared instance which does not need to handle threading
issues (i.e. a per-thread file log). Does this help with the vlog issue?

My point of view here is that as a developer I never know how I want
to categorize my log during development. Some people use class name as
a hack for doing this. What about functional programs that don't use
class/objects? What about logical component/classes that span multiple
classes? I always found class based grouping for logging as a hack. D
made the observation that classes are not always the best abstraction
unit so it introduced modules. std.log filters based on modules
(actually source files to be exact but if D had __MODULE__, std.log
would use that instead.)

I wasn't speaking so much about filtering logging based on classes (and BTW, most logging libraries use hierarchical symbols to denote logging instances, they don't necessarily have to follow class names), but simply being able to have multiple log instances. That is, instead of having one global instance of log, what about multiple instances (I don't care if they are named or not). They don't have to be based on some sort of name, just another place you can configure independently of the rest of the application. For example, I may want a log instance in my library that logs to some library log file independent of the full application log.

-Steve

Reply via email to