JFR Events
JFR Events and Wildfly
Monitoring:
After implementing jaeger tracing and the export for prometheus, Dynatrace became the new king in town. But to have a fast local monitor solution, Java Flight Recorder is the way to go(IMHO).
Here we go:
I used Azul JDKs, so their “mission control” was a natural fit.
jboss-deployment-structure.xml
...
<ear-subdeployments-isolated>true</ear-subdeployments-isolated>
<sub-deployment name="duckhawkwebservice.war">
<dependencies>
<module name="deployment.ServiceAgentConnector.rar" export="true"/>
<module name="org.apache.cxf" export="true"/>
<module name="org.apache.cxf.impl" export="true"/>
<module name="org.apache.httpcomponents" export="true"/>
<module name="org.bouncycastle.bcprov" export="true"/>
<module name="io.opentracing.opentracing-noop" export="true"/>
<module name="net.bytebuddy" export="true"/>
<module name="jdk.jfr" export="true"/>
</dependencies>
</sub-deployment>
...
package de.codecoverage.tools.jfr;
import jdk.jfr.Category;
import jdk.jfr.Description;
import jdk.jfr.Event;
import jdk.jfr.Label;
import jdk.jfr.Name;
import jdk.jfr.StackTrace;
public interface CCEvents
{
public static CCEvent createGenricEvent() {
CCEvent event = new CCEvent();
event.begin();
return event;
}
public static CCEventSpecific createSpecificEvent() {
CCEventSpecific event = new CCEventSpecific();
event.begin();
return event;
}
@Description("Simple event with a message")
@Category({ "CC", "Events", "General" })
@Name("CCEvent")
public class CCEvent extends Event implements AutoCloseable
{
@Label("Message")
@Description("A simple string message")
protected /*protected: to be used in derived class*/ String message;
public void setMessage(String message) {
this.message = message;
}
@Override
public void close() {
this.commit();
}
protected CCEvent() {
}
}
@Description("Simple event wich can hold a message and a value")
@Category({ "CC", "Events", "Specific" })
@Name("CCEventSpecific")
@StackTrace(false)
public class CCEventSpecific extends CCEvent
{
@Label("Value")
@Description("A value")
protected /*protected: to be used in derived class*/ long value;
public void setValue(long value) {
this.value = value;
}
protected CCEventSpecific() {
}
}
public final class TestDriver {
// Main class: de.codecoverage.tools.jfr.CCEvents$TestDriver
public static void main(String[] args) throws InterruptedException {
stackDepth2(); // to give a stack depth
}
private static void stackDepth2() throws InterruptedException {
stackDepth1();
}
private static void stackDepth1() throws InterruptedException {
for (int i = 0; i < 1000; i++) {
try (var event = CCEvents.createSpecificEvent()) {
event.setMessage(String.valueOf(i));
event.setValue(i);
try (var cc = CCEvents.createGenricEvent()) {
var str = String.valueOf(i);
cc.setMessage(str + " - " + str);
Thread.sleep(100);
System.out.printf("CCEvent enabled = %B%n", event.isEnabled());
System.out.printf("CCEvent shouldCommit = %B%n", event.shouldCommit());
}
Thread.sleep(400);
System.out.printf("CCEventSpecific enabled = %B%n", event.isEnabled());
System.out.printf("CCEventSpecific shouldCommit = %B%n", event.shouldCommit());
}
}
}
}
}
isEnabled() and shouldCommit() are intentionally ignored because then the work done is roughly the same(JFR enabled).
Copilot explanation:
This Java code is part of a package de.codecoverage.tools.jfr
and it defines an interface CCEvents
which contains two classes CCEvent
and CCEventSpecific
, and a TestDriver
class.
The CCEvent
class is a simple event with a message. It extends the Event
class and implements the AutoCloseable
interface. The AutoCloseable
interface is used to allow the CCEvent
object to be used in a try-with-resources statement, which automatically calls the close
method when the try block exits. The close
method in turn calls the commit
method. The CCEvent
class has a protected message
field, which can be set using the setMessage
method. The message
field is annotated with @Label
and @Description
, which are used to provide metadata about the field for the Java Flight Recorder (JFR) framework.
The CCEventSpecific
class extends CCEvent
and adds an additional value
field, which can be set using the setValue
method. This class represents a more specific event that can hold both a message and a value. The value
field is also annotated with @Label
and @Description
.
The CCEvents
interface also provides two static methods createGenricEvent
and createSpecificEvent
for creating instances of CCEvent
and CCEventSpecific
respectively. These methods call the begin
method on the newly created event before returning it.
The TestDriver
class contains a main
method which is the entry point of the program. The main
method calls the stackDepth2
method, which in turn calls the stackDepth1
method. The stackDepth1
method creates a number of CCEventSpecific
and CCEvent
objects in a loop, sets their message and value fields, and checks whether they are enabled and should be committed. The Thread.sleep
method is used to introduce a delay between the creation of each event. The printf
method is used to print the status of the events to the console.