mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 20:16:47 +03:00
Fix serialization of NPE in logger (#4055)
Fixes an error when the logger processes NPE: ``` [internal-logger-error] One of the printers failed to write a message: java.lang.NullPointerException ```
This commit is contained in:
parent
97ab0d7d5a
commit
b8967b96b9
@ -16,7 +16,7 @@ import io.circe._
|
||||
*/
|
||||
case class SerializedException(
|
||||
name: String,
|
||||
message: String,
|
||||
message: Option[String],
|
||||
stackTrace: Seq[SerializedException.TraceElement],
|
||||
cause: Option[SerializedException]
|
||||
)
|
||||
@ -33,7 +33,7 @@ object SerializedException {
|
||||
): SerializedException =
|
||||
SerializedException(
|
||||
name = name,
|
||||
message = message,
|
||||
message = Some(message),
|
||||
stackTrace = stackTrace,
|
||||
cause = Some(cause)
|
||||
)
|
||||
@ -45,18 +45,13 @@ object SerializedException {
|
||||
message: String,
|
||||
stackTrace: Seq[SerializedException.TraceElement]
|
||||
): SerializedException =
|
||||
SerializedException(
|
||||
new SerializedException(
|
||||
name = name,
|
||||
message = message,
|
||||
message = Some(message),
|
||||
stackTrace = stackTrace,
|
||||
cause = None
|
||||
)
|
||||
|
||||
/** Creates a [[SerializedException]] from a [[Throwable]].
|
||||
*/
|
||||
def apply(throwable: Throwable): SerializedException =
|
||||
fromException(throwable)
|
||||
|
||||
/** Encodes a JVM [[Throwable]] as [[SerializedException]].
|
||||
*/
|
||||
def fromException(throwable: Throwable): SerializedException = {
|
||||
@ -66,7 +61,7 @@ object SerializedException {
|
||||
else Option(throwable.getCause).map(fromException)
|
||||
SerializedException(
|
||||
name = Option(clazz.getCanonicalName).getOrElse(clazz.getName),
|
||||
message = throwable.getMessage,
|
||||
message = Option(throwable.getMessage),
|
||||
stackTrace = throwable.getStackTrace.toSeq.map(encodeStackTraceElement),
|
||||
cause = cause
|
||||
)
|
||||
@ -164,7 +159,7 @@ object SerializedException {
|
||||
): Decoder.Result[SerializedException] = {
|
||||
for {
|
||||
name <- json.get[String](JsonFields.Name)
|
||||
message <- json.get[String](JsonFields.Message)
|
||||
message <- json.get[Option[String]](JsonFields.Message)
|
||||
stackTrace <- json.get[Seq[TraceElement]](JsonFields.StackTrace)
|
||||
cause <-
|
||||
json.getOrElse[Option[SerializedException]](JsonFields.Cause)(None)
|
||||
|
@ -0,0 +1,33 @@
|
||||
package org.enso.loggingservice.internal
|
||||
|
||||
import org.enso.loggingservice.LogLevel
|
||||
import org.enso.loggingservice.internal.protocol.{
|
||||
SerializedException,
|
||||
WSLogMessage
|
||||
}
|
||||
import org.scalatest.OptionValues
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.wordspec.AnyWordSpec
|
||||
|
||||
import java.time.Instant
|
||||
import java.time.temporal.ChronoUnit
|
||||
|
||||
class DefaultLogMessageRendererSpec
|
||||
extends AnyWordSpec
|
||||
with Matchers
|
||||
with OptionValues {
|
||||
|
||||
"DefaultLogMessageRenderer" should {
|
||||
"render NullPointerException" in {
|
||||
val renderer = new DefaultLogMessageRenderer(printExceptions = true)
|
||||
val ts = Instant.now().truncatedTo(ChronoUnit.MILLIS)
|
||||
|
||||
val exception =
|
||||
SerializedException.fromException(new NullPointerException)
|
||||
val message =
|
||||
WSLogMessage(LogLevel.Trace, ts, "group", "message", Some(exception))
|
||||
|
||||
noException should be thrownBy renderer.render(message)
|
||||
}
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ class SerializedExceptionSpec
|
||||
extends AnyWordSpec
|
||||
with Matchers
|
||||
with OptionValues {
|
||||
|
||||
"SerializedException" should {
|
||||
"serialize and deserialize with nested causes" in {
|
||||
val cause = SerializedException(
|
||||
@ -25,7 +26,7 @@ class SerializedExceptionSpec
|
||||
SerializedException.TraceElement("e2", "loc2"),
|
||||
SerializedException.TraceElement("e3", "loc3")
|
||||
),
|
||||
cause = cause
|
||||
cause
|
||||
)
|
||||
|
||||
exception.asJson
|
||||
@ -33,5 +34,15 @@ class SerializedExceptionSpec
|
||||
.toOption
|
||||
.value shouldEqual exception
|
||||
}
|
||||
|
||||
"be created from NullPointerException" in {
|
||||
val exception = new NullPointerException()
|
||||
val result = SerializedException.fromException(exception)
|
||||
|
||||
result.name shouldEqual exception.getClass.getName
|
||||
result.message shouldEqual None
|
||||
result.cause shouldEqual None
|
||||
result.stackTrace shouldBe Symbol("nonEmpty")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,17 +14,31 @@ import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.wordspec.AnyWordSpec
|
||||
|
||||
class WSLogMessageSpec extends AnyWordSpec with Matchers with OptionValues {
|
||||
|
||||
"WSLogMessage" should {
|
||||
"serialize and deserialize to the same thing" in {
|
||||
val ts = Instant.now().truncatedTo(ChronoUnit.MILLIS)
|
||||
|
||||
val message1 = WSLogMessage(LogLevel.Trace, ts, "group", "message", None)
|
||||
message1.asJson.as[WSLogMessage].toOption.value shouldEqual message1
|
||||
noException should be thrownBy message1.asJson.noSpaces
|
||||
|
||||
val exception = SerializedException("name", "message", Seq(), None)
|
||||
val exception = SerializedException("name", "message", Seq())
|
||||
val message2 =
|
||||
WSLogMessage(LogLevel.Trace, ts, "group", "message", Some(exception))
|
||||
message2.asJson.as[WSLogMessage].toOption.value shouldEqual message2
|
||||
noException should be thrownBy message2.asJson.noSpaces
|
||||
}
|
||||
|
||||
"serialize NullPointerException" in {
|
||||
val ts = Instant.now().truncatedTo(ChronoUnit.MILLIS)
|
||||
|
||||
val exception =
|
||||
SerializedException.fromException(new NullPointerException)
|
||||
val message =
|
||||
WSLogMessage(LogLevel.Trace, ts, "group", "message", Some(exception))
|
||||
message.asJson.as[WSLogMessage].toOption.value shouldEqual message
|
||||
noException should be thrownBy message.asJson.noSpaces
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user