HasLoggingContext

Interface for exceptions that carry log fields, to provide structured logging context when an exception is logged. When passing a cause exception to one of the methods on Logger, it will check if the given exception implements this interface, and if it does, these fields will be added to the log.

Use the field/rawJsonField functions to construct log fields.

This is useful when you are throwing an exception from somewhere down in the stack, but do logging further up the stack, and you have structured data that you want to attach to the exception log. In this case, one may typically resort to string concatenation, but this interface allows you to have the benefits of structured logging for exceptions as well.

You can implement this interface for your custom exception types. If you just want to throw an exception with logging context and don't need a custom type, throw ExceptionWithLoggingContext.

Example

import dev.hermannm.devlog.HasLoggingContext
import dev.hermannm.devlog.field
import dev.hermannm.devlog.getLogger

private val log = getLogger()

fun example(order: Order) {
try {
updateOrder(order)
} catch (e: Exception) {
log.error(e) { "Failed to update order" }
}
}

fun updateOrder(order: Order) {
if (!order.canBeUpdated()) {
throw OrderUpdateException("Cannot update finalized order", order)
}
}

class OrderUpdateException(
override val message: String,
order: Order,
) : RuntimeException(), HasLoggingContext {
override val logFields = listOf(field("order", order))
}

The log.error would then give the following log output (using logstash-logback-encoder), with the order log field from OrderUpdateException attached:

{
"message": "Failed to update order",
"stack_trace": "...OrderUpdateException: Cannot update finalized order...",
"order": { ... },
// ...timestamp etc.
}

Properties

Link copied to clipboard

Will be attached to the log when passed through cause to one of Logger's methods.