getsentry / sentry-kotlin-multiplatform

Sentry SDK for Kotlin Multiplatform
MIT License
134 stars 19 forks source link

Breadcrumbs Don't Seem to Work Right on iOS #99

Closed alexwhb closed 1 year ago

alexwhb commented 1 year ago

Environment

iOS

0.2.0 for the shared kmm code and 8.4.0 for the iOS library using SPM

Steps to Reproduce

I wrote a custom log writer that adds bread crumbs to my sentry log every time something is globally logged in my app. This works great on Android and will add all the breadcrumbs to my error / crash log, but on iOS the only way I can seem to get a breadcrumb to log with my error / exception is to write it in the capture exception scope like this:

Sentry.captureException(throwable) {
    it.addBreadcrumb(Breadcrumb.debug("TEST"))
}

Expected Result

Expected that the last 100 breadcrumb before the exception will be reported since 100 is the default config value. Obviously assuming I logged that many things before the error / exception was logged.

Actual Result

I only see my "TEST" breadcrumb because that one is recorded in the scope. Again this is only a weird behavior on iOS. It works fine on Android.

Here's my logger code that is written in my common kotlin module and works fine for Android, but not for iOS:

class SentryLogWriter(
    private val minSeverity: Severity,
    private val minCrashSeverity: Severity,
) : LogWriter() {
    init {
        check(minSeverity <= minCrashSeverity) {
            "minSeverity ($minSeverity) cannot be greater than minCrashSeverity ($minCrashSeverity)"
        }
    }

    override fun isLoggable(severity: Severity): Boolean = severity >= minSeverity

    override fun log(severity: Severity, message: String, tag: String, throwable: Throwable?) {
        if (throwable == null) {
            Sentry.addBreadcrumb(
                Breadcrumb(
                    severity.toSentryLevel(),
                    message = message,
                    category = tag
                )
            )
        }
        if (throwable != null && severity >= minCrashSeverity) {
            Sentry.captureException(throwable) {
                it.addBreadcrumb(Breadcrumb.debug("TEST this is a Test"))
            }
        }
    }
}

fun Severity.toSentryLevel(): SentryLevel {
    return when (this) {
        Severity.Debug -> SentryLevel.DEBUG
        Severity.Info -> SentryLevel.INFO
        Severity.Warn -> SentryLevel.WARNING
        Severity.Error -> SentryLevel.ERROR
        Severity.Assert -> SentryLevel.FATAL
        else -> throw IllegalArgumentException("Unsupported severity level")
    }
}

Any advice would be greatly appreciated. I spent the better part of a day playing with this and couldn't get it working right. But I'm super excited this KMM library exists now.

romtsn commented 1 year ago

hey thanks for trying out the SDK and reporting the issue. We'll look into this soon.

Just to confirm - when you add a breadcrumb to the scope like this:

Sentry.captureException(throwable) {
    it.addBreadcrumb(Breadcrumb.debug("TEST"))
}

it works, but when you just call Sentry.addBreadcrumb it doesn't on iOS?

alexwhb commented 1 year ago

Hey thanks for the quick reply. Yes that's 100% correct. Everything else seems fine. Also thanks for building this KMM library out. I'm really excited to use it.

buenaflor commented 1 year ago

@alexwhb hi! does it not work 100% of the time on your end? Unfortunately, I have troubles reproducing it with your code sample as it seems to be logging fine during my testing. Do you have another code sample where it doesn't work?

alexwhb commented 1 year ago

@buenaflor correct. As long as I'm logging breadcrumbs in the global scope it doesn't work at all on iOS. I won't have time today or tomorrow, but likely Wednesday I can create a sample project to reproduce it.

alexwhb commented 1 year ago

@buenaflor @romtsn Here's a sample project where I demo the implementation I'm playing with and how breadcurmbs don't work on the iOS side. You'll need to update the dsn with your own in Utils.kt. Let me know if you have any questions about the project, and note that I didn't write and Android implementation really, since the Android side has worked fine for me.

Note that I'm doing a debug log before the crash code is called, which should set a breadcrumb, and does on Android but not here. These are the methods that crash the app and should be logging the breadcrumb:



    public fun logError() {
        Logger.d("Tag") { "This should be a breadcumb" }

        try {
            throw Exception("I'm a crash")
        } catch (e: Throwable) {
            Logger.e(e) { "some message" }
        }
    }

    public fun crash() {
        Logger.d("Tag") { "This should be a breadcumb" }
        throw Exception("I'm a crash")
    }
buenaflor commented 1 year ago

@alexwhb Thanks for the time Alex, I've figured out why this is happening. The iOS beforeBreadcrumb hook will discard breadcrumbs if it is not explicitly set up.

Meanwhile you can add this to your Sentry.init while we work on a quick fix:

it.beforeBreadcrumb = { breadcrumb ->
  breadcrumb
}
alexwhb commented 1 year ago

@buenaflor this is great!! Thank you so much! I appreciate your time looking into this.