Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | 164x 164x 164x 164x 164x 83x 83x 2x 81x 164x 164x 81x 164x 164x 19x 6419x 6419x 2082x 6419x | import type { AbstractMaskingInstruction } from "./MaskingInstruction.js";
/**
* LogMasker — applies masking instructions to log messages before clustering.
*
* Maps 1:1 to Python `LogMasker` class (drain3/masking.py).
*
* The masker scans raw log messages for recognized patterns (IP addresses,
* numbers, UUIDs, etc.) and replaces matched substrings with labeled
* placeholders like `<IP>`, `<NUM>`, or `<*>`.
*
* Masking runs BEFORE the Drain algorithm so that variable parts of log
* messages are normalized before tokenization and clustering. This
* dramatically improves template quality.
*
* Key design decisions:
* - Instructions are applied sequentially (not combined regex), matching
* Python behavior exactly. This ensures deterministic replacement order.
* - Multiple instructions can share the same mask name. This allows, for
* example, two different IP regex patterns that both produce `<IP>`.
* - The special mask name `"*"` indicates a catch-all parameter — any
* instruction with this name produces `<*>` in the output.
*/
export class LogMasker {
/** All masking instructions in application order. */
readonly instructions: readonly AbstractMaskingInstruction[];
/** Prefix wrapper for masked parameters (e.g. `<` in `<IP>`). */
readonly maskPrefix: string;
/** Suffix wrapper for masked parameters (e.g. `>` in `<IP>`). */
readonly maskSuffix: string;
/** Distinct mask names across all instructions. */
readonly maskNames: readonly string[];
/** Pre-built map: maskName → AbstractMaskingInstruction[] for fast lookup. */
private readonly _instructionsByName: ReadonlyMap<
string,
readonly AbstractMaskingInstruction[]
>;
/**
* Creates a LogMasker.
*
* @param instructions - Ordered list of masking instructions (applied sequentially).
* @param maskPrefix - Left delimiter for masked values. Default: `"<"`.
* @param maskSuffix - Right delimiter for masked values. Default: `">"`.
*/
constructor(
instructions: readonly AbstractMaskingInstruction[],
maskPrefix: string = "<",
maskSuffix: string = ">",
) {
this.instructions = instructions;
this.maskPrefix = maskPrefix;
this.maskSuffix = maskSuffix;
// Build mask name → instructions map
const byName = new Map<string, AbstractMaskingInstruction[]>();
for (const inst of instructions) {
const list = byName.get(inst.maskName);
if (list) {
list.push(inst);
} else {
byName.set(inst.maskName, [inst]);
}
}
// Freeze each list for immutability
const frozen = new Map<string, readonly AbstractMaskingInstruction[]>();
for (const [name, list] of byName) {
frozen.set(name, Object.freeze([...list]));
}
this._instructionsByName = frozen;
this.maskNames = Object.freeze([...frozen.keys()]);
}
/**
* Returns all instructions registered under the given mask name.
*
* Python: masker.instructions_by_mask_name(name)
*
* Useful for parameter extraction, where the engine needs to know
* which regex patterns correspond to which mask name.
*
* @param name - The mask name to look up (e.g. "IP", "NUM").
* @returns Frozen array of instructions, or empty array if none found.
*/
instructionsByMaskName(name: string): readonly AbstractMaskingInstruction[] {
return this._instructionsByName.get(name) ?? [];
}
/**
* Applies all masking instructions to a log message.
*
* Python: LogMasker.mask(s) → str
*
* Instructions are applied sequentially in the order they were
* registered. Each instruction's regex is matched globally, and all
* matches are replaced with `<MASK_NAME>` (using the configured
* prefix/suffix).
*
* Example:
* ```
* const masker = new LogMasker([NUM_MASK], "<", ">");
* masker.mask("error code 42 occurred");
* // → "error code <NUM> occurred"
* ```
*
* @param content - The raw log message to mask.
* @returns The masked log message with parameters replaced.
*/
mask(content: string): string {
let result = content;
for (const instruction of this.instructions) {
result = instruction.mask(result, this.maskPrefix, this.maskSuffix);
}
return result;
}
}
|