I have a Tomcat server running a large application. It has two classes similar to this example:
public abstract class ClassA {
private static final Logger LOGGER = Logger.getLogger(ClassA.class);
// ...
public File methodA(ICancellable cancel) {
URL request = new URL("an URL");
LOGGER.debug("Calling ClassB.methodB(type)");
File f = classB.methodB(request, "type", cancel);
LOGGER.debug("The call to ClassB.methodB(type)"
+ " returned the File==" + f);
// ...
}
}
public class ClassB {
private static final Logger LOGGER = Logger.getLogger(ClassB.class);
// ...
public static synchronized File methodB(URL url, String type,
ICancellable cancel)
{
final String thisMethodsName = "ClassB.methodB(url: " + url
+ ", type:" + type + ", cancel: " + cancel + ")";
LOGGER.debug("Entering method: " + thisMethodsName);
// ...
return f;
}
}
The application works properly, and ClassA.methodA() initially calls succesfully to ClassB.methodB(), as I can see in the log files:
[...]
14/02/2013 12:34:56 DEBUG ClassA:123 - Calling ClassB.methodB(type)
14/02/2013 12:34:56 DEBUG ClassB:456 - Entering method: ClassB.methodB(url: anURL, type: type, cancel: #1234);
[...]
14/02/2013 12:34:56 DEBUG ClassA:125 - The call to ClassB.methodB(type) returned the File=="aFile".
[...]
My problem is after the server is working for some time, it stops calling ClassB.methodB(). the application gets hung and it simply writes this to the log:
[...]
14/02/2013 12:34:56 DEBUG ClassA:123 - Calling ClassB.methodB(type)
That's the last line of the log file. ClassB.methodB() isn't actually called.
I suspected it could be due to opened resources that werent closed, but I'm trying to locate all the code that did that, and after fixsing so, it still happens.
What can be causing this? How can I continue searching for the cause?
JVM version: 1.6.0_13
Tomcat version: 6.0.18
Is it possible that there is a thread deadlock bug involving some code that you didn't paste? Your ClassB.methodB method is synchronized. You probably have some other thread that is holding and not releasing the synchronized lock on ClassB.class, preventing the thread that is doing the logging from ever acquiring that lock and entering the method.
Enable the debug mode and assign breakpoints in your code. Use IDE ( preferrably eclipse) to go step by step.
Eclipse has plugins like findbugs or PMD to scan the code and find out possible bugs.
Manually go through every conditions, method calls, loops to see flaws.
If you have written the complete app, then you would know where to look at. If not, it would still be good to check all that is written
Related
I'm new to loggers and I just wanted to ask if i will get an error if my log level is info, then i have something like:
logger.debug("hello " + object.getMethod());
And it is not inside an if block like below:
if(LOGGER.isDebugEnabled){...}
Also, will it have an impact on the time that an application may respond. If its not inside the if block statement?
All the log methods check for the level internally too. The reason we have isXYZEnabled methods if for performance.
Consider the following call:
logger.debug("Value of myObject is: " + hugeObject.toString());
and assume that hugeObject is, as its name suggests, huge. Constructing a string representation of it might be both time and memory consuming, and ultimately pointless, since after you created the string, nothing will be logged if the level isn't set to debug. Instead, you could explicitly check the level before performing this converstion, and save the time it could have taken:
if (logger.isDebugEnabled()) {
logger.debug("Value of myObject is: " + hugeObject.toString());
}
I want to log WebView console events. They sometimes pick up quirks in the underlying browser used and can help with troubleshooting.
It is possible to use an Sun implementation class to interact with the WebView console:
import
//...
WebConsoleListener.setDefaultListener((webView, message, lineNumber, sourceId) ->
LOGGER.info(() -> "WebConsoleListener: " + message + "[" + webEngine.getLocation() + ":" + lineNumber + "]")
);
However, com.sun.javafx.webkit.WebConsoleListener, is an implementation class and not part of the JavaFX public API.
What is the public API for getting JavaFX WebView console events?
Alternatively, what is the correct way to get these events for troubleshooting?
You can enable browser console logging via Java™ 2 platform's core logging facilities by adding this to logging.properties:
com.sun.webkit.WebPage.level = FINE
Make sure that a log handler with FINE or lower level is present in the logging configuration or the logs will be filtered before they are logged. Example:
handlers = java.util.logging.ConsoleHandler
.level = INFO
java.util.logging.ConsoleHandler.level = ALL
java.util.logging.ConsoleHandler.formatter = java.util.logging.XMLFormatter
com.sun.webkit.WebPage.level = FINE
Here's a more in-depth explanation of how I figured that out:
WebConsoleListener#setDefaultListener(WebConsoleListener) calls WebPageClientImpl#setConsoleListener(WebConsoleListener).
WebPageClientImpl#setConsoleListener(WebConsoleListener) stores the listener in its static field consoleListener.
consoleListener is only interacted with by WebPageClientImpl#addMessageToConsole(String,int,String).
WebPageClientImpl#addMessageToConsole(String,int,String) overrides WebPageClient#addMessageToConsole(String,int,String).
WebPageClient#addMessageToConsole(String,int,String) is called by WebPage#fwkAddMessageToConsole(String,int,String). There are no other call sites in the code base at the time of this writing.
That same method logs the console information:
log.log(Level.FINE, "fwkAddMessageToConsole(): message = " + message
+ ", lineNumber = " + lineNumber + ", sourceId = " + sourceId);
That means you can get the logging you need by enabling FINE logging on com.sun.webkit.WebPage limiting the implementation-level dependency to logging configuration:
com.sun.webkit.WebPage.level = FINE
I could not find a public API for this.
Based on my review of the OpenJDK JFX repo source, there isn't a public API for this.
This solution is still not ideal as it depends on a private implementation classname, but that dependency is in a configuration file where if the implementation class changes or disappears, the impact is a loss of logging rather than a likely fatal NoClassDefFoundError or NoSuchMethodError.
For logging purposes, I created a method logTitle() that prints out the calling method name for our TestNG tests. Sample code is below.
#Test
public void test1() throws Exception {
method1();
}
public static void method1() throws Exception {
Utils.logTitle(2);
}
...
public static void logTitle(Integer level) throws Exception {
// Gets calling method name
String method = Thread.currentThread().getStackTrace()[2].getMethodName();
// This would get current method name
switch (level) {
case 1:
logger.info("=======================================================");
logger.info(method);
logger.info("=======================================================");
break;
case 2:
logger.info("------------------------------------");
logger.info(method);
logger.info("------------------------------------");
break;
case 3:
logger.info("---------------------");
logger.info(method);
logger.info("---------------------");
break;
case 4:
logger.info("--------- " + method + " ------------");
break;
default:
logger.info(method);
}
}
The problem is I am getting different results for logTitle() on two different machines.
Everyone's laptop returns correctly:
2016-06-20 14:22:06 INFO - ------------------------------------
2016-06-20 14:22:06 INFO - method1
2016-06-20 14:22:06 INFO - ------------------------------------
Our dev unix box returns differently:
2016-06-20 14:42:26 INFO - ------------------------------------
2016-06-20 14:42:26 INFO - logTitle
2016-06-20 14:42:26 INFO - ------------------------------------
This works correctly on everyone else's laptop, just not the dev unix box. I think the dev unix box is using IBM's version of Java, while everyone else is using Oracle's version of Java, but not sure if that is the culprit or not.
Any ideas?
From Javadoc:
Some virtual machines may, under some circumstances, omit one or more stack frames from the stack trace. In the extreme case, a virtual machine that has no stack trace information concerning this throwable is permitted to return a zero-length array from this method.
So, the only guaranteed way to do this is to use aspects, or collect stack trace with some other custom way. But you can combine this approach with fallback to some way of getting current method's name (for case when your logTitle method will be inlined). It can be found here, for example. Again, no guarantee, but better chance.
The simpler way to have a test method name is by using a #BeforeMethod and injecting the Method. See TestNG's documentation, here.
Just store the name somewhere and use it in your log (why not in a #AfterMethod ?)
My guess, and as mentioned by MeBigFatGuy. This can happen because of the different in implementation/defaults of the JIT compiler of the IBM/Oracle JVM when doing method inlining optimization.
I suggest running the code in the dev unix box with
-Xjit:disableInlining
and see if the issue disappear.
If this will work for you it may be fine for testing, but as mentioned in Alexey Adamovskiy answer we cannot trust java to be consist in the stack frames.
See also:
Would Java inline method(s) during optimization?
Selectively disabling the JIT compiler
Java method inlining
performance considerations
I guess the behavior is JVM specific. In the past I came up with this solution:
// find first stack trace entry that is not in this class
Optional<StackTraceElement> ste = Iterables.tryFind(
Arrays.asList(new RuntimeException().getStackTrace()),
new Predicate<StackTraceElement>() {
#Override
public boolean apply(StackTraceElement input) {
return !input.getClassName().equals(PutYourClassHere.class.getName());
}
});
if (ste.isPresent()) {
LOG.trace("Method called by: {}.{}", ste.get().getClassName(), ste.get().getMethodName());
}
The snippet is using Google Guava because this is for Java 7. If you have Java 8, you can use Streams API and lambdas. I made the ste.isPresent() check because I encountered an empty stack trace once. As far as I remember the Oracle JVM is skipping stack traces when the same exception is thrown over and over again.
EDIT: Java 8 way
Optional<StackTraceElement> ste = Arrays.stream(new RuntimeException().getStackTrace())
.filter(x -> !x.getClassName().equals(Utils.class.getName()))
.findFirst();
I think its the specific depth that is causing the issue which is 2 in your scenario.
So, instead of writing
String method = Thread.currentThread().getStackTrace()[2].getMethodName();
if you write
StackTraceElement[] ste = Thread.currentThread().getStackTrace();
String method = null;
boolean doNext = false;
for (StackTraceElement s : ste) {
if (doNext) {
method = s.getMethodName();
return;
}
doNext = s.getMethodName().equals("getStackTrace");
}
It will work only for JDK 1.5+
The other option is as below:
String method = new Object(){}.getClass().getEnclosingMethod().getName();
Or a slower option will be :
String method = new Exception().getStackTrace()[0].getMethodName();
As this will create an instance of Exception everytime.
Hope that helps you out.
Log4J finds the method name by searching down the stack trace until it finds the target class name which must be passed in, then reads the method name.
In your code, you could use a similar technique - instead of a static method Utils you could create an instance in your test, passing in the class of the test:
Utils utils = new Utils(MyTest.class);
Then use the previously mentioned search technique in the Utils.logTitle() method.
Utils.logTitle() would search forwards through stack trace elements of a newly created Throwable until it finds the first element with the desired target class.
Log4j 2 uses the fully qualified class name of the Logger to locate the class and method from which the Logger was called. The code to find the location follows below. Feel free to use it.
Note that the loop starts from the bottom of the stacktrace; this is necessary to detect exceptional cases where the logger is called recursively (perhaps from the toString() method of an object that was logged). In such cases we want to report the first class/method that called the Logger, not the last one, so we have no choice but to walk the stack trace from the bottom up.
public static StackTraceElement calcLocation(final String fqcnOfLogger) {
if (fqcnOfLogger == null) {
return null;
}
// LOG4J2-1029 new Throwable().getStackTrace is faster
// than Thread.currentThread().getStackTrace().
final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
StackTraceElement last = null;
for (int i = stackTrace.length - 1; i > 0; i--) {
final String className = stackTrace[i].getClassName();
if (fqcnOfLogger.equals(className)) {
return last;
}
last = stackTrace[i];
}
return null;
}
Context:
I have created a small (java) multithread server for a game. Despite my best efforts of following the best practices it turned out that some methods that were intended to be called from just one thread got called from 2 or more threads. After debugging and analysis I have managed to "fix" my design but I was wondering:
The question:
Is there a tool (or if not - is it possible (and how) to be developed) that allows you to mark some methods with annotations like #SingleThread or #ThreadCount(2) or #ThreadNameLike("my_fancy_thread_group*") which counts/monitors/logs access to these methods like:
#SingleThread - checks if this method is always accessed by only thread
#ThreadCount(2) - is accessed by two threads exactly
#ThreadNameLike - is accessed only by threads with name matching the pattern(s)
The idea is to do a TEST run of the program and get at least log record that annotated condition is violated.
I was thinking that probably AspectJ can do the job to some extend with it's pointcuts but then I realized that some approach similar to Dagger / Dagger2 will be better, i.e. when you want to test your server you will have to turn on an annotation processor (let's called it hypothetically "SafetyFirst") which will generate adapter (wrapper?) classes which contain the monitoring code. Then you will run the server, run some load tests and then check the logs for violations (or in an ideal world - get a report file).
I fully realize that such tool:
will not provide 100% coverage of all potential cases;
will mask/trigger heisenbugs
will slow down the examined program
but at very least it can serve as an early warning system that will clearly advertise violations of the intended design.
I used a similar test with AspectJ load time weaving for intended printing of all function calls within my package.
Best way of load time weaving is you dont dirty your classes like compile time wevaing. When you remove -javaagent:<path to aspectj lib> and your custom astpect lib classpath entry from your run command. Then all all gone, clear.
I made some changes and implemented a test covering #ThreadCount functionality you asked. You need to download and install AspectJ.
Please see code snippets:
aspect Profile {
private static Map<String, AtomicInteger> counterMap = new HashMap<String, AtomicInteger>();
pointcut threadCountPc(test.ThreadCount tc) : execution(* test..*(..)) && #annotation(tc);
Object around(test.ThreadCount tc) : threadCountPc(tc) {
String signature = thisJoinPointStaticPart.getSignature().toString();
AtomicInteger counter = getCounter(signature);
int currentValue = counter.incrementAndGet();
if (currentValue >= tc.value()){
System.out.println("[Thread Name:" + Thread.currentThread().getName() +
"] Method Name:" + signature + ", threadCount:" + currentValue + " exceeds " + tc.value());
}
try{
return proceed(tc);
}finally{
counter.decrementAndGet();
}
}
private static AtomicInteger getCounter(String methodName){
AtomicInteger value = counterMap.get(methodName);
if (value == null){
synchronized (counterMap){
value = counterMap.get(methodName);
if (value == null){
value = new AtomicInteger(0);
counterMap.put(methodName, value);
}
}
}
return value;
}
}
Compiling: "C:/aspectj1.8/bin/ajc.bat" profile_ft.aj -cp C:/aspectj1.8/lib/aspectjrt.jar;../test/. -1.6 -outxml -outjar profile_ft.jar
Running: java -javaagent:C:/aspectj1.8/lib/aspectjweaver.jar -cp aspectj/profile_ft.jar;test test.Test1
I got a recommendation to use this syntax when logging in java:
if (logger.isLoggable(Log.FINE))
{
logger.fine("bla"+" bla"+" bla");
}
The reason for this is to avoid the redundant construction of the parameter string incase the logging level is lower than "FINE". (in the example above - 5 redundant string object. (" bla"X3, " bla bla" and "bla bla bla").
I'd like to hear what others are doing about this or if you think that this is necessary at all.
Thanks!!
Some newer logging frameworks allow you to specify arguments as parameters, and won't evaluate them if there's no logging.
The example I found is LogBack, the successor to Log4j. Here's the info: http://www.infoq.com/news/2007/08/logback
This gives you the best of both worlds, so to speak. Elegant syntax yet good performance.
Log4j code example:
if( logger.isDebugEnabled() ) {
logger.debug( "User with account " +
user.getAccount() + " failed authentication; " +
"supplied crypted password " + user.crypt(password) +
" does not match." );
}
Equivalent LogBack code:
logger.debug( "User with account {} failed authentication; " +
"supplied crypted password {} does not match.",
user.getAccount(), user.crypt(password) );
This defers the cost of message assembly until LOGBack has ascertained whether or not this message will be viewed. It doesn't defer the cost of retrieving expensive parameters, such as the password crypting in the above example.
String objects are immutable, and repeated concatenation is therefore an expensive operation. It requires repeated memory allocation, object creation and iteration. Considering that some logging calls at the finer log levels can be invoked thousands or millions of times per minute, it might be a considerable performance gain to do as you illustrate. Though, for a smaller application, it might not be worth the extra effort.
As a side note: You can save even more performance, where this is truly critical by using a constant such as this:
public static final boolean DEBUG = false;
If you now wrap the logging code in an if-block such as this, the JVM will be able to completely optimize away the debug calls when running in product mode. This is as close as you get to a C #ifdef.
if (Globals.DEBUG) {
// Logging call
}
Absolutely necessary for debug type logging. It something like 10x quicker to check the log level first than create the string and throw it away.
This is an improvement (good) but it can be improved on a little.
Set up final flags for each logging level (FINE, etc) in a global object used as config, then use a StringBuffer to build up your debugging output -- you can even format numbers into the stream at the same time.
public class MyAppConfig {
public final boolean FINE=true;
// ... other fields
}
public class MyApp {
void someFunction() {
...
int imagesProcessed;
imagesProcessed = processImages();
if (MyAppConfig.FINE) logger.fine(new StringBuffer(35).
append("Count of images processed: ").append(imagesProcessed).toString());
...
}
}
Here the string buffer is set up with an 'initial capacity' of 35 characters. If you know how many characters are going to be generated you can provide hints to StringBuffer.