summaryrefslogtreecommitdiff
path: root/mailman/core/logging.py
blob: 608b59c2c3f93ffa39cade13887ac6321b1fb44a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# Copyright (C) 2006-2008 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
# GNU Mailman is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# GNU Mailman.  If not, see <http://www.gnu.org/licenses/>.

"""Logging initialization, using Python's standard logging package."""

from __future__ import absolute_import

import os
import sys
import codecs
import logging
import ConfigParser

from mailman.config import config
from mailman.config.helpers import as_boolean, as_log_level


_handlers = []



class ReopenableFileHandler(logging.Handler):
    def __init__(self, filename):
        self._filename = filename
        self._stream = self._open()
        logging.Handler.__init__(self)

    def _open(self):
        return codecs.open(self._filename, 'a', 'utf-8')

    def flush(self):
        if self._stream:
            self._stream.flush()

    def emit(self, record):
        # It's possible for the stream to have been closed by the time we get
        # here, due to the shut down semantics.  This mostly happens in the
        # test suite, but be defensive anyway.
        stream = (self._stream if self._stream else sys.stderr)
        try:
            msg = self.format(record)
            fs = '%s\n'
            try:
                stream.write(fs % msg)
            except UnicodeError:
                stream.write(fs % msg.encode('string-escape'))
            self.flush()
        except:
            self.handleError(record)

    def close(self):
        self.flush()
        self._stream.close()
        self._stream = None
        logging.Handler.close(self)

    def reopen(self):
        self._stream.close()
        self._stream = self._open()



def initialize(propagate=False):
    # First, find the root logger and configure the logging subsystem.
    # Initialize the root logger, then create a formatter for all the sublogs.
    logging.basicConfig(format=config.logging.root.format,
                        datefmt=config.logging.root.datefmt,
                        level=as_log_level(config.logging.root.level))
    # Create the subloggers
    for logger_config in config.logger_configs:
        logger_name = 'mailman.' + logger_config.name.split('.')[-1]
        log = logging.getLogger(logger_name)
        # Get settings from log configuration file (or defaults).
        log_format      = logger_config.format
        log_datefmt     = logger_config.datefmt
        # Propagation to the root logger is how we handle logging to stderr
        # when the qrunners are not run as a subprocess of mailmanctl.
        log.propagate   = as_boolean(logger_config.propagate)
        # Set the logger's level.
        log.setLevel(as_log_level(logger_config.level))
        # Create a formatter for this logger, then a handler, and link the
        # formatter to the handler.
        formatter = logging.Formatter(fmt=log_format, datefmt=log_datefmt)
        path_str  = logger_config.path
        path_abs  = os.path.normpath(os.path.join(config.LOG_DIR, path_str))
        handler   = ReopenableFileHandler(path_abs)
        _handlers.append(handler)
        handler.setFormatter(formatter)
        log.addHandler(handler)



def reopen():
    for handler in _handlers:
        handler.reopen()