Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import io.sentry.SpanStatus

private const val TRACE_ORIGIN = "auto.db.sqlite"

internal class SQLiteSpanManager(
/** Span instrumentation for [SentrySupportSQLiteOpenHelper]. */
internal class OpenHelperSpans(
private val scopes: IScopes = ScopesAdapter.getInstance(),
private val databaseName: String? = null,
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import android.database.CursorWindow
*/
internal class SentryCrossProcessCursor(
private val delegate: CrossProcessCursor,
private val spanManager: SQLiteSpanManager,
private val spans: OpenHelperSpans,
private val sql: String,
) : CrossProcessCursor by delegate {
// We have to start the span only the first time, regardless of how many times its methods get
Expand All @@ -25,22 +25,22 @@ internal class SentryCrossProcessCursor(
return delegate.count
}
isSpanStarted = true
return spanManager.performSql(sql) { delegate.count }
return spans.performSql(sql) { delegate.count }
}

override fun onMove(oldPosition: Int, newPosition: Int): Boolean {
if (isSpanStarted) {
return delegate.onMove(oldPosition, newPosition)
}
isSpanStarted = true
return spanManager.performSql(sql) { delegate.onMove(oldPosition, newPosition) }
return spans.performSql(sql) { delegate.onMove(oldPosition, newPosition) }
}

override fun fillWindow(position: Int, window: CursorWindow?) {
if (isSpanStarted) {
return delegate.fillWindow(position, window)
}
isSpanStarted = true
return spanManager.performSql(sql) { delegate.fillWindow(position, window) }
return spans.performSql(sql) { delegate.fillWindow(position, window) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ import androidx.sqlite.db.SupportSQLiteStatement
* and it's created automatically by the [SentrySupportSQLiteOpenHelper].
*
* @param delegate The [SupportSQLiteDatabase] instance to delegate calls to.
* @param sqLiteSpanManager The [SQLiteSpanManager] responsible for the creation of the spans.
* @param spans The [OpenHelperSpans] manager responsible for the creation of the spans.
*/
internal class SentrySupportSQLiteDatabase(
private val delegate: SupportSQLiteDatabase,
private val sqLiteSpanManager: SQLiteSpanManager,
private val spans: OpenHelperSpans,
) : SupportSQLiteDatabase by delegate {
/**
* Compiles the given SQL statement. It will return Sentry's wrapper around
Expand All @@ -28,35 +28,34 @@ internal class SentrySupportSQLiteDatabase(
* @return Compiled statement.
*/
override fun compileStatement(sql: String): SupportSQLiteStatement =
SentrySupportSQLiteStatement(delegate.compileStatement(sql), sqLiteSpanManager, sql)
SentrySupportSQLiteStatement(delegate.compileStatement(sql), spans, sql)

@Suppress("AcronymName") // To keep consistency with framework method name.
override fun execPerConnectionSQL(
sql: String,
@SuppressLint("ArrayReturn") bindArgs: Array<out Any?>?,
) {
sqLiteSpanManager.performSql(sql) { delegate.execPerConnectionSQL(sql, bindArgs) }
spans.performSql(sql) { delegate.execPerConnectionSQL(sql, bindArgs) }
}

override fun query(query: String): Cursor =
sqLiteSpanManager.performSql(query) { delegate.query(query) }
override fun query(query: String): Cursor = spans.performSql(query) { delegate.query(query) }

override fun query(query: String, bindArgs: Array<out Any?>): Cursor =
sqLiteSpanManager.performSql(query) { delegate.query(query, bindArgs) }
spans.performSql(query) { delegate.query(query, bindArgs) }

override fun query(query: SupportSQLiteQuery): Cursor =
sqLiteSpanManager.performSql(query.sql) { delegate.query(query) }
spans.performSql(query.sql) { delegate.query(query) }

override fun query(query: SupportSQLiteQuery, cancellationSignal: CancellationSignal?): Cursor =
sqLiteSpanManager.performSql(query.sql) { delegate.query(query, cancellationSignal) }
spans.performSql(query.sql) { delegate.query(query, cancellationSignal) }

@Throws(SQLException::class)
override fun execSQL(sql: String) {
sqLiteSpanManager.performSql(sql) { delegate.execSQL(sql) }
spans.performSql(sql) { delegate.execSQL(sql) }
}

@Throws(SQLException::class)
override fun execSQL(sql: String, bindArgs: Array<out Any?>) {
sqLiteSpanManager.performSql(sql) { delegate.execSQL(sql, bindArgs) }
spans.performSql(sql) { delegate.execSQL(sql, bindArgs) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ import androidx.sqlite.db.SupportSQLiteOpenHelper
public class SentrySupportSQLiteOpenHelper
private constructor(private val delegate: SupportSQLiteOpenHelper) :
SupportSQLiteOpenHelper by delegate {
private val sqLiteSpanManager = SQLiteSpanManager(databaseName = delegate.databaseName)
private val spans = OpenHelperSpans(databaseName = delegate.databaseName)

private val sentryWritableDatabase: SupportSQLiteDatabase by lazy {
SentrySupportSQLiteDatabase(delegate.writableDatabase, sqLiteSpanManager)
SentrySupportSQLiteDatabase(delegate.writableDatabase, spans)
}

private val sentryReadableDatabase: SupportSQLiteDatabase by lazy {
SentrySupportSQLiteDatabase(delegate.readableDatabase, sqLiteSpanManager)
SentrySupportSQLiteDatabase(delegate.readableDatabase, spans)
}

override val writableDatabase: SupportSQLiteDatabase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,22 @@ import androidx.sqlite.db.SupportSQLiteStatement
* [SentrySupportSQLiteDatabase.compileStatement].
*
* @param delegate The [SupportSQLiteStatement] instance to delegate calls to.
* @param sqLiteSpanManager The [SQLiteSpanManager] responsible for the creation of the spans.
* @param spans The [OpenHelperSpans] manager responsible for the creation of the spans.
* @param sql The query string.
*/
internal class SentrySupportSQLiteStatement(
private val delegate: SupportSQLiteStatement,
private val sqLiteSpanManager: SQLiteSpanManager,
private val spans: OpenHelperSpans,
private val sql: String,
) : SupportSQLiteStatement by delegate {
override fun execute() = sqLiteSpanManager.performSql(sql) { delegate.execute() }
override fun execute() = spans.performSql(sql) { delegate.execute() }

override fun executeUpdateDelete(): Int =
sqLiteSpanManager.performSql(sql) { delegate.executeUpdateDelete() }
override fun executeUpdateDelete(): Int = spans.performSql(sql) { delegate.executeUpdateDelete() }

override fun executeInsert(): Long =
sqLiteSpanManager.performSql(sql) { delegate.executeInsert() }
override fun executeInsert(): Long = spans.performSql(sql) { delegate.executeInsert() }

override fun simpleQueryForLong(): Long =
sqLiteSpanManager.performSql(sql) { delegate.simpleQueryForLong() }
override fun simpleQueryForLong(): Long = spans.performSql(sql) { delegate.simpleQueryForLong() }

override fun simpleQueryForString(): String? =
sqLiteSpanManager.performSql(sql) { delegate.simpleQueryForString() }
spans.performSql(sql) { delegate.simpleQueryForString() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,17 @@ private const val SQLITE_TRACE_ORIGIN = "auto.db.sqlite"
private val EMPTY_NANO_TIME = SentryNanotimeDate(Date(0), 0L)

/** Span instrumentation for [SentrySQLiteDriver]. */
internal class SQLiteSpanInstrumentation(
private val scopes: IScopes,
private val dbMetadata: DbMetadata,
) {
internal class DriverSpans(private val scopes: IScopes, private val dbMetadata: DbMetadata) {

private val stackTraceFactory = SentryStackTraceFactory(scopes.options)

/**
* Returns a timestamp in nanoseconds for use with [recordSpan]. Timestamp is ns-precise if the
* active parent span uses a [SentryNanotimeDate] (the ordinary case); otherwise it's ms-precise.
* Returns a timestamp in nanoseconds for use with [record]. Timestamp is ns-precise if the active
* parent span uses a [SentryNanotimeDate] (the ordinary case); otherwise it's ms-precise.
*
* Note: Internalizing the start time in [recordSpan] would shift spans to end-of-work on the
* trace timeline, which is less desirable; callers capture the start before doing database work
* and pass it back to [recordSpan].
* Note: Internalizing the start time in [record] would shift spans to end-of-work on the trace
* timeline, which is less desirable; callers capture the start before doing database work and
* pass it back to [record].
*/
fun startTimestamp(): Long =
// Try to retain nanosecond precision + avoid SentryDate allocation...
Expand All @@ -43,7 +40,7 @@ internal class SQLiteSpanInstrumentation(
?: scopes.options.dateProvider.now().nanoTimestamp()

/** Records a `db.sql.query` span. */
fun recordSpan(
fun record(
sql: String,
startTimestampNanos: Long,
durationNanos: Long,
Expand Down Expand Up @@ -74,14 +71,11 @@ internal class SQLiteSpanInstrumentation(
companion object {

/**
* Returns [SQLiteSpanInstrumentation] based on the [fileName] argument passed to
* Returns [DriverSpans] based on the [fileName] argument passed to
* [SQLiteDriver.open][androidx.sqlite.SQLiteDriver.open].
*/
fun fromFileName(
fileName: String,
scopes: IScopes = ScopesAdapter.getInstance(),
): SQLiteSpanInstrumentation =
SQLiteSpanInstrumentation(scopes, dbMetadataFromFileName(fileName))
fun fromFileName(fileName: String, scopes: IScopes = ScopesAdapter.getInstance()): DriverSpans =
DriverSpans(scopes, dbMetadataFromFileName(fileName))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import androidx.sqlite.SQLiteStatement

internal class SentrySQLiteConnection(
private val delegate: SQLiteConnection,
private val spans: SQLiteSpanInstrumentation,
private val spans: DriverSpans,
) : SQLiteConnection by delegate {

override fun prepare(sql: String): SQLiteStatement {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ internal class SentrySQLiteDriver private constructor(private val delegate: SQLi
val connection = delegate.open(fileName)

return try {
val spans = SQLiteSpanInstrumentation.fromFileName(fileName)
val spans = DriverSpans.fromFileName(fileName)
// create() ensures delegate is unwrapped, so we don't need to protect against double-wrapping
// the connection.
SentrySQLiteConnection(connection, spans)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import io.sentry.SpanStatus
*/
internal class SentrySQLiteStatement(
private val delegate: SQLiteStatement,
private val spans: SQLiteSpanInstrumentation,
private val spans: DriverSpans,
private val sql: String,
private val nanoTimeProvider: () -> Long = { System.nanoTime() },
) : SQLiteStatement by delegate {
Expand Down Expand Up @@ -74,6 +74,6 @@ internal class SentrySQLiteStatement(
val duration = accumulatedDbNanos
firstStepTimestampNanos = null
accumulatedDbNanos = 0L
spans.recordSpan(sql, startNanos, duration, status, throwable)
spans.record(sql, startNanos, duration, status, throwable)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,21 @@ import org.junit.Before
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever

class SQLiteSpanManagerTest {
class OpenHelperSpansTest {
private class Fixture {
private val scopes = mock<IScopes>()
lateinit var sentryTracer: SentryTracer
lateinit var options: SentryOptions

fun getSut(isSpanActive: Boolean = true, databaseName: String? = null): SQLiteSpanManager {
fun getSut(isSpanActive: Boolean = true, databaseName: String? = null): OpenHelperSpans {
options = SentryOptions().apply { dsn = "https://key@sentry.io/proj" }
whenever(scopes.options).thenReturn(options)
sentryTracer = SentryTracer(TransactionContext("name", "op"), scopes)

if (isSpanActive) {
whenever(scopes.span).thenReturn(sentryTracer)
}
return SQLiteSpanManager(scopes, databaseName)
return OpenHelperSpans(scopes, databaseName)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import org.mockito.kotlin.whenever
class SentryCrossProcessCursorTest {
private class Fixture {
private val scopes = mock<IScopes>()
private val spanManager = SQLiteSpanManager(scopes)
private val spans = OpenHelperSpans(scopes)
val mockCursor = mock<CrossProcessCursor>()
lateinit var options: SentryOptions
lateinit var sentryTracer: SentryTracer
Expand All @@ -33,7 +33,7 @@ class SentryCrossProcessCursorTest {
if (isSpanActive) {
whenever(scopes.span).thenReturn(sentryTracer)
}
return SentryCrossProcessCursor(mockCursor, spanManager, sql)
return SentryCrossProcessCursor(mockCursor, spans, sql)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import org.mockito.kotlin.whenever
class SentrySupportSQLiteDatabaseTest {
private class Fixture {
private val scopes = mock<IScopes>()
private val spanManager = SQLiteSpanManager(scopes)
private val spans = OpenHelperSpans(scopes)
val mockDatabase = mock<SupportSQLiteDatabase>()
lateinit var sentryTracer: SentryTracer
lateinit var options: SentryOptions
Expand All @@ -41,7 +41,7 @@ class SentrySupportSQLiteDatabaseTest {
whenever(scopes.span).thenReturn(sentryTracer)
}

return SentrySupportSQLiteDatabase(mockDatabase, spanManager)
return SentrySupportSQLiteDatabase(mockDatabase, spans)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import org.mockito.kotlin.whenever
class SentrySupportSQLiteStatementTest {
private class Fixture {
private val scopes = mock<IScopes>()
private val spanManager = SQLiteSpanManager(scopes)
private val spans = OpenHelperSpans(scopes)
val mockStatement = mock<SupportSQLiteStatement>()
lateinit var sentryTracer: SentryTracer
lateinit var options: SentryOptions
Expand All @@ -31,7 +31,7 @@ class SentrySupportSQLiteStatementTest {
if (isSpanActive) {
whenever(scopes.span).thenReturn(sentryTracer)
}
return SentrySupportSQLiteStatement(mockStatement, spanManager, sql)
return SentrySupportSQLiteStatement(mockStatement, spans, sql)
}
}

Expand Down
Loading
Loading