-
-
Notifications
You must be signed in to change notification settings - Fork 472
Expand file tree
/
Copy pathSQLiteSpanInstrumentation.kt
More file actions
85 lines (71 loc) · 2.79 KB
/
Copy pathSQLiteSpanInstrumentation.kt
File metadata and controls
85 lines (71 loc) · 2.79 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
80
81
82
83
84
85
package io.sentry.sqlite
import io.sentry.IScopes
import io.sentry.Instrumenter
import io.sentry.ScopesAdapter
import io.sentry.SentryDate
import io.sentry.SentryLongDate
import io.sentry.SentryStackTraceFactory
import io.sentry.SpanDataConvention
import io.sentry.SpanStatus
private const val SQLITE_TRACE_ORIGIN = "auto.db.sqlite"
/** Shared span creation and metadata for SQLite instrumentation. */
internal class SQLiteSpanInstrumentation(
private val scopes: IScopes,
private val dbMetadata: DbMetadata,
) {
private val stackTraceFactory = SentryStackTraceFactory(scopes.options)
/**
* Returns a start timestamp for a `db.sql.query` span.
*
* Exposed so callers can capture a wall-clock start before accumulating database time.
* Internalizing the start time in [recordSpan] would shift spans to end-of-work on the trace
* timeline, which is less desirable.
*/
fun startTimestamp(): SentryDate = scopes.options.dateProvider.now()
/** Records a `db.sql.query` span from [startTimestamp] to the moment of invocation. */
fun recordSpan(
sql: String,
startTimestamp: SentryDate,
status: SpanStatus,
throwable: Throwable? = null,
) {
recordSpan(sql, startTimestamp, endTimestamp = null, status, throwable)
}
/** Records a `db.sql.query` span from [startTimestamp] to [startTimestamp] + [durationNanos]. */
fun recordSpan(
sql: String,
startTimestamp: SentryDate,
durationNanos: Long,
status: SpanStatus,
throwable: Throwable? = null,
) {
val endTimestamp = SentryLongDate(startTimestamp.nanoTimestamp() + durationNanos)
recordSpan(sql, startTimestamp, endTimestamp, status, throwable)
}
private fun recordSpan(
sql: String,
startTimestamp: SentryDate,
endTimestamp: SentryDate?,
status: SpanStatus,
throwable: Throwable?,
) {
scopes.span?.startChild("db.sql.query", sql, startTimestamp, Instrumenter.SENTRY)?.apply {
spanContext.origin = SQLITE_TRACE_ORIGIN
throwable?.let { this.throwable = it }
val isMainThread = scopes.options.threadChecker.isMainThread
setData(SpanDataConvention.BLOCKED_MAIN_THREAD_KEY, isMainThread)
if (isMainThread) {
setData(SpanDataConvention.CALL_STACK_KEY, stackTraceFactory.inAppCallStack)
}
dbMetadata.name?.let { setData(SpanDataConvention.DB_NAME_KEY, it) }
setData(SpanDataConvention.DB_SYSTEM_KEY, dbMetadata.system)
finish(status, endTimestamp)
}
}
companion object {
fun fromDatabaseName(databaseName: String?, scopes: IScopes = ScopesAdapter.getInstance()) =
SQLiteSpanInstrumentation(scopes, dbMetadataFromDatabaseName(databaseName))
fun fromFileName(fileName: String, scopes: IScopes = ScopesAdapter.getInstance()) =
SQLiteSpanInstrumentation(scopes, dbMetadataFromFileName(fileName))
}
}