docs: add user guide, cookbook, and rewrite README

This commit is contained in:
Tiara Rodney 2026-03-14 04:33:53 +01:00
parent 741b959820
commit 1a74f2afa4
No known key found for this signature in database
GPG key ID: 5CD8EC1D46106723
3 changed files with 621 additions and 54 deletions

View file

@ -1,37 +1,216 @@
# Using logging in multiple modules
# Logging cookbook
Multiple calls to `logging.getLogger('someLogger')` return a reference to the
same logger object. This is true not only within the same module, but also
across modules as long as it is in the same Python interpreter process. It is
true for references to the same object; additionally, application code can
define and configure a parent logger in one module and create (but not
configure) a child logger in a separate module, and all logger calls to the
child will pass up to the parent. Here is a main module:
Recipes and patterns for common logging tasks with `@administratrix/esm-logging`.
``javascript
import * as logging from 'eslib/logging';
import * as my_module from './my_module';
## Using logging across multiple modules
// create logger with 'spam_application'
var logger = logging.getLogger('spam_application');
logger.setLevel(logging.DEBUG);
`getLogger` returns the same logger instance for a given scope name across
your entire application. Configure handlers on a parent logger and create
child loggers in each module:
// create file handler which logs even debug messages
var fh = logging.FileHandler('spam.log')
fh.setLevel(logging.DEBUG);
```javascript
// main.js
import * as logging from '@administratrix/esm-logging';
import { ConsoleHandler } from '@administratrix/esm-logging/src/handler';
import { Formatter } from '@administratrix/esm-logging/src/formatter';
import { doWork } from './worker.js';
// create console handler with a higher log level
var ch = logging.StreamHandler();
ch.setLevel(logging.ERROR);
const logger = logging.manager.MANAGER.getLogger('myapp');
logger.setLevel(logging.log_level.DEBUG);
// create formatter and add it to the handlers
var formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s');
fh.setFormatter(formatter);
ch.setFormatter(formatter);
const handler = new ConsoleHandler();
handler.level = logging.log_level.DEBUG;
handler.formatter = new Formatter({
fmt: '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
});
logger.addHandler(handler);
// add the handlers to the logger
logger.addHandler(fh);
logger.addHandler(ch);
logger.info('creating an instance of auxiliary_module.Auxiliary')
logger.info('Application starting');
doWork();
logger.info('Application finished');
```
```javascript
// worker.js
import * as logging from '@administratrix/esm-logging';
const logger = logging.manager.MANAGER.getLogger('myapp.worker');
export function doWork() {
logger.debug('Starting work');
// ... do something ...
logger.info('Work completed');
}
```
Because `myapp.worker` is a child of `myapp`, its records propagate up to the
handler configured on `myapp`. No handler configuration is needed in
`worker.js`.
Output:
```
2026-03-14 10:00:00.000 - myapp - INFO - Application starting
2026-03-14 10:00:00.001 - myapp.worker - DEBUG - Starting work
2026-03-14 10:00:00.002 - myapp.worker - INFO - Work completed
2026-03-14 10:00:00.003 - myapp - INFO - Application finished
```
## Logging to multiple destinations
Attach multiple handlers to a single logger, each with its own level and
formatter:
```javascript
import * as logging from '@administratrix/esm-logging';
import { ConsoleHandler, StderrHandler } from '@administratrix/esm-logging/src/handler';
import { Formatter } from '@administratrix/esm-logging/src/formatter';
const logger = logging.manager.MANAGER.getLogger('myapp');
logger.setLevel(logging.log_level.DEBUG);
// console handler: shows everything with detailed format
const consoleHandler = new ConsoleHandler();
consoleHandler.level = logging.log_level.DEBUG;
consoleHandler.formatter = new Formatter({
fmt: '%(asctime)s [%(levelname)s] %(name)s: %(message)s',
});
logger.addHandler(consoleHandler);
// stderr handler: only errors, compact format
const errorHandler = new StderrHandler(logging.log_level.ERROR);
errorHandler.formatter = new Formatter({
fmt: 'ERROR %(asctime)s %(name)s: %(message)s',
datefmt: '%Y-%m-%d %H:%M:%S',
});
logger.addHandler(errorHandler);
```
## Using basicConfig for simple scripts
For quick scripts, `basicConfig` sets up a handler on the root logger:
```javascript
import * as logging from '@administratrix/esm-logging';
logging.config.basicConfig({
level: logging.log_level.INFO,
format: '%(levelname)s: %(message)s',
});
const logger = logging.manager.MANAGER.getLogger('script');
logger.info('Running');
logger.warning('Check this');
```
Output:
```
INFO: Running
WARNING: Check this
```
## Filtering records
### By scope
Only allow records from a specific part of the hierarchy:
```javascript
import { Filter } from '@administratrix/esm-logging/src/filter';
const dbFilter = new Filter('myapp.db');
handler.addFilter(dbFilter);
// handler now only processes records from 'myapp.db' and its children
```
### By custom criteria
Use any object with a `filter(record)` method:
```javascript
handler.addFilter({
filter(record) {
// only pass records that contain 'important' in the message
return record.msg.includes('important');
}
});
```
## Custom formatters
Create formatters with different format strings for different contexts:
```javascript
import { Formatter } from '@administratrix/esm-logging/src/formatter';
// detailed format for development
const devFormatter = new Formatter({
fmt: '%(asctime)s %(levelname)s %(name)s: %(message)s',
datefmt: '%H:%M:%S',
});
// compact format for production
const prodFormatter = new Formatter({
fmt: '%(levelname)s:%(name)s:%(message)s',
});
```
## Custom handlers
Subclass `Handler` and implement `emit(record)`:
```javascript
import { Handler } from '@administratrix/esm-logging/src/handler';
class BufferHandler extends Handler {
constructor(level) {
super(level);
this.buffer = [];
}
emit(record) {
try {
this.buffer.push(this.format(record));
if (this.buffer.length >= 100) {
this.flush();
}
} catch (e) {
this.handleError(record);
}
}
flush() {
// send buffered records somewhere
const batch = this.buffer.splice(0);
// ... process batch ...
}
}
```
## Disabling logging below a threshold
The manager's `disable` property suppresses all logging at or below a given
level across all loggers:
```javascript
import * as logging from '@administratrix/esm-logging';
// suppress DEBUG and INFO globally
logging.manager.MANAGER.disable = logging.log_level.INFO;
```
## Reconfiguring with force
`basicConfig` only takes effect once. To reconfigure, use `force: true`:
```javascript
logging.config.basicConfig({
level: logging.log_level.DEBUG,
format: '%(asctime)s %(message)s',
force: true,
});
```
This removes and closes all existing handlers on the root logger before
applying the new configuration.