Cleaned up stack-trace cleanup method invocation

This commit is contained in:
Robinson 2023-04-29 00:46:16 +02:00
parent e24dbcd0b1
commit 95d7006c74
No known key found for this signature in database
GPG Key ID: 8E7DB78588BD6F5C
8 changed files with 86 additions and 83 deletions

View File

@ -19,6 +19,9 @@ package dorkbox.network.aeron
import dorkbox.network.Configuration import dorkbox.network.Configuration
import dorkbox.network.connection.EndPoint import dorkbox.network.connection.EndPoint
import dorkbox.network.connection.ListenerManager import dorkbox.network.connection.ListenerManager
import dorkbox.network.connection.ListenerManager.Companion.cleanAllStackTrace
import dorkbox.network.connection.ListenerManager.Companion.cleanStackTrace
import dorkbox.network.connection.ListenerManager.Companion.cleanStackTraceInternal
import dorkbox.network.exceptions.AeronDriverException import dorkbox.network.exceptions.AeronDriverException
import dorkbox.network.exceptions.ClientRetryException import dorkbox.network.exceptions.ClientRetryException
import io.aeron.Aeron import io.aeron.Aeron
@ -78,7 +81,7 @@ internal class AeronDriverInternal(endPoint: EndPoint<*>?, private val config: C
it(exception) it(exception)
} catch (t: Throwable) { } catch (t: Throwable) {
// NOTE: when we remove stuff, we ONLY want to remove the "tail" of the stacktrace, not ALL parts of the stacktrace // NOTE: when we remove stuff, we ONLY want to remove the "tail" of the stacktrace, not ALL parts of the stacktrace
ListenerManager.cleanStackTrace(t) t.cleanStackTrace()
driverLogger.error("Global error with Aeron", t) driverLogger.error("Global error with Aeron", t)
} }
} }
@ -117,7 +120,7 @@ internal class AeronDriverInternal(endPoint: EndPoint<*>?, private val config: C
val filter = config.aeronErrorFilter val filter = config.aeronErrorFilter
aeronErrorHandler = { error -> aeronErrorHandler = { error ->
if (filter(error)) { if (filter(error)) {
ListenerManager.cleanStackTrace(error) error.cleanStackTrace()
// send this out to the listener-manager so we can be notified of global errors // send this out to the listener-manager so we can be notified of global errors
notifyError(AeronDriverException(error)) notifyError(AeronDriverException(error))
} }
@ -187,14 +190,12 @@ internal class AeronDriverInternal(endPoint: EndPoint<*>?, private val config: C
} }
if (!running) { if (!running) {
logger.debug { "Starting Aeron Media driver [$driverId]" }
// try to start. If we start/stop too quickly, it's a problem // try to start. If we start/stop too quickly, it's a problem
var count = 10 var count = 10
while (count-- > 0) { while (count-- > 0) {
try { try {
mediaDriver = MediaDriver.launch(context.context) mediaDriver = MediaDriver.launch(context.context)
logger.debug { "Started the Aeron Media driver [$driverId]" } logger.debug { "Successfully started the Aeron Media driver [$driverId]" }
break break
} catch (e: Exception) { } catch (e: Exception) {
logger.warn(e) { "Unable to start the Aeron Media driver [$driverId] at ${context.directory}. Retrying $count more times..." } logger.warn(e) { "Unable to start the Aeron Media driver [$driverId] at ${context.directory}. Retrying $count more times..." }
@ -258,7 +259,7 @@ internal class AeronDriverInternal(endPoint: EndPoint<*>?, private val config: C
if (aeron1 == null || aeron1.isClosed) { if (aeron1 == null || aeron1.isClosed) {
// there was an error connecting to the aeron client or media driver. // there was an error connecting to the aeron client or media driver.
val ex = ClientRetryException("Error adding a publication to aeron") val ex = ClientRetryException("Error adding a publication to aeron")
ListenerManager.cleanAllStackTrace(ex) ex.cleanAllStackTrace()
throw ex throw ex
} }
@ -266,9 +267,9 @@ internal class AeronDriverInternal(endPoint: EndPoint<*>?, private val config: C
aeron1.addPublication(uri, streamId) aeron1.addPublication(uri, streamId)
} catch (e: Exception) { } catch (e: Exception) {
// this happens if the aeron media driver cannot actually establish connection // this happens if the aeron media driver cannot actually establish connection
ListenerManager.cleanAllStackTrace(e) e.cleanAllStackTrace()
val ex = ClientRetryException("Error adding a publication", e) val ex = ClientRetryException("Error adding a publication", e)
ListenerManager.cleanAllStackTrace(ex) ex.cleanAllStackTrace()
throw ex throw ex
} }
@ -306,7 +307,7 @@ internal class AeronDriverInternal(endPoint: EndPoint<*>?, private val config: C
if (aeron1 == null || aeron1.isClosed) { if (aeron1 == null || aeron1.isClosed) {
// there was an error connecting to the aeron client or media driver. // there was an error connecting to the aeron client or media driver.
val ex = ClientRetryException("Error adding a publication to aeron") val ex = ClientRetryException("Error adding a publication to aeron")
ListenerManager.cleanAllStackTrace(ex) ex.cleanAllStackTrace()
throw ex throw ex
} }
@ -314,17 +315,17 @@ internal class AeronDriverInternal(endPoint: EndPoint<*>?, private val config: C
aeron1.addExclusivePublication(uri, streamId) aeron1.addExclusivePublication(uri, streamId)
} catch (e: Exception) { } catch (e: Exception) {
// this happens if the aeron media driver cannot actually establish connection // this happens if the aeron media driver cannot actually establish connection
ListenerManager.cleanAllStackTrace(e) e.cleanStackTraceInternal()
ListenerManager.cleanAllStackTrace(e.cause) e.cause?.cleanStackTraceInternal()
val ex = ClientRetryException("Error adding a publication", e) val ex = ClientRetryException("Error adding a publication", e)
ListenerManager.cleanAllStackTrace(ex) ex.cleanAllStackTrace()
throw ex throw ex
} }
if (publication == null) { if (publication == null) {
// there was an error connecting to the aeron client or media driver. // there was an error connecting to the aeron client or media driver.
val ex = ClientRetryException("Error adding a publication") val ex = ClientRetryException("Error adding a publication")
ListenerManager.cleanAllStackTrace(ex) ex.cleanAllStackTrace()
throw ex throw ex
} }
@ -356,7 +357,7 @@ internal class AeronDriverInternal(endPoint: EndPoint<*>?, private val config: C
if (aeron1 == null || aeron1.isClosed) { if (aeron1 == null || aeron1.isClosed) {
// there was an error connecting to the aeron client or media driver. // there was an error connecting to the aeron client or media driver.
val ex = ClientRetryException("Error adding a subscription to aeron") val ex = ClientRetryException("Error adding a subscription to aeron")
ListenerManager.cleanAllStackTrace(ex) ex.cleanAllStackTrace()
throw ex throw ex
} }

View File

@ -18,7 +18,7 @@ package dorkbox.network.aeron.mediaDriver
import dorkbox.network.aeron.AeronDriver import dorkbox.network.aeron.AeronDriver
import dorkbox.network.aeron.mediaDriver.MediaDriverConnection.Companion.uri import dorkbox.network.aeron.mediaDriver.MediaDriverConnection.Companion.uri
import dorkbox.network.connection.ListenerManager import dorkbox.network.connection.ListenerManager.Companion.cleanAllStackTrace
import dorkbox.network.exceptions.ClientRetryException import dorkbox.network.exceptions.ClientRetryException
import dorkbox.network.exceptions.ClientTimedOutException import dorkbox.network.exceptions.ClientTimedOutException
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@ -69,7 +69,7 @@ internal open class ClientIpcDriver(aeronDriver: AeronDriver,
// ESPECIALLY if it is with the same streamID // ESPECIALLY if it is with the same streamID
// this check is in the "reconnect" logic // this check is in the "reconnect" logic
val publication = aeronDriver.addExclusivePublication(publicationUri, "IPC", streamId) val publication = aeronDriver.addExclusivePublication(publicationUri, logInfo, streamId)
// always include the linger timeout, so we don't accidentally kill ourself by taking too long // always include the linger timeout, so we don't accidentally kill ourself by taking too long
val timoutInNanos = TimeUnit.SECONDS.toNanos(connectionTimeoutSec.toLong()) + aeronDriver.getLingerNs() val timoutInNanos = TimeUnit.SECONDS.toNanos(connectionTimeoutSec.toLong()) + aeronDriver.getLingerNs()
@ -86,10 +86,10 @@ internal open class ClientIpcDriver(aeronDriver: AeronDriver,
if (!success) { if (!success) {
aeronDriver.closeAndDeletePublication(publication, listenType) aeronDriver.closeAndDeletePublication(publication, listenType)
val clientTimedOutException = ClientTimedOutException("Cannot create publication IPC connection to server") val clientTimedOutException = ClientTimedOutException("Cannot create publication IPC connection to server")
ListenerManager.cleanAllStackTrace(clientTimedOutException) clientTimedOutException.cleanAllStackTrace()
throw clientTimedOutException throw clientTimedOutException
} }
this.publication = publication this.publication = publication
} }

View File

@ -19,7 +19,7 @@ package dorkbox.network.aeron.mediaDriver
import dorkbox.netUtil.IPv6 import dorkbox.netUtil.IPv6
import dorkbox.network.aeron.AeronDriver import dorkbox.network.aeron.AeronDriver
import dorkbox.network.aeron.mediaDriver.MediaDriverConnection.Companion.uri import dorkbox.network.aeron.mediaDriver.MediaDriverConnection.Companion.uri
import dorkbox.network.connection.ListenerManager import dorkbox.network.connection.ListenerManager.Companion.cleanAllStackTrace
import dorkbox.network.exceptions.ClientRetryException import dorkbox.network.exceptions.ClientRetryException
import dorkbox.network.exceptions.ClientTimedOutException import dorkbox.network.exceptions.ClientTimedOutException
import io.aeron.CommonContext import io.aeron.CommonContext
@ -39,7 +39,7 @@ internal class ClientUdpDriver(aeronDriver: AeronDriver,
sessionId: Int, sessionId: Int,
connectionTimeoutSec: Int = 0, connectionTimeoutSec: Int = 0,
isReliable: Boolean, isReliable: Boolean,
listenType: String) : logInfo: String) :
MediaDriverClient( MediaDriverClient(
aeronDriver = aeronDriver, aeronDriver = aeronDriver,
port = port, port = port,
@ -47,7 +47,7 @@ internal class ClientUdpDriver(aeronDriver: AeronDriver,
sessionId = sessionId, sessionId = sessionId,
connectionTimeoutSec = connectionTimeoutSec, connectionTimeoutSec = connectionTimeoutSec,
isReliable = isReliable, isReliable = isReliable,
listenType = listenType logInfo = logInfo
) { ) {
var success: Boolean = false var success: Boolean = false
@ -75,7 +75,7 @@ internal class ClientUdpDriver(aeronDriver: AeronDriver,
// For publications, if we add them "too quickly" (faster than the 'linger' timeout), Aeron will throw exceptions. // For publications, if we add them "too quickly" (faster than the 'linger' timeout), Aeron will throw exceptions.
// ESPECIALLY if it is with the same streamID. This was noticed as a problem with IPC // ESPECIALLY if it is with the same streamID. This was noticed as a problem with IPC
val publication = aeronDriver.addExclusivePublication(publicationUri, listenType, streamId) val publication = aeronDriver.addExclusivePublication(publicationUri, logInfo, streamId)
// this will cause us to listen on the interface that connects with the remote address, instead of ALL interfaces. // this will cause us to listen on the interface that connects with the remote address, instead of ALL interfaces.
@ -97,7 +97,7 @@ internal class ClientUdpDriver(aeronDriver: AeronDriver,
.controlEndpoint(isIpv4, addressString, port+1) .controlEndpoint(isIpv4, addressString, port+1)
.controlMode(CommonContext.MDC_CONTROL_MODE_DYNAMIC) .controlMode(CommonContext.MDC_CONTROL_MODE_DYNAMIC)
val subscription = aeronDriver.addSubscription(subscriptionUri, listenType, streamId) val subscription = aeronDriver.addSubscription(subscriptionUri, logInfo, streamId)
// always include the linger timeout, so we don't accidentally kill ourselves by taking too long // always include the linger timeout, so we don't accidentally kill ourselves by taking too long
@ -117,8 +117,10 @@ internal class ClientUdpDriver(aeronDriver: AeronDriver,
aeronDriver.closeAndDeleteSubscription(subscription, "ClientUDP") aeronDriver.closeAndDeleteSubscription(subscription, "ClientUDP")
aeronDriver.closeAndDeletePublication(publication, "ClientUDP") aeronDriver.closeAndDeletePublication(publication, "ClientUDP")
val ex = ClientTimedOutException("Cannot create publication to $listenType $addressString in $connectionTimeoutSec seconds") sessionIdAllocator.free(sessionId)
ListenerManager.cleanAllStackTrace(ex)
val ex = ClientTimedOutException("Cannot create publication $logInfo $addressString in $connectionTimeoutSec seconds")
ex.cleanAllStackTrace()
throw ex throw ex
} }

View File

@ -26,6 +26,8 @@ import dorkbox.network.aeron.AeronDriver
import dorkbox.network.aeron.BacklogStat import dorkbox.network.aeron.BacklogStat
import dorkbox.network.aeron.EventPoller import dorkbox.network.aeron.EventPoller
import dorkbox.network.connection.EventDispatcher.Companion.EVENT import dorkbox.network.connection.EventDispatcher.Companion.EVENT
import dorkbox.network.connection.ListenerManager.Companion.cleanStackTrace
import dorkbox.network.connection.ListenerManager.Companion.cleanStackTraceInternal
import dorkbox.network.connection.streaming.StreamingControl import dorkbox.network.connection.streaming.StreamingControl
import dorkbox.network.connection.streaming.StreamingData import dorkbox.network.connection.streaming.StreamingData
import dorkbox.network.connection.streaming.StreamingManager import dorkbox.network.connection.streaming.StreamingManager
@ -506,7 +508,7 @@ internal constructor(val type: Class<*>,
val exception = newException( val exception = newException(
"[$aeronLogInfo] Error sending message. (Connection in non-connected state longer than linger timeout. ${errorCodeName(result)})" "[$aeronLogInfo] Error sending message. (Connection in non-connected state longer than linger timeout. ${errorCodeName(result)})"
) )
ListenerManager.cleanStackTraceInternal(exception) exception.cleanStackTraceInternal()
listenerManager.notifyError(exception) listenerManager.notifyError(exception)
throw exception throw exception
} }
@ -536,7 +538,7 @@ internal constructor(val type: Class<*>,
// more critical error sending the message. we shouldn't retry or anything. // more critical error sending the message. we shouldn't retry or anything.
// this exception will be a ClientException or a ServerException // this exception will be a ClientException or a ServerException
val exception = newException("[$aeronLogInfo] Error sending handshake message. $message (${errorCodeName(result)})") val exception = newException("[$aeronLogInfo] Error sending handshake message. $message (${errorCodeName(result)})")
ListenerManager.cleanStackTraceInternal(exception) exception.cleanStackTraceInternal()
listenerManager.notifyError(exception) listenerManager.notifyError(exception)
throw exception throw exception
} }
@ -545,7 +547,7 @@ internal constructor(val type: Class<*>,
throw e throw e
} else { } else {
val exception = newException("[$aeronLogInfo] Error serializing handshake message $message", e) val exception = newException("[$aeronLogInfo] Error serializing handshake message $message", e)
ListenerManager.cleanStackTrace(exception, 2) // 2 because we do not want to see the stack for the abstract `newException` exception.cleanStackTrace(2) // 2 because we do not want to see the stack for the abstract `newException`
listenerManager.notifyError(exception) listenerManager.notifyError(exception)
throw exception throw exception
} }
@ -832,7 +834,7 @@ internal constructor(val type: Class<*>,
// +2 because we do not want to see the stack for the abstract `newException` // +2 because we do not want to see the stack for the abstract `newException`
// +3 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is // +3 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is
// where we see who is calling "send()" // where we see who is calling "send()"
ListenerManager.cleanStackTrace(exception, 5) exception.cleanStackTrace(5)
return false return false
} else { } else {
// publication was actually closed, so no bother throwing an error // publication was actually closed, so no bother throwing an error
@ -875,7 +877,7 @@ internal constructor(val type: Class<*>,
// +2 because we do not want to see the stack for the abstract `newException` // +2 because we do not want to see the stack for the abstract `newException`
// +3 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is // +3 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is
// where we see who is calling "send()" // where we see who is calling "send()"
ListenerManager.cleanStackTrace(exception, 5) exception.cleanStackTrace(5)
return false return false
} }
} }

View File

@ -41,9 +41,9 @@ internal class ListenerManager<CONNECTION: Connection>(private val logger: KLogg
* *
* Neither of these are useful in resolving exception handling from a users perspective, and only clutter the stacktrace. * Neither of these are useful in resolving exception handling from a users perspective, and only clutter the stacktrace.
*/ */
fun cleanStackTrace(throwable: Throwable, adjustedStartOfStack: Int = 0) { fun Throwable.cleanStackTrace(adjustedStartOfStack: Int = 0) {
// we never care about coroutine stacks, so filter then to start with. // we never care about coroutine stacks, so filter then to start with.
val origStackTrace = throwable.stackTrace val origStackTrace = this.stackTrace
val size = origStackTrace.size val size = origStackTrace.size
if (size == 0) { if (size == 0) {
@ -84,14 +84,14 @@ internal class ListenerManager<CONNECTION: Connection>(private val logger: KLogg
if (newEndIndex > 0) { if (newEndIndex > 0) {
if (savedFirstStack != null) { if (savedFirstStack != null) {
// we want to save the FIRST stack frame also, maybe // we want to save the FIRST stack frame also, maybe
throwable.stackTrace = savedFirstStack + stackTrace.copyOfRange(newStartIndex, newEndIndex) this.stackTrace = savedFirstStack + stackTrace.copyOfRange(newStartIndex, newEndIndex)
} else { } else {
throwable.stackTrace = stackTrace.copyOfRange(newStartIndex, newEndIndex) this.stackTrace = stackTrace.copyOfRange(newStartIndex, newEndIndex)
} }
} else { } else {
// keep just one, since it's a stack frame INSIDE our network library, and we need that! // keep just one, since it's a stack frame INSIDE our network library, and we need that!
throwable.stackTrace = stackTrace.copyOfRange(0, 1) this.stackTrace = stackTrace.copyOfRange(0, 1)
} }
} }
@ -100,9 +100,9 @@ internal class ListenerManager<CONNECTION: Connection>(private val logger: KLogg
* *
* Neither of these are useful in resolving exception handling from a users perspective, and only clutter the stacktrace. * Neither of these are useful in resolving exception handling from a users perspective, and only clutter the stacktrace.
*/ */
fun cleanStackTraceInternal(throwable: Throwable) { fun Throwable.cleanStackTraceInternal() {
// NOTE: when we remove stuff, we ONLY want to remove the "tail" of the stacktrace, not ALL parts of the stacktrace // NOTE: when we remove stuff, we ONLY want to remove the "tail" of the stacktrace, not ALL parts of the stacktrace
val stackTrace = throwable.stackTrace val stackTrace = this.stackTrace
val size = stackTrace.size val size = stackTrace.size
if (size == 0) { if (size == 0) {
@ -113,7 +113,7 @@ internal class ListenerManager<CONNECTION: Connection>(private val logger: KLogg
val firstDorkboxIndex = stackTrace.indexOfFirst { it.className.startsWith("dorkbox.network.") } val firstDorkboxIndex = stackTrace.indexOfFirst { it.className.startsWith("dorkbox.network.") }
val lastDorkboxIndex = stackTrace.indexOfLast { it.className.startsWith("dorkbox.network.") } val lastDorkboxIndex = stackTrace.indexOfLast { it.className.startsWith("dorkbox.network.") }
throwable.stackTrace = stackTrace.filterIndexed { index, element -> this.stackTrace = stackTrace.filterIndexed { index, element ->
val stackName = element.className val stackName = element.className
if (index <= firstDorkboxIndex && index >= lastDorkboxIndex) { if (index <= firstDorkboxIndex && index >= lastDorkboxIndex) {
false false
@ -130,12 +130,8 @@ internal class ListenerManager<CONNECTION: Connection>(private val logger: KLogg
* *
* We only want the error message, because we do something based on it (and the full stack trace is meaningless) * We only want the error message, because we do something based on it (and the full stack trace is meaningless)
*/ */
fun cleanAllStackTrace(throwable: Throwable?) { fun Throwable.cleanAllStackTrace() {
if (throwable == null) { val stackTrace = this.stackTrace
return
}
val stackTrace = throwable.stackTrace
val size = stackTrace.size val size = stackTrace.size
if (size == 0) { if (size == 0) {
@ -143,7 +139,7 @@ internal class ListenerManager<CONNECTION: Connection>(private val logger: KLogg
} }
// throw everything out // throw everything out
throwable.stackTrace = stackTrace.copyOfRange(0, 1) this.stackTrace = stackTrace.copyOfRange(0, 1)
} }
internal inline fun <reified T> add(thing: T, array: Array<T>): Array<T> { internal inline fun <reified T> add(thing: T, array: Array<T>): Array<T> {
@ -376,7 +372,7 @@ internal class ListenerManager<CONNECTION: Connection>(private val logger: KLogg
it(connection) it(connection)
} catch (t: Throwable) { } catch (t: Throwable) {
// NOTE: when we remove stuff, we ONLY want to remove the "tail" of the stacktrace, not ALL parts of the stacktrace // NOTE: when we remove stuff, we ONLY want to remove the "tail" of the stacktrace, not ALL parts of the stacktrace
cleanStackTrace(t) t.cleanStackTrace()
logger.error("Connection ${connection.id} error", t) logger.error("Connection ${connection.id} error", t)
} }
} }
@ -391,7 +387,7 @@ internal class ListenerManager<CONNECTION: Connection>(private val logger: KLogg
it(connection) it(connection)
} catch (t: Throwable) { } catch (t: Throwable) {
// NOTE: when we remove stuff, we ONLY want to remove the "tail" of the stacktrace, not ALL parts of the stacktrace // NOTE: when we remove stuff, we ONLY want to remove the "tail" of the stacktrace, not ALL parts of the stacktrace
cleanStackTrace(t) t.cleanStackTrace()
logger.error("Connection ${connection.id} error", t) logger.error("Connection ${connection.id} error", t)
} }
} }
@ -406,7 +402,7 @@ internal class ListenerManager<CONNECTION: Connection>(private val logger: KLogg
it(connection) it(connection)
} catch (t: Throwable) { } catch (t: Throwable) {
// NOTE: when we remove stuff, we ONLY want to remove the "tail" of the stacktrace, not ALL parts of the stacktrace // NOTE: when we remove stuff, we ONLY want to remove the "tail" of the stacktrace, not ALL parts of the stacktrace
cleanStackTrace(t) t.cleanStackTrace()
logger.error("Connection ${connection.id} error", t) logger.error("Connection ${connection.id} error", t)
} }
} }
@ -425,7 +421,7 @@ internal class ListenerManager<CONNECTION: Connection>(private val logger: KLogg
it(connection, exception) it(connection, exception)
} catch (t: Throwable) { } catch (t: Throwable) {
// NOTE: when we remove stuff, we ONLY want to remove the "tail" of the stacktrace, not ALL parts of the stacktrace // NOTE: when we remove stuff, we ONLY want to remove the "tail" of the stacktrace, not ALL parts of the stacktrace
cleanStackTrace(t) t.cleanStackTrace()
logger.error("Connection ${connection.id} error", t) logger.error("Connection ${connection.id} error", t)
} }
} }
@ -444,7 +440,7 @@ internal class ListenerManager<CONNECTION: Connection>(private val logger: KLogg
it(exception) it(exception)
} catch (t: Throwable) { } catch (t: Throwable) {
// NOTE: when we remove stuff, we ONLY want to remove the "tail" of the stacktrace, not ALL parts of the stacktrace // NOTE: when we remove stuff, we ONLY want to remove the "tail" of the stacktrace, not ALL parts of the stacktrace
cleanStackTrace(t) t.cleanStackTrace()
logger.error("Global error", t) logger.error("Global error", t)
} }
} }
@ -486,7 +482,7 @@ internal class ListenerManager<CONNECTION: Connection>(private val logger: KLogg
try { try {
func(connection, message) func(connection, message)
} catch (t: Throwable) { } catch (t: Throwable) {
cleanStackTrace(t) t.cleanStackTrace()
logger.error("Connection ${connection.id} error", t) logger.error("Connection ${connection.id} error", t)
notifyError(connection, t) notifyError(connection, t)
} }

View File

@ -158,7 +158,7 @@ internal class StreamingManager<CONNECTION : Connection>(
// +2 because we do not want to see the stack for the abstract `newException` // +2 because we do not want to see the stack for the abstract `newException`
// +3 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is // +3 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is
// where we see who is calling "send()" // where we see who is calling "send()"
ListenerManager.cleanStackTrace(exception, 2) exception.cleanStackTrace(2)
throw exception throw exception
} }
@ -192,7 +192,7 @@ internal class StreamingManager<CONNECTION : Connection>(
// +2 because we do not want to see the stack for the abstract `newException` // +2 because we do not want to see the stack for the abstract `newException`
// +3 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is // +3 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is
// where we see who is calling "send()" // where we see who is calling "send()"
ListenerManager.cleanStackTrace(exception, 2) exception.cleanStackTrace(2)
throw exception throw exception
} }
} else { } else {
@ -206,7 +206,7 @@ internal class StreamingManager<CONNECTION : Connection>(
// +2 because we do not want to see the stack for the abstract `newException` // +2 because we do not want to see the stack for the abstract `newException`
// +3 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is // +3 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is
// where we see who is calling "send()" // where we see who is calling "send()"
ListenerManager.cleanStackTrace(exception, 2) exception.cleanStackTrace(2)
throw exception throw exception
} }
} else { } else {
@ -228,7 +228,7 @@ internal class StreamingManager<CONNECTION : Connection>(
// +2 because we do not want to see the stack for the abstract `newException` // +2 because we do not want to see the stack for the abstract `newException`
// +3 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is // +3 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is
// where we see who is calling "send()" // where we see who is calling "send()"
ListenerManager.cleanStackTrace(exception, 2) exception.cleanStackTrace(2)
throw exception throw exception
} }
StreamingState.UNKNOWN -> { StreamingState.UNKNOWN -> {
@ -242,7 +242,7 @@ internal class StreamingManager<CONNECTION : Connection>(
// +2 because we do not want to see the stack for the abstract `newException` // +2 because we do not want to see the stack for the abstract `newException`
// +3 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is // +3 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is
// where we see who is calling "send()" // where we see who is calling "send()"
ListenerManager.cleanStackTrace(exception, 2) exception.cleanStackTrace(2)
throw exception throw exception
} }
} }
@ -276,7 +276,7 @@ internal class StreamingManager<CONNECTION : Connection>(
// +2 because we do not want to see the stack for the abstract `newException` // +2 because we do not want to see the stack for the abstract `newException`
// +3 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is // +3 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is
// where we see who is calling "send()" // where we see who is calling "send()"
ListenerManager.cleanStackTrace(exception, 5) exception.cleanStackTrace(5)
throw exception throw exception
} }
} }
@ -304,7 +304,7 @@ internal class StreamingManager<CONNECTION : Connection>(
// +2 because we do not want to see the stack for the abstract `newException` // +2 because we do not want to see the stack for the abstract `newException`
// +4 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is // +4 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is
// where we see who is calling "send()" // where we see who is calling "send()"
ListenerManager.cleanStackTrace(exception, 6) exception.cleanStackTrace(6)
throw exception throw exception
} else { } else {
// send it up! // send it up!
@ -355,7 +355,7 @@ internal class StreamingManager<CONNECTION : Connection>(
// +2 because we do not want to see the stack for the abstract `newException` // +2 because we do not want to see the stack for the abstract `newException`
// +3 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is // +3 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is
// where we see who is calling "send()" // where we see who is calling "send()"
ListenerManager.cleanStackTrace(exception, 5) exception.cleanStackTrace(5)
throw exception throw exception
} }
@ -420,7 +420,7 @@ internal class StreamingManager<CONNECTION : Connection>(
// +2 because we do not want to see the stack for the abstract `newException` // +2 because we do not want to see the stack for the abstract `newException`
// +3 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is // +3 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is
// where we see who is calling "send()" // where we see who is calling "send()"
ListenerManager.cleanStackTrace(exception, 5) exception.cleanStackTrace(5)
throw exception throw exception
} }
} catch (e: Exception) { } catch (e: Exception) {
@ -482,7 +482,7 @@ internal class StreamingManager<CONNECTION : Connection>(
// +2 because we do not want to see the stack for the abstract `newException` // +2 because we do not want to see the stack for the abstract `newException`
// +3 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is // +3 more because we do not need to see the "internals" for sending messages. The important part of the stack trace is
// where we see who is calling "send()" // where we see who is calling "send()"
ListenerManager.cleanStackTrace(exception, 5) exception.cleanStackTrace(5)
throw exception throw exception
} else { } else {
// send it up! // send it up!

View File

@ -19,7 +19,8 @@ import dorkbox.network.Client
import dorkbox.network.aeron.AeronDriver import dorkbox.network.aeron.AeronDriver
import dorkbox.network.aeron.mediaDriver.MediaDriverClient import dorkbox.network.aeron.mediaDriver.MediaDriverClient
import dorkbox.network.connection.Connection import dorkbox.network.connection.Connection
import dorkbox.network.connection.ListenerManager import dorkbox.network.connection.ListenerManager.Companion.cleanAllStackTrace
import dorkbox.network.connection.ListenerManager.Companion.cleanStackTraceInternal
import dorkbox.network.exceptions.ClientRejectedException import dorkbox.network.exceptions.ClientRejectedException
import dorkbox.network.exceptions.ClientTimedOutException import dorkbox.network.exceptions.ClientTimedOutException
import dorkbox.network.exceptions.ServerException import dorkbox.network.exceptions.ServerException
@ -85,7 +86,7 @@ internal class ClientHandshake<CONNECTION: Connection>(
// it must be a registration message // it must be a registration message
if (message !is HandshakeMessage) { if (message !is HandshakeMessage) {
failedException = ClientRejectedException("[$aeronLogInfo] cancelled handshake for unrecognized message: $message") failedException = ClientRejectedException("[$aeronLogInfo] cancelled handshake for unrecognized message: $message")
ListenerManager.cleanAllStackTrace(failedException) .apply { cleanAllStackTrace() }
return@FragmentAssembler return@FragmentAssembler
} }
@ -93,7 +94,7 @@ internal class ClientHandshake<CONNECTION: Connection>(
if (message.state == HandshakeMessage.INVALID) { if (message.state == HandshakeMessage.INVALID) {
val cause = ServerException(message.errorMessage ?: "Unknown").apply { stackTrace = stackTrace.copyOfRange(0, 1) } val cause = ServerException(message.errorMessage ?: "Unknown").apply { stackTrace = stackTrace.copyOfRange(0, 1) }
failedException = ClientRejectedException("[$aeronLogInfo}] (${message.connectKey}) cancelled handshake", cause) failedException = ClientRejectedException("[$aeronLogInfo}] (${message.connectKey}) cancelled handshake", cause)
ListenerManager.cleanAllStackTrace(failedException) .apply { cleanAllStackTrace() }
return@FragmentAssembler return@FragmentAssembler
} }
@ -122,7 +123,7 @@ internal class ClientHandshake<CONNECTION: Connection>(
connectionHelloInfo = crypto.decrypt(registrationData, serverPublicKeyBytes) connectionHelloInfo = crypto.decrypt(registrationData, serverPublicKeyBytes)
} else { } else {
failedException = ClientRejectedException("[$aeronLogInfo}] (${message.connectKey}) canceled handshake for message without registration and/or public key info") failedException = ClientRejectedException("[$aeronLogInfo}] (${message.connectKey}) canceled handshake for message without registration and/or public key info")
ListenerManager.cleanAllStackTrace(failedException) .apply { cleanAllStackTrace() }
} }
} }
HandshakeMessage.HELLO_ACK_IPC -> { HandshakeMessage.HELLO_ACK_IPC -> {
@ -146,7 +147,7 @@ internal class ClientHandshake<CONNECTION: Connection>(
kryoRegistrationDetails = regDetails) kryoRegistrationDetails = regDetails)
} else { } else {
failedException = ClientRejectedException("[$aeronLogInfo] (${message.connectKey}) canceled handshake for message without registration data") failedException = ClientRejectedException("[$aeronLogInfo] (${message.connectKey}) canceled handshake for message without registration data")
ListenerManager.cleanAllStackTrace(failedException) .apply { cleanAllStackTrace() }
} }
} }
HandshakeMessage.DONE_ACK -> { HandshakeMessage.DONE_ACK -> {
@ -155,7 +156,7 @@ internal class ClientHandshake<CONNECTION: Connection>(
else -> { else -> {
val stateString = HandshakeMessage.toStateString(message.state) val stateString = HandshakeMessage.toStateString(message.state)
failedException = ClientRejectedException("[$aeronLogInfo] (${message.connectKey}) cancelled handshake for message that is $stateString") failedException = ClientRejectedException("[$aeronLogInfo] (${message.connectKey}) cancelled handshake for message that is $stateString")
ListenerManager.cleanAllStackTrace(failedException) .apply { cleanAllStackTrace() }
} }
} }
} }
@ -301,7 +302,7 @@ internal class ClientHandshake<CONNECTION: Connection>(
aeronDriver.closeAndDeletePublication(handshakeConnection.publication, "ClientHandshake") aeronDriver.closeAndDeletePublication(handshakeConnection.publication, "ClientHandshake")
val exception = ClientTimedOutException("Waiting for registration response from server") val exception = ClientTimedOutException("Waiting for registration response from server")
ListenerManager.cleanStackTraceInternal(exception) exception.cleanStackTraceInternal()
throw exception throw exception
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2020 dorkbox, llc * Copyright 2023 dorkbox, llc
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,6 +17,7 @@ package dorkbox.network.rmi
import dorkbox.network.connection.Connection import dorkbox.network.connection.Connection
import dorkbox.network.connection.ListenerManager import dorkbox.network.connection.ListenerManager
import dorkbox.network.connection.ListenerManager.Companion.cleanStackTrace
import dorkbox.network.rmi.messages.ConnectionObjectCreateRequest import dorkbox.network.rmi.messages.ConnectionObjectCreateRequest
import dorkbox.network.rmi.messages.ConnectionObjectCreateResponse import dorkbox.network.rmi.messages.ConnectionObjectCreateResponse
import dorkbox.network.rmi.messages.ConnectionObjectDeleteRequest import dorkbox.network.rmi.messages.ConnectionObjectDeleteRequest
@ -47,7 +48,7 @@ class RmiManagerConnections<CONNECTION: Connection> internal constructor(
val response = if (implObject is Exception) { val response = if (implObject is Exception) {
// whoops! // whoops!
ListenerManager.cleanStackTrace(implObject) implObject.cleanStackTrace()
logger.error("RMI error connection ${connection.id}", implObject) logger.error("RMI error connection ${connection.id}", implObject)
listenerManager.notifyError(connection, implObject) listenerManager.notifyError(connection, implObject)
ConnectionObjectCreateResponse(RmiUtils.packShorts(callbackId, RemoteObjectStorage.INVALID_RMI)) ConnectionObjectCreateResponse(RmiUtils.packShorts(callbackId, RemoteObjectStorage.INVALID_RMI))
@ -55,7 +56,7 @@ class RmiManagerConnections<CONNECTION: Connection> internal constructor(
val rmiId = connection.rmi.saveImplObject(implObject) val rmiId = connection.rmi.saveImplObject(implObject)
if (rmiId == RemoteObjectStorage.INVALID_RMI) { if (rmiId == RemoteObjectStorage.INVALID_RMI) {
val exception = NullPointerException("Trying to create an RMI object with the INVALID_RMI id!!") val exception = NullPointerException("Trying to create an RMI object with the INVALID_RMI id!!")
ListenerManager.cleanStackTrace(exception) exception.cleanStackTrace()
logger.error("RMI error connection ${connection.id}", exception) logger.error("RMI error connection ${connection.id}", exception)
listenerManager.notifyError(connection, exception) listenerManager.notifyError(connection, exception)
} }
@ -77,7 +78,7 @@ class RmiManagerConnections<CONNECTION: Connection> internal constructor(
// we only create the proxy + execute the callback if the RMI id is valid! // we only create the proxy + execute the callback if the RMI id is valid!
if (rmiId == RemoteObjectStorage.INVALID_RMI) { if (rmiId == RemoteObjectStorage.INVALID_RMI) {
val exception = Exception("RMI ID '${rmiId}' is invalid. Unable to create RMI object on server.") val exception = Exception("RMI ID '${rmiId}' is invalid. Unable to create RMI object on server.")
ListenerManager.cleanStackTrace(exception) exception.cleanStackTrace()
logger.error("RMI error connection ${connection.id}", exception) logger.error("RMI error connection ${connection.id}", exception)
listenerManager.notifyError(connection, exception) listenerManager.notifyError(connection, exception)
return return
@ -95,10 +96,10 @@ class RmiManagerConnections<CONNECTION: Connection> internal constructor(
// this should be executed on a NEW coroutine! // this should be executed on a NEW coroutine!
try { try {
callback(proxyObject) callback(proxyObject)
} catch (e: Exception) { } catch (exception: Exception) {
ListenerManager.cleanStackTrace(e) exception.cleanStackTrace()
logger.error("RMI error connection ${connection.id}", e) logger.error("RMI error connection ${connection.id}", exception)
listenerManager.notifyError(connection, e) listenerManager.notifyError(connection, exception)
} }
} }
@ -110,8 +111,8 @@ class RmiManagerConnections<CONNECTION: Connection> internal constructor(
// we only delete the impl object if the RMI id is valid! // we only delete the impl object if the RMI id is valid!
if (rmiId == RemoteObjectStorage.INVALID_RMI) { if (rmiId == RemoteObjectStorage.INVALID_RMI) {
val exception = Exception("RMI ID '${rmiId}' is invalid. Unable to delete RMI object!") val exception = Exception("Unable to delete RMI object!")
ListenerManager.cleanStackTrace(exception) exception.cleanStackTrace()
logger.error("RMI error connection ${connection.id}", exception) logger.error("RMI error connection ${connection.id}", exception)
listenerManager.notifyError(connection, exception) listenerManager.notifyError(connection, exception)
return return
@ -134,8 +135,8 @@ class RmiManagerConnections<CONNECTION: Connection> internal constructor(
// we only create the proxy + execute the callback if the RMI id is valid! // we only create the proxy + execute the callback if the RMI id is valid!
if (rmiId == RemoteObjectStorage.INVALID_RMI) { if (rmiId == RemoteObjectStorage.INVALID_RMI) {
val exception = Exception("RMI ID '${rmiId}' is invalid. Unable to create RMI object on server.") val exception = Exception("Unable to create RMI object on server.")
ListenerManager.cleanStackTrace(exception) exception.cleanStackTrace()
logger.error("RMI error connection ${connection.id}", exception) logger.error("RMI error connection ${connection.id}", exception)
listenerManager.notifyError(connection, exception) listenerManager.notifyError(connection, exception)
return return
@ -155,7 +156,7 @@ class RmiManagerConnections<CONNECTION: Connection> internal constructor(
* Methods supporting Remote Method Invocation and Objects. A new one is created for each connection (because the connection is different for each one) * Methods supporting Remote Method Invocation and Objects. A new one is created for each connection (because the connection is different for each one)
*/ */
fun getNewRmiSupport(connection: Connection): RmiSupportConnection<CONNECTION> { fun getNewRmiSupport(connection: Connection): RmiSupportConnection<CONNECTION> {
@Suppress("LeakingThis", "UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
return RmiSupportConnection(logger, connection as CONNECTION, responseManager, serialization, getGlobalAction) return RmiSupportConnection(logger, connection as CONNECTION, responseManager, serialization, getGlobalAction)
} }
} }