[ 
https://issues.apache.org/jira/browse/LOGGING-137?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12896447#action_12896447
 ] 

Doug Bateman edited comment on LOGGING-137 at 8/9/10 12:17 AM:
---------------------------------------------------------------

Hey Sebastian,

Yeah, the patch file does have a spurious update to svn:ignore.  It adds 
".settings/" to the list.  Eclipse complains and that directory has been 
included in commons-lang and commons-io, but overlooked in commons-logging.  
However, you're right, that's really a separate issue.  So consider it gone.

The .java files do duplicate the .patch file.  Normally I'd just give the 
.patch file, but since we were having a discussion in channel I included the 
.java files too for ease of reading.  For the update, which would you prefer... 
Java files for patch files?

I'll remove the @author tag.  I was about to take it out, but noticed all the 
other files still had them.

Regarding the null return by CallStackUtil, it's really a non-issue since it 
can never happen.  The only place getCallerClassName(1) is used is inside of 
LogFactory.getLog().  And LogFactory.getLog() is guaranteed to have an 
immediate caller (depth=1), otherwise it never would have been called in the 
first place.  Nobody else can use CallStackUtil because it is package scope... 
It didn't seem relevant to the public API for logging... and if it was ever to 
be published, it probably should be in commons-lang.  I suppose I could have 
just made private methods inside of LogFactory, but I didn't want to add the 
clutter and package scope seemed appropriate.  That aside, the JavaDoc does 
actually discuss meaning of a null return, however I'll update the docs to make 
it a bit more obvious.

The non-final fields were strictly a matter of simplicity, since the compiler 
objects to a possible double assignment to the file in the try and again in the 
catch.  It objects even when using separate try/catch blocks for each set.  
However, I can work around that by using local variables in the initializer, so 
that's what I'll do.

CallStackUtil.getCallerJava14() doesn't actually scan the trace twice.  The i 
counter only ever increases.  First it scans to find the invocation to the 
"CallStackUtil" methods on the stack (to skip past the reflection calls), and 
then it scans further until it's past the "CallStackUtil" methods.  Leaving the 
interesting part of the call stack, which is then read at the requested depth.  
getCallerJava10() actually works the same way.  It just uses 
"stackTrace.lastIndexOf()" to accomplish this, since it's reading the stack as 
a string.

I too wanted to use Thread.getStackTrace().  However I noticed in the JavaDoc 
that it can throw SecurityExceptions, while Throwable.getStackTrace() does not. 
 I have no idea why they decided to allow that in one but not the other.  And 
of course Thread.getStackTrace() isn't available until Java 5.0 instead of 1.4. 
 So following the "keep it simple" rule, I decided to use 
Throwable.getStackTrace().  I don't imagine the performance difference is 
measurable since Throwable.getStackTrace() likely uses the exact same native 
code underneath.  And the extra object allocation is insignificant in 
comparison to the use of Java reflection.  If after all this, you still think I 
should add support for Java 5.0's Thread.getStackTrace() I'm happy to do add it.

I made isAtLeastJava14 non-volatile deliberately as well.  In actuality, it 
could probably be made final, since I cant imagine a case where those catch 
blocks would ever be hit, except maybe in the case of a SecurityException.  I 
had simply decided to make the implementation fault tolerant in the event I was 
wrong.  I didn't make it volatile because I wanted to avoid the memory flush.  
If a thread has a stale copy of the flag no harm is done... that stale copy 
would always have the value true (from the static initializer which is 
synchronized by the classloader).  And that just means the catch blocks would 
be hit again, and that thread would catch the exception and set it's cached 
copy to false as well... no memory flush required.  I should probably comment 
that though, since it is unintuitive.

I'll submit an update.  Would you prefer it as java files or a single patch 
file?


      was (Author: dougbateman):
    Hey Sebastian,

Yeah, the patch file does have a spurious update to svn:ignore.  It adds 
".settings/" to the list.  Eclipse complains and that directory has been 
included in commons-lang and commons-io, but overlooked in commons-logging.  
However, you're right, that's really a separate issue.  So consider it gone.

The .java files do duplicate the .patch file.  Normally I'd just give the 
.patch file, but since we were having a discussion in channel I included the 
.java files too for ease of reading.  For the update, which would you prefer... 
Java files for patch files?

I'll remove the @author tag.  I was about to take it out, but noticed all the 
other files still had them.

