#282 Simple logging

tompalmer Fri 11 Jul 2008

I know that polluting Obj is bad, but could we possibly add simple logging there, with methods logError, logInfo, and maybe logDetail? Along with a simple dispatch system that organizes things by the class where log call occurs? Anything else fancier (like choosing a custom logging category or checking the current log level) would require calls to separate logging classes.

The default would also be to dump all "info" and "error" level messages to Sys.err.

That would making logging a nice breeze (and consistent if in the core) compared to most other systems.

I imagine the log methods looking something like this:

Void logError(Str message, Err err := null) {/* ... */}

tompalmer Sat 12 Jul 2008

Thanks for the links, and you are right. I didn't investigate the current APIs before posting. Apologies on that.

I was thinking more about echo. It's so convenient (and nicely so) that I'm afraid it will be too easy for people to use that for logging. If logInfo is equally accessible, people might go through logging correctly.

Also, I'd usually rather not go through the effort of digging up a particular log object (as in const static Log log = Log.get("acme")). I'd rather just get one named for my pod (or "pod::Type" or whatever) in most cases.

As ever, just a thought.

brian Sat 12 Jul 2008

Tom, I can see where you are coming from, but I don't want to pollute the Obj namespace with anything not critical. I think adding echo was a big deal since we prevent application classes from using it (although it is so useful to make it worthwhile). In this case I'm not sure using a log is really more onerous than using what it takes to print in Java:

Log.get("acme").error("...")
System.out.printLine("ERROR: ...")

If we can come up with a convention or way to pass in "my current pod name or type qname" into the get method we could do something like:

Log.self.trace("...")

There isn't any language feature to do that right now though.

I think the important thing is that I agree logging should be standardized across everything - even the core system functions. So I decided to build logging into sys directly (with 3 whole classes!) which was a hard pill for me to swallow since I want to keep sys as small as possible.

tompalmer Sat 12 Jul 2008

Thanks for the info. I thought of something that might work. How about each type gets its own log by default (using a once method even for lazy init), so you can do things like this:

type.log.info("Hello, world!")
if (type.log.isDebug) {
  type.log.debug("No, really. Hello, world!")
}

Is that a good compromise?

And people can always go get their custom-named logs if wanted. I think the one sneaky thing here is that you'd get the log for the current object's type (meaning the subtype if there is one). To be sure to get the log for the lexically scoped type (which is what people would probably expect), you'd have to say Type.type.log.info("whatever"). Still, I think either is probably good enough in most cases.

I agree that the current Fan model is much like in Java. I just think it should be easier than that for the common case.

brian Sat 12 Jul 2008

Tom - I'm with you a 100% on making it so easy that you can't help but use it (therefore creating consistent logging). I like your idea - the very common case is that there is a log per pod (actually that is what I have already in fand, web, webapp, etc). So my proposal is this:

Log Pod.log()   { return Log.get(name) }
Log Type.log()  { return pod.log }

So we can now just write:

// new way
type.error("...")
obj.type.info("...")

// which is a shortcut for:
Log.get(type.pod.name).error("...")
Log.get(obj.type.pod.name).info("...")

I really like that idea. It creates a good simple convention.

tompalmer Sat 12 Jul 2008

Glad to hear that might work out.

brian Sun 13 Jul 2008

done for next build

tompalmer Sun 13 Jul 2008

Awesome.

By the way, is that type.error("...") or type.log.error("...")?

Also, is there some way to reference a pod statically by name? Or just by API with strings (or type.pod)?

brian Sun 13 Jul 2008

By the way, is that type.error("...") or type.log.error("...")?

type.log.error(...)

katox Tue 14 Oct 2008

When writing debug log statements, we expect that they will be turned off most of the time. Therefore be aware of the hidden costs of string concatenation. You can use the isDebug method to skip creating a log message.

A proper way but who does it? Most people skip the test or they remove the logging code after they are finished with debugging. Thinking about recent changes what about using ?. operator to simplify that even more? Instead of:

if (type.log.isDebug) {
  type.log.debug("No, really. Hello, world!")
}

we could write

type.log.debug?.echo("Complex value: " + fac(10));
// or
type.debugLog?.echo("Complex value: " + fac(10));
// or
type.log("debug")?.echo("Complex value: " + fac(10));
// else?

not sure about the syntax but something less verbose would be very nice. If plain . operator was disallowed for possibly null objects it would be perfectly safe...

But integrated logging is sweet in any case.

And maybe trace debug level could be added -- the most used logging systems converged to five levels (log4j/logback). (JCL has even more -- not used and deployed with buggy implementation of custom Level.)

tompalmer Wed 15 Oct 2008

Interesting thoughts.

Side note, I still think type.log isn't what most people want most of the time (since instances of subclasses will end up logging to the wrong place), which is one of the reasons I promote # to reference the surrounding type (in a static sense).

brian Wed 15 Oct 2008

Side note, I still think type.log isn't what most people want most of the time (since instances of subclasses will end up logging to the wrong place), which is one of the reasons I promote # to reference the surrounding type (in a static sense).

I'm not sure I follow that. In that case # would mean the same thing as .type wouldn't it? Neither of those solutions would solve the subclass issue. Although the advantage of # is that it would work in a static context.

tompalmer Wed 15 Oct 2008

I take # to mean the lexically enclosing class, not the class of this, though I guess I might have missed the meanings of #slot as to whether it cares about the type of this.

Login or Signup to reply.