HHH-17336 - JFR events - Session open, Session close

https://hibernate.atlassian.net/browse/HHH-17336
This commit is contained in:
Steve Ebersole 2023-09-14 08:18:46 -05:00
parent 9d515dd182
commit 9ce2d25041
7 changed files with 165 additions and 0 deletions

View File

@ -89,6 +89,8 @@ dependencies {
testImplementation testLibs.byteman testImplementation testLibs.byteman
testImplementation testLibs.jfrUnit
testRuntimeOnly testLibs.log4j2 testRuntimeOnly testLibs.log4j2
testRuntimeOnly libs.byteBuddy testRuntimeOnly libs.byteBuddy

View File

@ -0,0 +1,34 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
*/
package org.hibernate.event.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;
/**
* @author Steve Ebersole
*/
@Name(SessionClosedEvent.NAME)
@Label("Session Closed")
@Category("Hibernate ORM")
@Description("Hibernate Session closed")
@StackTrace(false)
public class SessionClosedEvent extends Event {
public static final String NAME = "org.hibernate.orm.SessionClosed";
@Label("Session Identifier" )
public String sessionIdentifier;
@Override
public String toString() {
return NAME + "(" + sessionIdentifier + ")";
}
}

View File

@ -0,0 +1,34 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
*/
package org.hibernate.event.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;
/**
* @author Steve Ebersole
*/
@Name(SessionOpenEvent.NAME)
@Label("Session Opened")
@Category("Hibernate ORM")
@Description("Hibernate Session opened")
@StackTrace(false)
public class SessionOpenEvent extends Event {
public static final String NAME = "org.hibernate.orm.SessionOpened";
@Label("Session Identifier" )
public String sessionIdentifier;
@Override
public String toString() {
return NAME + "(" + sessionIdentifier + ")";
}
}

View File

@ -69,6 +69,8 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.Status; import org.hibernate.engine.spi.Status;
import org.hibernate.engine.transaction.spi.TransactionImplementor; import org.hibernate.engine.transaction.spi.TransactionImplementor;
import org.hibernate.engine.transaction.spi.TransactionObserver; import org.hibernate.engine.transaction.spi.TransactionObserver;
import org.hibernate.event.jfr.SessionClosedEvent;
import org.hibernate.event.jfr.SessionOpenEvent;
import org.hibernate.event.spi.AutoFlushEvent; import org.hibernate.event.spi.AutoFlushEvent;
import org.hibernate.event.spi.AutoFlushEventListener; import org.hibernate.event.spi.AutoFlushEventListener;
import org.hibernate.event.spi.ClearEvent; import org.hibernate.event.spi.ClearEvent;
@ -228,6 +230,11 @@ public class SessionImpl
public SessionImpl(SessionFactoryImpl factory, SessionCreationOptions options) { public SessionImpl(SessionFactoryImpl factory, SessionCreationOptions options) {
super( factory, options ); super( factory, options );
final SessionOpenEvent sessionOpenEvent = new SessionOpenEvent();
if ( sessionOpenEvent.isEnabled() ) {
sessionOpenEvent.begin();
}
persistenceContext = createPersistenceContext(); persistenceContext = createPersistenceContext();
actionQueue = createActionQueue(); actionQueue = createActionQueue();
@ -272,6 +279,14 @@ public class SessionImpl
if ( log.isTraceEnabled() ) { if ( log.isTraceEnabled() ) {
log.tracef( "Opened Session [%s] at timestamp: %s", getSessionIdentifier(), currentTimeMillis() ); log.tracef( "Opened Session [%s] at timestamp: %s", getSessionIdentifier(), currentTimeMillis() );
} }
if ( sessionOpenEvent.isEnabled() ) {
sessionOpenEvent.end();
if ( sessionOpenEvent.shouldCommit() ) {
sessionOpenEvent.sessionIdentifier = getSessionIdentifier().toString();
sessionOpenEvent.commit();
}
}
} }
private FlushMode getInitialFlushMode() { private FlushMode getInitialFlushMode() {
@ -413,6 +428,11 @@ public class SessionImpl
log.tracef( "Closing session [%s]", getSessionIdentifier() ); log.tracef( "Closing session [%s]", getSessionIdentifier() );
} }
final SessionClosedEvent sessionClosedEvent = new SessionClosedEvent();
if ( sessionClosedEvent.isEnabled() ) {
sessionClosedEvent.begin();
}
// todo : we want this check if usage is JPA, but not native Hibernate usage // todo : we want this check if usage is JPA, but not native Hibernate usage
final SessionFactoryImplementor sessionFactory = getSessionFactory(); final SessionFactoryImplementor sessionFactory = getSessionFactory();
if ( sessionFactory.getSessionFactoryOptions().isJpaBootstrap() ) { if ( sessionFactory.getSessionFactoryOptions().isJpaBootstrap() ) {
@ -435,6 +455,14 @@ public class SessionImpl
if ( statistics.isStatisticsEnabled() ) { if ( statistics.isStatisticsEnabled() ) {
statistics.closeSession(); statistics.closeSession();
} }
if ( sessionClosedEvent.isEnabled() ) {
sessionClosedEvent.end();
if ( sessionClosedEvent.shouldCommit() ) {
sessionClosedEvent.sessionIdentifier = getSessionIdentifier().toString();
sessionClosedEvent.commit();
}
}
} }
private boolean isTransactionInProgressAndNotMarkedForRollback() { private boolean isTransactionInProgressAndNotMarkedForRollback() {

View File

@ -0,0 +1,58 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
*/
package org.hibernate.orm.test.event.jfr;
import java.util.List;
import org.hibernate.event.jfr.SessionClosedEvent;
import org.hibernate.event.jfr.SessionOpenEvent;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import jdk.jfr.consumer.RecordedEvent;
import org.moditect.jfrunit.EnableEvent;
import org.moditect.jfrunit.JfrEventTest;
import org.moditect.jfrunit.JfrEvents;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Steve Ebersole
*/
@JfrEventTest
@DomainModel
@SessionFactory
public class SessionEventTests {
public JfrEvents jfrEvents = new JfrEvents();
@Test
@EnableEvent(SessionOpenEvent.NAME)
@EnableEvent(SessionClosedEvent.NAME)
public void testSessionOpenEvent(SessionFactoryScope scope) {
final String openedSessionIdentifier = scope.fromSession( (session) -> {
final List<RecordedEvent> events = jfrEvents.events().filter( recordedEvent -> recordedEvent.hasField("sessionIdentifier" ) ).toList();
assertThat( events ).hasSize( 1 );
final RecordedEvent event = events.get( 0 );
assertThat( event.getEventType().getName() ).isEqualTo( SessionOpenEvent.NAME );
assertThat( event.getString( "sessionIdentifier" ) ).isEqualTo( session.getSessionIdentifier().toString() );
jfrEvents.reset();
return event.getString( "sessionIdentifier" );
} );
final List<RecordedEvent> events = jfrEvents.events().filter( recordedEvent -> recordedEvent.hasField("sessionIdentifier" ) ).toList();
assertThat( events ).hasSize( 1 );
final RecordedEvent event = events.get( 0 );
assertThat( event.getEventType().getName() ).isEqualTo( SessionClosedEvent.NAME );
assertThat( event.getString( "sessionIdentifier" ) ).isEqualTo( openedSessionIdentifier );
}
}

View File

@ -0,0 +1,5 @@
/**
* Tests for Hibernate's JFR events. Well the events are roduced on Java 11, the JfrUnit
* framewqork used in testing only works on JDK 16+.
*/
package org.hibernate.test.event.jfr;

View File

@ -177,6 +177,8 @@ dependencyResolutionManagement {
def wildFlyTxnClientVersion = version "wildFlyTxnClient", "2.0.0.Final" def wildFlyTxnClientVersion = version "wildFlyTxnClient", "2.0.0.Final"
def xapoolVersion = version "xapool", "1.5.0" def xapoolVersion = version "xapool", "1.5.0"
def jfrUnitVersion = version "jfrUnit", "1.0.0.Alpha2"
library( "junit5Api", "org.junit.jupiter", "junit-jupiter-api" ).versionRef( junit5Version ) library( "junit5Api", "org.junit.jupiter", "junit-jupiter-api" ).versionRef( junit5Version )
library( "junit5Engine", "org.junit.jupiter", "junit-jupiter-engine" ).versionRef( junit5Version ) library( "junit5Engine", "org.junit.jupiter", "junit-jupiter-engine" ).versionRef( junit5Version )
library( "junit5Params", "org.junit.jupiter", "junit-jupiter-params" ).versionRef( junit5Version ) library( "junit5Params", "org.junit.jupiter", "junit-jupiter-params" ).versionRef( junit5Version )
@ -206,6 +208,8 @@ dependencyResolutionManagement {
library( "wildFlyTxnClient", "org.wildfly.transaction", "wildfly-transaction-client-jakarta" ).versionRef( wildFlyTxnClientVersion ) library( "wildFlyTxnClient", "org.wildfly.transaction", "wildfly-transaction-client-jakarta" ).versionRef( wildFlyTxnClientVersion )
library( "weld", "org.jboss.weld.se", "weld-se-shaded" ).versionRef( weldVersion ) library( "weld", "org.jboss.weld.se", "weld-se-shaded" ).versionRef( weldVersion )
library( "jfrUnit", "org.moditect.jfrunit", "jfrunit-core" ).versionRef( jfrUnitVersion )
} }
dbLibs { dbLibs {
def h2Version = version "h2", overrideableVersion( "gradle.libs.versions.h2", "2.2.224" ) def h2Version = version "h2", overrideableVersion( "gradle.libs.versions.h2", "2.2.224" )