Adds a `logging.FileHandler` to the attached engine's logger when the start event occurs and removes it again when then completed event occurs. A handler is needed to remove `FileHandler` object when the complete event occurs so that further runs of different engines write only to
| 27 | |
| 28 | |
| 29 | class LogfileHandler: |
| 30 | """ |
| 31 | Adds a `logging.FileHandler` to the attached engine's logger when the start event occurs and removes it again when |
| 32 | then completed event occurs. |
| 33 | |
| 34 | A handler is needed to remove `FileHandler` object when the complete event occurs so that further runs of different |
| 35 | engines write only to the log files they should, rather than previous files. Multiple handlers can write to the same |
| 36 | file which allows output from train and evaluation engine objects to be condensed in one file. If the given output |
| 37 | directory doesn't exist it will by default be created when the start event occurs. This can be used in conjunction |
| 38 | with `CheckpointSaver` to save a log file to the same destination as the saved checkpoints. Since the handler is |
| 39 | added possibly after other logging events during initialisation, not all logging data will be retained. |
| 40 | |
| 41 | Args: |
| 42 | output_dir: directory to save the log file to |
| 43 | filename: name of the file to save log to |
| 44 | loglevel: log level for the handler |
| 45 | formatter: format string for the `logging.Formatter` set for the handler |
| 46 | create_dir: if True, create `output_dir` if it doesn't exist |
| 47 | """ |
| 48 | |
| 49 | def __init__( |
| 50 | self, |
| 51 | output_dir: str, |
| 52 | filename: str = "log.txt", |
| 53 | loglevel: int = logging.INFO, |
| 54 | formatter: str = "%(asctime)s %(name)s %(levelname)s: %(message)s", |
| 55 | create_dir: bool = True, |
| 56 | ): |
| 57 | self.output_dir: str = output_dir |
| 58 | self.filename: str = filename |
| 59 | self.loglevel: int = loglevel |
| 60 | self.formatter: str = formatter |
| 61 | self.create_dir: bool = create_dir |
| 62 | self.logger: logging.Logger | None = None |
| 63 | self.handler: logging.FileHandler | None = None |
| 64 | |
| 65 | def attach(self, engine: Engine) -> None: |
| 66 | self.logger = engine.logger |
| 67 | engine.add_event_handler(Events.STARTED, self._start) |
| 68 | engine.add_event_handler(Events.COMPLETED, self._completed) |
| 69 | |
| 70 | def _start(self, engine: Engine) -> None: |
| 71 | if self.create_dir and not os.path.exists(self.output_dir): |
| 72 | os.makedirs(self.output_dir, exist_ok=True) |
| 73 | |
| 74 | self.handler = logging.FileHandler(os.path.join(self.output_dir, self.filename)) |
| 75 | self.handler.setLevel(self.loglevel) |
| 76 | self.handler.setFormatter(logging.Formatter(self.formatter)) |
| 77 | |
| 78 | if self.logger is not None: |
| 79 | self.logger.addHandler(self.handler) |
| 80 | else: |
| 81 | raise AttributeError("`self.logger` must not be None in start event") |
| 82 | |
| 83 | def _completed(self, engine: Engine) -> None: |
| 84 | if self.logger is not None and self.handler is not None: |
| 85 | self.logger.removeHandler(self.handler) |
| 86 | self.handler.close() |
no outgoing calls
searching dependent graphs…