From b2d7026d519c0e41a35ccfdef8a2137af175ae5f Mon Sep 17 00:00:00 2001 From: Dmitry Murzin Date: Thu, 18 Nov 2021 16:57:11 +0300 Subject: [PATCH] Use Exception Analyzer for error reporting --- .../rainbow/IrExceptionAnalyzerReporter.kt | 8 ++ .../indent/rainbow/IrSentryErrorReporter.kt | 116 ------------------ src/main/resources/META-INF/plugin.xml | 2 +- 3 files changed, 9 insertions(+), 117 deletions(-) create mode 100644 src/main/kotlin/indent/rainbow/IrExceptionAnalyzerReporter.kt delete mode 100644 src/main/kotlin/indent/rainbow/IrSentryErrorReporter.kt diff --git a/src/main/kotlin/indent/rainbow/IrExceptionAnalyzerReporter.kt b/src/main/kotlin/indent/rainbow/IrExceptionAnalyzerReporter.kt new file mode 100644 index 0000000..331bdc1 --- /dev/null +++ b/src/main/kotlin/indent/rainbow/IrExceptionAnalyzerReporter.kt @@ -0,0 +1,8 @@ +package indent.rainbow + +import com.intellij.diagnostic.ITNReporter +import com.intellij.openapi.diagnostic.IdeaLoggingEvent + +class IrExceptionAnalyzerReporter : ITNReporter() { + override fun showErrorInRelease(event: IdeaLoggingEvent): Boolean = true +} diff --git a/src/main/kotlin/indent/rainbow/IrSentryErrorReporter.kt b/src/main/kotlin/indent/rainbow/IrSentryErrorReporter.kt deleted file mode 100644 index 8c74086..0000000 --- a/src/main/kotlin/indent/rainbow/IrSentryErrorReporter.kt +++ /dev/null @@ -1,116 +0,0 @@ -package indent.rainbow - -import com.intellij.diagnostic.IdeaReportingEvent -import com.intellij.diagnostic.ReportMessages -import com.intellij.ide.DataManager -import com.intellij.ide.plugins.IdeaPluginDescriptor -import com.intellij.idea.IdeaLogger -import com.intellij.notification.NotificationType -import com.intellij.openapi.actionSystem.CommonDataKeys -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.application.ApplicationNamesInfo -import com.intellij.openapi.application.ex.ApplicationInfoEx -import com.intellij.openapi.diagnostic.ErrorReportSubmitter -import com.intellij.openapi.diagnostic.IdeaLoggingEvent -import com.intellij.openapi.diagnostic.SubmittedReportInfo -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.progress.Task.Backgroundable -import com.intellij.openapi.util.SystemInfo -import com.intellij.util.Consumer -import io.sentry.DefaultSentryClientFactory -import io.sentry.SentryClient -import io.sentry.dsn.Dsn -import io.sentry.event.Event -import io.sentry.event.EventBuilder -import io.sentry.event.interfaces.ExceptionInterface -import io.sentry.event.interfaces.SentryException -import java.awt.Component -import java.util.* - -// https://plugin-dev.com/intellij/general/error-reporting/ -class IrSentryErrorReporter : ErrorReportSubmitter() { - - override fun getReportActionText(): String = "Report to Author" - - override fun submit( - events: Array, - additionalInfo: String?, - parentComponent: Component, - consumer: Consumer, - ): Boolean { - val context = DataManager.getInstance().getDataContext(parentComponent) - val project = CommonDataKeys.PROJECT.getData(context) - object : Backgroundable(project, "Sending error report") { - override fun run(indicator: ProgressIndicator) { - val sentryEvent = createEvent(events) - sentryEvent.withMessage(additionalInfo) - attachExtraInfo(sentryEvent) - - retry { - // synchronous, since we have `getAsyncEnabled = false` - sentryClient.sendEvent(sentryEvent) - } - ApplicationManager.getApplication().invokeLater { - ReportMessages.GROUP - .createNotification("Thank you for submitting your report!", NotificationType.INFORMATION) - .setImportant(false) - .notify(project) - consumer.consume(SubmittedReportInfo(SubmittedReportInfo.SubmissionStatus.NEW_ISSUE)) - } - } - }.queue() - return true - } - - private fun createEvent(events: Array): EventBuilder { - // this is the tricky part - // ideaEvent.throwable is a com.intellij.diagnostic.IdeaReportingEvent.TextBasedThrowable - // This is a wrapper and is only providing the original stacktrace via 'printStackTrace(...)', - // but not via 'getStackTrace()'. - // - // Sentry accesses Throwable.getStackTrace(), - // So, we workaround this by retrieving the original exception from the data property - val errors = events - .filterIsInstance() - .mapTo(ArrayDeque(events.size)) { - val throwable = it.data.throwable - SentryException(throwable, throwable.stackTrace) - } - - return EventBuilder() - .withLevel(Event.Level.ERROR) - .withSentryInterface(ExceptionInterface(errors)) - } - - private fun attachExtraInfo(event: EventBuilder) { - (pluginDescriptor as? IdeaPluginDescriptor)?.let { - event.withRelease(it.version) - } - event.withExtra("last_action", IdeaLogger.ourLastActionId) - - event.withTag("OS Name", SystemInfo.OS_NAME) - event.withTag("Java Version", SystemInfo.JAVA_VERSION) - - val namesInfo = ApplicationNamesInfo.getInstance() - event.withTag("App Name", namesInfo.productName) - event.withTag("App Full Name", namesInfo.fullProductName) - - val appInfo = ApplicationInfoEx.getInstanceEx() - event.withTag("App Version name", appInfo.versionName) - event.withTag("Is EAP", appInfo.isEAP.toString()) - event.withTag("App Build", appInfo.build.asString()) - event.withTag("App Version", appInfo.fullVersion) - } -} - -private val sentryClient: SentryClient = initSentryClient() - -private fun initSentryClient(): SentryClient { - val factory = object : DefaultSentryClientFactory() { - override fun getInAppFrames(dsn: Dsn): Collection = listOf("indent.rainbow") - override fun getAsyncEnabled(dsn: Dsn?): Boolean = false - } - - val dsn = ResourceBundle.getBundle("sentry").getString("dsn") - return factory.createClient(dsn) -} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 8aa11a3..7529581 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -33,7 +33,7 @@ - +