summaryrefslogtreecommitdiff
path: root/Mailman/loginit.py
blob: fac01c0fb826212517a51d33f1dcb37424c11d65 (plain) (blame)
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# Copyright (C) 2006 by the Free Software Foundation, Inc.
#
# This program 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 2
# of the License, or (at your option) any later version.
#
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

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

This module cannot be called 'logging' because that would interfere with the
import below.  Ah, for Python 2.5 and absolute imports.
"""

import os
import codecs
import logging

from Mailman.configuration import config

FMT     = '%(asctime)s (%(process)d) %(message)s'
DATEFMT = '%b %d %H:%M:%S %Y'
LOGGERS = (
    'bounce',
    'config',
    'error',
    'locks',
    'mischief',
    'post',
    'qrunner',
    'smtp',
    'smtp-failure',
    'subscribe',
    'vette',
    )

_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):
        self._stream.flush()

    def emit(self, record):
        try:
            msg = self.format(record)
            fs = '%s\n'
            try:
                self._stream.write(fs % msg)
            except UnicodeError:
                self._stream.write(fs % msg.encode('string-escape'))
            self.flush()
        except:
            self.handleError(record)

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

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



def initialize(propagate=False):
    # XXX Don't call logging.basicConfig() because in Python 2.3, it adds a
    # handler to the root logger that we don't want.  When Python 2.4 is the
    # minimum requirement, we can use basicConfig() with keyword arguments.
    #
    # The current set of Mailman logs are:
    #
    # error         - All exceptions go to this log
    # bounce        - All bounce processing logs go here
    # mischief      - Various types of hostile activity
    # post          - Information about messages posted to mailing lists
    # vette         - Information related to admindb activity
    # smtp          - Successful SMTP activity
    # smtp-failure  - Unsuccessful SMTP activity
    # subscribe     - Information about leaves/joins
    # config        - Configuration issues
    # locks         - Lock steals
    # qrunner       - qrunner start/stops
    #
    # There was also a 'debug' logger, but that was mostly unused, so instead
    # we'll use debug level on existing loggers.
    #
    # Start by creating a common formatter and the root logger.
    formatter = logging.Formatter(fmt=FMT, datefmt=DATEFMT)
    log = logging.getLogger('mailman')
    handler = logging.StreamHandler()
    handler.setFormatter(formatter)
    log.addHandler(handler)
    log.setLevel(logging.INFO)
    # Create the subloggers
    for logger in LOGGERS:
        log = logging.getLogger('mailman.' + logger)
        # 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 = propagate
        handler = ReopenableFileHandler(os.path.join(config.LOG_DIR, logger))
        _handlers.append(handler)
        handler.setFormatter(formatter)
        log.addHandler(handler)


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