diff --git a/link/adapters/present.py b/link/adapters/present.py index 09c13bf..fb20f57 100644 --- a/link/adapters/present.py +++ b/link/adapters/present.py @@ -18,3 +18,23 @@ def update_idle_entities(response: events.IdleEntitiesListed) -> None: update(translator.to_primary_key(identifier) for identifier in response.identifiers) return update_idle_entities + + +def create_state_change_logger( + translator: IdentificationTranslator, log: Callable[[str], None] +) -> Callable[[events.StateChanged], None]: + """Create a logger that logs state changes of entities.""" + + def log_state_change(state_change: events.StateChanged) -> None: + context = { + "identifier": translator.to_primary_key(state_change.identifier), + "operation": state_change.operation.name, + "transition": { + "old": state_change.transition.current.__name__, + "new": state_change.transition.new.__name__, + }, + "command": state_change.command.name, + } + log(f"Entity state changed {context}") + + return log_state_change diff --git a/link/infrastructure/link.py b/link/infrastructure/link.py index e407a3c..06f0f77 100644 --- a/link/infrastructure/link.py +++ b/link/infrastructure/link.py @@ -1,6 +1,7 @@ """Contains the link decorator that is used by the user to establish a link.""" from __future__ import annotations +import logging from collections.abc import Callable from functools import partial from typing import Any, Mapping, Optional @@ -9,9 +10,9 @@ from link.adapters.custom_types import PrimaryKey from link.adapters.gateway import DJLinkGateway from link.adapters.identification import IdentificationTranslator -from link.adapters.present import create_idle_entities_updater +from link.adapters.present import create_idle_entities_updater, create_state_change_logger from link.domain import commands, events -from link.service.handlers import delete, list_idle_entities, pull +from link.service.handlers import delete, list_idle_entities, log_state_change, pull from link.service.messagebus import CommandHandlers, EventHandlers, MessageBus from link.service.uow import UnitOfWork @@ -46,6 +47,7 @@ def inner(obj: type) -> Any: uow = UnitOfWork(gateway) source_restriction: IterationCallbackList[PrimaryKey] = IterationCallbackList() idle_entities_updater = create_idle_entities_updater(translator, create_content_replacer(source_restriction)) + logger = logging.getLogger(obj.__name__) command_handlers: CommandHandlers = {} command_handlers[commands.PullEntities] = partial(pull, uow=uow) command_handlers[commands.DeleteEntities] = partial(delete, uow=uow) @@ -53,7 +55,9 @@ def inner(obj: type) -> Any: list_idle_entities, uow=uow, output_port=idle_entities_updater ) event_handlers: EventHandlers = {} - event_handlers[events.StateChanged] = [lambda event: None] + event_handlers[events.StateChanged] = [ + partial(log_state_change, log=create_state_change_logger(translator, logger.info)) + ] event_handlers[events.InvalidOperationRequested] = [lambda event: None] bus = MessageBus(uow, command_handlers, event_handlers) controller = DJController(bus, translator) diff --git a/link/service/handlers.py b/link/service/handlers.py index d3bdfe5..625c9c7 100644 --- a/link/service/handlers.py +++ b/link/service/handlers.py @@ -32,3 +32,8 @@ def list_idle_entities( with uow: idle = uow.link.list_idle_entities() output_port(events.IdleEntitiesListed(idle)) + + +def log_state_change(event: events.StateChanged, log: Callable[[events.StateChanged], None]) -> None: + """Log the state change of an entity.""" + log(event)