Pudu programming language
Menu
Package

@chrismichaelps / pudu-lang-log

Structured event logging for Pudu: message templates, enrichment, filtering, formatting, and sinks

0.1.0Apache-2.01

InstallClose

Masking.pudu

Pudu82 lines3.7 KB

GitHub ↗
1/** @Log.Domain.Masking.Module — sensitive members and text hidden in values */2module PuduLangLog.Domain.Masking34import Std.Regex as Regex5import PuduLangLog as Log67/// The value with every structure member and dictionary entry of a listed name, at any depth,8/// replaced by the mask text; names compare ignoring case.9export fn members(held: &Log.Value, names: &Array[Str], mask: Str) -> Log.Value {10  match held {11    case Log.Scalar(_) => *held12    case Log.Sequence(items) => Log.Sequence(items.map(|item: Log.Value| members(&item, names, mask)))13    case Log.Structure(shape) => Log.Structure(Log.Structure {14        ..shape,15        properties: shape.properties.map(|member: Log.Property| property(&member, names, mask))16      })17    case Log.Dictionary(entries) => Log.Dictionary(entries.map(|entry: Log.Entry| Log.Entry {18          key: entry.key,19          value: match entry.key {20            case Log.Text(key) => if listed(names, key) { Log.Scalar(Log.Text(mask)) } else { members(&entry.value, names, mask) }21            case _ => members(&entry.value, names, mask)22          }23        }))24  }25}2627/// The property with its value replaced by the mask text when its name is listed, and otherwise28/// with its listed members hidden.29export fn property(named: &Log.Property, names: &Array[Str], mask: Str) -> Log.Property {30  Log.Property{name: named.name, value: if listed(names, named.name) { Log.Scalar(Log.Text(mask)) } else { members(&named.value, names, mask) }}31}3233/// The value with every match of the patterns inside its text, at any depth, replaced by the mask34/// text. Keys and other scalars are kept.35export fn text(held: &Log.Value, patterns: &Array[Regex.Regex], mask: Str) -> Log.Value {36  match held {37    case Log.Scalar(Log.Text(written)) => {38      var masked = written39      for pattern in patterns { masked = Regex.replaceAll(&pattern, masked, mask) }40      Log.Scalar(Log.Text(masked))41    }42    case Log.Scalar(_) => *held43    case Log.Sequence(items) => Log.Sequence(items.map(|item: Log.Value| text(&item, patterns, mask)))44    case Log.Structure(shape) => Log.Structure(Log.Structure{..shape, properties: shape.properties.map(|member: Log.Property| Log.Property{name: member.name, value: text(&member.value, patterns, mask)})})45    case Log.Dictionary(entries) => Log.Dictionary(entries.map(|entry: Log.Entry| Log.Entry{key: entry.key, value: text(&entry.value, patterns, mask)}))46  }47}4849/// A structure of the tag without its listed members, or none for any other value; names compare50/// ignoring case.51export fn ignoring(held: &Log.Value, tag: Str, names: &Array[Str]) -> Option[Log.Value] {52  let shape = tagged(held, tag) ?53  Some(Log.Structure(Log.Structure{..shape, properties: shape.properties.filter(|member: Log.Property| !listed(names, member.name))}))54}5556/// A structure of the tag with its listed members replaced by the mask text, or none for any other57/// value; names compare ignoring case.58export fn masking(held: &Log.Value, tag: Str, names: &Array[Str], mask: Str) -> Option[Log.Value] {59  let shape = tagged(held, tag) ?60  Some(Log.Structure(Log.Structure {61        ..shape,62        properties: shape.properties.map(|member: Log.Property| if listed(names, member.name) { Log.Property{name: member.name, value: Log.Scalar(Log.Text(mask))} } else { member })63      }))64}6566/// The structure of a value when it carries the tag.67fn tagged(held: &Log.Value, tag: Str) -> Option[Log.Structure] {68  match held {69    case Log.Structure(shape) => if shape.tag == Some(tag) { Some(shape) } else { None }70    case _ => None71  }72}7374/// Whether a name is listed, ignoring case.75fn listed(names: &Array[Str], name: Str) -> Bool {76  let lowered = name.toLower()77  for candidate in names {78    if candidate.toLower() == lowered { return true }79  }80  false81}82