#!/usr/bin/env python3
# The MIT License (MIT)
#
# Copyright (c) 2014-2018 <see AUTHORS.txt>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# Modules
# ------------------------------------------------
# std
import logging
import logging.handlers
import os
import queue
# ...
# ------------------------------------------------
__all__ = [
"Logger"
]
# Classes
# ------------------------------------------------
[docs]class Logger(object):
"""
Sets the *root* :class:`logging.Logger` up.
The EMSM logger queues all log records until the :file:`emsm.log` can be
acquired without side effects. This is the case, when the
:class:`~emsm.core.application.Application` acquired the *file lock*.
The queued records are then pushed to the :file:`emsm.log`.
The EMSM logging stategy requires, that each module uses its own
logger instance:
.. code-block:: python
>>> import logging
>>> log = logging.getLogger(__file__)
"""
def __init__(self, app):
"""
"""
self._app = app
self._log_dir = app.paths().logs()
# The root logger
self._root_log = logging.getLogger()
self._root_log.setLevel(logging.INFO)
# The EMSM log format.
self._log_format = logging.Formatter(
fmt="[{asctime}][{levelname:8}][{module:25}] {message}",
datefmt="%Y-%m-%d %H:%M:%S", style="{"
)
# Used to store the log records until we can access the *emsm.log*.
# As soon as *emsm.log* is opened, we write all records in the queue
# to the log file.
# These attributes are set to None, as soon as the log file is opened.
self._log_queue = queue.Queue()
self._log_queue_handler = logging.handlers.QueueHandler(self._log_queue)
self._root_log.addHandler(self._log_queue_handler)
# The FileHandler for the EMSM log file (usually *emsm.log*)
# The file is opened, as soon as the Application acquired the file lock.
#
# See also:
# * setup()
self._log_file_handler = None
return None
[docs] def setup(self):
"""
Opens the :file:`emsm.log` and pushes all queued log recods to the log
file.
.. hint::
This method requires that the Application aquired the file lock.
"""
# We use the rotating file handler so that the logfiles are
# automatically compressed, when they are bigger than 10mb.
self._log_file_handler = logging.handlers.RotatingFileHandler(
os.path.join(self._log_dir, "emsm.log"),
maxBytes = 10*1024**2,
backupCount = 5
)
self._log_file_handler.setFormatter(self._log_format)
# Push the queued records to the file handler.
while not self._log_queue.empty():
record = self._log_queue.get(block=False)
self._log_file_handler.handle(record)
# Add the file handler to the root logger and remove the queue handler.
self._root_log.addHandler(self._log_file_handler)
self._root_log.removeHandler(self._log_queue_handler)
self._log_queue_handler = None
self._log_queue = None
return None