Java Exceptions counter on JVM HotSpot
Asked Answered
O

1

6

I am wondering is it possible to log every exception which occurs on JVM level without changing application code? By every exception I mean caught and uncaught exception... I would like to analyze those logs later and group them by exception type (class) and simply count exceptions by type. I am using HotSpot ;)

Maybe there is smarter why of doing it? For example by any free profiler (YourKit has it but it is not free)? I think that JRockit has exception counter in management console, but don't see anything similar for HotSpot.

Offense answered 9/5, 2014 at 9:50 Comment(6)
By default exceptions are sent to stderr; therefore if you redirect stderr you should get your exceptions wherever it is that you redirected.Shoebill
@Shoebill but then he won't see exceptions which where caught and not printed.Mucronate
@Mucronate ah yeah, I didn't see that part... Well, short of instrumenting the code I don't see a way to do thatShoebill
You could change the Throwable constructor to log whenever it is created. I wouldn't do this in production, but to get a better understanding of your application it might be worth it.Infiltration
@PeterLawrey I thought about that, there is a topic about that somewhere here ;)Offense
@PeterLawrey An interesting idea. Though not all constructed exceptions are thrown and not all thrown exceptions are constructed :) E.g. HotSpot may throw implicit exceptions (NullPointerException, ArithmeticException, ArrayIndexOutOfBoundsException, ClassCastException etc.) in a fast-path using a preallocated instance (without creating a new Throwable object). Don't forget to add -XX:-OmitStackTraceInFastThrow to prevent this.Backwoods
B
6

I believe there are free tools to do it, but even making your own tool is easy. JVMTI will help.

Here is a simple JVMTI agent I made to trace all exceptions:

#include <jni.h>
#include <jvmti.h>
#include <string.h>
#include <stdio.h>

void JNICALL ExceptionCallback(jvmtiEnv* jvmti, JNIEnv* env, jthread thread,
                               jmethodID method, jlocation location, jobject exception,
                               jmethodID catch_method, jlocation catch_location) {
    char* class_name;
    jclass exception_class = (*env)->GetObjectClass(env, exception);
    (*jvmti)->GetClassSignature(jvmti, exception_class, &class_name, NULL);
    printf("Exception: %s\n", class_name);
}


JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
    jvmtiEnv* jvmti;
    jvmtiEventCallbacks callbacks;
    jvmtiCapabilities capabilities;

    (*vm)->GetEnv(vm, (void**)&jvmti, JVMTI_VERSION_1_0);

    memset(&capabilities, 0, sizeof(capabilities));
    capabilities.can_generate_exception_events = 1;
    (*jvmti)->AddCapabilities(jvmti, &capabilities);

    memset(&callbacks, 0, sizeof(callbacks));
    callbacks.Exception = ExceptionCallback;
    (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));
    (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_EXCEPTION, NULL);

    return 0;
}

To use it, make a shared library (.so) from the given source code, and run Java with -agentpath option:

java -agentpath:libextrace.so MyApplication

This will log all exception class names on stdout. ExceptionCallback also receives a thread, a method and a location where the exception occured, so you can extend the callback to print much more details.

Backwoods answered 9/5, 2014 at 15:2 Comment(2)
I am wondering is it possible to achieve similar functionality with java instrumentation? (java.lang.instrument)Offense
@Offense Instrumentation allows you to modify Java bytecode, but not all exceptions come from 'athrow' bytecode. Some of them are thrown by native library code and some are implicitly thrown by JVM. The closest thing you can do by instrumentation is probably Peter's suggestion of modifying Throwable constructor. A the same time JVMTI agent will handle all the cases automatically.Backwoods

© 2022 - 2024 — McMap. All rights reserved.