-
-
Notifications
You must be signed in to change notification settings - Fork 472
Expand file tree
/
Copy pathSentrySQLiteStatement.kt
More file actions
79 lines (69 loc) · 2.28 KB
/
Copy pathSentrySQLiteStatement.kt
File metadata and controls
79 lines (69 loc) · 2.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package io.sentry.sqlite
import androidx.sqlite.SQLiteStatement
import io.sentry.SpanStatus
/**
* Wraps a [SQLiteStatement] and records a single Sentry span covering all [step] calls for the
* statement's lifetime (until [step] iteration is complete or the statement is [reset] or
* [closed][close]).
*
* Span duration is restricted to accumulated database time, i.e., each [step] call is individually
* timed and the durations are summed. Time the application spends between steps (e.g., processing
* rows, sleeping, or doing I/O) is intentionally excluded.
*
* Not thread-safe: assumes sequential access within each SQL statement (normal SQLite usage).
*/
internal class SentrySQLiteStatement(
private val delegate: SQLiteStatement,
private val spans: DriverSpans,
private val sql: String,
private val nanoTimeProvider: () -> Long = { System.nanoTime() },
) : SQLiteStatement by delegate {
private var firstStepTimestampNanos: Long? = null
private var accumulatedDbNanos: Long = 0L
private var stepsComplete = false
private var closed = false
@Suppress("TooGenericExceptionCaught")
override fun step(): Boolean {
if (stepsComplete || closed) {
return delegate.step()
}
val beforeNanos = nanoTimeProvider()
return try {
if (firstStepTimestampNanos == null) {
firstStepTimestampNanos = spans.startTimestamp()
}
stepsComplete = !delegate.step()
accumulatedDbNanos += nanoTimeProvider() - beforeNanos
if (stepsComplete) {
recordSpan(SpanStatus.OK)
}
!stepsComplete
} catch (e: Throwable) {
accumulatedDbNanos += nanoTimeProvider() - beforeNanos
recordSpan(SpanStatus.INTERNAL_ERROR, e)
throw e
}
}
override fun reset() {
if (closed) {
return delegate.reset()
}
try {
recordSpan(SpanStatus.OK)
} finally {
delegate.reset()
stepsComplete = false
}
}
override fun close() {
closed = true
delegate.use { recordSpan(SpanStatus.OK) }
}
private fun recordSpan(status: SpanStatus, throwable: Throwable? = null) {
val startNanos = firstStepTimestampNanos ?: return
val duration = accumulatedDbNanos
firstStepTimestampNanos = null
accumulatedDbNanos = 0L
spans.record(sql, startNanos, duration, status, throwable)
}
}