Skip to content

Commit

Permalink
Fix stack trace not being included in structured logging payload. (#226)
Browse files Browse the repository at this point in the history
  • Loading branch information
SanjayVas authored Dec 15, 2023
1 parent a4a100c commit 3ecac81
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package org.wfanet.measurement.gcloud.logging

import com.google.gson.JsonObject
import java.io.PrintWriter
import java.io.StringWriter
import java.time.Instant
import java.util.logging.Formatter
import java.util.logging.Level
Expand All @@ -40,14 +42,14 @@ class StructuredLoggingFormatter : Formatter() {
private data class LogEntryPayload(
val severity: LogSeverity,
val timestamp: Instant,
val message: String,
val textPayload: String,
val sourceLocation: LogEntrySourceLocation,
) {
fun toJsonObject(): JsonObject {
return JsonObject().apply {
addProperty(LogFields.SEVERITY, severity.name)
addProperty(LogFields.TIME, timestamp.toString())
addProperty(LogFields.MESSAGE, message)
addProperty(LogFields.MESSAGE, textPayload)
add(LogFields.SOURCE_LOCATION, sourceLocation.toJsonObject())
}
}
Expand Down Expand Up @@ -78,10 +80,22 @@ class StructuredLoggingFormatter : Formatter() {
companion object {
private fun LogRecord.toEntryPayload(): LogEntryPayload {
val sourceLocation = LogEntrySourceLocation(function = "$sourceClassName.$sourceMethodName")
val textPayload =
if (thrown == null) {
message
} else {
StringWriter().use { stringWriter ->
PrintWriter(stringWriter).use { printWriter ->
printWriter.println(message)
thrown.printStackTrace(printWriter)
}
stringWriter.toString()
}
}
return LogEntryPayload(
level.toSeverity(),
Instant.ofEpochMilli(millis),
message,
textPayload,
sourceLocation
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.google.gson.JsonParser
import com.google.gson.JsonPrimitive
import java.io.ByteArrayOutputStream
import java.time.Instant
import java.util.logging.Level
import java.util.logging.Logger
import java.util.logging.StreamHandler
import org.junit.Before
Expand Down Expand Up @@ -66,4 +67,20 @@ class StructuredLoggingFormatterTest {
)
.containsExactly("function", JsonPrimitive(qualifiedFunctionName))
}

@Test
fun `logs entry with stack trace`() {
val innerClass: Class<*> = object {}.javaClass
val message = "Log message"
val exception = Exception("cause")

logger.log(Level.WARNING, message, exception)

loggingHandler.flush()
val log = logStream.toString()
val entryPayload: JsonObject = JsonParser.parseString(log).asJsonObject
val textPayload = entryPayload[StructuredLoggingFormatter.LogFields.MESSAGE].asString
assertThat(textPayload).startsWith(message)
assertThat(textPayload).contains(innerClass.enclosingClass.name)
}
}

0 comments on commit 3ecac81

Please sign in to comment.