On this page
Utility system logger๏
๐ Advanced ยท Lesson 04
Logging through the AetherUtilitySystem - the process-wide provider host every runtime object resolves its logger from. THE BOOT LAW: melder boots SILENT. Aether starts with a null SafeLogger and stays quiet until YOU attach something - no surprise stdout, no library spam. Two public doors: aether.attach_logger(logger) - attach one real logger (stdlib Logger or channel-style), or None to detach back to silence aether.enable_logging(logger) - attach explicitly, or with no argument try the configured automatic channel-logger policy Runtime objects (books, conduits, the frames themselves) resolve their loggers through the utility system's provider path.
Before you run๏
Use the Advanced guide for prerequisite concepts. Run from a checkout with Melder installed and Python 3.14 free-threading selected. The collection download includes the level's local helper modules.
Run the saved script๏
python UX_and_AIX_experiences/03_advanced/04_utility_system_logger.py
py -3.14t UX_and_AIX_experiences/03_advanced/04_utility_system_logger.py
Public surface๏
md.Aether().attach_logger, enable_logging, the boots-silent law
Code๏
1"""
2TIER: advanced (04)
3GOAL: Logging through the AetherUtilitySystem - the process-wide
4 provider host every runtime object resolves its logger from.
5 THE BOOT LAW: melder boots SILENT. Aether starts with a null
6 SafeLogger and stays quiet until YOU attach something - no
7 surprise stdout, no library spam. Two public doors:
8 aether.attach_logger(logger) - attach one real logger (stdlib
9 Logger or channel-style), or
10 None to detach back to silence
11 aether.enable_logging(logger) - attach explicitly, or with no
12 argument try the configured
13 automatic channel-logger policy
14 Runtime objects (books, conduits, the frames themselves) resolve
15 their loggers through the utility system's provider path.
16SURFACE EXERCISED: md.Aether().attach_logger, enable_logging,
17 the boots-silent law
18"""
19import logging
20
21import melder as md
22
23
24class CollectingHandler(logging.Handler):
25 """A tiny handler that keeps every record it sees."""
26
27 def __init__(self) -> None:
28 """Create an empty record sink owned by this demonstration."""
29 super().__init__()
30 self.records = []
31
32 def emit(self, record: logging.LogRecord) -> None:
33 """Retain the delivered record so the caller can inspect logger output."""
34 self.records.append(record)
35
36
37def main() -> None:
38 """Verify public attach, detach, and explicit enable behavior; release the handler."""
39 aether = md.Aether()
40
41 # Build a real stdlib logger with a capturing handler...
42 handler = CollectingHandler()
43 logger = logging.getLogger("melder-advanced-05")
44 logger.setLevel(logging.DEBUG)
45 logger.addHandler(handler)
46
47 # ...and attach it through the public post-boot seam.
48 aether.attach_logger(logger)
49 assert aether.logger is logger
50 print("logger attached; the world is no longer silent")
51
52 # Detaching is the same door with None - back to the null wrapper.
53 aether.attach_logger(None)
54 assert aether.logger is None
55 print("detached; melder is silent again (the boot default)")
56
57 # enable_logging(explicit) is attach; enable_logging() with no
58 # argument asks the configured channel policy instead.
59 aether.enable_logging(logger)
60 assert aether.logger is logger
61 print("enable_logging(explicit) attached the same logger")
62 aether.attach_logger(None)
63 assert aether.logger is None
64 logger.removeHandler(handler)
65 handler.close()
66
67
68if __name__ == "__main__":
69 main()
Check the outcome๏
The script contains its own assertions or demonstrated refusal paths. Run it to evaluate those checks against your installed version. The code above is taken directly from the saved file; no run output is invented here.