-
Notifications
You must be signed in to change notification settings - Fork 1
Compact Filter
LunarECL edited this page Feb 17, 2026
·
1 revision
Concise, grep-inspired shorthand for defining log filters. Complements the full DSL (addFilterRule) with ergonomic one-liners for common patterns.
// Instead of:
logger.addFilterRule("level >= WARN");
logger.addFilterRule("not message contains 'heartbeat'");
// Write:
logger.filter("WARN+ !~heartbeat");| Pattern | Meaning | Equivalent DSL |
|---|---|---|
LEVEL+ |
Level >= LEVEL | level >= LEVEL |
~keyword |
Message contains keyword | message contains 'keyword' |
!~keyword |
NOT contains keyword | not message contains 'keyword' |
ctx:key |
Context has key | context has 'key' |
ctx:key=val |
Context key equals value | context key == 'val' |
tpl:pattern |
Template equals pattern | template == 'pattern' |
!tpl:pattern |
Template NOT equals | not template == 'pattern' |
-
Space-separated = AND:
"WARN+ ~error"means both conditions must pass -
Level names are case-insensitive:
warn+=WARN+=Warn+ -
WARNINGaccepted as alias forWARN:WARNING+works -
Keywords are case-sensitive:
~Error≠~error
Keywords or values containing spaces need quoting:
logger.filter("~\"connection reset\""); // double quotes
logger.filter("ctx:msg=\"hello world\""); // quoted valueBoth single and double quotes work for the outer delimiter, but values cannot contain single quotes (DSL limitation). Use addFilterRule() or setFilter() predicate for values with '.
minta::LunarLog logger(minta::LogLevel::TRACE);
logger.filter("WARN+"); // only WARN and above
logger.filter("~timeout"); // must contain "timeout"
logger.filter("ctx:userId"); // must have userId in context
logger.filter("ctx:env=prod"); // context env must be "prod"
logger.filter("!~heartbeat"); // suppress heartbeat messages
// Multiple conditions in one call (AND-combined)
logger.filter("WARN+ ~error ctx:env=prod");Works with Named Sinks:
logger.addSink<minta::ConsoleSink>(minta::named("console"));
logger.addSink<minta::FileSink>(minta::named("errors"), "errors.log");
logger.addSink<minta::FileSink>(minta::named("audit"), "audit.log");
logger.sink("errors").filter("ERROR+");
logger.sink("console").filter("!~heartbeat !~health");
logger.sink("audit").filter("ctx:audit=true");Compact filters and full DSL rules coexist. All rules are AND-combined:
// Compact for simple rules
logger.filter("WARN+");
// Full DSL for complex rules
logger.addFilterRule("context has 'request_id'");
logger.addFilterRule("not template contains 'internal'");
// Both apply — entry must pass all rulesInvalid compact filter expressions throw std::invalid_argument:
try {
logger.filter("UNKNOWN+"); // unrecognized token
} catch (const std::invalid_argument& e) {
// "Unrecognized compact filter token: UNKNOWN+"
}
try {
logger.filter("~\"unterminated"); // missing closing quote
} catch (const std::invalid_argument& e) {
// "Unterminated quote in compact filter expression"
}
try {
logger.filter("~\"it's\""); // single quote in value
} catch (const std::invalid_argument& e) {
// suggests using addFilterRule() instead
}Empty expressions are silently ignored (no rules added):
logger.filter(""); // no-op
logger.filter(" "); // no-op-
LunarLog::filter()acquires the global filter mutex — safe to call concurrently with logging -
SinkProxy::filter()uses atomic batch addition (addFilterRules) — all rules in the expression become visible simultaneously
Compact filter rules are stored as regular filter rules. Clear them with the same methods:
logger.clearFilterRules(); // clears all global rules (compact + DSL)
logger.clearAllFilters(); // clears predicate + all rules
// Per-sink
logger.sink("errors").clearFilterRules();
logger.sink("errors").clearFilters();-
No OR logic: space-separated tokens are always AND. For OR, use separate
filter()calls or the full DSL -
No single quotes in values: DSL parser limitation. Use
addFilterRule()with predicate for these cases -
No escape sequences in quoted strings:
\"inside quotes is treated literally - Context keys with spaces: not supported (DSL limitation)
| Method | Scope | Description |
|---|---|---|
logger.filter(expr) |
Global | Parse compact expression, add rules under global mutex |
sink.filter(expr) |
Per-sink | Parse compact expression, add rules atomically to sink |
See also: Filtering, API Reference