freezeInheritance method
Freezes the current inherited configurations into descendant loggers.
"Bakes" this logger's effective configs down the logger tree where children have not explicitly set a field. Useful for performance (reduces resolution depth) or to snapshot state so future parent changes don't propagate dynamically.
Parameters:
force: Whentrue, re-snapshots fields that are already frozen on descendants (updates them to this logger's current effective value). Explicit user overrides are never overwritten byforce. Defaults tofalse(original behaviour — skips already-set fields).
Returns the total number of fields written across all affected
descendants. A return value of 0 means the call was a complete no-op.
How to use:
- Call on a logger to apply to all descendants recursively via registry.
force: trueis useful after a parent config change to re-snapshot.
Example: final written = parentLogger.freezeInheritance(); parentLogger.freezeInheritance(force: true); // re-snapshot
Implementation
int freezeInheritance({final bool force = false}) {
final callerConfig = _registry[name];
if (callerConfig != null &&
callerConfig.implicit &&
callerConfig.frozenFields.isEmpty) {
InternalLogger.log(
LogLevel.warning,
"freezeInheritance() called on implicit node '$name'. "
'This node was never explicitly configured. The freeze will propagate '
"resolved defaults. Consider calling Logger.configure('$name', ...) "
'first if intentional.',
);
}
int writtenCount = 0;
for (final key in _registry.keys) {
if (key == name || _isDescendant(key, name)) {
final childConfig = _registry[key]!;
bool changed = false;
// Helper: should this field be written?
// force=false → only if null; force=true → if null OR already frozen
// (but never if explicitly set by user).
bool shouldWrite({
required final String field,
required final bool isNull,
}) =>
isNull || (force && childConfig.frozenFields.contains(field));
final nextFrozenFields = Set<String>.from(childConfig.frozenFields);
bool? newEnabled = childConfig.enabled;
LogLevel? newLogLevel = childConfig.logLevel;
bool? newIncludeFileLineInHeader = childConfig.includeFileLineInHeader;
bool? newIncludeOrigin = childConfig.includeOrigin;
Map<LogLevel, int>? newStackMethodCount = childConfig.stackMethodCount;
Timestamp? newTimestamp = childConfig.timestamp;
StackTraceParser? newStackTraceParser = childConfig.stackTraceParser;
List<Handler>? newHandlers = childConfig.handlers;
bool? newAutoSinkBuffer = childConfig.autoSinkBuffer;
if (shouldWrite(
field: 'enabled',
isNull: childConfig.enabled == null,
)) {
newEnabled = enabled;
nextFrozenFields.add('enabled');
changed = true;
writtenCount++;
}
if (shouldWrite(
field: 'logLevel',
isNull: childConfig.logLevel == null,
)) {
newLogLevel = logLevel;
nextFrozenFields.add('logLevel');
changed = true;
writtenCount++;
}
if (shouldWrite(
field: 'includeFileLineInHeader',
isNull: childConfig.includeFileLineInHeader == null,
)) {
newIncludeFileLineInHeader = includeFileLineInHeader;
nextFrozenFields.add('includeFileLineInHeader');
changed = true;
writtenCount++;
}
if (shouldWrite(
field: 'includeOrigin',
isNull: childConfig.includeOrigin == null,
)) {
newIncludeOrigin = includeOrigin;
nextFrozenFields.add('includeOrigin');
changed = true;
writtenCount++;
}
if (shouldWrite(
field: 'stackMethodCount',
isNull: childConfig.stackMethodCount == null,
)) {
newStackMethodCount = Map.from(stackMethodCount);
nextFrozenFields.add('stackMethodCount');
changed = true;
writtenCount++;
}
if (shouldWrite(
field: 'timestamp',
isNull: childConfig.timestamp == null,
)) {
newTimestamp = timestamp;
nextFrozenFields.add('timestamp');
changed = true;
writtenCount++;
}
if (shouldWrite(
field: 'stackTraceParser',
isNull: childConfig.stackTraceParser == null,
)) {
newStackTraceParser = stackTraceParser;
nextFrozenFields.add('stackTraceParser');
changed = true;
writtenCount++;
}
if (shouldWrite(
field: 'handlers',
isNull: childConfig.handlers == null,
)) {
newHandlers = List.from(handlers);
nextFrozenFields.add('handlers');
changed = true;
writtenCount++;
}
if (shouldWrite(
field: 'autoSinkBuffer',
isNull: childConfig.autoSinkBuffer == null,
)) {
newAutoSinkBuffer = autoSinkBuffer;
nextFrozenFields.add('autoSinkBuffer');
changed = true;
writtenCount++;
}
if (changed) {
_registry[key] = childConfig.copyWith(
enabled: newEnabled,
logLevel: newLogLevel,
includeFileLineInHeader: newIncludeFileLineInHeader,
includeOrigin: newIncludeOrigin,
stackMethodCount: newStackMethodCount,
timestamp: newTimestamp,
stackTraceParser: newStackTraceParser,
handlers: newHandlers,
autoSinkBuffer: newAutoSinkBuffer,
version: childConfig.version + 1,
frozenFields: nextFrozenFields,
);
LoggerCache.invalidate(key);
}
}
}
return writtenCount;
}