44import static io .sentry .SpanDataConvention .DB_SYSTEM_KEY ;
55
66import com .jakewharton .nopen .annotation .Open ;
7+ import com .p6spy .engine .common .ConnectionInformation ;
78import com .p6spy .engine .common .StatementInformation ;
89import com .p6spy .engine .event .SimpleJdbcEventListener ;
910import io .sentry .IScopes ;
1011import io .sentry .ISentryLifecycleToken ;
1112import io .sentry .ISpan ;
1213import io .sentry .ScopesAdapter ;
1314import io .sentry .SentryIntegrationPackageStorage ;
14- import io .sentry .Span ;
1515import io .sentry .SpanOptions ;
1616import io .sentry .SpanStatus ;
1717import io .sentry .util .AutoClosableReentrantLock ;
2020import org .jetbrains .annotations .NotNull ;
2121import org .jetbrains .annotations .Nullable ;
2222
23- /** P6Spy JDBC event listener that creates {@link Span}s around database queries. */
2423@ Open
2524public class SentryJdbcEventListener extends SimpleJdbcEventListener {
2625 private static final String TRACE_ORIGIN = "auto.db.jdbc" ;
2726 private final @ NotNull IScopes scopes ;
28- private static final @ NotNull ThreadLocal <ISpan > CURRENT_SPAN = new ThreadLocal <>();
27+ private static final @ NotNull ThreadLocal <ISpan > CURRENT_QUERY_SPAN = new ThreadLocal <>();
28+ private static final @ NotNull ThreadLocal <ISpan > CURRENT_TRANSACTION_SPAN = new ThreadLocal <>();
2929
3030 private volatile @ Nullable DatabaseUtils .DatabaseDetails cachedDatabaseDetails = null ;
3131 protected final @ NotNull AutoClosableReentrantLock databaseDetailsLock =
@@ -47,24 +47,109 @@ public SentryJdbcEventListener() {
4747
4848 @ Override
4949 public void onBeforeAnyExecute (final @ NotNull StatementInformation statementInformation ) {
50- final ISpan parent = scopes .getSpan ();
51- if (parent != null && !parent .isNoOp ()) {
52- final @ NotNull SpanOptions spanOptions = new SpanOptions ();
53- spanOptions .setOrigin (TRACE_ORIGIN );
54- final ISpan span = parent .startChild ("db.query" , statementInformation .getSql (), spanOptions );
55- CURRENT_SPAN .set (span );
56- }
50+ startSpan (CURRENT_QUERY_SPAN , "db.query" , statementInformation .getSql ());
5751 }
5852
5953 @ Override
6054 public void onAfterAnyExecute (
6155 final @ NotNull StatementInformation statementInformation ,
6256 long timeElapsedNanos ,
6357 final @ Nullable SQLException e ) {
64- final ISpan span = CURRENT_SPAN .get ();
58+ finishSpan (CURRENT_QUERY_SPAN , statementInformation .getConnectionInformation (), e );
59+ }
60+
61+ @ Override
62+ public void onBeforeSetAutoCommit (
63+ final @ NotNull ConnectionInformation connectionInformation ,
64+ boolean newAutoCommit ,
65+ boolean currentAutoCommit ) {
66+ if (!isDatabaseTransactionTracingEnabled ()) {
67+ return ;
68+ }
69+ final boolean isSwitchingToManualCommit = !newAutoCommit && currentAutoCommit ;
70+ if (isSwitchingToManualCommit ) {
71+ startSpan (CURRENT_TRANSACTION_SPAN , "db.sql.transaction.begin" , "BEGIN" );
72+ }
73+ }
74+
75+ @ Override
76+ public void onAfterSetAutoCommit (
77+ final @ NotNull ConnectionInformation connectionInformation ,
78+ final boolean newAutoCommit ,
79+ final boolean oldAutoCommit ,
80+ final @ Nullable SQLException e ) {
81+ if (!isDatabaseTransactionTracingEnabled ()) {
82+ return ;
83+ }
84+ final boolean isSwitchingToManualCommit = !newAutoCommit && oldAutoCommit ;
85+ if (isSwitchingToManualCommit ) {
86+ finishSpan (CURRENT_TRANSACTION_SPAN , connectionInformation , e );
87+ }
88+ }
89+
90+ @ Override
91+ public void onBeforeCommit (final @ NotNull ConnectionInformation connectionInformation ) {
92+ if (!isDatabaseTransactionTracingEnabled ()) {
93+ return ;
94+ }
95+ startSpan (CURRENT_TRANSACTION_SPAN , "db.sql.transaction.commit" , "COMMIT" );
96+ }
97+
98+ @ Override
99+ public void onAfterCommit (
100+ final @ NotNull ConnectionInformation connectionInformation ,
101+ final long timeElapsedNanos ,
102+ final @ Nullable SQLException e ) {
103+ if (!isDatabaseTransactionTracingEnabled ()) {
104+ return ;
105+ }
106+ finishSpan (CURRENT_TRANSACTION_SPAN , connectionInformation , e );
107+ }
108+
109+ @ Override
110+ public void onBeforeRollback (final @ NotNull ConnectionInformation connectionInformation ) {
111+ if (!isDatabaseTransactionTracingEnabled ()) {
112+ return ;
113+ }
114+ startSpan (CURRENT_TRANSACTION_SPAN , "db.sql.transaction.rollback" , "ROLLBACK" );
115+ }
116+
117+ @ Override
118+ public void onAfterRollback (
119+ final @ NotNull ConnectionInformation connectionInformation ,
120+ final long timeElapsedNanos ,
121+ final @ Nullable SQLException e ) {
122+ if (!isDatabaseTransactionTracingEnabled ()) {
123+ return ;
124+ }
125+ finishSpan (CURRENT_TRANSACTION_SPAN , connectionInformation , e );
126+ }
127+
128+ private boolean isDatabaseTransactionTracingEnabled () {
129+ return scopes .getOptions ().isEnableDatabaseTransactionTracing ();
130+ }
131+
132+ private void startSpan (
133+ final @ NotNull ThreadLocal <ISpan > spanHolder ,
134+ final @ NotNull String operation ,
135+ final @ Nullable String description ) {
136+ final @ Nullable ISpan parent = scopes .getSpan ();
137+ if (parent != null && !parent .isNoOp ()) {
138+ final @ NotNull SpanOptions spanOptions = new SpanOptions ();
139+ spanOptions .setOrigin (TRACE_ORIGIN );
140+ final @ NotNull ISpan span = parent .startChild (operation , description , spanOptions );
141+ spanHolder .set (span );
142+ }
143+ }
144+
145+ private void finishSpan (
146+ final @ NotNull ThreadLocal <ISpan > spanHolder ,
147+ final @ Nullable ConnectionInformation connectionInformation ,
148+ final @ Nullable SQLException e ) {
149+ final @ Nullable ISpan span = spanHolder .get ();
65150
66151 if (span != null ) {
67- applyDatabaseDetailsToSpan (statementInformation , span );
152+ applyDatabaseDetailsToSpan (connectionInformation , span );
68153
69154 if (e != null ) {
70155 span .setThrowable (e );
@@ -73,7 +158,7 @@ public void onAfterAnyExecute(
73158 span .setStatus (SpanStatus .OK );
74159 }
75160 span .finish ();
76- CURRENT_SPAN . set ( null );
161+ spanHolder . remove ( );
77162 }
78163 }
79164
@@ -82,9 +167,9 @@ private void addPackageAndIntegrationInfo() {
82167 }
83168
84169 private void applyDatabaseDetailsToSpan (
85- final @ NotNull StatementInformation statementInformation , final @ NotNull ISpan span ) {
170+ final @ Nullable ConnectionInformation connectionInformation , final @ NotNull ISpan span ) {
86171 final @ NotNull DatabaseUtils .DatabaseDetails databaseDetails =
87- getOrComputeDatabaseDetails (statementInformation );
172+ getOrComputeDatabaseDetails (connectionInformation );
88173
89174 if (databaseDetails .getDbSystem () != null ) {
90175 span .setData (DB_SYSTEM_KEY , databaseDetails .getDbSystem ());
@@ -96,11 +181,11 @@ private void applyDatabaseDetailsToSpan(
96181 }
97182
98183 private @ NotNull DatabaseUtils .DatabaseDetails getOrComputeDatabaseDetails (
99- final @ NotNull StatementInformation statementInformation ) {
184+ final @ Nullable ConnectionInformation connectionInformation ) {
100185 if (cachedDatabaseDetails == null ) {
101186 try (final @ NotNull ISentryLifecycleToken ignored = databaseDetailsLock .acquire ()) {
102187 if (cachedDatabaseDetails == null ) {
103- cachedDatabaseDetails = DatabaseUtils .readFrom (statementInformation );
188+ cachedDatabaseDetails = DatabaseUtils .readFrom (connectionInformation );
104189 }
105190 }
106191 }
0 commit comments