sentry-java
sentry-java copied to clipboard
JDBC transactions not logged in queries
Integration
sentry-jdbc
Java Version
18
Version
7.10.0
Steps to Reproduce
I use Ktor for a API and am looking into a tool that can help monitor performance. I saw that Sentry supports JDBC queries, and that is something I am looking for.
I added to my build.gradle.kts:
id("io.sentry.jvm.gradle") version "4.7.1"
implementation("io.sentry:sentry-jdbc:7.10.0")
implementation("p6spy:p6spy:3.9.1")
sentry {
includeSourceContext = false
org = "foo"
projectName = "bar"
authToken = System.getenv("SENTRY_AUTH_TOKEN")
tracingInstrumentation {
enabled = true
}
autoInstallation {
enabled = true
}
}
My DB setup logic:
val db = Database.connect(P6DataSource(MysqlDataSource().apply {
setURL("jdbc:mysql://$dbHost/$dbName?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&rewriteBatchedInserts=true&rewriteBatchedStatements=true&batchSize=5000")
user = dbUser
password = dbPass
}))
Sentry init:
Sentry.init { options ->
options.dsn = "foo"
options.tracesSampleRate = 1.0
options.isDebug = true
options.enableTracing = true
options.isEnableMetrics = true
}
I then instrumented one of the endpoints by wrapping the logic:
val transaction = Sentry.startTransaction(name, operation)
try {
action()
} catch (e: Exception) {
transaction.throwable = e
transaction.status = SpanStatus.INTERNAL_ERROR
throw e
} finally {
transaction.finish()
}
Expected Result
I expect that Queries section of Sentry is now being filled, but I only see data in Traces.
In the logging I don't see anything related to JDBC. In the docs I don't see anything else that I would need to setup.
I am on the developer plan, but from what I see the queries section should be available until half July or so. Or am I already required to have a business plan?
Actual Result
I only see data in Traces, not in Queries and also not in Requests.
I do see the transactions logged in spy.log, so p6spy is working.
Sentry logging after a call happens:
DEBUG: Capturing transaction: ad39f934a059455e8a72d822ae3605c3
DEBUG: Serializing object: {
"transaction": "foo",
"start_timestamp": 1718554044.114437,
"timestamp": 1718554044.445066,
"type": "transaction",
"transaction_info": {
"source": "custom"
},
"event_id": "ad39f934a059455e8a72d822ae3605c3",
"contexts": {
"runtime": {
"name": "Amazon.com Inc.",
"version": "18.0.2"
},
"trace": {
"trace_id": "b3de03059f8648acbc33f36138d887b8",
"span_id": "dd688cd36b64435e",
"op": "request",
"origin": "manual"
}
},
"sdk": {
"name": "sentry.java",
"version": "7.10.0",
"packages": [
{
"name": "maven:io.sentry:sentry",
"version": "7.10.0"
},
{
"name": "maven:io.sentry:sentry-jdbc",
"version": "7.10.0"
}
],
"integrations": [
"UncaughtExceptionHandler",
"ShutdownHook",
"JDBC"
]
},
"environment": "production",
"platform": "java",
"user": {
"ip_address": "{{auto}}"
},
"server_name": "localhost"
}```
Hello @peterdk, can you confirm io.sentry.jdbc.SentryJdbcEventListener is actually being invoked in your setup? If so, does it find a valid transaction/span to create a child under?
@adinauer I can check, but how would I do that? I don't know if you can set breakpoints on library code? I'll try.
@Override
public void onBeforeAnyExecute(final @NotNull StatementInformation statementInformation) {
final ISpan parent = hub.getSpan();
if (parent != null && !parent.isNoOp()) {
final ISpan span = parent.startChild("db.query", statementInformation.getSql());
CURRENT_SPAN.set(span);
span.getSpanContext().setOrigin(TRACE_ORIGIN);
}
}
parent seems to be null, the breakpoint on span never triggers after the parent breakpoint.
I do use Kotlin and ktor, so it's inside a coroutine. Already tried wrapping the main trace fun content with
withContext(SentryContext()) {`
and also the DB call parent functions all as suspend, but no changes.
Also only wrapping non suspend functions part (including the DB calls) with a Transaction doesn't do anything.
Am I doing something wrong the the trace wrapping logic? span is empty, right after transaction start
val transaction = Sentry.startTransaction(name, operation)
try {
val hub = Sentry.getCurrentHub() //exists
val span = hub.span //null
doSomething()
I would expect that span would not be null?
Can you please take a look at https://docs.sentry.io/platforms/java/tracing/instrumentation/custom-instrumentation/#create-transaction-bound-to-the-current-scope and see if that helps?
Sorry, I guess this isn't too intuitive.
@adinauer I was just looking into that indeed. The span is not empty now! And indeed the JDBC breakpoint triggers and I do get query data now in Sentry! Great.
Maybe improve the docs a bit?
We'll discuss whether it makes sense to have separate methods in the future that make this more clear. We're currently changing lots of things in the SDK for v8 and this is one of the things on the list.
Created https://github.com/getsentry/sentry-java/issues/3760 to track docs improvements. Currently there's no plan to add separate methods but a new performance API is in the works.