# Logging System PlestyLib uses Python built-in logging throughout device, traffic, service, and utility layers. Central setup helper: `setup_logging` in `plesty.lib.utils.logger`. ## Purpose The logging system is used to: 1. Track device lifecycle events (connect, disconnect, query, write). 2. Record communication events in traffic managers. 3. Capture warnings and errors from validation and exception handling. 4. Provide file-based logs for troubleshooting and reproducibility. ## Setup API ```python from plesty.lib.utils.logger import setup_logging setup_logging(app_name="powermeter", level="INFO", console_print=True) ``` Function signature: ```python setup_logging(app_name, level: str = "INFO", console_print: bool = True) ``` Parameters: 1. `app_name`: Prefix used in log filename. 2. `level`: Log level string (`DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`). 3. `console_print`: If true, logs are sent to console in addition to file. ## Output Behavior When `setup_logging` runs: 1. Creates `logs/` in current working directory if missing. 2. Creates a timestamped log file: `logs/_YYYY-MM-DD_HH-MM-SS.log` 3. Configures logging format: `%(asctime)s | %(levelname)s | %(name)s | %(message)s` ## Minimal Example ```python from plesty.lib.utils.logger import setup_logging setup_logging(app_name="pm100d", level="DEBUG", console_print=True) # Then run your normal device logic. ``` ## Typical Integration Pattern Call setup once at process startup, before creating device instances: ```python import logging from plesty.lib.utils.logger import setup_logging from powermeter_device import PowermeterDevice setup_logging(app_name="powermeter_service", level="INFO", console_print=True) with PowermeterDevice("USB0::0x1313::0x8078::P0000001::INSTR", sensor_type="S155C") as dev: print(dev.identity()) logging.info("Connected to PM100D") logging.debug("Debug trace for identity query complete") ``` ## Developer Example Use this pattern when building or debugging a new device API implementation. ```python import logging from plesty.lib.device.base_tcp_scpi_device import BaseTCPScpiDevice class DemoScpiDevice(BaseTCPScpiDevice): def __init__(self, host: str, port: int): super().__init__(host=host, port=port) self.register_config("POWER", dtype=float, read_only=True, command="MEAS:POW") logging.info("Initialization finished.") def some_utility_function(): try: # do something logging.debug("xxx done") except Exception as e: logging.error(f"Error: {e}") ``` Why this helps developers: 1. `DEBUG` level captures fine-grained query/write traces. 2. File logs in `logs/` preserve run history for troubleshooting. 3. Console output helps while iterating quickly. ## End User Example Use this pattern in production-like scripts where operators mainly need status and errors. ```python import logging from plesty.lib.utils.logger import setup_logging from powermeter_device import PowermeterDevice setup_logging(app_name="powermeter_run", level="INFO", console_print=True) address = "USB0::0x1313::0x8078::P0000001::INSTR" try: with PowermeterDevice(address, sensor_type="S155C") as dev: value = dev.query("POWER") print(f"Power: {value}") logging.info(f"Measured power: {value}") except Exception as e: logging.error(f"Measurement failed: {e}") ``` Why this fits end users: 1. `INFO` level keeps output readable. 2. Important status/error events are visible without debug noise. 3. File logs can be attached when reporting issues. ## Where Logs Come From You will see logs from multiple layers, for example: 1. Base device classes: query and write operations. 2. Traffic managers: open/close/send/receive events. 3. Error handling utility: warnings and exceptions. 4. TCP server/client service components. ## Notes and Caveats 1. `logging.basicConfig` is process-global and typically only applies once. 2. If logging was configured earlier (by your app or tests), calling `setup_logging` later may not replace existing handlers. 3. Log file path is relative to the process current working directory. ## Recommended Practices 1. Call `setup_logging` at entry point (`__main__`, service launcher, test harness). 2. Use `DEBUG` only when diagnosing issues; use `INFO` for normal runs. 3. Keep `console_print=True` for interactive sessions. 4. Keep `console_print=False` for long-running services if console output is noisy. 5. Include clear device IDs/addresses in your own log messages for traceability.