11package ru.endlesscode.inspector.report
22
3- import io.sentry.DefaultSentryClientFactory
4- import io.sentry.DefaultSentryClientFactory.IN_APP_FRAMES_OPTION
5- import io.sentry.DefaultSentryClientFactory.UNCAUGHT_HANDLER_ENABLED_OPTION
3+ import io.sentry.Integration
64import io.sentry.Sentry
7- import io.sentry.SentryClientFactory
8- import io.sentry.connection.EventSendCallback
9- import io.sentry.event.Event
10- import io.sentry.event.EventBuilder
11- import io.sentry.event.UserBuilder
12- import io.sentry.event.interfaces.ExceptionInterface
13- import java.util.*
5+ import io.sentry.SentryEvent
6+ import io.sentry.protocol.Message
7+ import io.sentry.protocol.User
148
159/* *
1610 * Reporter that sends reports to Sentry.
1711 */
1812public class SentryReporter private constructor(
1913 dsn : String ,
20- factory : SentryClientFactory ,
14+ integrations : List < Integration > ,
2115 override val focus : ReporterFocus ,
2216 private val fields : Set <ReportField >,
2317) : Reporter {
2418
2519 override var enabled: Boolean = true
2620
27- private val sentry = Sentry .init (dsn, factory)
28-
2921 private val handlers = CompoundReportHandler ()
30- private val pendingExceptions = mutableMapOf<UUID , ExceptionData >()
3122
3223 init {
33- sentry.addEventSendCallback( object : EventSendCallback {
34- override fun onSuccess ( event : Event ) {
35- val reportedException = removePendingException(event.id)
36- if (reportedException != null ) {
37- handlers.onSuccess(event.message, reportedException)
38- }
39- }
24+ Sentry . init { options ->
25+ options.dsn = dsn
26+ options.release = " ${focus.environment.appName} @ ${focus.environment.appVersion} "
27+ options.addInAppInclude(focus.focusedPackage)
28+ options.enableUncaughtExceptionHandler = false
29+ integrations.forEach(options::addIntegration)
30+ }
4031
41- override fun onFailure (event : Event , exception : Exception ) {
42- val isErrorReport = removePendingException(event.id) != null
43- if (isErrorReport) {
44- handlers.onError(exception)
45- }
32+ Sentry .configureScope { scope ->
33+ scope.user = User ().apply {
34+ id = focus.environment.reporterId
4635 }
47- })
48-
49- sentry.release = focus.environment.appVersion
50- sentry.context.user = UserBuilder ()
51- .setId(focus.environment.reporterId)
52- .build()
36+ }
5337 }
5438
5539 override fun addHandler (handler : ReportHandler ) {
5640 handlers.addHandler(handler)
5741 }
5842
5943 override fun report (message : String , exception : Exception , async : Boolean ) {
60- val exceptionData = ExceptionData (exception)
61- handlers.beforeReport(message, exceptionData)
62-
63- val eventBuilder = EventBuilder ()
64- .withMessage(message)
65- .withSentryInterface(ExceptionInterface (exception))
66- .apply {
67- fields.asSequence()
68- .filter(ReportField ::show)
69- .forEach { withExtra(it.name, it.value) }
70- }
44+ val sentryMessage = Message ().apply {
45+ formatted = message
46+ }
7147
72- sentry.sendEvent(eventBuilder)
73- addPendingException(sentry.context.lastEventId, exceptionData)
74- }
48+ val event = SentryEvent (exception).apply {
49+ setMessage(sentryMessage)
50+ fields.asSequence()
51+ .filter(ReportField ::show)
52+ .forEach { setExtra(it.name, it.value) }
53+ }
54+ Sentry .captureEvent(event)
7555
76- private fun addPendingException (id : UUID , exception : ExceptionData ) {
77- pendingExceptions[id] = exception
56+ // We can't track errors on error sending. So we just assume that report was sent successfully.
57+ val exceptionData = ExceptionData (exception)
58+ handlers.onSuccess(message, exceptionData)
7859 }
7960
80- private fun removePendingException (id : UUID ): ExceptionData ? = pendingExceptions.remove(id)
81-
8261 /* *
8362 * Builder that should be used to build [SentryReporter].
8463 *
8564 * You should specify DSN with one of [setDataSourceName] methods.
8665 */
8766 public class Builder : Reporter .Builder () {
8867
89- private var clientFactory: SentryClientFactory ? = null
9068 private var dsn: String = " "
91- private var options : Map < String , String > = emptyMap ()
69+ private val integrations = mutableListOf< Integration > ()
9270
9371 /* *
94- * Set [SentryClientFactory], that will be used to create SentryClient.
72+ * Set Sentry [dsn].
73+ * See: [Setting the DSN](https://docs.sentry.io/clients/java/config/#setting-the-dsn)
9574 */
96- public fun setClientFactory ( clientFactory : SentryClientFactory ): Builder {
97- this .clientFactory = clientFactory
75+ public fun setDsn ( dsn : String ): Builder {
76+ this .dsn = dsn
9877 return this
9978 }
10079
101- /* *
102- * Set Sentry [dsn] with one string.
103- * See: https://docs.sentry.io/clients/java/config/#setting-the-dsn
104- */
80+ @Deprecated(" Use setDsn" , ReplaceWith (" setDsn(dsn)" ))
10581 public fun setDataSourceName (dsn : String ): Builder {
106- this .dsn = dsn
107- return this
82+ return setDsn(dsn)
10883 }
10984
110- /* *
111- * Set Sentry [dsn] built from separated parts.
112- * See: https://docs.sentry.io/clients/java/config/#setting-the-dsn
113- */
11485 @JvmOverloads
86+ @Deprecated(" Use setDsn" )
11587 public fun setDataSourceName (
11688 publicKey : String ,
11789 projectId : String ,
11890 protocol : String = "https",
11991 host : String = "sentry.io",
12092 port : String = "",
121- options : Map <String , String > = emptyMap(),
12293 ): Builder {
123- this . dsn = buildString {
94+ val dsn = buildString {
12495 append(protocol)
12596 append(" ://" )
12697 append(publicKey)
@@ -131,8 +102,12 @@ public class SentryReporter private constructor(
131102 append(projectId)
132103 }
133104
134- this .options = options
105+ return setDsn(dsn)
106+ }
135107
108+ /* * Adds given [integration] to Sentry. */
109+ public fun addIntegration (integration : Integration ): Builder {
110+ this .integrations.add(integration)
136111 return this
137112 }
138113
@@ -141,21 +116,12 @@ public class SentryReporter private constructor(
141116 */
142117 override fun build (): Reporter {
143118 require(dsn.isNotBlank()) {
144- " You should specify DSN with method `setDataSourceName (...)` and it shouldn't be blank."
119+ " You should specify DSN with method `setDsn (...)` and it shouldn't be blank."
145120 }
146121
147- val options = mutableMapOf (
148- IN_APP_FRAMES_OPTION to focus.focusedPackage,
149- UNCAUGHT_HANDLER_ENABLED_OPTION to " false"
150- )
151- options.putAll(this .options)
152-
153- val optionsString = options.asSequence()
154- .joinToString(prefix = " ?" , separator = " &" ) { (key, value) -> " $key =$value " }
155-
156122 return SentryReporter (
157- dsn = " $ dsn$optionsString " ,
158- factory = clientFactory ? : DefaultSentryClientFactory () ,
123+ dsn = dsn,
124+ integrations = integrations ,
159125 focus = focus,
160126 fields = fields
161127 )
0 commit comments