Here is the initial WIKI for the gwt incubator Logging design. Any feedback you have would be welcome.
That is,
log.warn("The value " + value.getValue() + " is invalid")
should result in nothing, rather than evaluating value.getValue() and
concatenating the result only to throw it away. :)
-Ray
Thanks Emily.
A few thoughts...
Firebug/Console Logging
- Agree with John - It seems console.log() is commonly made available in JavaScript libraries.
- I might suggest renaming the Firebug logger to, say, Console logger, and have the Firebug functionality degrade gracefully to console.log()
GWT.log
- Having GWT.log() as a target may be very useful was well
Server Side Logging
- I would almost argue this is a must-have, since that would be the only reasonable way to support logging in domain objects which are used on both client and server
JDK 1.4 vs log4j vs. Apache Commons
- I don't know what the numbers are, both in terms of actual projects using a particular API, or actual developers familiar with one API or another, but, log4j has been around longer, and therefore may be accepted/known
- I find JDK 1.4 logging to be a bit clumsy, although workable; I don't like their level names, or the default to only log SEVERE messages; plus, what is CONFIG anyway :)
- I like log4j for its straight forward levels and diverse set of available appenders, so, I'd like to see the gwt API and levels modeled after log4j
Direct Access to Loggers
- This is especially useful for widget loggers which may need to be manipulated at run time
- However, this could certainly wait till a later release, after use cases have been flushed out
Number of compile time options
- I like the simplified notion of logging either being turned on or off, with runtime log level filtering on top of that; it's much easier to explain and understand
- Having a multitude of compile time log levels can always be added later (I do think we should leave the door open to this option), but could also be left to a specialized logging package, or an advanced how-to
- I also think loggers need to be able to be turned off at compile time; Instantiating the loggers with GWT.create(...) would allow users an easy way to replace any logger with a Null Logger
Grouping/Categories
- I've seen multiple requests for both grouping (as in Firebug's console.group()), and categories (with different filters/levels by category)
Widget Loggers
- This may be a place where we'd want to make a user provided implementation plugable at compile time, as expect to see various specialized use cases
- A simple GWT.create(...) could take care of this requirement
FredOn Jan 31, 2008 2:07 PM, Emily Crutcher <e...@google.com> wrote:
Here is the initial WIKI for the gwt incubator Logging design. Any feedback you have would be welcome.
Cheers,
Emily
http://code.google.com/p/google-web-toolkit-incubator/wiki/Logging
--
"There are only 10 types of people in the world: Those who understand binary, and those who don't"
--
Fred Sauer
fr...@allen-sauer.com
On Thu, Jan 31, 2008 at 6:58 PM, Fred Sauer <fr...@allen-sauer.com> wrote:Firebug/Console Logging
- Agree with John - It seems console.log() is commonly made available in JavaScript libraries.
- I might suggest renaming the Firebug logger to, say, Console logger, and have the Firebug functionality degrade gracefully to console.log()
That seems like a good idea. Do you think you might implement this? As right now the plan is to use gwt-log's infrastructure for almost all this functionality.
GWT.log
- Having GWT.log() as a target may be very useful was well
I think I don't understand this comment, can you elaborate?
Server Side Logging
- I would almost argue this is a must-have, since that would be the only reasonable way to support logging in domain objects which are used on both client and server
I could see that argument. It will be slightly awkward code, because GWT.create will actually throw an error when run outside a GWT development environment, but it does seem like a useful feature.
JDK 1.4 vs log4j vs. Apache Commons
- I don't know what the numbers are, both in terms of actual projects using a particular API, or actual developers familiar with one API or another, but, log4j has been around longer, and therefore may be accepted/known
- I find JDK 1.4 logging to be a bit clumsy, although workable; I don't like their level names, or the default to only log SEVERE messages; plus, what is CONFIG anyway :)
- I like log4j for its straight forward levels and diverse set of available appenders, so, I'd like to see the gwt API and levels modeled after log4j
I like log4j as well, however my concern here is to create a API familiar to the greatest number of our users, which seems like it is the Java logging API. If you have data that would suggest otherwise, that would be interesting to see.
This would depend upon whether we can completely flush the call sites. As one of the big reasons we are creating a logging package is to maintain the zero cost logging messages when logging is turned off.Direct Access to Loggers
- This is especially useful for widget loggers which may need to be manipulated at run time
- However, this could certainly wait till a later release, after use cases have been flushed out
That being said, given the awesome work Scott/Mathew have done for dead code stripping, it might be easier then I think to create instance loggers.
I like this idea. One point that was made on a separate thread is that some programs want "severe" logging turned on at all time, which might make this feature come in sooner then expected.Number of compile time options
- I like the simplified notion of logging either being turned on or off, with runtime log level filtering on top of that; it's much easier to explain and understand
- Having a multitude of compile time log levels can always be added later (I do think we should leave the door open to this option), but could also be left to a specialized logging package, or an advanced how-to
- I also think loggers need to be able to be turned off at compile time; Instantiating the loggers with GWT.create(...) would allow users an easy way to replace any logger with a Null Logger
Right now, the goal is that we have absolutely no class or method invocations left so there should be no need for a Null Logger.
Grouping/Categories
- I've seen multiple requests for both grouping (as in Firebug's console.group()), and categories (with different filters/levels by category)
The way this is handled in the current design is that each handler has an optional set of parameters supplied to it. Those parameters can be used to specify group or category.
Widget Loggers
- This may be a place where we'd want to make a user provided implementation plugable at compile time, as expect to see various specialized use cases
- A simple GWT.create(...) could take care of this requirement
Yes, I'm creating TreeHandler to test this requirement.. My hope is all I need to do is guard the creation in a call to isLoggingEnabled()
Thanks for your great feedback!
Emily,On Feb 1, 2008 9:35 AM, Emily Crutcher <e...@google.com> wrote:On Thu, Jan 31, 2008 at 6:58 PM, Fred Sauer <fr...@allen-sauer.com> wrote:Firebug/Console Logging
- Agree with John - It seems console.log() is commonly made available in JavaScript libraries.
- I might suggest renaming the Firebug logger to, say, Console logger, and have the Firebug functionality degrade gracefully to console.log()
That seems like a good idea. Do you think you might implement this? As right now the plan is to use gwt-log's infrastructure for almost all this functionality.
It's on the to-do this. I currently have two separate loggers (i.e. firebug and console loggers). I need to at least disable the console logger when firebug(lite) is available (which is a one line code change), but I think it makes more sense to combine the two into a single logger with varying levels of integration with $wnd.console, depending on the browser and/or installed library or debugging facility. Over time, I also expect the browsers/libraries/frameworks to expand, and hopefully coalesce a bit around a common API, so I think some runtime detection at logger initialization will go a long ways here.
GWT.log
- Having GWT.log() as a target may be very useful was well
I think I don't understand this comment, can you elaborate?
I'm assuming that client code would call something like 'org.google.gwt.log.client.Log.debug(.., ...)', and that module configuration (via deferred binding parameters) would then target the provided messages to various logger such as $wnd.console, System.err, RPC, Widget, etc. Having the option of these messages go to hosted mode tree logger is what I was proposing here.
Server Side Logging
- I would almost argue this is a must-have, since that would be the only reasonable way to support logging in domain objects which are used on both client and server
I could see that argument. It will be slightly awkward code, because GWT.create will actually throw an error when run outside a GWT development environment, but it does seem like a useful feature.
I have this working in gwt-log with a bit of library magic, and I definitely think this is worth doing. Otherwise, I expect that the lack of a common logging API for both client and server is going to be a common struggling block.
JDK 1.4 vs log4j vs. Apache Commons
- I don't know what the numbers are, both in terms of actual projects using a particular API, or actual developers familiar with one API or another, but, log4j has been around longer, and therefore may be accepted/known
- I find JDK 1.4 logging to be a bit clumsy, although workable; I don't like their level names, or the default to only log SEVERE messages; plus, what is CONFIG anyway :)
- I like log4j for its straight forward levels and diverse set of available appenders, so, I'd like to see the gwt API and levels modeled after log4j
I like log4j as well, however my concern here is to create a API familiar to the greatest number of our users, which seems like it is the Java logging API. If you have data that would suggest otherwise, that would be interesting to see.
Maybe we could have a poll on GWT and GWTC (pinned?) to get an idea of the community thinks. Another option (slf4j does this), is to provide optional, API compatible, drop-in replacement for these logging libraries on the client side. (I'm not recommending this out of the gate, but might be an option to consider longer term if the community is really split down the middle on what to support.) In other words, while client code might write 'org.apache.log4j.Logger.getLogger("...").debug(...)', GWT would provide an implementation of that API that would do everything we talked about here.
If there is a strong community preference for JDK 1.4 style logging, I'll go with that, but would otherwise recommend we pick the 'better' logging solution to model ourselves after. (We must, of course, first agree upon which is the 'better' model.)
This would depend upon whether we can completely flush the call sites. As one of the big reasons we are creating a logging package is to maintain the zero cost logging messages when logging is turned off.Direct Access to Loggers
- This is especially useful for widget loggers which may need to be manipulated at run time
- However, this could certainly wait till a later release, after use cases have been flushed out
That being said, given the awesome work Scott/Mathew have done for dead code stripping, it might be easier then I think to create instance loggers.
In the worst case, the getFooLogger() methods could return null, which client code could guard against, and use to conditionally execute logging related code. However, I also expect that we can avoid this, based on compiler optimizations, which would allows us to return instead a NullLogger with lots of empty implementation methods in it, which would cause client logging code to get compiled out. For initialization/configuration code with side-effects users could always guard with Log.isLoggingEnabled(), or widgetLogger.isLoggerEnabled().
I like this idea. One point that was made on a separate thread is that some programs want "severe" logging turned on at all time, which might make this feature come in sooner then expected.Number of compile time options
- I like the simplified notion of logging either being turned on or off, with runtime log level filtering on top of that; it's much easier to explain and understand
- Having a multitude of compile time log levels can always be added later (I do think we should leave the door open to this option), but could also be left to a specialized logging package, or an advanced how-to
For gwt-log I felt that the implementation burden of allowing any of the log levels as compile time levels was low enough that this was worth doing. However, I can also see the benefit of providing only two levels (on/off) for a core GWT logging solution, to encourage better programming practices. That is, rather than someone leaving SEVERE/ERROR/FATAL logging turned on for production, the developer is encouraged to handle these cases in a application-meaningful way. Having a SEVERE logging message popup in a widget logger, or on my firebug console, when I am in Gmail is probably not going to provide the best user experience. (Although, neither does 'Oops, error 767' :)
There are implementation differences we will need to consider, e.g.
- The GWT tree logger would let you create two separate child trees, with logging messages separately going to each child tree, based on, say, category.
- Firebug logger's group()/endGroup() only allows you to be logging at the end of the log tree, be it inside a group or not.
- Other loggers may allow after-the-fact filtering/grouping to effectively separation/categorization
I would love to take a quick poll, from water-cooler discussions it seems like there are a sizable fraction of people who would like to see java.util.logging.Logger supported even though
a) only some of the Logger methods would be supported
b) there would be extra compiled overhead for creating and assigning null loggers in some cases.
c) there would be a bit of extra overhead when logging, as we would have to create and introduce LogRecords (which are useful though) into the system.
Do you agree?
On Fri, Feb 1, 2008 at 1:37 PM, Fred Sauer <fr...@allen-sauer.com> wrote:
On Feb 1, 2008 9:35 AM, Emily Crutcher <e...@google.com> wrote:
On Thu, Jan 31, 2008 at 6:58 PM, Fred Sauer <fr...@allen-sauer.com> wrote:Server Side Logging
- I would almost argue this is a must-have, since that would be the only reasonable way to support logging in domain objects which are used on both client and server
I could see that argument. It will be slightly awkward code, because GWT.create will actually throw an error when run outside a GWT development environment, but it does seem like a useful feature.
I have this working in gwt-log with a bit of library magic, and I definitely think this is worth doing. Otherwise, I expect that the lack of a common logging API for both client and server is going to be a common struggling block.
How does it work? As that seems like a cool technique.
JDK 1.4 vs log4j vs. Apache Commons
- I don't know what the numbers are, both in terms of actual projects using a particular API, or actual developers familiar with one API or another, but, log4j has been around longer, and therefore may be accepted/known
- I find JDK 1.4 logging to be a bit clumsy, although workable; I don't like their level names, or the default to only log SEVERE messages; plus, what is CONFIG anyway :)
- I like log4j for its straight forward levels and diverse set of available appenders, so, I'd like to see the gwt API and levels modeled after log4j
I like log4j as well, however my concern here is to create a API familiar to the greatest number of our users, which seems like it is the Java logging API. If you have data that would suggest otherwise, that would be interesting to see.
Maybe we could have a poll on GWT and GWTC (pinned?) to get an idea of the community thinks. Another option (slf4j does this), is to provide optional, API compatible, drop-in replacement for these logging libraries on the client side. (I'm not recommending this out of the gate, but might be an option to consider longer term if the community is really split down the middle on what to support.) In other words, while client code might write 'org.apache.log4j.Logger.getLogger("...").debug(...)', GWT would provide an implementation of that API that would do everything we talked about here.
If there is a strong community preference for JDK 1.4 style logging, I'll go with that, but would otherwise recommend we pick the 'better' logging solution to model ourselves after. (We must, of course, first agree upon which is the 'better' model.)
Aside from naming standards, what features do you see that should be added?
Emily,On Feb 1, 2008 4:53 PM, Emily Crutcher <e...@google.com> wrote:I would love to take a quick poll, from water-cooler discussions it seems like there are a sizable fraction of people who would like to see java.util.logging.Logger supported even though
a) only some of the Logger methods would be supported
b) there would be extra compiled overhead for creating and assigning null loggers in some cases.
c) there would be a bit of extra overhead when logging, as we would have to create and introduce LogRecords (which are useful though) into the system.
Do you agree?
First, for the record:
+1 log4j
Next, I want to briefly throw out he idea of mapped diagnostic context for people to consider:
http://logback.qos.ch/manual/mdc.html
Should this be a part of a GWT loggingAPI?
In my opinion, having ANY runtime overhead when logging is turned off is a deal breaker. I'm willing to live a few extras bytes in the compiled code, and even with a few clock cycles of one time initialization code. But, if I put a log statement anywhere in my code, I don't want to see any of it left in the compiled JavaScript. Of course, I understand that in some cases I might need a 'if (Log.isFooEnabled()) {...}' guard. So, if log records cannot be made to work in this scenario, then I must vote to throw them out the door.
On Fri, Feb 1, 2008 at 1:37 PM, Fred Sauer <fr...@allen-sauer.com> wrote:
On Feb 1, 2008 9:35 AM, Emily Crutcher <e...@google.com> wrote:
On Thu, Jan 31, 2008 at 6:58 PM, Fred Sauer <fr...@allen-sauer.com> wrote:Server Side Logging
- I would almost argue this is a must-have, since that would be the only reasonable way to support logging in domain objects which are used on both client and server
I could see that argument. It will be slightly awkward code, because GWT.create will actually throw an error when run outside a GWT development environment, but it does seem like a useful feature.
I have this working in gwt-log with a bit of library magic, and I definitely think this is worth doing. Otherwise, I expect that the lack of a common logging API for both client and server is going to be a common struggling block.
How does it work? As that seems like a cool technique.
A magician never reveals his tricks :). Seriously, though: In hosted mode I use two different byte code versions of the same classes. One is used by the JVM directly, via the same class loader tree which runs the servlets. The other is used by client code.
JDK 1.4 vs log4j vs. Apache Commons
- I don't know what the numbers are, both in terms of actual projects using a particular API, or actual developers familiar with one API or another, but, log4j has been around longer, and therefore may be accepted/known
- I find JDK 1.4 logging to be a bit clumsy, although workable; I don't like their level names, or the default to only log SEVERE messages; plus, what is CONFIG anyway :)
- I like log4j for its straight forward levels and diverse set of available appenders, so, I'd like to see the gwt API and levels modeled after log4j
I like log4j as well, however my concern here is to create a API familiar to the greatest number of our users, which seems like it is the Java logging API. If you have data that would suggest otherwise, that would be interesting to see.
Maybe we could have a poll on GWT and GWTC (pinned?) to get an idea of the community thinks. Another option (slf4j does this), is to provide optional, API compatible, drop-in replacement for these logging libraries on the client side. (I'm not recommending this out of the gate, but might be an option to consider longer term if the community is really split down the middle on what to support.) In other words, while client code might write 'org.apache.log4j.Logger.getLogger("...").debug(...)', GWT would provide an implementation of that API that would do everything we talked about here.
If there is a strong community preference for JDK 1.4 style logging, I'll go with that, but would otherwise recommend we pick the 'better' logging solution to model ourselves after. (We must, of course, first agree upon which is the 'better' model.)
Aside from naming standards, what features do you see that should be added?
The author of log4j, Ceki Gülcü, has written up his critique on JDK logging here:
http://www.jajakarta.org/log4j/jakarta-log4j-1.1.3/docs/critique.html
Of course, the full set of critiques, if you agree with them, really only apply in a JVM, and only if you are using the actual JDK logging implementation. Also, the impact of certain concerns can/could be eliminated by JVM optimizations.
Our own JDK-logging-inspired implementation wouldn't necessarily be affected by all the same issues. Things also become very different in web mode, with optimized JavaScript. However, I would imagine that if the gwt logging solution were to be modeled after JDK logging, then developers would likely be steered towards JDK logging on the server, and any JVM related concerns would have a real impact there.
Some log4j features I like:
- Straight forward log levels: DEBUG, INFO, WARN, ERROR, FATAL
- Low overhead at runtime
- Large number of available appenders
- Flexible pattern layout
- Well-known, mature
I really don't think the client logging design needs to have LogRecord
and probably not even categories. Those are more suitable for large
and long running apps, or fancy stuff like socket logging, or
Chainsaw-style log viewers, but I think GWT logging analysis may be
better done in a batch capture fashion. Launch the app, run your
tests, save the logs, and then post-process the logs. You could then
view the post-processed logs with a Chainsaw-style viewer as long as
there was sufficient information.
All of the runtime stuff of mapping categories to log levels and
appenders seems to me to be overly complex for GWT. My preference
would be for a simple design 'inspired' by log4j, and maybe a subset
of it.
-Ray
I'll preface this by saying that I have been a log4j user since its
inception, and never used Java logging, nor commons-logging. For me,
any runtime impact is unacceptable, be it codesize or performance. I
am also a little sensitive to API bloat, I prefer KISS designs.
I really don't think the client logging design needs to have LogRecord
and probably not even categories. Those are more suitable for large
and long running apps, or fancy stuff like socket logging, or
Chainsaw-style log viewers, but I think GWT logging analysis may be
better done in a batch capture fashion. Launch the app, run your
tests, save the logs, and then post-process the logs. You could then
view the post-processed logs with a Chainsaw-style viewer as long as
there was sufficient information.
All of the runtime stuff of mapping categories to log levels and
appenders seems to me to be overly complex for GWT. My preference
would be for a simple design 'inspired' by log4j, and maybe a subset
of it.
> So, for me, I think implementing that portion of java.util.logging which
> makes sense (for example, leaving out setLevel or else having a
> DynamicLogger implementation which does runtime-checks if we want to allow
> it), and then any code that uses that subset and is translatable can be
> shared freely between client and server and it will just work.
I'm unclear about whether you are agreeing or not :) I was suggesting
that a subset, inspired by the full logging APIs, and this most
certainly would run in the server. In the second paragraph, you argue
for subsetting java.util.logging, while I was suggesting forming a
subset 'inspired' by log4j. I would actually prefer a KISS 'commons'
approach, in that the 'cloud safe' code uses some
com.google.gwt.logging package, which can delegate on the server to
your logging API of choice. If you use the actual
java.util.logging.Logger class, you run into not only supporting
setLevel, but also addHandler(), getResourceBundle(), etc. which
means stubbing them out, and making sure that developers know to not
call them in client code (not without precedent, e.g. Exception stack
traces)
As for the overhead of the static final field and initializer, yes,
that may be acceptable in small doses, but I think littering all of
your client translatable code with Loggers (the usual practice I see
in J2EE apps) may be asking for trouble. Remember, aggressive
subclassing of JSO was poo-pooed because it was inefficient, until the
new compiler and JSO design arrived. I think similar caution is
warranted when considering any new complex package being dropped into
GWT, especially one that encourages people to sprinkle it through
their entire codebase. We should atleast be very upfront with users
about the overhead.
-Ray
On Feb 4, 2008 1:24 PM, John Tamplin <j...@google.com> wrote:...
> The problem with "inspired by" is that you can't use common code for server
> and client logging. If you have shared code and you want logging in that
> code, you will have a problem if you have different logging systems.
This is not a problem as long as the implementation delegates, this is
exactly what the myriad of commons-logging like APIs do, dynamically
bind to log4j, java.util.logging, or others (SimpleLog)
I'm unclear about whether you are agreeing or not :) I was suggesting
that a subset, inspired by the full logging APIs, and this most
certainly would run in the server. In the second paragraph, you argue
for subsetting java.util.logging, while I was suggesting forming a
subset 'inspired' by log4j. I would actually prefer a KISS 'commons'
approach, in that the 'cloud safe' code uses some
com.google.gwt.logging package, which can delegate on the server to
your logging API of choice. If you use the actual
java.util.logging.Logger class, you run into not only supporting
setLevel, but also addHandler(), getResourceBundle(), etc. which
means stubbing them out, and making sure that developers know to not
call them in client code (not without precedent, e.g. Exception stack
traces)
As for the overhead of the static final field and initializer, yes,
that may be acceptable in small doses, but I think littering all of
your client translatable code with Loggers (the usual practice I see
in J2EE apps) may be asking for trouble. Remember, aggressive
subclassing of JSO was poo-pooed because it was inefficient, until the
new compiler and JSO design arrived. I think similar caution is
warranted when considering any new complex package being dropped into
GWT, especially one that encourages people to sprinkle it through
their entire codebase. We should atleast be very upfront with users
about the overhead.
-Ray
I would add, that, *if* we were to end up agreeing that, say, log4j was better/preferable than JDK logging, then we could do exactly the same thing: replace org.apache.log4j.* implementations just you would java.util.*.
This is actually why I like the static API, as then we don't need to tell people how to use logging without causing code bloat, it happens automatically. Though I do think Fred had a good point about categories being useful, though it seems like a string category might be sufficient, and static final strings should go away I believe, though I will have to test...
Also, I'm not convinced that for shared code you wouldn't want an adapter anyway. As your logging needs when running code in hosted mode or web mode are different then your needs when you are running that same code on the server.
Categories are cornerstone of logging, and critically important when
> I really don't think the client logging design needs to have LogRecord
> and probably not even categories. Those are more suitable for large
> and long running apps
logging is used as alternative for running a debugger: if there is no
support for categories and per-category log level you can not drill
down to the finer level log messages of problem area without drowning
in messages from other areas.
Also consider the requirement that the same logging API must also work
when the code is executed in server (for shared code use). If the api
does not support categories, that also means no categories in the
server side for shared code, which probably is simply unacceptable for
many.
I think the latter can be easily handled by a String identifier,
because offline tools can easily process such files, as long as the
format of the fields in each log entry is consistent, (e.g.
Timestamp,Level, Identifier, Msg)
The former case, of controlling log levels during runtime I think is
not as useful for GWT and is much more applicable to long running
apps. I can see a need for it in some cases (e.g. DEBUG/TRACE
generates a bazillion msgs, so numerous it will kill the browser, so
you only want to TRACE class Bar) Still, I think this is the exception
and not the rule.
Ok, given recent posts it seems obvious there will be no existing solution everyone can agree on, so I retract my suggestion of implementing java.util.logging and agree with Emily and Ray (and maybe others) that we should inconvenience everyone equaly and suggest:
- create a new API for GWT and shared code optimized/limited to our needs
- the server side would not do any logging itself but delegate to any of the popular logging solutions, configurable in some way
- client side would support categories but not different log levels per category, but on the server side they could if the underlying log system supported it
Comments?
- client side API would have zero overhead if turned off, small one-use overhead (ie, object allocation) is acceptable for other debug levels but must still have zero overhead at filtered call sites
--
John A. Tamplin
Software Engineer, Google
On Feb 5, 2008 9:00 AM, John Tamplin <j...@google.com> wrote:Ok, given recent posts it seems obvious there will be no existing solution everyone can agree on, so I retract my suggestion of implementing java.util.logging and agree with Emily and Ray (and maybe others) that we should inconvenience everyone equaly and suggest:
- create a new API for GWT and shared code optimized/limited to our needs
- the server side would not do any logging itself but delegate to any of the popular logging solutions, configurable in some way
- client side would support categories but not different log levels per category, but on the server side they could if the underlying log system supported it
I don't see why we couldn't add client side *runtime* support for different log levels by category as well.
Comments?
- client side API would have zero overhead if turned off, small one-use overhead (ie, object allocation) is acceptable for other debug levels but must still have zero overhead at filtered call sites
--
John A. Tamplin
Software Engineer, Google
--
-Ray
I hope wasn't misunderstood. I'm not completely opposed to the
java.util.logging idea, I was just concerned about it's apparent
'heavy' nature and conceptual weight (I tend to prefer simple APIs). I
think if these fears were alleviated, I'd be mostly ambivalent whether
it was com.google.gwt or j.u.logging. On the plus side, j.u.logging
could be added to the official list of JRE Emul classes. :) The
benefit of designing your own API from scratch is it seems you can
control the conceptual weight and performance characteristics more
deterministically vs implementing an existing API for the first time.
> - client side would support categories but not different log levels
> per category
I don't see point in having categories if they don't have individually
configurable levels (the category would not be much more than prefix
for the log message).
But, I think the real use cases (increased logging of specific problem
areas at development time) can be satisfied just fine with runtime
filtering. The per category levels would not need to have any effect
on the compile time behavior or optimizations, simply some messages
would be skipped based on category/level combination at runtime. Or am
i again missing something? :)
I don't see why we couldn't add client side *runtime* support for different log levels by category as well.
-Ray
My 2 cents is that while it is possible to use deferred binding for
all of the log levels, I think the better sweet spot is simply ON/OFF
(statically w/deferred binding), and use dynamic checks when logging
is on. It's my expectation that production mode apps will use a
NullLogger with no logging compiled in of any kind. DB will remove
callsite log calls for the other log levels, but you still end up with
the whole logging apparatus and support classes compiled into your app
for the levels that are on. I know people imagine handling exceptions
and logging WARN/ERROR even in production apps, but IMHO, it's much
better to handle these with a user visible error feedback.
Perfect.
I think the current plan is to support both use cases, as there are big projects that have told us they'd like to use one or the other, so we'd have the following deferred binding:
logging:on -- logging is supported, all logging statements are compiled in. Initial logging level is WARN unless overridden by a logging URL argument.
logging:off -- no logging support
logging:production -- SEVERE logging messages are compiled in. Logging level is set to SEVERE. No URL logging level argument support. Logging levels can still be set in code.
My thoughts here are only half-formed, and I'm not entirely sure if it
would be useful to anyone, but I thought I'd throw it out there
anyway. People seem to want categories to aid in filtering log
output, but there is some pushback because implementing different log
levels on different categories seems to stymie static dead code
removal. What if there was a configuration file, similar to
log4j.xml, that specifies the category log levels and is read at
compile time? Would this be useful? Would it permit the static dead
code removal that seems to be a top priority? Is it too complex for a
first pass?
Ian
--
Tired of pop-ups, security holes, and spyware?
Try Firefox: http://www.getfirefox.com
Regarding the interplay between statically-determined logging levels
and categories with different levels, what about the equivalent of
log4j.xml?
My thoughts here are only half-formed, and I'm not entirely sure if it
would be useful to anyone, but I thought I'd throw it out there
anyway. People seem to want categories to aid in filtering log
output, but there is some pushback because implementing different log
levels on different categories seems to stymie static dead code
removal. What if there was a configuration file, similar to
log4j.xml, that specifies the category log levels and is read at
compile time? Would this be useful? Would it permit the static dead
code removal that seems to be a top priority? Is it too complex for a
first pass?
On Feb 5, 2008 1:25 PM, Emily Crutcher <e...@google.com> wrote:I think the current plan is to support both use cases, as there are big projects that have told us they'd like to use one or the other, so we'd have the following deferred binding:
logging:on -- logging is supported, all logging statements are compiled in. Initial logging level is WARN unless overridden by a logging URL argument.
If you only support the logging level via the URL, then this is a static deferred binding option, right?
logging:off -- no logging support
logging:production -- SEVERE logging messages are compiled in. Logging level is set to SEVERE. No URL logging level argument support. Logging levels can still be set in code.
Can the logging levels be set lower than severe, or is that only to basically turn off logging at runtime? If the former, you will have massive overhead for simply building with logging turned on, and in the latter case I am not sure of the use case for having the code present but only allowing severe logs to be turned on or off at runtime.
I'd prefer DEBUG/FINEST (or whatever is the lowest) instead of WARN for the beginner trying to get Log.debug(....) to just work.
logging:off -- no logging supportok
logging:production -- SEVERE logging messages are compiled in. Logging level is set to SEVERE. No URL logging level argument support. Logging levels can still be set in code.
I'd prefer we omit this last option, so that we discourage the use of logging as a production solution to unexpected runtime problems. Those problems should be addressed differently in the UI, in an application reasonable way. Production should mean logging turned off.
Can the logging levels be set lower than severe, or is that only to basically turn off logging at runtime? If the former, you will have massive overhead for simply building with logging turned on, and in the latter case I am not sure of the use case for having the code present but only allowing severe logs to be turned on or off at runtime.
I would expect to be able to adjust the runtime log level as follows:
compile time level <= run time level <= OFF
i.e. you can always reduce the amount of logging at run time.
In any case it should be understood that there is additional overhead when any type of compile time logging is enabled. Adjusting the runtime log level is only a means of temporarily throttling messages for the purpose of easier debugging during development. I think we can reinforce this by, for example, generating a log message to indicate any change in runtime log level.
Suppose a developer were to set the compile time level to 'FINEST', but then thought all they needed to do for production was to set the runtime level to OFF (via say Log.setCurrentLogLevel(OFF) in onModuleLoad()). By always emitting a message like 'Log level changed to ....', the developer could not be lulled into thinking that logging was somehow actually completely turned off.
(Actually, for the specific case when the runtime level is set to 'OFF', it might not hurt to spit out another message with information on how to properly turn logging off in production.)
--
private void genPropProviders(PrintWriter pw) {
for (Iterator iter = moduleProps.iterator(); iter.hasNext();) {
Property prop = (Property) iter.next();
String activeValue = prop.getActiveValue();
if (activeValue == null) {
// Emit a provider function, defined by the user in module config.
PropertyProvider provider = prop.getProvider();
...
Which seems to say that yes, it is omitted.
-Ray
I'd prefer DEBUG/FINEST (or whatever is the lowest) instead of WARN for the beginner trying to get Log.debug(....) to just work.
I see your point, but as a developer I would want to easily add messages that do not show up by default. Maybe though setting the levels at CONFIG then documenting FINE and FINEST might be better then starting them at WARN...
logging:production -- SEVERE logging messages are compiled in. Logging level is set to SEVERE. No URL logging level argument support. Logging levels can still be set in code.
I'd prefer we omit this last option, so that we discourage the use of logging as a production solution to unexpected runtime problems. Those problems should be addressed differently in the UI, in an application reasonable way. Production should mean logging turned off.
Unfortunately we know of some applications that are waiting for this library that do not agree with you. They plan to also do something intelligent in the UI, but want to use the RPC handlers they are already going to have set up to actually log the error.
On Feb 5, 2008 1:33 PM, Emily Crutcher <e...@google.com> wrote:I'd prefer DEBUG/FINEST (or whatever is the lowest) instead of WARN for the beginner trying to get Log.debug(....) to just work.
I see your point, but as a developer I would want to easily add messages that do not show up by default. Maybe though setting the levels at CONFIG then documenting FINE and FINEST might be better then starting them at WARN...
My first take on it is this:
- Day one, I start to use logging.
- Of all the Log.debug()/warn()/info()/error()/trace()/whatever() methods, which am I most likely to use? I would think it would be Log.debug(). If I get no output before the default is WARN, then I'm a bit confused.
- I'm not going to have a lot of debug statements out of the box, so I don't mind seeing everything
- Day three, I'm starting to do a lot more logging and now I'm thinking about actually using the different levels and about throttling back from 'show be everything'
- This is where your "but as a developer I would want to easily add messages that do not show up by default" comes in
I'll admit there is a flip side:
- If I inherit a module/library that does a lot of logging, I would be overwhelmed if by default the l saw everything
- If GWT core did a lot of low level logging, I wouldn't want to see that by default either
This whole 'libraries/modules with their own logging code' issue does make be reconsider the notion of categories or some kind of separation of logging control. What if instead of categories we used a different deferred binding trick:
Let's say the base log interface is:
com.google.gwt.client.log.Log
The 'foo' library developer could extend that interface to:
public interface com.libmaker.gwt.foo.FooLog
extends com.google.gwt.client.log.Log {
}
and then instantiate a global log class to be used exclusively by the 'foo' library with:
static Log log = GWT.create(com.libmaker.gwt.foo.FooLog.class);
Separately, the 'bar' application developer could also extend the base interface to:
public interface com.appmaker.gwt.bar.BarLog
extends com.google.gwt.client.log.Log {
}
and instantiate a log implementation dedicated to the 'bar' application with:
static Log log = GWT.create(com.appmaker.gwt.bar.BarLog.class);
Then the compile time log level of both the 'foo' library and the 'bar' application could be controlled independently:
<replace-with class='com.google.gwt.client.log.impl.LogImplOff'>
<when-type-is class='com.appmaker.gwt.bar.BarLog' />
</replace-with>
<replace-with class='com.google.gwt.client.log.impl.LogImplDebug'>
<when-type-is class='com.libmaker.gwt.foo.FooLog' />
</replace-with>
I like our library developers, I don't want to make them mess with deferred bindings if they don't have to. Besides, I'd rather let the user decide what logging information to see from each library. This, to me, is a very persuasive argument that we should support category filtering on the client.
On Feb 5, 2008 4:51 PM, Emily Crutcher <e...@google.com> wrote:Ok, but how do you propose doing this without eitherI like our library developers, I don't want to make them mess with deferred bindings if they don't have to. Besides, I'd rather let the user decide what logging information to see from each library. This, to me, is a very persuasive argument that we should support category filtering on the client.
a) exploding the number of permutations
b) doing category level checks at runtime
To me, neither of those are acceptable and are much worse than not having per-category level checks on the client.
--
John A. Tamplin
Software Engineer, Google
On Feb 5, 2008 4:40 PM, Fred Sauer <fr...@allen-sauer.com> wrote:On Feb 5, 2008 1:33 PM, Emily Crutcher <e...@google.com> wrote:I'd prefer DEBUG/FINEST (or whatever is the lowest) instead of WARN for the beginner trying to get Log.debug(....) to just work.
I see your point, but as a developer I would want to easily add messages that do not show up by default. Maybe though setting the levels at CONFIG then documenting FINE and FINEST might be better then starting them at WARN...
My first take on it is this:
- Day one, I start to use logging.
- Of all the Log.debug()/warn()/info()/error()/trace()/whatever() methods, which am I most likely to use? I would think it would be Log.debug(). If I get no output before the default is WARN, then I'm a bit confused.
- I'm not going to have a lot of debug statements out of the box, so I don't mind seeing everything
- Day three, I'm starting to do a lot more logging and now I'm thinking about actually using the different levels and about throttling back from 'show be everything'
- This is where your "but as a developer I would want to easily add messages that do not show up by default" comes in
This is where the java logging levels actually help you, as a naive user I would use "info", "warn", or "config". I'm pretty sure I would not use "fine", "finner", "finest", so if we bump down the logging level to "config", then hopefully both use cases would be met.
I'll admit there is a flip side:This whole 'libraries/modules with their own logging code' issue does make be reconsider the notion of categories or some kind of separation of logging control. What if instead of categories we used a different deferred binding trick:
- If I inherit a module/library that does a lot of logging, I would be overwhelmed if by default the l saw everything
- If GWT core did a lot of low level logging, I wouldn't want to see that by default either
Let's say the base log interface is:
com.google.gwt.client.log.Log
The 'foo' library developer could extend that interface to:
public interface com.libmaker.gwt.foo.FooLog
extends com.google.gwt.client.log.Log {
}
and then instantiate a global log class to be used exclusively by the 'foo' library with:
static Log log = GWT.create(com.libmaker.gwt.foo.FooLog.class);
Separately, the 'bar' application developer could also extend the base interface to:
public interface com.appmaker.gwt.bar.BarLog
extends com.google.gwt.client.log.Log {
}
and instantiate a log implementation dedicated to the 'bar' application with:
static Log log = GWT.create(com.appmaker.gwt.bar.BarLog.class);
Then the compile time log level of both the 'foo' library and the 'bar' application could be controlled independently:
<replace-with class='com.google.gwt.client.log.impl.LogImplOff'>
<when-type-is class='com.appmaker.gwt.bar.BarLog' />
</replace-with>
<replace-with class='com.google.gwt.client.log.impl.LogImplDebug'>
<when-type-is class='com.libmaker.gwt.foo.FooLog' />
</replace-with>
I like our library developers, I don't want to make them mess with deferred bindings if they don't have to. Besides, I'd rather let the user decide what logging information to see from each library. This, to me, is a very persuasive argument that we should support category filtering on the client.
Hey, I think that means we agree.
I think we can simplify a bit for the application developer:
- Keep the above deferred binding sub interface capability for library developers, GWT proper and so on.
- Provide all the necessary defaults in the GWT logging *.gwt.xml module file for the application developer, so that she can just call Log.foo(...) out of the box, without having to create a sub interface
- Large/complex projects can later follow the library developer route and add sub interfaces if they really need to
Why are level checks at runtime a problem?
I'm not sure I understand. The call to log would look like this:
Log.warn("my message", "category");
If logging is "production" or "off", the message is completely removed. If logging is on, then the LogImpl class would have to check if the category is enabled, but that should be relatively small code.
What if libraries did this:
Log logger = GWT.create(com.google.gwt.client.log.Log.class,
"com.libmaker.gwt.foo.Foo");
instead of this:
Log logger = GWT.create(com.libmaker.gwt.foo.FooLog.class)
You could then statically determine a log level for each category.
The generator that gets invoked to instantiate the Log interface could
look at some configuration item (in module.gwt.xml, or in log4j.xml,
or whatever) to determine which kind of logger to return. If
"com.libmaker.gwt.foo.Foo" is set to OFF, then the generator returns
NullLogger. If it's set to FINE then it returns the FineLogger, etc.
I think this would capture the best parts of Fred's suggestion,
without tripping over Emily's concern about making library writers
into deferred binding experts. I _think_ it also avoids creating an
explosion of deferred binding permutations, but I might be missing
something.
Thoughts?
--
John A. Tamplin
Software Engineer, Google
I think we can simplify a bit for the application developer:
- Keep the above deferred binding sub interface capability for library developers, GWT proper and so on.
- Provide all the necessary defaults in the GWT logging *.gwt.xml module file for the application developer, so that she can just call Log.foo(...) out of the box, without having to create a sub interface
- Large/complex projects can later follow the library developer route and add sub interfaces if they really need to
I agree that people should be able to create sub interfaces, however I still would not want to make them have to, which means I'm still in favor of category level logging control.
I like the idea of GWT.create() with arguments, there are many reasons it would be very cool, but the last thing I want to do right now is distract our wonderful compiler team with the design for logging and I believe there are more compelling use cases out there to champion the feature. That being said, Ian, I think you are right that if it existed we could probably figure out some very clever ways to use it.
If I'm understanding correctly, then I think you guys are saying that
GWT.create() will _eventually_ be extended and, when that happens,
setting the category for a logger via GWT.create() would be the right
way to go. If all that's true, then I think we should take a
forwards-compatible version of Fred's suggestion until create() gets
additional parameters. As discussed in another thread, adding
parameters to create() doesn't add power to create(), it just adds
convenience, so everything that could be done with extra create()
parameters can already be done today.
I'd suggest something like this:
/**
* @gwt.logCategory com.libmaker.gwt.foo.Foo
*/
public interface FooLogger extends Logger {
}
Logger log = GWT.create(com.libmaker.gwt.foo.FooLogger.class);
Once GWT.create() gets additional parameters, the Logger generator
could look first at a category passed to create(), and second at the
@gwt.logCategory annotation. Either way, the category is set at
compile time, which means the compiler could statically determine
which kind of logger to instantiate based on some kind of category ->
level configuration.
Also, I think I agree with Emily's earlier assertion that getting
library makers to learn how to configure deferred binding is too much
to ask, but now, instead of configuring it, they'd just be using
it--sort of like application writers who want to use RPC.
If I'm understanding correctly, then I think you guys are saying that
GWT.create() will _eventually_ be extended and, when that happens,
setting the category for a logger via GWT.create() would be the right
way to go. If all that's true, then I think we should take a
forwards-compatible version of Fred's suggestion until create() gets
additional parameters. As discussed in another thread, adding
parameters to create() doesn't add power to create(), it just adds
convenience, so everything that could be done with extra create()
parameters can already be done today.
I'd suggest something like this:
/**
* @gwt.logCategory com.libmaker.gwt.foo.Foo
*/
I might be beating a dead horse here, but a wise man once told me that
instead of doing printf-style debugging, you should replace the
printfs with log statements. Then, in the future, when you have to
debug the same or similar problem all over again, you already have all
the debug output you need--you just have to turn it on. I think a
good logging framework, coupled with wise application thereof can
easily be better than a debugger in most cases and it's _always_ more
persistent, simply by definition. I hope the logging framework under
discussion will be the "good logging framework" half of that equation
(and I'm optimistic, what with all the lively discussion here).