Regarding the null return by CallStackUtil, it's really a non-issue since it 
can never happen.  The only place getCallerClassName(1) is used is inside of 
LogFactory.getLog().  And LogFactory.getLog() is guaranteed to have an 
immediate caller (depth=1), otherwise it never would have been called in the 
first place.  Nobody else can use CallStackUtil because it is package scope... 
It didn't seem relevent to the public API for logging... and if it was ever to 
be published, it probably should be in commons-lang.  I suppose I could have 
just made private methods inside of LogFactory, but I didn't want to add the 
clutter and package scope seemed appropriate.  That aside, the JavaDoc does 
actually discuss meaning of a null return, however I'll update the docs to make 
it a bit more obvious.

The non-final fields were strictly a matter of simplicity, since the compiler 
objects to a possible double assignment to the file in the try and again in the 
catch.  It objects even when using separate try/catch blocks for each set.  
However, I can work around that by using local variables in the initializer, so 
that's what I'll do.

CallStackUtil.getCallerJava14() doesn't actually scan the trace twice.  The i 
counter only ever increases.  First it scans to find the invocation to the 
"CallStackUtil" methods on the stack (to skip past the reflection calls), and 
then it scans further until it's past the "CallStackUtil" methods.  Leaving the 
interesting part of the call stack, which is then read at the requested depth.  
getCallerJava10() actually works the same way.  It just uses 
"stackTrace.lastIndexOf()" to accomplish this, since it's reading the stack as 
a string.

I too wanted to use Thread.getStackTrace().  However I noticed in the JavaDoc 
that it can throw SecurityExceptions, while Throwable.getStackTrace() does not. 
 I have no idea why they decided to allow that in one but not the other.  And 
of course Thread.getStackTrace() isn't available until Java 5.0 instead of 1.4. 
 So following the "keep it simple" rule, I decided to use 
Throwable.getStackTrace().  I don't imagine the performance difference is 
measurable since Throwable.getStackTrace() likely uses the exact same native 
code underneath.  And the extra object allocation is insignificant in 
comparision to the use of Java reflection.  If after all this, you still think 
I should add support for Java 5.0's Thread.getStackTrace() I'm happy to do add 
it.

I made isAtLeastJava14 non-volatile deliberately as well.  In actuality, it 
could probably be made final, since I cant imagine a case where those catch 
blocks would ever be hit, except maybe in the case of a SecurityException.  I 
had simply decided to make the implementation fault tolerant in the event I was 
wrong.  I didn't make it volatile because I wanted to avoid the memory flush.  
If a thread has a stale copy of the flag no harm is done... that stale copy 
would always have the value true (from the static initializer which is 
synchronized by the classloader).  And that just means the catch blocks would 
be hit again, and that thread would catch the exception and set it's cached 
copy to false as well... no memory flush required.  I should probably comment 
that though, since it is unintuitive.

I'll submit an update.  Would you prefer it as java files or a single patch 
file?

  
> LogFactory.getLog()
> -------------------
>
>                 Key: LOGGING-137
>                 URL: https://issues.apache.org/jira/browse/LOGGING-137
>             Project: Commons Logging
>          Issue Type: New Feature
>    Affects Versions: 1.1.2
>            Reporter: Doug Bateman
>         Attachments: CallStack.patch, CallStackTest.java, CallStackUtil.java, 
> LogFactory.java
>
>   Original Estimate: 0.5h
>  Remaining Estimate: 0.5h
>
> Presently, in Apache Commons, the most common way to get a logger is to do 
> something like:
> public class MyClass {
>     private static Log log = LogFactory.getLog(MyClass.class);
> }
> Notice how MyClass.class (or alternatively a string name) is passed as a 
> parameter.  The annoying aspect of this is that sometimes the class name 
> doesn't get updated when doing copy/paste operations.  A desirable 
> alternative might be:
> public class MyClass {
>     private static Log log = LogFactory.getLog(); //class name inferred from 
> call stack
> }
> With such an approach there are two possible concerns I can foresee:
>     * Call stack inspection isn't terribly fast.  However since Loggers are 
> generally initialized only once, when the class is first loaded, performance 
> isn't likely to be a major problem.
>     * Commons-logging is Java 1.1 compatible.  Thus care must be taken to 
> ensure compatibility isn't broken.
>     * Commons-logging doesn't depend on commons-lang, and thus the utilities 
> in commons-lang cannot be used.
> In Java 1.4, the call stack is easily obtained using Thread.getCallStack().  
> Prior to Java 1.4, the only way to obtain the call stack is to inspect the 
> stack trace of an exception.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to