Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Logging an object and masking specific fields

Tags:

kotlin

I have to log an object with around 60 fields, of which some are nested, to temporarily debug when specific exceptions occurs. However, not all fields can be included in the logs, so I have to mask or completely exclude them.

The added complexity is that the class from which the objects are derived, is generated with an OpenAPI plugin and I can thus not directly modify it.

Now, I am looking for a simple and concise solution to either serialize or toString these objects and exclude some of the fields.

For example, if I would have the following object:

val color: Color = Color(
    RGB(
        r = "255", 
        g = "255", 
        b = "255"), 
    Opacity(value = 0.95)
)

I would like to hide Opacity and mask a part of r, like this:

Color(RGB=(r="xx5", g="255", b="255")) or any other way to represent the object

I could of course write a custom method to do this for me, but this would become quite verbose.

Are there any specific alternatives that are worth looking into?

like image 507
Dominique M Avatar asked Sep 01 '25 04:09

Dominique M


1 Answers

I suggest this approach

  1. Serialize the object tree to JSON using Jackson or some other serializer
  2. Use a specialist masking JSON library to filter what you want. There are many; I illustrate one: https://github.com/Breus/json-masker
  3. My solution masks out the RGB.r field wholly, rather than some kind of partial masking. The library can likely do this. See ValueMaskers

Code

import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import dev.blaauwendraad.masker.json.JsonMasker
import dev.blaauwendraad.masker.json.config.JsonMaskingConfig

fun main(args: Array<String>) {
    val color: Color = Color(
        RGB(
            r = "255",
            g = "255",
            b = "255",
        ),
        Opacity(value = 0.95),
    )
    log(color)
}

val jacksonMapper = jacksonObjectMapper()

val jsonMasker = JsonMasker.getMasker(
    JsonMaskingConfig.builder()
        .maskJsonPaths(setOf("$.rgb.r", "$.opacity"))
        .build(),
);

fun log(value: Any) {
    val unmaskedJson = jacksonMapper.writeValueAsString(value)
    println("Unmasked:\n${unmaskedJson}\n")
    val maskedJson = jsonMasker.mask(unmaskedJson)
    println("Masked:\n${maskedJson}")
}

data class RGB(val r: String, val g: String, val b: String)
data class Opacity(val value: Double)
data class Color(val rgb: RGB, val opacity: Opacity)

Output:

Unmasked:
{"rgb":{"r":"255","g":"255","b":"255"},"opacity":{"value":0.95}}

Masked:
{"rgb":{"r":"***","g":"255","b":"255"},"opacity":{"value":"###"}}
like image 185
AndrewL Avatar answered Sep 02 '25 19:09

AndrewL