Implement nested log redaction (Telemetry-002)
RedactionEnricher now projects each property into a mutable view the ILogRedactor
can edit: scalars stay as their CLR value, while StructureValue/SequenceValue/
DictionaryValue become nested IDictionary<string,object?>/IList<object?> the
redactor descends into recursively. A field nested inside a destructured {@Object}
can now be masked or removed — closing the gap documented as a limitation.
- Project/Rebuild round-trip preserves StructureValue.TypeTag and original
dictionary keys; redactor-synthesised plain dicts/lists are rebuilt too.
- Untouched properties are not reallocated: structural ValueEquals skips write-back
unless a property actually changed. Scalar fast path and no-redactor/no-property
short-circuits retained.
- +5 nested-reach tests (mask/remove a field, sequence element, dictionary value,
two-levels-deep); the old 'cannot reach' limitation test replaced. Serilog 34, 0 warnings.
- ILogRedactor XML doc + library README updated to document the recursive reach.
This commit is contained in:
@@ -55,13 +55,19 @@ Trace↔log correlation is automatic: `TraceContextEnricher` reads `Activity.Cur
|
||||
log event and attaches `trace_id` and `span_id`, so log events produced inside a traced request
|
||||
carry the same span identity as the trace backend.
|
||||
|
||||
**Redaction reach.** A registered `ILogRedactor` may **remove** or **replace** any top-level
|
||||
property, and `RedactionEnricher` honours both (a removed key is dropped from the event). The seam
|
||||
sees the unwrapped value of scalar properties only — a destructured `{@Object}` property is exposed
|
||||
as its raw Serilog `StructureValue` wrapper, so a redactor can replace/remove the whole structured
|
||||
property but **cannot** mask a field nested inside it. To protect a sensitive field of a logged
|
||||
object, log it as its own scalar property (do not destructure it) or remove the whole property by
|
||||
key. See the `ILogRedactor` XML doc for the full contract.
|
||||
**Redaction reach.** A registered `ILogRedactor` may **remove** or **replace** any value, and
|
||||
`RedactionEnricher` honours both (a removed key is dropped from the event). Scalar properties appear
|
||||
as their unwrapped CLR value; **destructured** properties are projected into mutable views the
|
||||
redactor can descend into — a `{@Object}` is an `IDictionary<string, object?>` of its fields, a
|
||||
logged collection an `IList<object?>`, a logged dictionary an `IDictionary<string, object?>` — all
|
||||
recursively, so a field **nested inside** a destructured object can be masked or removed:
|
||||
|
||||
```csharp
|
||||
if (properties["command"] is IDictionary<string, object?> command) command["apiKey"] = "***";
|
||||
```
|
||||
|
||||
Structure type tags and dictionary keys are preserved on rebuild, and untouched properties are left
|
||||
intact (not reallocated). See the `ILogRedactor` XML doc for the full contract.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user