xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/logging/handlers.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker# Copyright 2001-2021 by Vinay Sajip. All Rights Reserved.
2*cda5da8dSAndroid Build Coastguard Worker#
3*cda5da8dSAndroid Build Coastguard Worker# Permission to use, copy, modify, and distribute this software and its
4*cda5da8dSAndroid Build Coastguard Worker# documentation for any purpose and without fee is hereby granted,
5*cda5da8dSAndroid Build Coastguard Worker# provided that the above copyright notice appear in all copies and that
6*cda5da8dSAndroid Build Coastguard Worker# both that copyright notice and this permission notice appear in
7*cda5da8dSAndroid Build Coastguard Worker# supporting documentation, and that the name of Vinay Sajip
8*cda5da8dSAndroid Build Coastguard Worker# not be used in advertising or publicity pertaining to distribution
9*cda5da8dSAndroid Build Coastguard Worker# of the software without specific, written prior permission.
10*cda5da8dSAndroid Build Coastguard Worker# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
11*cda5da8dSAndroid Build Coastguard Worker# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
12*cda5da8dSAndroid Build Coastguard Worker# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
13*cda5da8dSAndroid Build Coastguard Worker# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
14*cda5da8dSAndroid Build Coastguard Worker# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15*cda5da8dSAndroid Build Coastguard Worker# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*cda5da8dSAndroid Build Coastguard Worker
17*cda5da8dSAndroid Build Coastguard Worker"""
18*cda5da8dSAndroid Build Coastguard WorkerAdditional handlers for the logging package for Python. The core package is
19*cda5da8dSAndroid Build Coastguard Workerbased on PEP 282 and comments thereto in comp.lang.python.
20*cda5da8dSAndroid Build Coastguard Worker
21*cda5da8dSAndroid Build Coastguard WorkerCopyright (C) 2001-2021 Vinay Sajip. All Rights Reserved.
22*cda5da8dSAndroid Build Coastguard Worker
23*cda5da8dSAndroid Build Coastguard WorkerTo use, simply 'import logging.handlers' and log away!
24*cda5da8dSAndroid Build Coastguard Worker"""
25*cda5da8dSAndroid Build Coastguard Worker
26*cda5da8dSAndroid Build Coastguard Workerimport io, logging, socket, os, pickle, struct, time, re
27*cda5da8dSAndroid Build Coastguard Workerfrom stat import ST_DEV, ST_INO, ST_MTIME
28*cda5da8dSAndroid Build Coastguard Workerimport queue
29*cda5da8dSAndroid Build Coastguard Workerimport threading
30*cda5da8dSAndroid Build Coastguard Workerimport copy
31*cda5da8dSAndroid Build Coastguard Worker
32*cda5da8dSAndroid Build Coastguard Worker#
33*cda5da8dSAndroid Build Coastguard Worker# Some constants...
34*cda5da8dSAndroid Build Coastguard Worker#
35*cda5da8dSAndroid Build Coastguard Worker
36*cda5da8dSAndroid Build Coastguard WorkerDEFAULT_TCP_LOGGING_PORT    = 9020
37*cda5da8dSAndroid Build Coastguard WorkerDEFAULT_UDP_LOGGING_PORT    = 9021
38*cda5da8dSAndroid Build Coastguard WorkerDEFAULT_HTTP_LOGGING_PORT   = 9022
39*cda5da8dSAndroid Build Coastguard WorkerDEFAULT_SOAP_LOGGING_PORT   = 9023
40*cda5da8dSAndroid Build Coastguard WorkerSYSLOG_UDP_PORT             = 514
41*cda5da8dSAndroid Build Coastguard WorkerSYSLOG_TCP_PORT             = 514
42*cda5da8dSAndroid Build Coastguard Worker
43*cda5da8dSAndroid Build Coastguard Worker_MIDNIGHT = 24 * 60 * 60  # number of seconds in a day
44*cda5da8dSAndroid Build Coastguard Worker
45*cda5da8dSAndroid Build Coastguard Workerclass BaseRotatingHandler(logging.FileHandler):
46*cda5da8dSAndroid Build Coastguard Worker    """
47*cda5da8dSAndroid Build Coastguard Worker    Base class for handlers that rotate log files at a certain point.
48*cda5da8dSAndroid Build Coastguard Worker    Not meant to be instantiated directly.  Instead, use RotatingFileHandler
49*cda5da8dSAndroid Build Coastguard Worker    or TimedRotatingFileHandler.
50*cda5da8dSAndroid Build Coastguard Worker    """
51*cda5da8dSAndroid Build Coastguard Worker    namer = None
52*cda5da8dSAndroid Build Coastguard Worker    rotator = None
53*cda5da8dSAndroid Build Coastguard Worker
54*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, filename, mode, encoding=None, delay=False, errors=None):
55*cda5da8dSAndroid Build Coastguard Worker        """
56*cda5da8dSAndroid Build Coastguard Worker        Use the specified filename for streamed logging
57*cda5da8dSAndroid Build Coastguard Worker        """
58*cda5da8dSAndroid Build Coastguard Worker        logging.FileHandler.__init__(self, filename, mode=mode,
59*cda5da8dSAndroid Build Coastguard Worker                                     encoding=encoding, delay=delay,
60*cda5da8dSAndroid Build Coastguard Worker                                     errors=errors)
61*cda5da8dSAndroid Build Coastguard Worker        self.mode = mode
62*cda5da8dSAndroid Build Coastguard Worker        self.encoding = encoding
63*cda5da8dSAndroid Build Coastguard Worker        self.errors = errors
64*cda5da8dSAndroid Build Coastguard Worker
65*cda5da8dSAndroid Build Coastguard Worker    def emit(self, record):
66*cda5da8dSAndroid Build Coastguard Worker        """
67*cda5da8dSAndroid Build Coastguard Worker        Emit a record.
68*cda5da8dSAndroid Build Coastguard Worker
69*cda5da8dSAndroid Build Coastguard Worker        Output the record to the file, catering for rollover as described
70*cda5da8dSAndroid Build Coastguard Worker        in doRollover().
71*cda5da8dSAndroid Build Coastguard Worker        """
72*cda5da8dSAndroid Build Coastguard Worker        try:
73*cda5da8dSAndroid Build Coastguard Worker            if self.shouldRollover(record):
74*cda5da8dSAndroid Build Coastguard Worker                self.doRollover()
75*cda5da8dSAndroid Build Coastguard Worker            logging.FileHandler.emit(self, record)
76*cda5da8dSAndroid Build Coastguard Worker        except Exception:
77*cda5da8dSAndroid Build Coastguard Worker            self.handleError(record)
78*cda5da8dSAndroid Build Coastguard Worker
79*cda5da8dSAndroid Build Coastguard Worker    def rotation_filename(self, default_name):
80*cda5da8dSAndroid Build Coastguard Worker        """
81*cda5da8dSAndroid Build Coastguard Worker        Modify the filename of a log file when rotating.
82*cda5da8dSAndroid Build Coastguard Worker
83*cda5da8dSAndroid Build Coastguard Worker        This is provided so that a custom filename can be provided.
84*cda5da8dSAndroid Build Coastguard Worker
85*cda5da8dSAndroid Build Coastguard Worker        The default implementation calls the 'namer' attribute of the
86*cda5da8dSAndroid Build Coastguard Worker        handler, if it's callable, passing the default name to
87*cda5da8dSAndroid Build Coastguard Worker        it. If the attribute isn't callable (the default is None), the name
88*cda5da8dSAndroid Build Coastguard Worker        is returned unchanged.
89*cda5da8dSAndroid Build Coastguard Worker
90*cda5da8dSAndroid Build Coastguard Worker        :param default_name: The default name for the log file.
91*cda5da8dSAndroid Build Coastguard Worker        """
92*cda5da8dSAndroid Build Coastguard Worker        if not callable(self.namer):
93*cda5da8dSAndroid Build Coastguard Worker            result = default_name
94*cda5da8dSAndroid Build Coastguard Worker        else:
95*cda5da8dSAndroid Build Coastguard Worker            result = self.namer(default_name)
96*cda5da8dSAndroid Build Coastguard Worker        return result
97*cda5da8dSAndroid Build Coastguard Worker
98*cda5da8dSAndroid Build Coastguard Worker    def rotate(self, source, dest):
99*cda5da8dSAndroid Build Coastguard Worker        """
100*cda5da8dSAndroid Build Coastguard Worker        When rotating, rotate the current log.
101*cda5da8dSAndroid Build Coastguard Worker
102*cda5da8dSAndroid Build Coastguard Worker        The default implementation calls the 'rotator' attribute of the
103*cda5da8dSAndroid Build Coastguard Worker        handler, if it's callable, passing the source and dest arguments to
104*cda5da8dSAndroid Build Coastguard Worker        it. If the attribute isn't callable (the default is None), the source
105*cda5da8dSAndroid Build Coastguard Worker        is simply renamed to the destination.
106*cda5da8dSAndroid Build Coastguard Worker
107*cda5da8dSAndroid Build Coastguard Worker        :param source: The source filename. This is normally the base
108*cda5da8dSAndroid Build Coastguard Worker                       filename, e.g. 'test.log'
109*cda5da8dSAndroid Build Coastguard Worker        :param dest:   The destination filename. This is normally
110*cda5da8dSAndroid Build Coastguard Worker                       what the source is rotated to, e.g. 'test.log.1'.
111*cda5da8dSAndroid Build Coastguard Worker        """
112*cda5da8dSAndroid Build Coastguard Worker        if not callable(self.rotator):
113*cda5da8dSAndroid Build Coastguard Worker            # Issue 18940: A file may not have been created if delay is True.
114*cda5da8dSAndroid Build Coastguard Worker            if os.path.exists(source):
115*cda5da8dSAndroid Build Coastguard Worker                os.rename(source, dest)
116*cda5da8dSAndroid Build Coastguard Worker        else:
117*cda5da8dSAndroid Build Coastguard Worker            self.rotator(source, dest)
118*cda5da8dSAndroid Build Coastguard Worker
119*cda5da8dSAndroid Build Coastguard Workerclass RotatingFileHandler(BaseRotatingHandler):
120*cda5da8dSAndroid Build Coastguard Worker    """
121*cda5da8dSAndroid Build Coastguard Worker    Handler for logging to a set of files, which switches from one file
122*cda5da8dSAndroid Build Coastguard Worker    to the next when the current file reaches a certain size.
123*cda5da8dSAndroid Build Coastguard Worker    """
124*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, filename, mode='a', maxBytes=0, backupCount=0,
125*cda5da8dSAndroid Build Coastguard Worker                 encoding=None, delay=False, errors=None):
126*cda5da8dSAndroid Build Coastguard Worker        """
127*cda5da8dSAndroid Build Coastguard Worker        Open the specified file and use it as the stream for logging.
128*cda5da8dSAndroid Build Coastguard Worker
129*cda5da8dSAndroid Build Coastguard Worker        By default, the file grows indefinitely. You can specify particular
130*cda5da8dSAndroid Build Coastguard Worker        values of maxBytes and backupCount to allow the file to rollover at
131*cda5da8dSAndroid Build Coastguard Worker        a predetermined size.
132*cda5da8dSAndroid Build Coastguard Worker
133*cda5da8dSAndroid Build Coastguard Worker        Rollover occurs whenever the current log file is nearly maxBytes in
134*cda5da8dSAndroid Build Coastguard Worker        length. If backupCount is >= 1, the system will successively create
135*cda5da8dSAndroid Build Coastguard Worker        new files with the same pathname as the base file, but with extensions
136*cda5da8dSAndroid Build Coastguard Worker        ".1", ".2" etc. appended to it. For example, with a backupCount of 5
137*cda5da8dSAndroid Build Coastguard Worker        and a base file name of "app.log", you would get "app.log",
138*cda5da8dSAndroid Build Coastguard Worker        "app.log.1", "app.log.2", ... through to "app.log.5". The file being
139*cda5da8dSAndroid Build Coastguard Worker        written to is always "app.log" - when it gets filled up, it is closed
140*cda5da8dSAndroid Build Coastguard Worker        and renamed to "app.log.1", and if files "app.log.1", "app.log.2" etc.
141*cda5da8dSAndroid Build Coastguard Worker        exist, then they are renamed to "app.log.2", "app.log.3" etc.
142*cda5da8dSAndroid Build Coastguard Worker        respectively.
143*cda5da8dSAndroid Build Coastguard Worker
144*cda5da8dSAndroid Build Coastguard Worker        If maxBytes is zero, rollover never occurs.
145*cda5da8dSAndroid Build Coastguard Worker        """
146*cda5da8dSAndroid Build Coastguard Worker        # If rotation/rollover is wanted, it doesn't make sense to use another
147*cda5da8dSAndroid Build Coastguard Worker        # mode. If for example 'w' were specified, then if there were multiple
148*cda5da8dSAndroid Build Coastguard Worker        # runs of the calling application, the logs from previous runs would be
149*cda5da8dSAndroid Build Coastguard Worker        # lost if the 'w' is respected, because the log file would be truncated
150*cda5da8dSAndroid Build Coastguard Worker        # on each run.
151*cda5da8dSAndroid Build Coastguard Worker        if maxBytes > 0:
152*cda5da8dSAndroid Build Coastguard Worker            mode = 'a'
153*cda5da8dSAndroid Build Coastguard Worker        if "b" not in mode:
154*cda5da8dSAndroid Build Coastguard Worker            encoding = io.text_encoding(encoding)
155*cda5da8dSAndroid Build Coastguard Worker        BaseRotatingHandler.__init__(self, filename, mode, encoding=encoding,
156*cda5da8dSAndroid Build Coastguard Worker                                     delay=delay, errors=errors)
157*cda5da8dSAndroid Build Coastguard Worker        self.maxBytes = maxBytes
158*cda5da8dSAndroid Build Coastguard Worker        self.backupCount = backupCount
159*cda5da8dSAndroid Build Coastguard Worker
160*cda5da8dSAndroid Build Coastguard Worker    def doRollover(self):
161*cda5da8dSAndroid Build Coastguard Worker        """
162*cda5da8dSAndroid Build Coastguard Worker        Do a rollover, as described in __init__().
163*cda5da8dSAndroid Build Coastguard Worker        """
164*cda5da8dSAndroid Build Coastguard Worker        if self.stream:
165*cda5da8dSAndroid Build Coastguard Worker            self.stream.close()
166*cda5da8dSAndroid Build Coastguard Worker            self.stream = None
167*cda5da8dSAndroid Build Coastguard Worker        if self.backupCount > 0:
168*cda5da8dSAndroid Build Coastguard Worker            for i in range(self.backupCount - 1, 0, -1):
169*cda5da8dSAndroid Build Coastguard Worker                sfn = self.rotation_filename("%s.%d" % (self.baseFilename, i))
170*cda5da8dSAndroid Build Coastguard Worker                dfn = self.rotation_filename("%s.%d" % (self.baseFilename,
171*cda5da8dSAndroid Build Coastguard Worker                                                        i + 1))
172*cda5da8dSAndroid Build Coastguard Worker                if os.path.exists(sfn):
173*cda5da8dSAndroid Build Coastguard Worker                    if os.path.exists(dfn):
174*cda5da8dSAndroid Build Coastguard Worker                        os.remove(dfn)
175*cda5da8dSAndroid Build Coastguard Worker                    os.rename(sfn, dfn)
176*cda5da8dSAndroid Build Coastguard Worker            dfn = self.rotation_filename(self.baseFilename + ".1")
177*cda5da8dSAndroid Build Coastguard Worker            if os.path.exists(dfn):
178*cda5da8dSAndroid Build Coastguard Worker                os.remove(dfn)
179*cda5da8dSAndroid Build Coastguard Worker            self.rotate(self.baseFilename, dfn)
180*cda5da8dSAndroid Build Coastguard Worker        if not self.delay:
181*cda5da8dSAndroid Build Coastguard Worker            self.stream = self._open()
182*cda5da8dSAndroid Build Coastguard Worker
183*cda5da8dSAndroid Build Coastguard Worker    def shouldRollover(self, record):
184*cda5da8dSAndroid Build Coastguard Worker        """
185*cda5da8dSAndroid Build Coastguard Worker        Determine if rollover should occur.
186*cda5da8dSAndroid Build Coastguard Worker
187*cda5da8dSAndroid Build Coastguard Worker        Basically, see if the supplied record would cause the file to exceed
188*cda5da8dSAndroid Build Coastguard Worker        the size limit we have.
189*cda5da8dSAndroid Build Coastguard Worker        """
190*cda5da8dSAndroid Build Coastguard Worker        # See bpo-45401: Never rollover anything other than regular files
191*cda5da8dSAndroid Build Coastguard Worker        if os.path.exists(self.baseFilename) and not os.path.isfile(self.baseFilename):
192*cda5da8dSAndroid Build Coastguard Worker            return False
193*cda5da8dSAndroid Build Coastguard Worker        if self.stream is None:                 # delay was set...
194*cda5da8dSAndroid Build Coastguard Worker            self.stream = self._open()
195*cda5da8dSAndroid Build Coastguard Worker        if self.maxBytes > 0:                   # are we rolling over?
196*cda5da8dSAndroid Build Coastguard Worker            msg = "%s\n" % self.format(record)
197*cda5da8dSAndroid Build Coastguard Worker            self.stream.seek(0, 2)  #due to non-posix-compliant Windows feature
198*cda5da8dSAndroid Build Coastguard Worker            if self.stream.tell() + len(msg) >= self.maxBytes:
199*cda5da8dSAndroid Build Coastguard Worker                return True
200*cda5da8dSAndroid Build Coastguard Worker        return False
201*cda5da8dSAndroid Build Coastguard Worker
202*cda5da8dSAndroid Build Coastguard Workerclass TimedRotatingFileHandler(BaseRotatingHandler):
203*cda5da8dSAndroid Build Coastguard Worker    """
204*cda5da8dSAndroid Build Coastguard Worker    Handler for logging to a file, rotating the log file at certain timed
205*cda5da8dSAndroid Build Coastguard Worker    intervals.
206*cda5da8dSAndroid Build Coastguard Worker
207*cda5da8dSAndroid Build Coastguard Worker    If backupCount is > 0, when rollover is done, no more than backupCount
208*cda5da8dSAndroid Build Coastguard Worker    files are kept - the oldest ones are deleted.
209*cda5da8dSAndroid Build Coastguard Worker    """
210*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, filename, when='h', interval=1, backupCount=0,
211*cda5da8dSAndroid Build Coastguard Worker                 encoding=None, delay=False, utc=False, atTime=None,
212*cda5da8dSAndroid Build Coastguard Worker                 errors=None):
213*cda5da8dSAndroid Build Coastguard Worker        encoding = io.text_encoding(encoding)
214*cda5da8dSAndroid Build Coastguard Worker        BaseRotatingHandler.__init__(self, filename, 'a', encoding=encoding,
215*cda5da8dSAndroid Build Coastguard Worker                                     delay=delay, errors=errors)
216*cda5da8dSAndroid Build Coastguard Worker        self.when = when.upper()
217*cda5da8dSAndroid Build Coastguard Worker        self.backupCount = backupCount
218*cda5da8dSAndroid Build Coastguard Worker        self.utc = utc
219*cda5da8dSAndroid Build Coastguard Worker        self.atTime = atTime
220*cda5da8dSAndroid Build Coastguard Worker        # Calculate the real rollover interval, which is just the number of
221*cda5da8dSAndroid Build Coastguard Worker        # seconds between rollovers.  Also set the filename suffix used when
222*cda5da8dSAndroid Build Coastguard Worker        # a rollover occurs.  Current 'when' events supported:
223*cda5da8dSAndroid Build Coastguard Worker        # S - Seconds
224*cda5da8dSAndroid Build Coastguard Worker        # M - Minutes
225*cda5da8dSAndroid Build Coastguard Worker        # H - Hours
226*cda5da8dSAndroid Build Coastguard Worker        # D - Days
227*cda5da8dSAndroid Build Coastguard Worker        # midnight - roll over at midnight
228*cda5da8dSAndroid Build Coastguard Worker        # W{0-6} - roll over on a certain day; 0 - Monday
229*cda5da8dSAndroid Build Coastguard Worker        #
230*cda5da8dSAndroid Build Coastguard Worker        # Case of the 'when' specifier is not important; lower or upper case
231*cda5da8dSAndroid Build Coastguard Worker        # will work.
232*cda5da8dSAndroid Build Coastguard Worker        if self.when == 'S':
233*cda5da8dSAndroid Build Coastguard Worker            self.interval = 1 # one second
234*cda5da8dSAndroid Build Coastguard Worker            self.suffix = "%Y-%m-%d_%H-%M-%S"
235*cda5da8dSAndroid Build Coastguard Worker            self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}(\.\w+)?$"
236*cda5da8dSAndroid Build Coastguard Worker        elif self.when == 'M':
237*cda5da8dSAndroid Build Coastguard Worker            self.interval = 60 # one minute
238*cda5da8dSAndroid Build Coastguard Worker            self.suffix = "%Y-%m-%d_%H-%M"
239*cda5da8dSAndroid Build Coastguard Worker            self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}(\.\w+)?$"
240*cda5da8dSAndroid Build Coastguard Worker        elif self.when == 'H':
241*cda5da8dSAndroid Build Coastguard Worker            self.interval = 60 * 60 # one hour
242*cda5da8dSAndroid Build Coastguard Worker            self.suffix = "%Y-%m-%d_%H"
243*cda5da8dSAndroid Build Coastguard Worker            self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}(\.\w+)?$"
244*cda5da8dSAndroid Build Coastguard Worker        elif self.when == 'D' or self.when == 'MIDNIGHT':
245*cda5da8dSAndroid Build Coastguard Worker            self.interval = 60 * 60 * 24 # one day
246*cda5da8dSAndroid Build Coastguard Worker            self.suffix = "%Y-%m-%d"
247*cda5da8dSAndroid Build Coastguard Worker            self.extMatch = r"^\d{4}-\d{2}-\d{2}(\.\w+)?$"
248*cda5da8dSAndroid Build Coastguard Worker        elif self.when.startswith('W'):
249*cda5da8dSAndroid Build Coastguard Worker            self.interval = 60 * 60 * 24 * 7 # one week
250*cda5da8dSAndroid Build Coastguard Worker            if len(self.when) != 2:
251*cda5da8dSAndroid Build Coastguard Worker                raise ValueError("You must specify a day for weekly rollover from 0 to 6 (0 is Monday): %s" % self.when)
252*cda5da8dSAndroid Build Coastguard Worker            if self.when[1] < '0' or self.when[1] > '6':
253*cda5da8dSAndroid Build Coastguard Worker                raise ValueError("Invalid day specified for weekly rollover: %s" % self.when)
254*cda5da8dSAndroid Build Coastguard Worker            self.dayOfWeek = int(self.when[1])
255*cda5da8dSAndroid Build Coastguard Worker            self.suffix = "%Y-%m-%d"
256*cda5da8dSAndroid Build Coastguard Worker            self.extMatch = r"^\d{4}-\d{2}-\d{2}(\.\w+)?$"
257*cda5da8dSAndroid Build Coastguard Worker        else:
258*cda5da8dSAndroid Build Coastguard Worker            raise ValueError("Invalid rollover interval specified: %s" % self.when)
259*cda5da8dSAndroid Build Coastguard Worker
260*cda5da8dSAndroid Build Coastguard Worker        self.extMatch = re.compile(self.extMatch, re.ASCII)
261*cda5da8dSAndroid Build Coastguard Worker        self.interval = self.interval * interval # multiply by units requested
262*cda5da8dSAndroid Build Coastguard Worker        # The following line added because the filename passed in could be a
263*cda5da8dSAndroid Build Coastguard Worker        # path object (see Issue #27493), but self.baseFilename will be a string
264*cda5da8dSAndroid Build Coastguard Worker        filename = self.baseFilename
265*cda5da8dSAndroid Build Coastguard Worker        if os.path.exists(filename):
266*cda5da8dSAndroid Build Coastguard Worker            t = os.stat(filename)[ST_MTIME]
267*cda5da8dSAndroid Build Coastguard Worker        else:
268*cda5da8dSAndroid Build Coastguard Worker            t = int(time.time())
269*cda5da8dSAndroid Build Coastguard Worker        self.rolloverAt = self.computeRollover(t)
270*cda5da8dSAndroid Build Coastguard Worker
271*cda5da8dSAndroid Build Coastguard Worker    def computeRollover(self, currentTime):
272*cda5da8dSAndroid Build Coastguard Worker        """
273*cda5da8dSAndroid Build Coastguard Worker        Work out the rollover time based on the specified time.
274*cda5da8dSAndroid Build Coastguard Worker        """
275*cda5da8dSAndroid Build Coastguard Worker        result = currentTime + self.interval
276*cda5da8dSAndroid Build Coastguard Worker        # If we are rolling over at midnight or weekly, then the interval is already known.
277*cda5da8dSAndroid Build Coastguard Worker        # What we need to figure out is WHEN the next interval is.  In other words,
278*cda5da8dSAndroid Build Coastguard Worker        # if you are rolling over at midnight, then your base interval is 1 day,
279*cda5da8dSAndroid Build Coastguard Worker        # but you want to start that one day clock at midnight, not now.  So, we
280*cda5da8dSAndroid Build Coastguard Worker        # have to fudge the rolloverAt value in order to trigger the first rollover
281*cda5da8dSAndroid Build Coastguard Worker        # at the right time.  After that, the regular interval will take care of
282*cda5da8dSAndroid Build Coastguard Worker        # the rest.  Note that this code doesn't care about leap seconds. :)
283*cda5da8dSAndroid Build Coastguard Worker        if self.when == 'MIDNIGHT' or self.when.startswith('W'):
284*cda5da8dSAndroid Build Coastguard Worker            # This could be done with less code, but I wanted it to be clear
285*cda5da8dSAndroid Build Coastguard Worker            if self.utc:
286*cda5da8dSAndroid Build Coastguard Worker                t = time.gmtime(currentTime)
287*cda5da8dSAndroid Build Coastguard Worker            else:
288*cda5da8dSAndroid Build Coastguard Worker                t = time.localtime(currentTime)
289*cda5da8dSAndroid Build Coastguard Worker            currentHour = t[3]
290*cda5da8dSAndroid Build Coastguard Worker            currentMinute = t[4]
291*cda5da8dSAndroid Build Coastguard Worker            currentSecond = t[5]
292*cda5da8dSAndroid Build Coastguard Worker            currentDay = t[6]
293*cda5da8dSAndroid Build Coastguard Worker            # r is the number of seconds left between now and the next rotation
294*cda5da8dSAndroid Build Coastguard Worker            if self.atTime is None:
295*cda5da8dSAndroid Build Coastguard Worker                rotate_ts = _MIDNIGHT
296*cda5da8dSAndroid Build Coastguard Worker            else:
297*cda5da8dSAndroid Build Coastguard Worker                rotate_ts = ((self.atTime.hour * 60 + self.atTime.minute)*60 +
298*cda5da8dSAndroid Build Coastguard Worker                    self.atTime.second)
299*cda5da8dSAndroid Build Coastguard Worker
300*cda5da8dSAndroid Build Coastguard Worker            r = rotate_ts - ((currentHour * 60 + currentMinute) * 60 +
301*cda5da8dSAndroid Build Coastguard Worker                currentSecond)
302*cda5da8dSAndroid Build Coastguard Worker            if r < 0:
303*cda5da8dSAndroid Build Coastguard Worker                # Rotate time is before the current time (for example when
304*cda5da8dSAndroid Build Coastguard Worker                # self.rotateAt is 13:45 and it now 14:15), rotation is
305*cda5da8dSAndroid Build Coastguard Worker                # tomorrow.
306*cda5da8dSAndroid Build Coastguard Worker                r += _MIDNIGHT
307*cda5da8dSAndroid Build Coastguard Worker                currentDay = (currentDay + 1) % 7
308*cda5da8dSAndroid Build Coastguard Worker            result = currentTime + r
309*cda5da8dSAndroid Build Coastguard Worker            # If we are rolling over on a certain day, add in the number of days until
310*cda5da8dSAndroid Build Coastguard Worker            # the next rollover, but offset by 1 since we just calculated the time
311*cda5da8dSAndroid Build Coastguard Worker            # until the next day starts.  There are three cases:
312*cda5da8dSAndroid Build Coastguard Worker            # Case 1) The day to rollover is today; in this case, do nothing
313*cda5da8dSAndroid Build Coastguard Worker            # Case 2) The day to rollover is further in the interval (i.e., today is
314*cda5da8dSAndroid Build Coastguard Worker            #         day 2 (Wednesday) and rollover is on day 6 (Sunday).  Days to
315*cda5da8dSAndroid Build Coastguard Worker            #         next rollover is simply 6 - 2 - 1, or 3.
316*cda5da8dSAndroid Build Coastguard Worker            # Case 3) The day to rollover is behind us in the interval (i.e., today
317*cda5da8dSAndroid Build Coastguard Worker            #         is day 5 (Saturday) and rollover is on day 3 (Thursday).
318*cda5da8dSAndroid Build Coastguard Worker            #         Days to rollover is 6 - 5 + 3, or 4.  In this case, it's the
319*cda5da8dSAndroid Build Coastguard Worker            #         number of days left in the current week (1) plus the number
320*cda5da8dSAndroid Build Coastguard Worker            #         of days in the next week until the rollover day (3).
321*cda5da8dSAndroid Build Coastguard Worker            # The calculations described in 2) and 3) above need to have a day added.
322*cda5da8dSAndroid Build Coastguard Worker            # This is because the above time calculation takes us to midnight on this
323*cda5da8dSAndroid Build Coastguard Worker            # day, i.e. the start of the next day.
324*cda5da8dSAndroid Build Coastguard Worker            if self.when.startswith('W'):
325*cda5da8dSAndroid Build Coastguard Worker                day = currentDay # 0 is Monday
326*cda5da8dSAndroid Build Coastguard Worker                if day != self.dayOfWeek:
327*cda5da8dSAndroid Build Coastguard Worker                    if day < self.dayOfWeek:
328*cda5da8dSAndroid Build Coastguard Worker                        daysToWait = self.dayOfWeek - day
329*cda5da8dSAndroid Build Coastguard Worker                    else:
330*cda5da8dSAndroid Build Coastguard Worker                        daysToWait = 6 - day + self.dayOfWeek + 1
331*cda5da8dSAndroid Build Coastguard Worker                    newRolloverAt = result + (daysToWait * (60 * 60 * 24))
332*cda5da8dSAndroid Build Coastguard Worker                    if not self.utc:
333*cda5da8dSAndroid Build Coastguard Worker                        dstNow = t[-1]
334*cda5da8dSAndroid Build Coastguard Worker                        dstAtRollover = time.localtime(newRolloverAt)[-1]
335*cda5da8dSAndroid Build Coastguard Worker                        if dstNow != dstAtRollover:
336*cda5da8dSAndroid Build Coastguard Worker                            if not dstNow:  # DST kicks in before next rollover, so we need to deduct an hour
337*cda5da8dSAndroid Build Coastguard Worker                                addend = -3600
338*cda5da8dSAndroid Build Coastguard Worker                            else:           # DST bows out before next rollover, so we need to add an hour
339*cda5da8dSAndroid Build Coastguard Worker                                addend = 3600
340*cda5da8dSAndroid Build Coastguard Worker                            newRolloverAt += addend
341*cda5da8dSAndroid Build Coastguard Worker                    result = newRolloverAt
342*cda5da8dSAndroid Build Coastguard Worker        return result
343*cda5da8dSAndroid Build Coastguard Worker
344*cda5da8dSAndroid Build Coastguard Worker    def shouldRollover(self, record):
345*cda5da8dSAndroid Build Coastguard Worker        """
346*cda5da8dSAndroid Build Coastguard Worker        Determine if rollover should occur.
347*cda5da8dSAndroid Build Coastguard Worker
348*cda5da8dSAndroid Build Coastguard Worker        record is not used, as we are just comparing times, but it is needed so
349*cda5da8dSAndroid Build Coastguard Worker        the method signatures are the same
350*cda5da8dSAndroid Build Coastguard Worker        """
351*cda5da8dSAndroid Build Coastguard Worker        t = int(time.time())
352*cda5da8dSAndroid Build Coastguard Worker        if t >= self.rolloverAt:
353*cda5da8dSAndroid Build Coastguard Worker            # See #89564: Never rollover anything other than regular files
354*cda5da8dSAndroid Build Coastguard Worker            if os.path.exists(self.baseFilename) and not os.path.isfile(self.baseFilename):
355*cda5da8dSAndroid Build Coastguard Worker                # The file is not a regular file, so do not rollover, but do
356*cda5da8dSAndroid Build Coastguard Worker                # set the next rollover time to avoid repeated checks.
357*cda5da8dSAndroid Build Coastguard Worker                self.rolloverAt = self.computeRollover(t)
358*cda5da8dSAndroid Build Coastguard Worker                return False
359*cda5da8dSAndroid Build Coastguard Worker
360*cda5da8dSAndroid Build Coastguard Worker            return True
361*cda5da8dSAndroid Build Coastguard Worker        return False
362*cda5da8dSAndroid Build Coastguard Worker
363*cda5da8dSAndroid Build Coastguard Worker    def getFilesToDelete(self):
364*cda5da8dSAndroid Build Coastguard Worker        """
365*cda5da8dSAndroid Build Coastguard Worker        Determine the files to delete when rolling over.
366*cda5da8dSAndroid Build Coastguard Worker
367*cda5da8dSAndroid Build Coastguard Worker        More specific than the earlier method, which just used glob.glob().
368*cda5da8dSAndroid Build Coastguard Worker        """
369*cda5da8dSAndroid Build Coastguard Worker        dirName, baseName = os.path.split(self.baseFilename)
370*cda5da8dSAndroid Build Coastguard Worker        fileNames = os.listdir(dirName)
371*cda5da8dSAndroid Build Coastguard Worker        result = []
372*cda5da8dSAndroid Build Coastguard Worker        # See bpo-44753: Don't use the extension when computing the prefix.
373*cda5da8dSAndroid Build Coastguard Worker        n, e = os.path.splitext(baseName)
374*cda5da8dSAndroid Build Coastguard Worker        prefix = n + '.'
375*cda5da8dSAndroid Build Coastguard Worker        plen = len(prefix)
376*cda5da8dSAndroid Build Coastguard Worker        for fileName in fileNames:
377*cda5da8dSAndroid Build Coastguard Worker            if self.namer is None:
378*cda5da8dSAndroid Build Coastguard Worker                # Our files will always start with baseName
379*cda5da8dSAndroid Build Coastguard Worker                if not fileName.startswith(baseName):
380*cda5da8dSAndroid Build Coastguard Worker                    continue
381*cda5da8dSAndroid Build Coastguard Worker            else:
382*cda5da8dSAndroid Build Coastguard Worker                # Our files could be just about anything after custom naming, but
383*cda5da8dSAndroid Build Coastguard Worker                # likely candidates are of the form
384*cda5da8dSAndroid Build Coastguard Worker                # foo.log.DATETIME_SUFFIX or foo.DATETIME_SUFFIX.log
385*cda5da8dSAndroid Build Coastguard Worker                if (not fileName.startswith(baseName) and fileName.endswith(e) and
386*cda5da8dSAndroid Build Coastguard Worker                    len(fileName) > (plen + 1) and not fileName[plen+1].isdigit()):
387*cda5da8dSAndroid Build Coastguard Worker                    continue
388*cda5da8dSAndroid Build Coastguard Worker
389*cda5da8dSAndroid Build Coastguard Worker            if fileName[:plen] == prefix:
390*cda5da8dSAndroid Build Coastguard Worker                suffix = fileName[plen:]
391*cda5da8dSAndroid Build Coastguard Worker                # See bpo-45628: The date/time suffix could be anywhere in the
392*cda5da8dSAndroid Build Coastguard Worker                # filename
393*cda5da8dSAndroid Build Coastguard Worker                parts = suffix.split('.')
394*cda5da8dSAndroid Build Coastguard Worker                for part in parts:
395*cda5da8dSAndroid Build Coastguard Worker                    if self.extMatch.match(part):
396*cda5da8dSAndroid Build Coastguard Worker                        result.append(os.path.join(dirName, fileName))
397*cda5da8dSAndroid Build Coastguard Worker                        break
398*cda5da8dSAndroid Build Coastguard Worker        if len(result) < self.backupCount:
399*cda5da8dSAndroid Build Coastguard Worker            result = []
400*cda5da8dSAndroid Build Coastguard Worker        else:
401*cda5da8dSAndroid Build Coastguard Worker            result.sort()
402*cda5da8dSAndroid Build Coastguard Worker            result = result[:len(result) - self.backupCount]
403*cda5da8dSAndroid Build Coastguard Worker        return result
404*cda5da8dSAndroid Build Coastguard Worker
405*cda5da8dSAndroid Build Coastguard Worker    def doRollover(self):
406*cda5da8dSAndroid Build Coastguard Worker        """
407*cda5da8dSAndroid Build Coastguard Worker        do a rollover; in this case, a date/time stamp is appended to the filename
408*cda5da8dSAndroid Build Coastguard Worker        when the rollover happens.  However, you want the file to be named for the
409*cda5da8dSAndroid Build Coastguard Worker        start of the interval, not the current time.  If there is a backup count,
410*cda5da8dSAndroid Build Coastguard Worker        then we have to get a list of matching filenames, sort them and remove
411*cda5da8dSAndroid Build Coastguard Worker        the one with the oldest suffix.
412*cda5da8dSAndroid Build Coastguard Worker        """
413*cda5da8dSAndroid Build Coastguard Worker        if self.stream:
414*cda5da8dSAndroid Build Coastguard Worker            self.stream.close()
415*cda5da8dSAndroid Build Coastguard Worker            self.stream = None
416*cda5da8dSAndroid Build Coastguard Worker        # get the time that this sequence started at and make it a TimeTuple
417*cda5da8dSAndroid Build Coastguard Worker        currentTime = int(time.time())
418*cda5da8dSAndroid Build Coastguard Worker        dstNow = time.localtime(currentTime)[-1]
419*cda5da8dSAndroid Build Coastguard Worker        t = self.rolloverAt - self.interval
420*cda5da8dSAndroid Build Coastguard Worker        if self.utc:
421*cda5da8dSAndroid Build Coastguard Worker            timeTuple = time.gmtime(t)
422*cda5da8dSAndroid Build Coastguard Worker        else:
423*cda5da8dSAndroid Build Coastguard Worker            timeTuple = time.localtime(t)
424*cda5da8dSAndroid Build Coastguard Worker            dstThen = timeTuple[-1]
425*cda5da8dSAndroid Build Coastguard Worker            if dstNow != dstThen:
426*cda5da8dSAndroid Build Coastguard Worker                if dstNow:
427*cda5da8dSAndroid Build Coastguard Worker                    addend = 3600
428*cda5da8dSAndroid Build Coastguard Worker                else:
429*cda5da8dSAndroid Build Coastguard Worker                    addend = -3600
430*cda5da8dSAndroid Build Coastguard Worker                timeTuple = time.localtime(t + addend)
431*cda5da8dSAndroid Build Coastguard Worker        dfn = self.rotation_filename(self.baseFilename + "." +
432*cda5da8dSAndroid Build Coastguard Worker                                     time.strftime(self.suffix, timeTuple))
433*cda5da8dSAndroid Build Coastguard Worker        if os.path.exists(dfn):
434*cda5da8dSAndroid Build Coastguard Worker            os.remove(dfn)
435*cda5da8dSAndroid Build Coastguard Worker        self.rotate(self.baseFilename, dfn)
436*cda5da8dSAndroid Build Coastguard Worker        if self.backupCount > 0:
437*cda5da8dSAndroid Build Coastguard Worker            for s in self.getFilesToDelete():
438*cda5da8dSAndroid Build Coastguard Worker                os.remove(s)
439*cda5da8dSAndroid Build Coastguard Worker        if not self.delay:
440*cda5da8dSAndroid Build Coastguard Worker            self.stream = self._open()
441*cda5da8dSAndroid Build Coastguard Worker        newRolloverAt = self.computeRollover(currentTime)
442*cda5da8dSAndroid Build Coastguard Worker        while newRolloverAt <= currentTime:
443*cda5da8dSAndroid Build Coastguard Worker            newRolloverAt = newRolloverAt + self.interval
444*cda5da8dSAndroid Build Coastguard Worker        #If DST changes and midnight or weekly rollover, adjust for this.
445*cda5da8dSAndroid Build Coastguard Worker        if (self.when == 'MIDNIGHT' or self.when.startswith('W')) and not self.utc:
446*cda5da8dSAndroid Build Coastguard Worker            dstAtRollover = time.localtime(newRolloverAt)[-1]
447*cda5da8dSAndroid Build Coastguard Worker            if dstNow != dstAtRollover:
448*cda5da8dSAndroid Build Coastguard Worker                if not dstNow:  # DST kicks in before next rollover, so we need to deduct an hour
449*cda5da8dSAndroid Build Coastguard Worker                    addend = -3600
450*cda5da8dSAndroid Build Coastguard Worker                else:           # DST bows out before next rollover, so we need to add an hour
451*cda5da8dSAndroid Build Coastguard Worker                    addend = 3600
452*cda5da8dSAndroid Build Coastguard Worker                newRolloverAt += addend
453*cda5da8dSAndroid Build Coastguard Worker        self.rolloverAt = newRolloverAt
454*cda5da8dSAndroid Build Coastguard Worker
455*cda5da8dSAndroid Build Coastguard Workerclass WatchedFileHandler(logging.FileHandler):
456*cda5da8dSAndroid Build Coastguard Worker    """
457*cda5da8dSAndroid Build Coastguard Worker    A handler for logging to a file, which watches the file
458*cda5da8dSAndroid Build Coastguard Worker    to see if it has changed while in use. This can happen because of
459*cda5da8dSAndroid Build Coastguard Worker    usage of programs such as newsyslog and logrotate which perform
460*cda5da8dSAndroid Build Coastguard Worker    log file rotation. This handler, intended for use under Unix,
461*cda5da8dSAndroid Build Coastguard Worker    watches the file to see if it has changed since the last emit.
462*cda5da8dSAndroid Build Coastguard Worker    (A file has changed if its device or inode have changed.)
463*cda5da8dSAndroid Build Coastguard Worker    If it has changed, the old file stream is closed, and the file
464*cda5da8dSAndroid Build Coastguard Worker    opened to get a new stream.
465*cda5da8dSAndroid Build Coastguard Worker
466*cda5da8dSAndroid Build Coastguard Worker    This handler is not appropriate for use under Windows, because
467*cda5da8dSAndroid Build Coastguard Worker    under Windows open files cannot be moved or renamed - logging
468*cda5da8dSAndroid Build Coastguard Worker    opens the files with exclusive locks - and so there is no need
469*cda5da8dSAndroid Build Coastguard Worker    for such a handler. Furthermore, ST_INO is not supported under
470*cda5da8dSAndroid Build Coastguard Worker    Windows; stat always returns zero for this value.
471*cda5da8dSAndroid Build Coastguard Worker
472*cda5da8dSAndroid Build Coastguard Worker    This handler is based on a suggestion and patch by Chad J.
473*cda5da8dSAndroid Build Coastguard Worker    Schroeder.
474*cda5da8dSAndroid Build Coastguard Worker    """
475*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, filename, mode='a', encoding=None, delay=False,
476*cda5da8dSAndroid Build Coastguard Worker                 errors=None):
477*cda5da8dSAndroid Build Coastguard Worker        if "b" not in mode:
478*cda5da8dSAndroid Build Coastguard Worker            encoding = io.text_encoding(encoding)
479*cda5da8dSAndroid Build Coastguard Worker        logging.FileHandler.__init__(self, filename, mode=mode,
480*cda5da8dSAndroid Build Coastguard Worker                                     encoding=encoding, delay=delay,
481*cda5da8dSAndroid Build Coastguard Worker                                     errors=errors)
482*cda5da8dSAndroid Build Coastguard Worker        self.dev, self.ino = -1, -1
483*cda5da8dSAndroid Build Coastguard Worker        self._statstream()
484*cda5da8dSAndroid Build Coastguard Worker
485*cda5da8dSAndroid Build Coastguard Worker    def _statstream(self):
486*cda5da8dSAndroid Build Coastguard Worker        if self.stream:
487*cda5da8dSAndroid Build Coastguard Worker            sres = os.fstat(self.stream.fileno())
488*cda5da8dSAndroid Build Coastguard Worker            self.dev, self.ino = sres[ST_DEV], sres[ST_INO]
489*cda5da8dSAndroid Build Coastguard Worker
490*cda5da8dSAndroid Build Coastguard Worker    def reopenIfNeeded(self):
491*cda5da8dSAndroid Build Coastguard Worker        """
492*cda5da8dSAndroid Build Coastguard Worker        Reopen log file if needed.
493*cda5da8dSAndroid Build Coastguard Worker
494*cda5da8dSAndroid Build Coastguard Worker        Checks if the underlying file has changed, and if it
495*cda5da8dSAndroid Build Coastguard Worker        has, close the old stream and reopen the file to get the
496*cda5da8dSAndroid Build Coastguard Worker        current stream.
497*cda5da8dSAndroid Build Coastguard Worker        """
498*cda5da8dSAndroid Build Coastguard Worker        # Reduce the chance of race conditions by stat'ing by path only
499*cda5da8dSAndroid Build Coastguard Worker        # once and then fstat'ing our new fd if we opened a new log stream.
500*cda5da8dSAndroid Build Coastguard Worker        # See issue #14632: Thanks to John Mulligan for the problem report
501*cda5da8dSAndroid Build Coastguard Worker        # and patch.
502*cda5da8dSAndroid Build Coastguard Worker        try:
503*cda5da8dSAndroid Build Coastguard Worker            # stat the file by path, checking for existence
504*cda5da8dSAndroid Build Coastguard Worker            sres = os.stat(self.baseFilename)
505*cda5da8dSAndroid Build Coastguard Worker        except FileNotFoundError:
506*cda5da8dSAndroid Build Coastguard Worker            sres = None
507*cda5da8dSAndroid Build Coastguard Worker        # compare file system stat with that of our stream file handle
508*cda5da8dSAndroid Build Coastguard Worker        if not sres or sres[ST_DEV] != self.dev or sres[ST_INO] != self.ino:
509*cda5da8dSAndroid Build Coastguard Worker            if self.stream is not None:
510*cda5da8dSAndroid Build Coastguard Worker                # we have an open file handle, clean it up
511*cda5da8dSAndroid Build Coastguard Worker                self.stream.flush()
512*cda5da8dSAndroid Build Coastguard Worker                self.stream.close()
513*cda5da8dSAndroid Build Coastguard Worker                self.stream = None  # See Issue #21742: _open () might fail.
514*cda5da8dSAndroid Build Coastguard Worker                # open a new file handle and get new stat info from that fd
515*cda5da8dSAndroid Build Coastguard Worker                self.stream = self._open()
516*cda5da8dSAndroid Build Coastguard Worker                self._statstream()
517*cda5da8dSAndroid Build Coastguard Worker
518*cda5da8dSAndroid Build Coastguard Worker    def emit(self, record):
519*cda5da8dSAndroid Build Coastguard Worker        """
520*cda5da8dSAndroid Build Coastguard Worker        Emit a record.
521*cda5da8dSAndroid Build Coastguard Worker
522*cda5da8dSAndroid Build Coastguard Worker        If underlying file has changed, reopen the file before emitting the
523*cda5da8dSAndroid Build Coastguard Worker        record to it.
524*cda5da8dSAndroid Build Coastguard Worker        """
525*cda5da8dSAndroid Build Coastguard Worker        self.reopenIfNeeded()
526*cda5da8dSAndroid Build Coastguard Worker        logging.FileHandler.emit(self, record)
527*cda5da8dSAndroid Build Coastguard Worker
528*cda5da8dSAndroid Build Coastguard Worker
529*cda5da8dSAndroid Build Coastguard Workerclass SocketHandler(logging.Handler):
530*cda5da8dSAndroid Build Coastguard Worker    """
531*cda5da8dSAndroid Build Coastguard Worker    A handler class which writes logging records, in pickle format, to
532*cda5da8dSAndroid Build Coastguard Worker    a streaming socket. The socket is kept open across logging calls.
533*cda5da8dSAndroid Build Coastguard Worker    If the peer resets it, an attempt is made to reconnect on the next call.
534*cda5da8dSAndroid Build Coastguard Worker    The pickle which is sent is that of the LogRecord's attribute dictionary
535*cda5da8dSAndroid Build Coastguard Worker    (__dict__), so that the receiver does not need to have the logging module
536*cda5da8dSAndroid Build Coastguard Worker    installed in order to process the logging event.
537*cda5da8dSAndroid Build Coastguard Worker
538*cda5da8dSAndroid Build Coastguard Worker    To unpickle the record at the receiving end into a LogRecord, use the
539*cda5da8dSAndroid Build Coastguard Worker    makeLogRecord function.
540*cda5da8dSAndroid Build Coastguard Worker    """
541*cda5da8dSAndroid Build Coastguard Worker
542*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, host, port):
543*cda5da8dSAndroid Build Coastguard Worker        """
544*cda5da8dSAndroid Build Coastguard Worker        Initializes the handler with a specific host address and port.
545*cda5da8dSAndroid Build Coastguard Worker
546*cda5da8dSAndroid Build Coastguard Worker        When the attribute *closeOnError* is set to True - if a socket error
547*cda5da8dSAndroid Build Coastguard Worker        occurs, the socket is silently closed and then reopened on the next
548*cda5da8dSAndroid Build Coastguard Worker        logging call.
549*cda5da8dSAndroid Build Coastguard Worker        """
550*cda5da8dSAndroid Build Coastguard Worker        logging.Handler.__init__(self)
551*cda5da8dSAndroid Build Coastguard Worker        self.host = host
552*cda5da8dSAndroid Build Coastguard Worker        self.port = port
553*cda5da8dSAndroid Build Coastguard Worker        if port is None:
554*cda5da8dSAndroid Build Coastguard Worker            self.address = host
555*cda5da8dSAndroid Build Coastguard Worker        else:
556*cda5da8dSAndroid Build Coastguard Worker            self.address = (host, port)
557*cda5da8dSAndroid Build Coastguard Worker        self.sock = None
558*cda5da8dSAndroid Build Coastguard Worker        self.closeOnError = False
559*cda5da8dSAndroid Build Coastguard Worker        self.retryTime = None
560*cda5da8dSAndroid Build Coastguard Worker        #
561*cda5da8dSAndroid Build Coastguard Worker        # Exponential backoff parameters.
562*cda5da8dSAndroid Build Coastguard Worker        #
563*cda5da8dSAndroid Build Coastguard Worker        self.retryStart = 1.0
564*cda5da8dSAndroid Build Coastguard Worker        self.retryMax = 30.0
565*cda5da8dSAndroid Build Coastguard Worker        self.retryFactor = 2.0
566*cda5da8dSAndroid Build Coastguard Worker
567*cda5da8dSAndroid Build Coastguard Worker    def makeSocket(self, timeout=1):
568*cda5da8dSAndroid Build Coastguard Worker        """
569*cda5da8dSAndroid Build Coastguard Worker        A factory method which allows subclasses to define the precise
570*cda5da8dSAndroid Build Coastguard Worker        type of socket they want.
571*cda5da8dSAndroid Build Coastguard Worker        """
572*cda5da8dSAndroid Build Coastguard Worker        if self.port is not None:
573*cda5da8dSAndroid Build Coastguard Worker            result = socket.create_connection(self.address, timeout=timeout)
574*cda5da8dSAndroid Build Coastguard Worker        else:
575*cda5da8dSAndroid Build Coastguard Worker            result = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
576*cda5da8dSAndroid Build Coastguard Worker            result.settimeout(timeout)
577*cda5da8dSAndroid Build Coastguard Worker            try:
578*cda5da8dSAndroid Build Coastguard Worker                result.connect(self.address)
579*cda5da8dSAndroid Build Coastguard Worker            except OSError:
580*cda5da8dSAndroid Build Coastguard Worker                result.close()  # Issue 19182
581*cda5da8dSAndroid Build Coastguard Worker                raise
582*cda5da8dSAndroid Build Coastguard Worker        return result
583*cda5da8dSAndroid Build Coastguard Worker
584*cda5da8dSAndroid Build Coastguard Worker    def createSocket(self):
585*cda5da8dSAndroid Build Coastguard Worker        """
586*cda5da8dSAndroid Build Coastguard Worker        Try to create a socket, using an exponential backoff with
587*cda5da8dSAndroid Build Coastguard Worker        a max retry time. Thanks to Robert Olson for the original patch
588*cda5da8dSAndroid Build Coastguard Worker        (SF #815911) which has been slightly refactored.
589*cda5da8dSAndroid Build Coastguard Worker        """
590*cda5da8dSAndroid Build Coastguard Worker        now = time.time()
591*cda5da8dSAndroid Build Coastguard Worker        # Either retryTime is None, in which case this
592*cda5da8dSAndroid Build Coastguard Worker        # is the first time back after a disconnect, or
593*cda5da8dSAndroid Build Coastguard Worker        # we've waited long enough.
594*cda5da8dSAndroid Build Coastguard Worker        if self.retryTime is None:
595*cda5da8dSAndroid Build Coastguard Worker            attempt = True
596*cda5da8dSAndroid Build Coastguard Worker        else:
597*cda5da8dSAndroid Build Coastguard Worker            attempt = (now >= self.retryTime)
598*cda5da8dSAndroid Build Coastguard Worker        if attempt:
599*cda5da8dSAndroid Build Coastguard Worker            try:
600*cda5da8dSAndroid Build Coastguard Worker                self.sock = self.makeSocket()
601*cda5da8dSAndroid Build Coastguard Worker                self.retryTime = None # next time, no delay before trying
602*cda5da8dSAndroid Build Coastguard Worker            except OSError:
603*cda5da8dSAndroid Build Coastguard Worker                #Creation failed, so set the retry time and return.
604*cda5da8dSAndroid Build Coastguard Worker                if self.retryTime is None:
605*cda5da8dSAndroid Build Coastguard Worker                    self.retryPeriod = self.retryStart
606*cda5da8dSAndroid Build Coastguard Worker                else:
607*cda5da8dSAndroid Build Coastguard Worker                    self.retryPeriod = self.retryPeriod * self.retryFactor
608*cda5da8dSAndroid Build Coastguard Worker                    if self.retryPeriod > self.retryMax:
609*cda5da8dSAndroid Build Coastguard Worker                        self.retryPeriod = self.retryMax
610*cda5da8dSAndroid Build Coastguard Worker                self.retryTime = now + self.retryPeriod
611*cda5da8dSAndroid Build Coastguard Worker
612*cda5da8dSAndroid Build Coastguard Worker    def send(self, s):
613*cda5da8dSAndroid Build Coastguard Worker        """
614*cda5da8dSAndroid Build Coastguard Worker        Send a pickled string to the socket.
615*cda5da8dSAndroid Build Coastguard Worker
616*cda5da8dSAndroid Build Coastguard Worker        This function allows for partial sends which can happen when the
617*cda5da8dSAndroid Build Coastguard Worker        network is busy.
618*cda5da8dSAndroid Build Coastguard Worker        """
619*cda5da8dSAndroid Build Coastguard Worker        if self.sock is None:
620*cda5da8dSAndroid Build Coastguard Worker            self.createSocket()
621*cda5da8dSAndroid Build Coastguard Worker        #self.sock can be None either because we haven't reached the retry
622*cda5da8dSAndroid Build Coastguard Worker        #time yet, or because we have reached the retry time and retried,
623*cda5da8dSAndroid Build Coastguard Worker        #but are still unable to connect.
624*cda5da8dSAndroid Build Coastguard Worker        if self.sock:
625*cda5da8dSAndroid Build Coastguard Worker            try:
626*cda5da8dSAndroid Build Coastguard Worker                self.sock.sendall(s)
627*cda5da8dSAndroid Build Coastguard Worker            except OSError: #pragma: no cover
628*cda5da8dSAndroid Build Coastguard Worker                self.sock.close()
629*cda5da8dSAndroid Build Coastguard Worker                self.sock = None  # so we can call createSocket next time
630*cda5da8dSAndroid Build Coastguard Worker
631*cda5da8dSAndroid Build Coastguard Worker    def makePickle(self, record):
632*cda5da8dSAndroid Build Coastguard Worker        """
633*cda5da8dSAndroid Build Coastguard Worker        Pickles the record in binary format with a length prefix, and
634*cda5da8dSAndroid Build Coastguard Worker        returns it ready for transmission across the socket.
635*cda5da8dSAndroid Build Coastguard Worker        """
636*cda5da8dSAndroid Build Coastguard Worker        ei = record.exc_info
637*cda5da8dSAndroid Build Coastguard Worker        if ei:
638*cda5da8dSAndroid Build Coastguard Worker            # just to get traceback text into record.exc_text ...
639*cda5da8dSAndroid Build Coastguard Worker            dummy = self.format(record)
640*cda5da8dSAndroid Build Coastguard Worker        # See issue #14436: If msg or args are objects, they may not be
641*cda5da8dSAndroid Build Coastguard Worker        # available on the receiving end. So we convert the msg % args
642*cda5da8dSAndroid Build Coastguard Worker        # to a string, save it as msg and zap the args.
643*cda5da8dSAndroid Build Coastguard Worker        d = dict(record.__dict__)
644*cda5da8dSAndroid Build Coastguard Worker        d['msg'] = record.getMessage()
645*cda5da8dSAndroid Build Coastguard Worker        d['args'] = None
646*cda5da8dSAndroid Build Coastguard Worker        d['exc_info'] = None
647*cda5da8dSAndroid Build Coastguard Worker        # Issue #25685: delete 'message' if present: redundant with 'msg'
648*cda5da8dSAndroid Build Coastguard Worker        d.pop('message', None)
649*cda5da8dSAndroid Build Coastguard Worker        s = pickle.dumps(d, 1)
650*cda5da8dSAndroid Build Coastguard Worker        slen = struct.pack(">L", len(s))
651*cda5da8dSAndroid Build Coastguard Worker        return slen + s
652*cda5da8dSAndroid Build Coastguard Worker
653*cda5da8dSAndroid Build Coastguard Worker    def handleError(self, record):
654*cda5da8dSAndroid Build Coastguard Worker        """
655*cda5da8dSAndroid Build Coastguard Worker        Handle an error during logging.
656*cda5da8dSAndroid Build Coastguard Worker
657*cda5da8dSAndroid Build Coastguard Worker        An error has occurred during logging. Most likely cause -
658*cda5da8dSAndroid Build Coastguard Worker        connection lost. Close the socket so that we can retry on the
659*cda5da8dSAndroid Build Coastguard Worker        next event.
660*cda5da8dSAndroid Build Coastguard Worker        """
661*cda5da8dSAndroid Build Coastguard Worker        if self.closeOnError and self.sock:
662*cda5da8dSAndroid Build Coastguard Worker            self.sock.close()
663*cda5da8dSAndroid Build Coastguard Worker            self.sock = None        #try to reconnect next time
664*cda5da8dSAndroid Build Coastguard Worker        else:
665*cda5da8dSAndroid Build Coastguard Worker            logging.Handler.handleError(self, record)
666*cda5da8dSAndroid Build Coastguard Worker
667*cda5da8dSAndroid Build Coastguard Worker    def emit(self, record):
668*cda5da8dSAndroid Build Coastguard Worker        """
669*cda5da8dSAndroid Build Coastguard Worker        Emit a record.
670*cda5da8dSAndroid Build Coastguard Worker
671*cda5da8dSAndroid Build Coastguard Worker        Pickles the record and writes it to the socket in binary format.
672*cda5da8dSAndroid Build Coastguard Worker        If there is an error with the socket, silently drop the packet.
673*cda5da8dSAndroid Build Coastguard Worker        If there was a problem with the socket, re-establishes the
674*cda5da8dSAndroid Build Coastguard Worker        socket.
675*cda5da8dSAndroid Build Coastguard Worker        """
676*cda5da8dSAndroid Build Coastguard Worker        try:
677*cda5da8dSAndroid Build Coastguard Worker            s = self.makePickle(record)
678*cda5da8dSAndroid Build Coastguard Worker            self.send(s)
679*cda5da8dSAndroid Build Coastguard Worker        except Exception:
680*cda5da8dSAndroid Build Coastguard Worker            self.handleError(record)
681*cda5da8dSAndroid Build Coastguard Worker
682*cda5da8dSAndroid Build Coastguard Worker    def close(self):
683*cda5da8dSAndroid Build Coastguard Worker        """
684*cda5da8dSAndroid Build Coastguard Worker        Closes the socket.
685*cda5da8dSAndroid Build Coastguard Worker        """
686*cda5da8dSAndroid Build Coastguard Worker        self.acquire()
687*cda5da8dSAndroid Build Coastguard Worker        try:
688*cda5da8dSAndroid Build Coastguard Worker            sock = self.sock
689*cda5da8dSAndroid Build Coastguard Worker            if sock:
690*cda5da8dSAndroid Build Coastguard Worker                self.sock = None
691*cda5da8dSAndroid Build Coastguard Worker                sock.close()
692*cda5da8dSAndroid Build Coastguard Worker            logging.Handler.close(self)
693*cda5da8dSAndroid Build Coastguard Worker        finally:
694*cda5da8dSAndroid Build Coastguard Worker            self.release()
695*cda5da8dSAndroid Build Coastguard Worker
696*cda5da8dSAndroid Build Coastguard Workerclass DatagramHandler(SocketHandler):
697*cda5da8dSAndroid Build Coastguard Worker    """
698*cda5da8dSAndroid Build Coastguard Worker    A handler class which writes logging records, in pickle format, to
699*cda5da8dSAndroid Build Coastguard Worker    a datagram socket.  The pickle which is sent is that of the LogRecord's
700*cda5da8dSAndroid Build Coastguard Worker    attribute dictionary (__dict__), so that the receiver does not need to
701*cda5da8dSAndroid Build Coastguard Worker    have the logging module installed in order to process the logging event.
702*cda5da8dSAndroid Build Coastguard Worker
703*cda5da8dSAndroid Build Coastguard Worker    To unpickle the record at the receiving end into a LogRecord, use the
704*cda5da8dSAndroid Build Coastguard Worker    makeLogRecord function.
705*cda5da8dSAndroid Build Coastguard Worker
706*cda5da8dSAndroid Build Coastguard Worker    """
707*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, host, port):
708*cda5da8dSAndroid Build Coastguard Worker        """
709*cda5da8dSAndroid Build Coastguard Worker        Initializes the handler with a specific host address and port.
710*cda5da8dSAndroid Build Coastguard Worker        """
711*cda5da8dSAndroid Build Coastguard Worker        SocketHandler.__init__(self, host, port)
712*cda5da8dSAndroid Build Coastguard Worker        self.closeOnError = False
713*cda5da8dSAndroid Build Coastguard Worker
714*cda5da8dSAndroid Build Coastguard Worker    def makeSocket(self):
715*cda5da8dSAndroid Build Coastguard Worker        """
716*cda5da8dSAndroid Build Coastguard Worker        The factory method of SocketHandler is here overridden to create
717*cda5da8dSAndroid Build Coastguard Worker        a UDP socket (SOCK_DGRAM).
718*cda5da8dSAndroid Build Coastguard Worker        """
719*cda5da8dSAndroid Build Coastguard Worker        if self.port is None:
720*cda5da8dSAndroid Build Coastguard Worker            family = socket.AF_UNIX
721*cda5da8dSAndroid Build Coastguard Worker        else:
722*cda5da8dSAndroid Build Coastguard Worker            family = socket.AF_INET
723*cda5da8dSAndroid Build Coastguard Worker        s = socket.socket(family, socket.SOCK_DGRAM)
724*cda5da8dSAndroid Build Coastguard Worker        return s
725*cda5da8dSAndroid Build Coastguard Worker
726*cda5da8dSAndroid Build Coastguard Worker    def send(self, s):
727*cda5da8dSAndroid Build Coastguard Worker        """
728*cda5da8dSAndroid Build Coastguard Worker        Send a pickled string to a socket.
729*cda5da8dSAndroid Build Coastguard Worker
730*cda5da8dSAndroid Build Coastguard Worker        This function no longer allows for partial sends which can happen
731*cda5da8dSAndroid Build Coastguard Worker        when the network is busy - UDP does not guarantee delivery and
732*cda5da8dSAndroid Build Coastguard Worker        can deliver packets out of sequence.
733*cda5da8dSAndroid Build Coastguard Worker        """
734*cda5da8dSAndroid Build Coastguard Worker        if self.sock is None:
735*cda5da8dSAndroid Build Coastguard Worker            self.createSocket()
736*cda5da8dSAndroid Build Coastguard Worker        self.sock.sendto(s, self.address)
737*cda5da8dSAndroid Build Coastguard Worker
738*cda5da8dSAndroid Build Coastguard Workerclass SysLogHandler(logging.Handler):
739*cda5da8dSAndroid Build Coastguard Worker    """
740*cda5da8dSAndroid Build Coastguard Worker    A handler class which sends formatted logging records to a syslog
741*cda5da8dSAndroid Build Coastguard Worker    server. Based on Sam Rushing's syslog module:
742*cda5da8dSAndroid Build Coastguard Worker    http://www.nightmare.com/squirl/python-ext/misc/syslog.py
743*cda5da8dSAndroid Build Coastguard Worker    Contributed by Nicolas Untz (after which minor refactoring changes
744*cda5da8dSAndroid Build Coastguard Worker    have been made).
745*cda5da8dSAndroid Build Coastguard Worker    """
746*cda5da8dSAndroid Build Coastguard Worker
747*cda5da8dSAndroid Build Coastguard Worker    # from <linux/sys/syslog.h>:
748*cda5da8dSAndroid Build Coastguard Worker    # ======================================================================
749*cda5da8dSAndroid Build Coastguard Worker    # priorities/facilities are encoded into a single 32-bit quantity, where
750*cda5da8dSAndroid Build Coastguard Worker    # the bottom 3 bits are the priority (0-7) and the top 28 bits are the
751*cda5da8dSAndroid Build Coastguard Worker    # facility (0-big number). Both the priorities and the facilities map
752*cda5da8dSAndroid Build Coastguard Worker    # roughly one-to-one to strings in the syslogd(8) source code.  This
753*cda5da8dSAndroid Build Coastguard Worker    # mapping is included in this file.
754*cda5da8dSAndroid Build Coastguard Worker    #
755*cda5da8dSAndroid Build Coastguard Worker    # priorities (these are ordered)
756*cda5da8dSAndroid Build Coastguard Worker
757*cda5da8dSAndroid Build Coastguard Worker    LOG_EMERG     = 0       #  system is unusable
758*cda5da8dSAndroid Build Coastguard Worker    LOG_ALERT     = 1       #  action must be taken immediately
759*cda5da8dSAndroid Build Coastguard Worker    LOG_CRIT      = 2       #  critical conditions
760*cda5da8dSAndroid Build Coastguard Worker    LOG_ERR       = 3       #  error conditions
761*cda5da8dSAndroid Build Coastguard Worker    LOG_WARNING   = 4       #  warning conditions
762*cda5da8dSAndroid Build Coastguard Worker    LOG_NOTICE    = 5       #  normal but significant condition
763*cda5da8dSAndroid Build Coastguard Worker    LOG_INFO      = 6       #  informational
764*cda5da8dSAndroid Build Coastguard Worker    LOG_DEBUG     = 7       #  debug-level messages
765*cda5da8dSAndroid Build Coastguard Worker
766*cda5da8dSAndroid Build Coastguard Worker    #  facility codes
767*cda5da8dSAndroid Build Coastguard Worker    LOG_KERN      = 0       #  kernel messages
768*cda5da8dSAndroid Build Coastguard Worker    LOG_USER      = 1       #  random user-level messages
769*cda5da8dSAndroid Build Coastguard Worker    LOG_MAIL      = 2       #  mail system
770*cda5da8dSAndroid Build Coastguard Worker    LOG_DAEMON    = 3       #  system daemons
771*cda5da8dSAndroid Build Coastguard Worker    LOG_AUTH      = 4       #  security/authorization messages
772*cda5da8dSAndroid Build Coastguard Worker    LOG_SYSLOG    = 5       #  messages generated internally by syslogd
773*cda5da8dSAndroid Build Coastguard Worker    LOG_LPR       = 6       #  line printer subsystem
774*cda5da8dSAndroid Build Coastguard Worker    LOG_NEWS      = 7       #  network news subsystem
775*cda5da8dSAndroid Build Coastguard Worker    LOG_UUCP      = 8       #  UUCP subsystem
776*cda5da8dSAndroid Build Coastguard Worker    LOG_CRON      = 9       #  clock daemon
777*cda5da8dSAndroid Build Coastguard Worker    LOG_AUTHPRIV  = 10      #  security/authorization messages (private)
778*cda5da8dSAndroid Build Coastguard Worker    LOG_FTP       = 11      #  FTP daemon
779*cda5da8dSAndroid Build Coastguard Worker    LOG_NTP       = 12      #  NTP subsystem
780*cda5da8dSAndroid Build Coastguard Worker    LOG_SECURITY  = 13      #  Log audit
781*cda5da8dSAndroid Build Coastguard Worker    LOG_CONSOLE   = 14      #  Log alert
782*cda5da8dSAndroid Build Coastguard Worker    LOG_SOLCRON   = 15      #  Scheduling daemon (Solaris)
783*cda5da8dSAndroid Build Coastguard Worker
784*cda5da8dSAndroid Build Coastguard Worker    #  other codes through 15 reserved for system use
785*cda5da8dSAndroid Build Coastguard Worker    LOG_LOCAL0    = 16      #  reserved for local use
786*cda5da8dSAndroid Build Coastguard Worker    LOG_LOCAL1    = 17      #  reserved for local use
787*cda5da8dSAndroid Build Coastguard Worker    LOG_LOCAL2    = 18      #  reserved for local use
788*cda5da8dSAndroid Build Coastguard Worker    LOG_LOCAL3    = 19      #  reserved for local use
789*cda5da8dSAndroid Build Coastguard Worker    LOG_LOCAL4    = 20      #  reserved for local use
790*cda5da8dSAndroid Build Coastguard Worker    LOG_LOCAL5    = 21      #  reserved for local use
791*cda5da8dSAndroid Build Coastguard Worker    LOG_LOCAL6    = 22      #  reserved for local use
792*cda5da8dSAndroid Build Coastguard Worker    LOG_LOCAL7    = 23      #  reserved for local use
793*cda5da8dSAndroid Build Coastguard Worker
794*cda5da8dSAndroid Build Coastguard Worker    priority_names = {
795*cda5da8dSAndroid Build Coastguard Worker        "alert":    LOG_ALERT,
796*cda5da8dSAndroid Build Coastguard Worker        "crit":     LOG_CRIT,
797*cda5da8dSAndroid Build Coastguard Worker        "critical": LOG_CRIT,
798*cda5da8dSAndroid Build Coastguard Worker        "debug":    LOG_DEBUG,
799*cda5da8dSAndroid Build Coastguard Worker        "emerg":    LOG_EMERG,
800*cda5da8dSAndroid Build Coastguard Worker        "err":      LOG_ERR,
801*cda5da8dSAndroid Build Coastguard Worker        "error":    LOG_ERR,        #  DEPRECATED
802*cda5da8dSAndroid Build Coastguard Worker        "info":     LOG_INFO,
803*cda5da8dSAndroid Build Coastguard Worker        "notice":   LOG_NOTICE,
804*cda5da8dSAndroid Build Coastguard Worker        "panic":    LOG_EMERG,      #  DEPRECATED
805*cda5da8dSAndroid Build Coastguard Worker        "warn":     LOG_WARNING,    #  DEPRECATED
806*cda5da8dSAndroid Build Coastguard Worker        "warning":  LOG_WARNING,
807*cda5da8dSAndroid Build Coastguard Worker        }
808*cda5da8dSAndroid Build Coastguard Worker
809*cda5da8dSAndroid Build Coastguard Worker    facility_names = {
810*cda5da8dSAndroid Build Coastguard Worker        "auth":         LOG_AUTH,
811*cda5da8dSAndroid Build Coastguard Worker        "authpriv":     LOG_AUTHPRIV,
812*cda5da8dSAndroid Build Coastguard Worker        "console":      LOG_CONSOLE,
813*cda5da8dSAndroid Build Coastguard Worker        "cron":         LOG_CRON,
814*cda5da8dSAndroid Build Coastguard Worker        "daemon":       LOG_DAEMON,
815*cda5da8dSAndroid Build Coastguard Worker        "ftp":          LOG_FTP,
816*cda5da8dSAndroid Build Coastguard Worker        "kern":         LOG_KERN,
817*cda5da8dSAndroid Build Coastguard Worker        "lpr":          LOG_LPR,
818*cda5da8dSAndroid Build Coastguard Worker        "mail":         LOG_MAIL,
819*cda5da8dSAndroid Build Coastguard Worker        "news":         LOG_NEWS,
820*cda5da8dSAndroid Build Coastguard Worker        "ntp":          LOG_NTP,
821*cda5da8dSAndroid Build Coastguard Worker        "security":     LOG_SECURITY,
822*cda5da8dSAndroid Build Coastguard Worker        "solaris-cron": LOG_SOLCRON,
823*cda5da8dSAndroid Build Coastguard Worker        "syslog":       LOG_SYSLOG,
824*cda5da8dSAndroid Build Coastguard Worker        "user":         LOG_USER,
825*cda5da8dSAndroid Build Coastguard Worker        "uucp":         LOG_UUCP,
826*cda5da8dSAndroid Build Coastguard Worker        "local0":       LOG_LOCAL0,
827*cda5da8dSAndroid Build Coastguard Worker        "local1":       LOG_LOCAL1,
828*cda5da8dSAndroid Build Coastguard Worker        "local2":       LOG_LOCAL2,
829*cda5da8dSAndroid Build Coastguard Worker        "local3":       LOG_LOCAL3,
830*cda5da8dSAndroid Build Coastguard Worker        "local4":       LOG_LOCAL4,
831*cda5da8dSAndroid Build Coastguard Worker        "local5":       LOG_LOCAL5,
832*cda5da8dSAndroid Build Coastguard Worker        "local6":       LOG_LOCAL6,
833*cda5da8dSAndroid Build Coastguard Worker        "local7":       LOG_LOCAL7,
834*cda5da8dSAndroid Build Coastguard Worker        }
835*cda5da8dSAndroid Build Coastguard Worker
836*cda5da8dSAndroid Build Coastguard Worker    #The map below appears to be trivially lowercasing the key. However,
837*cda5da8dSAndroid Build Coastguard Worker    #there's more to it than meets the eye - in some locales, lowercasing
838*cda5da8dSAndroid Build Coastguard Worker    #gives unexpected results. See SF #1524081: in the Turkish locale,
839*cda5da8dSAndroid Build Coastguard Worker    #"INFO".lower() != "info"
840*cda5da8dSAndroid Build Coastguard Worker    priority_map = {
841*cda5da8dSAndroid Build Coastguard Worker        "DEBUG" : "debug",
842*cda5da8dSAndroid Build Coastguard Worker        "INFO" : "info",
843*cda5da8dSAndroid Build Coastguard Worker        "WARNING" : "warning",
844*cda5da8dSAndroid Build Coastguard Worker        "ERROR" : "error",
845*cda5da8dSAndroid Build Coastguard Worker        "CRITICAL" : "critical"
846*cda5da8dSAndroid Build Coastguard Worker    }
847*cda5da8dSAndroid Build Coastguard Worker
848*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, address=('localhost', SYSLOG_UDP_PORT),
849*cda5da8dSAndroid Build Coastguard Worker                 facility=LOG_USER, socktype=None):
850*cda5da8dSAndroid Build Coastguard Worker        """
851*cda5da8dSAndroid Build Coastguard Worker        Initialize a handler.
852*cda5da8dSAndroid Build Coastguard Worker
853*cda5da8dSAndroid Build Coastguard Worker        If address is specified as a string, a UNIX socket is used. To log to a
854*cda5da8dSAndroid Build Coastguard Worker        local syslogd, "SysLogHandler(address="/dev/log")" can be used.
855*cda5da8dSAndroid Build Coastguard Worker        If facility is not specified, LOG_USER is used. If socktype is
856*cda5da8dSAndroid Build Coastguard Worker        specified as socket.SOCK_DGRAM or socket.SOCK_STREAM, that specific
857*cda5da8dSAndroid Build Coastguard Worker        socket type will be used. For Unix sockets, you can also specify a
858*cda5da8dSAndroid Build Coastguard Worker        socktype of None, in which case socket.SOCK_DGRAM will be used, falling
859*cda5da8dSAndroid Build Coastguard Worker        back to socket.SOCK_STREAM.
860*cda5da8dSAndroid Build Coastguard Worker        """
861*cda5da8dSAndroid Build Coastguard Worker        logging.Handler.__init__(self)
862*cda5da8dSAndroid Build Coastguard Worker
863*cda5da8dSAndroid Build Coastguard Worker        self.address = address
864*cda5da8dSAndroid Build Coastguard Worker        self.facility = facility
865*cda5da8dSAndroid Build Coastguard Worker        self.socktype = socktype
866*cda5da8dSAndroid Build Coastguard Worker        self.socket = None
867*cda5da8dSAndroid Build Coastguard Worker        self.createSocket()
868*cda5da8dSAndroid Build Coastguard Worker
869*cda5da8dSAndroid Build Coastguard Worker    def _connect_unixsocket(self, address):
870*cda5da8dSAndroid Build Coastguard Worker        use_socktype = self.socktype
871*cda5da8dSAndroid Build Coastguard Worker        if use_socktype is None:
872*cda5da8dSAndroid Build Coastguard Worker            use_socktype = socket.SOCK_DGRAM
873*cda5da8dSAndroid Build Coastguard Worker        self.socket = socket.socket(socket.AF_UNIX, use_socktype)
874*cda5da8dSAndroid Build Coastguard Worker        try:
875*cda5da8dSAndroid Build Coastguard Worker            self.socket.connect(address)
876*cda5da8dSAndroid Build Coastguard Worker            # it worked, so set self.socktype to the used type
877*cda5da8dSAndroid Build Coastguard Worker            self.socktype = use_socktype
878*cda5da8dSAndroid Build Coastguard Worker        except OSError:
879*cda5da8dSAndroid Build Coastguard Worker            self.socket.close()
880*cda5da8dSAndroid Build Coastguard Worker            if self.socktype is not None:
881*cda5da8dSAndroid Build Coastguard Worker                # user didn't specify falling back, so fail
882*cda5da8dSAndroid Build Coastguard Worker                raise
883*cda5da8dSAndroid Build Coastguard Worker            use_socktype = socket.SOCK_STREAM
884*cda5da8dSAndroid Build Coastguard Worker            self.socket = socket.socket(socket.AF_UNIX, use_socktype)
885*cda5da8dSAndroid Build Coastguard Worker            try:
886*cda5da8dSAndroid Build Coastguard Worker                self.socket.connect(address)
887*cda5da8dSAndroid Build Coastguard Worker                # it worked, so set self.socktype to the used type
888*cda5da8dSAndroid Build Coastguard Worker                self.socktype = use_socktype
889*cda5da8dSAndroid Build Coastguard Worker            except OSError:
890*cda5da8dSAndroid Build Coastguard Worker                self.socket.close()
891*cda5da8dSAndroid Build Coastguard Worker                raise
892*cda5da8dSAndroid Build Coastguard Worker
893*cda5da8dSAndroid Build Coastguard Worker    def createSocket(self):
894*cda5da8dSAndroid Build Coastguard Worker        """
895*cda5da8dSAndroid Build Coastguard Worker        Try to create a socket and, if it's not a datagram socket, connect it
896*cda5da8dSAndroid Build Coastguard Worker        to the other end. This method is called during handler initialization,
897*cda5da8dSAndroid Build Coastguard Worker        but it's not regarded as an error if the other end isn't listening yet
898*cda5da8dSAndroid Build Coastguard Worker        --- the method will be called again when emitting an event,
899*cda5da8dSAndroid Build Coastguard Worker        if there is no socket at that point.
900*cda5da8dSAndroid Build Coastguard Worker        """
901*cda5da8dSAndroid Build Coastguard Worker        address = self.address
902*cda5da8dSAndroid Build Coastguard Worker        socktype = self.socktype
903*cda5da8dSAndroid Build Coastguard Worker
904*cda5da8dSAndroid Build Coastguard Worker        if isinstance(address, str):
905*cda5da8dSAndroid Build Coastguard Worker            self.unixsocket = True
906*cda5da8dSAndroid Build Coastguard Worker            # Syslog server may be unavailable during handler initialisation.
907*cda5da8dSAndroid Build Coastguard Worker            # C's openlog() function also ignores connection errors.
908*cda5da8dSAndroid Build Coastguard Worker            # Moreover, we ignore these errors while logging, so it's not worse
909*cda5da8dSAndroid Build Coastguard Worker            # to ignore it also here.
910*cda5da8dSAndroid Build Coastguard Worker            try:
911*cda5da8dSAndroid Build Coastguard Worker                self._connect_unixsocket(address)
912*cda5da8dSAndroid Build Coastguard Worker            except OSError:
913*cda5da8dSAndroid Build Coastguard Worker                pass
914*cda5da8dSAndroid Build Coastguard Worker        else:
915*cda5da8dSAndroid Build Coastguard Worker            self.unixsocket = False
916*cda5da8dSAndroid Build Coastguard Worker            if socktype is None:
917*cda5da8dSAndroid Build Coastguard Worker                socktype = socket.SOCK_DGRAM
918*cda5da8dSAndroid Build Coastguard Worker            host, port = address
919*cda5da8dSAndroid Build Coastguard Worker            ress = socket.getaddrinfo(host, port, 0, socktype)
920*cda5da8dSAndroid Build Coastguard Worker            if not ress:
921*cda5da8dSAndroid Build Coastguard Worker                raise OSError("getaddrinfo returns an empty list")
922*cda5da8dSAndroid Build Coastguard Worker            for res in ress:
923*cda5da8dSAndroid Build Coastguard Worker                af, socktype, proto, _, sa = res
924*cda5da8dSAndroid Build Coastguard Worker                err = sock = None
925*cda5da8dSAndroid Build Coastguard Worker                try:
926*cda5da8dSAndroid Build Coastguard Worker                    sock = socket.socket(af, socktype, proto)
927*cda5da8dSAndroid Build Coastguard Worker                    if socktype == socket.SOCK_STREAM:
928*cda5da8dSAndroid Build Coastguard Worker                        sock.connect(sa)
929*cda5da8dSAndroid Build Coastguard Worker                    break
930*cda5da8dSAndroid Build Coastguard Worker                except OSError as exc:
931*cda5da8dSAndroid Build Coastguard Worker                    err = exc
932*cda5da8dSAndroid Build Coastguard Worker                    if sock is not None:
933*cda5da8dSAndroid Build Coastguard Worker                        sock.close()
934*cda5da8dSAndroid Build Coastguard Worker            if err is not None:
935*cda5da8dSAndroid Build Coastguard Worker                raise err
936*cda5da8dSAndroid Build Coastguard Worker            self.socket = sock
937*cda5da8dSAndroid Build Coastguard Worker            self.socktype = socktype
938*cda5da8dSAndroid Build Coastguard Worker
939*cda5da8dSAndroid Build Coastguard Worker    def encodePriority(self, facility, priority):
940*cda5da8dSAndroid Build Coastguard Worker        """
941*cda5da8dSAndroid Build Coastguard Worker        Encode the facility and priority. You can pass in strings or
942*cda5da8dSAndroid Build Coastguard Worker        integers - if strings are passed, the facility_names and
943*cda5da8dSAndroid Build Coastguard Worker        priority_names mapping dictionaries are used to convert them to
944*cda5da8dSAndroid Build Coastguard Worker        integers.
945*cda5da8dSAndroid Build Coastguard Worker        """
946*cda5da8dSAndroid Build Coastguard Worker        if isinstance(facility, str):
947*cda5da8dSAndroid Build Coastguard Worker            facility = self.facility_names[facility]
948*cda5da8dSAndroid Build Coastguard Worker        if isinstance(priority, str):
949*cda5da8dSAndroid Build Coastguard Worker            priority = self.priority_names[priority]
950*cda5da8dSAndroid Build Coastguard Worker        return (facility << 3) | priority
951*cda5da8dSAndroid Build Coastguard Worker
952*cda5da8dSAndroid Build Coastguard Worker    def close(self):
953*cda5da8dSAndroid Build Coastguard Worker        """
954*cda5da8dSAndroid Build Coastguard Worker        Closes the socket.
955*cda5da8dSAndroid Build Coastguard Worker        """
956*cda5da8dSAndroid Build Coastguard Worker        self.acquire()
957*cda5da8dSAndroid Build Coastguard Worker        try:
958*cda5da8dSAndroid Build Coastguard Worker            sock = self.socket
959*cda5da8dSAndroid Build Coastguard Worker            if sock:
960*cda5da8dSAndroid Build Coastguard Worker                self.socket = None
961*cda5da8dSAndroid Build Coastguard Worker                sock.close()
962*cda5da8dSAndroid Build Coastguard Worker            logging.Handler.close(self)
963*cda5da8dSAndroid Build Coastguard Worker        finally:
964*cda5da8dSAndroid Build Coastguard Worker            self.release()
965*cda5da8dSAndroid Build Coastguard Worker
966*cda5da8dSAndroid Build Coastguard Worker    def mapPriority(self, levelName):
967*cda5da8dSAndroid Build Coastguard Worker        """
968*cda5da8dSAndroid Build Coastguard Worker        Map a logging level name to a key in the priority_names map.
969*cda5da8dSAndroid Build Coastguard Worker        This is useful in two scenarios: when custom levels are being
970*cda5da8dSAndroid Build Coastguard Worker        used, and in the case where you can't do a straightforward
971*cda5da8dSAndroid Build Coastguard Worker        mapping by lowercasing the logging level name because of locale-
972*cda5da8dSAndroid Build Coastguard Worker        specific issues (see SF #1524081).
973*cda5da8dSAndroid Build Coastguard Worker        """
974*cda5da8dSAndroid Build Coastguard Worker        return self.priority_map.get(levelName, "warning")
975*cda5da8dSAndroid Build Coastguard Worker
976*cda5da8dSAndroid Build Coastguard Worker    ident = ''          # prepended to all messages
977*cda5da8dSAndroid Build Coastguard Worker    append_nul = True   # some old syslog daemons expect a NUL terminator
978*cda5da8dSAndroid Build Coastguard Worker
979*cda5da8dSAndroid Build Coastguard Worker    def emit(self, record):
980*cda5da8dSAndroid Build Coastguard Worker        """
981*cda5da8dSAndroid Build Coastguard Worker        Emit a record.
982*cda5da8dSAndroid Build Coastguard Worker
983*cda5da8dSAndroid Build Coastguard Worker        The record is formatted, and then sent to the syslog server. If
984*cda5da8dSAndroid Build Coastguard Worker        exception information is present, it is NOT sent to the server.
985*cda5da8dSAndroid Build Coastguard Worker        """
986*cda5da8dSAndroid Build Coastguard Worker        try:
987*cda5da8dSAndroid Build Coastguard Worker            msg = self.format(record)
988*cda5da8dSAndroid Build Coastguard Worker            if self.ident:
989*cda5da8dSAndroid Build Coastguard Worker                msg = self.ident + msg
990*cda5da8dSAndroid Build Coastguard Worker            if self.append_nul:
991*cda5da8dSAndroid Build Coastguard Worker                msg += '\000'
992*cda5da8dSAndroid Build Coastguard Worker
993*cda5da8dSAndroid Build Coastguard Worker            # We need to convert record level to lowercase, maybe this will
994*cda5da8dSAndroid Build Coastguard Worker            # change in the future.
995*cda5da8dSAndroid Build Coastguard Worker            prio = '<%d>' % self.encodePriority(self.facility,
996*cda5da8dSAndroid Build Coastguard Worker                                                self.mapPriority(record.levelname))
997*cda5da8dSAndroid Build Coastguard Worker            prio = prio.encode('utf-8')
998*cda5da8dSAndroid Build Coastguard Worker            # Message is a string. Convert to bytes as required by RFC 5424
999*cda5da8dSAndroid Build Coastguard Worker            msg = msg.encode('utf-8')
1000*cda5da8dSAndroid Build Coastguard Worker            msg = prio + msg
1001*cda5da8dSAndroid Build Coastguard Worker
1002*cda5da8dSAndroid Build Coastguard Worker            if not self.socket:
1003*cda5da8dSAndroid Build Coastguard Worker                self.createSocket()
1004*cda5da8dSAndroid Build Coastguard Worker
1005*cda5da8dSAndroid Build Coastguard Worker            if self.unixsocket:
1006*cda5da8dSAndroid Build Coastguard Worker                try:
1007*cda5da8dSAndroid Build Coastguard Worker                    self.socket.send(msg)
1008*cda5da8dSAndroid Build Coastguard Worker                except OSError:
1009*cda5da8dSAndroid Build Coastguard Worker                    self.socket.close()
1010*cda5da8dSAndroid Build Coastguard Worker                    self._connect_unixsocket(self.address)
1011*cda5da8dSAndroid Build Coastguard Worker                    self.socket.send(msg)
1012*cda5da8dSAndroid Build Coastguard Worker            elif self.socktype == socket.SOCK_DGRAM:
1013*cda5da8dSAndroid Build Coastguard Worker                self.socket.sendto(msg, self.address)
1014*cda5da8dSAndroid Build Coastguard Worker            else:
1015*cda5da8dSAndroid Build Coastguard Worker                self.socket.sendall(msg)
1016*cda5da8dSAndroid Build Coastguard Worker        except Exception:
1017*cda5da8dSAndroid Build Coastguard Worker            self.handleError(record)
1018*cda5da8dSAndroid Build Coastguard Worker
1019*cda5da8dSAndroid Build Coastguard Workerclass SMTPHandler(logging.Handler):
1020*cda5da8dSAndroid Build Coastguard Worker    """
1021*cda5da8dSAndroid Build Coastguard Worker    A handler class which sends an SMTP email for each logging event.
1022*cda5da8dSAndroid Build Coastguard Worker    """
1023*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, mailhost, fromaddr, toaddrs, subject,
1024*cda5da8dSAndroid Build Coastguard Worker                 credentials=None, secure=None, timeout=5.0):
1025*cda5da8dSAndroid Build Coastguard Worker        """
1026*cda5da8dSAndroid Build Coastguard Worker        Initialize the handler.
1027*cda5da8dSAndroid Build Coastguard Worker
1028*cda5da8dSAndroid Build Coastguard Worker        Initialize the instance with the from and to addresses and subject
1029*cda5da8dSAndroid Build Coastguard Worker        line of the email. To specify a non-standard SMTP port, use the
1030*cda5da8dSAndroid Build Coastguard Worker        (host, port) tuple format for the mailhost argument. To specify
1031*cda5da8dSAndroid Build Coastguard Worker        authentication credentials, supply a (username, password) tuple
1032*cda5da8dSAndroid Build Coastguard Worker        for the credentials argument. To specify the use of a secure
1033*cda5da8dSAndroid Build Coastguard Worker        protocol (TLS), pass in a tuple for the secure argument. This will
1034*cda5da8dSAndroid Build Coastguard Worker        only be used when authentication credentials are supplied. The tuple
1035*cda5da8dSAndroid Build Coastguard Worker        will be either an empty tuple, or a single-value tuple with the name
1036*cda5da8dSAndroid Build Coastguard Worker        of a keyfile, or a 2-value tuple with the names of the keyfile and
1037*cda5da8dSAndroid Build Coastguard Worker        certificate file. (This tuple is passed to the `starttls` method).
1038*cda5da8dSAndroid Build Coastguard Worker        A timeout in seconds can be specified for the SMTP connection (the
1039*cda5da8dSAndroid Build Coastguard Worker        default is one second).
1040*cda5da8dSAndroid Build Coastguard Worker        """
1041*cda5da8dSAndroid Build Coastguard Worker        logging.Handler.__init__(self)
1042*cda5da8dSAndroid Build Coastguard Worker        if isinstance(mailhost, (list, tuple)):
1043*cda5da8dSAndroid Build Coastguard Worker            self.mailhost, self.mailport = mailhost
1044*cda5da8dSAndroid Build Coastguard Worker        else:
1045*cda5da8dSAndroid Build Coastguard Worker            self.mailhost, self.mailport = mailhost, None
1046*cda5da8dSAndroid Build Coastguard Worker        if isinstance(credentials, (list, tuple)):
1047*cda5da8dSAndroid Build Coastguard Worker            self.username, self.password = credentials
1048*cda5da8dSAndroid Build Coastguard Worker        else:
1049*cda5da8dSAndroid Build Coastguard Worker            self.username = None
1050*cda5da8dSAndroid Build Coastguard Worker        self.fromaddr = fromaddr
1051*cda5da8dSAndroid Build Coastguard Worker        if isinstance(toaddrs, str):
1052*cda5da8dSAndroid Build Coastguard Worker            toaddrs = [toaddrs]
1053*cda5da8dSAndroid Build Coastguard Worker        self.toaddrs = toaddrs
1054*cda5da8dSAndroid Build Coastguard Worker        self.subject = subject
1055*cda5da8dSAndroid Build Coastguard Worker        self.secure = secure
1056*cda5da8dSAndroid Build Coastguard Worker        self.timeout = timeout
1057*cda5da8dSAndroid Build Coastguard Worker
1058*cda5da8dSAndroid Build Coastguard Worker    def getSubject(self, record):
1059*cda5da8dSAndroid Build Coastguard Worker        """
1060*cda5da8dSAndroid Build Coastguard Worker        Determine the subject for the email.
1061*cda5da8dSAndroid Build Coastguard Worker
1062*cda5da8dSAndroid Build Coastguard Worker        If you want to specify a subject line which is record-dependent,
1063*cda5da8dSAndroid Build Coastguard Worker        override this method.
1064*cda5da8dSAndroid Build Coastguard Worker        """
1065*cda5da8dSAndroid Build Coastguard Worker        return self.subject
1066*cda5da8dSAndroid Build Coastguard Worker
1067*cda5da8dSAndroid Build Coastguard Worker    def emit(self, record):
1068*cda5da8dSAndroid Build Coastguard Worker        """
1069*cda5da8dSAndroid Build Coastguard Worker        Emit a record.
1070*cda5da8dSAndroid Build Coastguard Worker
1071*cda5da8dSAndroid Build Coastguard Worker        Format the record and send it to the specified addressees.
1072*cda5da8dSAndroid Build Coastguard Worker        """
1073*cda5da8dSAndroid Build Coastguard Worker        try:
1074*cda5da8dSAndroid Build Coastguard Worker            import smtplib
1075*cda5da8dSAndroid Build Coastguard Worker            from email.message import EmailMessage
1076*cda5da8dSAndroid Build Coastguard Worker            import email.utils
1077*cda5da8dSAndroid Build Coastguard Worker
1078*cda5da8dSAndroid Build Coastguard Worker            port = self.mailport
1079*cda5da8dSAndroid Build Coastguard Worker            if not port:
1080*cda5da8dSAndroid Build Coastguard Worker                port = smtplib.SMTP_PORT
1081*cda5da8dSAndroid Build Coastguard Worker            smtp = smtplib.SMTP(self.mailhost, port, timeout=self.timeout)
1082*cda5da8dSAndroid Build Coastguard Worker            msg = EmailMessage()
1083*cda5da8dSAndroid Build Coastguard Worker            msg['From'] = self.fromaddr
1084*cda5da8dSAndroid Build Coastguard Worker            msg['To'] = ','.join(self.toaddrs)
1085*cda5da8dSAndroid Build Coastguard Worker            msg['Subject'] = self.getSubject(record)
1086*cda5da8dSAndroid Build Coastguard Worker            msg['Date'] = email.utils.localtime()
1087*cda5da8dSAndroid Build Coastguard Worker            msg.set_content(self.format(record))
1088*cda5da8dSAndroid Build Coastguard Worker            if self.username:
1089*cda5da8dSAndroid Build Coastguard Worker                if self.secure is not None:
1090*cda5da8dSAndroid Build Coastguard Worker                    smtp.ehlo()
1091*cda5da8dSAndroid Build Coastguard Worker                    smtp.starttls(*self.secure)
1092*cda5da8dSAndroid Build Coastguard Worker                    smtp.ehlo()
1093*cda5da8dSAndroid Build Coastguard Worker                smtp.login(self.username, self.password)
1094*cda5da8dSAndroid Build Coastguard Worker            smtp.send_message(msg)
1095*cda5da8dSAndroid Build Coastguard Worker            smtp.quit()
1096*cda5da8dSAndroid Build Coastguard Worker        except Exception:
1097*cda5da8dSAndroid Build Coastguard Worker            self.handleError(record)
1098*cda5da8dSAndroid Build Coastguard Worker
1099*cda5da8dSAndroid Build Coastguard Workerclass NTEventLogHandler(logging.Handler):
1100*cda5da8dSAndroid Build Coastguard Worker    """
1101*cda5da8dSAndroid Build Coastguard Worker    A handler class which sends events to the NT Event Log. Adds a
1102*cda5da8dSAndroid Build Coastguard Worker    registry entry for the specified application name. If no dllname is
1103*cda5da8dSAndroid Build Coastguard Worker    provided, win32service.pyd (which contains some basic message
1104*cda5da8dSAndroid Build Coastguard Worker    placeholders) is used. Note that use of these placeholders will make
1105*cda5da8dSAndroid Build Coastguard Worker    your event logs big, as the entire message source is held in the log.
1106*cda5da8dSAndroid Build Coastguard Worker    If you want slimmer logs, you have to pass in the name of your own DLL
1107*cda5da8dSAndroid Build Coastguard Worker    which contains the message definitions you want to use in the event log.
1108*cda5da8dSAndroid Build Coastguard Worker    """
1109*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, appname, dllname=None, logtype="Application"):
1110*cda5da8dSAndroid Build Coastguard Worker        logging.Handler.__init__(self)
1111*cda5da8dSAndroid Build Coastguard Worker        try:
1112*cda5da8dSAndroid Build Coastguard Worker            import win32evtlogutil, win32evtlog
1113*cda5da8dSAndroid Build Coastguard Worker            self.appname = appname
1114*cda5da8dSAndroid Build Coastguard Worker            self._welu = win32evtlogutil
1115*cda5da8dSAndroid Build Coastguard Worker            if not dllname:
1116*cda5da8dSAndroid Build Coastguard Worker                dllname = os.path.split(self._welu.__file__)
1117*cda5da8dSAndroid Build Coastguard Worker                dllname = os.path.split(dllname[0])
1118*cda5da8dSAndroid Build Coastguard Worker                dllname = os.path.join(dllname[0], r'win32service.pyd')
1119*cda5da8dSAndroid Build Coastguard Worker            self.dllname = dllname
1120*cda5da8dSAndroid Build Coastguard Worker            self.logtype = logtype
1121*cda5da8dSAndroid Build Coastguard Worker            # Administrative privileges are required to add a source to the registry.
1122*cda5da8dSAndroid Build Coastguard Worker            # This may not be available for a user that just wants to add to an
1123*cda5da8dSAndroid Build Coastguard Worker            # existing source - handle this specific case.
1124*cda5da8dSAndroid Build Coastguard Worker            try:
1125*cda5da8dSAndroid Build Coastguard Worker                self._welu.AddSourceToRegistry(appname, dllname, logtype)
1126*cda5da8dSAndroid Build Coastguard Worker            except Exception as e:
1127*cda5da8dSAndroid Build Coastguard Worker                # This will probably be a pywintypes.error. Only raise if it's not
1128*cda5da8dSAndroid Build Coastguard Worker                # an "access denied" error, else let it pass
1129*cda5da8dSAndroid Build Coastguard Worker                if getattr(e, 'winerror', None) != 5:  # not access denied
1130*cda5da8dSAndroid Build Coastguard Worker                    raise
1131*cda5da8dSAndroid Build Coastguard Worker            self.deftype = win32evtlog.EVENTLOG_ERROR_TYPE
1132*cda5da8dSAndroid Build Coastguard Worker            self.typemap = {
1133*cda5da8dSAndroid Build Coastguard Worker                logging.DEBUG   : win32evtlog.EVENTLOG_INFORMATION_TYPE,
1134*cda5da8dSAndroid Build Coastguard Worker                logging.INFO    : win32evtlog.EVENTLOG_INFORMATION_TYPE,
1135*cda5da8dSAndroid Build Coastguard Worker                logging.WARNING : win32evtlog.EVENTLOG_WARNING_TYPE,
1136*cda5da8dSAndroid Build Coastguard Worker                logging.ERROR   : win32evtlog.EVENTLOG_ERROR_TYPE,
1137*cda5da8dSAndroid Build Coastguard Worker                logging.CRITICAL: win32evtlog.EVENTLOG_ERROR_TYPE,
1138*cda5da8dSAndroid Build Coastguard Worker         }
1139*cda5da8dSAndroid Build Coastguard Worker        except ImportError:
1140*cda5da8dSAndroid Build Coastguard Worker            print("The Python Win32 extensions for NT (service, event "\
1141*cda5da8dSAndroid Build Coastguard Worker                        "logging) appear not to be available.")
1142*cda5da8dSAndroid Build Coastguard Worker            self._welu = None
1143*cda5da8dSAndroid Build Coastguard Worker
1144*cda5da8dSAndroid Build Coastguard Worker    def getMessageID(self, record):
1145*cda5da8dSAndroid Build Coastguard Worker        """
1146*cda5da8dSAndroid Build Coastguard Worker        Return the message ID for the event record. If you are using your
1147*cda5da8dSAndroid Build Coastguard Worker        own messages, you could do this by having the msg passed to the
1148*cda5da8dSAndroid Build Coastguard Worker        logger being an ID rather than a formatting string. Then, in here,
1149*cda5da8dSAndroid Build Coastguard Worker        you could use a dictionary lookup to get the message ID. This
1150*cda5da8dSAndroid Build Coastguard Worker        version returns 1, which is the base message ID in win32service.pyd.
1151*cda5da8dSAndroid Build Coastguard Worker        """
1152*cda5da8dSAndroid Build Coastguard Worker        return 1
1153*cda5da8dSAndroid Build Coastguard Worker
1154*cda5da8dSAndroid Build Coastguard Worker    def getEventCategory(self, record):
1155*cda5da8dSAndroid Build Coastguard Worker        """
1156*cda5da8dSAndroid Build Coastguard Worker        Return the event category for the record.
1157*cda5da8dSAndroid Build Coastguard Worker
1158*cda5da8dSAndroid Build Coastguard Worker        Override this if you want to specify your own categories. This version
1159*cda5da8dSAndroid Build Coastguard Worker        returns 0.
1160*cda5da8dSAndroid Build Coastguard Worker        """
1161*cda5da8dSAndroid Build Coastguard Worker        return 0
1162*cda5da8dSAndroid Build Coastguard Worker
1163*cda5da8dSAndroid Build Coastguard Worker    def getEventType(self, record):
1164*cda5da8dSAndroid Build Coastguard Worker        """
1165*cda5da8dSAndroid Build Coastguard Worker        Return the event type for the record.
1166*cda5da8dSAndroid Build Coastguard Worker
1167*cda5da8dSAndroid Build Coastguard Worker        Override this if you want to specify your own types. This version does
1168*cda5da8dSAndroid Build Coastguard Worker        a mapping using the handler's typemap attribute, which is set up in
1169*cda5da8dSAndroid Build Coastguard Worker        __init__() to a dictionary which contains mappings for DEBUG, INFO,
1170*cda5da8dSAndroid Build Coastguard Worker        WARNING, ERROR and CRITICAL. If you are using your own levels you will
1171*cda5da8dSAndroid Build Coastguard Worker        either need to override this method or place a suitable dictionary in
1172*cda5da8dSAndroid Build Coastguard Worker        the handler's typemap attribute.
1173*cda5da8dSAndroid Build Coastguard Worker        """
1174*cda5da8dSAndroid Build Coastguard Worker        return self.typemap.get(record.levelno, self.deftype)
1175*cda5da8dSAndroid Build Coastguard Worker
1176*cda5da8dSAndroid Build Coastguard Worker    def emit(self, record):
1177*cda5da8dSAndroid Build Coastguard Worker        """
1178*cda5da8dSAndroid Build Coastguard Worker        Emit a record.
1179*cda5da8dSAndroid Build Coastguard Worker
1180*cda5da8dSAndroid Build Coastguard Worker        Determine the message ID, event category and event type. Then
1181*cda5da8dSAndroid Build Coastguard Worker        log the message in the NT event log.
1182*cda5da8dSAndroid Build Coastguard Worker        """
1183*cda5da8dSAndroid Build Coastguard Worker        if self._welu:
1184*cda5da8dSAndroid Build Coastguard Worker            try:
1185*cda5da8dSAndroid Build Coastguard Worker                id = self.getMessageID(record)
1186*cda5da8dSAndroid Build Coastguard Worker                cat = self.getEventCategory(record)
1187*cda5da8dSAndroid Build Coastguard Worker                type = self.getEventType(record)
1188*cda5da8dSAndroid Build Coastguard Worker                msg = self.format(record)
1189*cda5da8dSAndroid Build Coastguard Worker                self._welu.ReportEvent(self.appname, id, cat, type, [msg])
1190*cda5da8dSAndroid Build Coastguard Worker            except Exception:
1191*cda5da8dSAndroid Build Coastguard Worker                self.handleError(record)
1192*cda5da8dSAndroid Build Coastguard Worker
1193*cda5da8dSAndroid Build Coastguard Worker    def close(self):
1194*cda5da8dSAndroid Build Coastguard Worker        """
1195*cda5da8dSAndroid Build Coastguard Worker        Clean up this handler.
1196*cda5da8dSAndroid Build Coastguard Worker
1197*cda5da8dSAndroid Build Coastguard Worker        You can remove the application name from the registry as a
1198*cda5da8dSAndroid Build Coastguard Worker        source of event log entries. However, if you do this, you will
1199*cda5da8dSAndroid Build Coastguard Worker        not be able to see the events as you intended in the Event Log
1200*cda5da8dSAndroid Build Coastguard Worker        Viewer - it needs to be able to access the registry to get the
1201*cda5da8dSAndroid Build Coastguard Worker        DLL name.
1202*cda5da8dSAndroid Build Coastguard Worker        """
1203*cda5da8dSAndroid Build Coastguard Worker        #self._welu.RemoveSourceFromRegistry(self.appname, self.logtype)
1204*cda5da8dSAndroid Build Coastguard Worker        logging.Handler.close(self)
1205*cda5da8dSAndroid Build Coastguard Worker
1206*cda5da8dSAndroid Build Coastguard Workerclass HTTPHandler(logging.Handler):
1207*cda5da8dSAndroid Build Coastguard Worker    """
1208*cda5da8dSAndroid Build Coastguard Worker    A class which sends records to a web server, using either GET or
1209*cda5da8dSAndroid Build Coastguard Worker    POST semantics.
1210*cda5da8dSAndroid Build Coastguard Worker    """
1211*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, host, url, method="GET", secure=False, credentials=None,
1212*cda5da8dSAndroid Build Coastguard Worker                 context=None):
1213*cda5da8dSAndroid Build Coastguard Worker        """
1214*cda5da8dSAndroid Build Coastguard Worker        Initialize the instance with the host, the request URL, and the method
1215*cda5da8dSAndroid Build Coastguard Worker        ("GET" or "POST")
1216*cda5da8dSAndroid Build Coastguard Worker        """
1217*cda5da8dSAndroid Build Coastguard Worker        logging.Handler.__init__(self)
1218*cda5da8dSAndroid Build Coastguard Worker        method = method.upper()
1219*cda5da8dSAndroid Build Coastguard Worker        if method not in ["GET", "POST"]:
1220*cda5da8dSAndroid Build Coastguard Worker            raise ValueError("method must be GET or POST")
1221*cda5da8dSAndroid Build Coastguard Worker        if not secure and context is not None:
1222*cda5da8dSAndroid Build Coastguard Worker            raise ValueError("context parameter only makes sense "
1223*cda5da8dSAndroid Build Coastguard Worker                             "with secure=True")
1224*cda5da8dSAndroid Build Coastguard Worker        self.host = host
1225*cda5da8dSAndroid Build Coastguard Worker        self.url = url
1226*cda5da8dSAndroid Build Coastguard Worker        self.method = method
1227*cda5da8dSAndroid Build Coastguard Worker        self.secure = secure
1228*cda5da8dSAndroid Build Coastguard Worker        self.credentials = credentials
1229*cda5da8dSAndroid Build Coastguard Worker        self.context = context
1230*cda5da8dSAndroid Build Coastguard Worker
1231*cda5da8dSAndroid Build Coastguard Worker    def mapLogRecord(self, record):
1232*cda5da8dSAndroid Build Coastguard Worker        """
1233*cda5da8dSAndroid Build Coastguard Worker        Default implementation of mapping the log record into a dict
1234*cda5da8dSAndroid Build Coastguard Worker        that is sent as the CGI data. Overwrite in your class.
1235*cda5da8dSAndroid Build Coastguard Worker        Contributed by Franz Glasner.
1236*cda5da8dSAndroid Build Coastguard Worker        """
1237*cda5da8dSAndroid Build Coastguard Worker        return record.__dict__
1238*cda5da8dSAndroid Build Coastguard Worker
1239*cda5da8dSAndroid Build Coastguard Worker    def getConnection(self, host, secure):
1240*cda5da8dSAndroid Build Coastguard Worker        """
1241*cda5da8dSAndroid Build Coastguard Worker        get a HTTP[S]Connection.
1242*cda5da8dSAndroid Build Coastguard Worker
1243*cda5da8dSAndroid Build Coastguard Worker        Override when a custom connection is required, for example if
1244*cda5da8dSAndroid Build Coastguard Worker        there is a proxy.
1245*cda5da8dSAndroid Build Coastguard Worker        """
1246*cda5da8dSAndroid Build Coastguard Worker        import http.client
1247*cda5da8dSAndroid Build Coastguard Worker        if secure:
1248*cda5da8dSAndroid Build Coastguard Worker            connection = http.client.HTTPSConnection(host, context=self.context)
1249*cda5da8dSAndroid Build Coastguard Worker        else:
1250*cda5da8dSAndroid Build Coastguard Worker            connection = http.client.HTTPConnection(host)
1251*cda5da8dSAndroid Build Coastguard Worker        return connection
1252*cda5da8dSAndroid Build Coastguard Worker
1253*cda5da8dSAndroid Build Coastguard Worker    def emit(self, record):
1254*cda5da8dSAndroid Build Coastguard Worker        """
1255*cda5da8dSAndroid Build Coastguard Worker        Emit a record.
1256*cda5da8dSAndroid Build Coastguard Worker
1257*cda5da8dSAndroid Build Coastguard Worker        Send the record to the web server as a percent-encoded dictionary
1258*cda5da8dSAndroid Build Coastguard Worker        """
1259*cda5da8dSAndroid Build Coastguard Worker        try:
1260*cda5da8dSAndroid Build Coastguard Worker            import urllib.parse
1261*cda5da8dSAndroid Build Coastguard Worker            host = self.host
1262*cda5da8dSAndroid Build Coastguard Worker            h = self.getConnection(host, self.secure)
1263*cda5da8dSAndroid Build Coastguard Worker            url = self.url
1264*cda5da8dSAndroid Build Coastguard Worker            data = urllib.parse.urlencode(self.mapLogRecord(record))
1265*cda5da8dSAndroid Build Coastguard Worker            if self.method == "GET":
1266*cda5da8dSAndroid Build Coastguard Worker                if (url.find('?') >= 0):
1267*cda5da8dSAndroid Build Coastguard Worker                    sep = '&'
1268*cda5da8dSAndroid Build Coastguard Worker                else:
1269*cda5da8dSAndroid Build Coastguard Worker                    sep = '?'
1270*cda5da8dSAndroid Build Coastguard Worker                url = url + "%c%s" % (sep, data)
1271*cda5da8dSAndroid Build Coastguard Worker            h.putrequest(self.method, url)
1272*cda5da8dSAndroid Build Coastguard Worker            # support multiple hosts on one IP address...
1273*cda5da8dSAndroid Build Coastguard Worker            # need to strip optional :port from host, if present
1274*cda5da8dSAndroid Build Coastguard Worker            i = host.find(":")
1275*cda5da8dSAndroid Build Coastguard Worker            if i >= 0:
1276*cda5da8dSAndroid Build Coastguard Worker                host = host[:i]
1277*cda5da8dSAndroid Build Coastguard Worker            # See issue #30904: putrequest call above already adds this header
1278*cda5da8dSAndroid Build Coastguard Worker            # on Python 3.x.
1279*cda5da8dSAndroid Build Coastguard Worker            # h.putheader("Host", host)
1280*cda5da8dSAndroid Build Coastguard Worker            if self.method == "POST":
1281*cda5da8dSAndroid Build Coastguard Worker                h.putheader("Content-type",
1282*cda5da8dSAndroid Build Coastguard Worker                            "application/x-www-form-urlencoded")
1283*cda5da8dSAndroid Build Coastguard Worker                h.putheader("Content-length", str(len(data)))
1284*cda5da8dSAndroid Build Coastguard Worker            if self.credentials:
1285*cda5da8dSAndroid Build Coastguard Worker                import base64
1286*cda5da8dSAndroid Build Coastguard Worker                s = ('%s:%s' % self.credentials).encode('utf-8')
1287*cda5da8dSAndroid Build Coastguard Worker                s = 'Basic ' + base64.b64encode(s).strip().decode('ascii')
1288*cda5da8dSAndroid Build Coastguard Worker                h.putheader('Authorization', s)
1289*cda5da8dSAndroid Build Coastguard Worker            h.endheaders()
1290*cda5da8dSAndroid Build Coastguard Worker            if self.method == "POST":
1291*cda5da8dSAndroid Build Coastguard Worker                h.send(data.encode('utf-8'))
1292*cda5da8dSAndroid Build Coastguard Worker            h.getresponse()    #can't do anything with the result
1293*cda5da8dSAndroid Build Coastguard Worker        except Exception:
1294*cda5da8dSAndroid Build Coastguard Worker            self.handleError(record)
1295*cda5da8dSAndroid Build Coastguard Worker
1296*cda5da8dSAndroid Build Coastguard Workerclass BufferingHandler(logging.Handler):
1297*cda5da8dSAndroid Build Coastguard Worker    """
1298*cda5da8dSAndroid Build Coastguard Worker  A handler class which buffers logging records in memory. Whenever each
1299*cda5da8dSAndroid Build Coastguard Worker  record is added to the buffer, a check is made to see if the buffer should
1300*cda5da8dSAndroid Build Coastguard Worker  be flushed. If it should, then flush() is expected to do what's needed.
1301*cda5da8dSAndroid Build Coastguard Worker    """
1302*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, capacity):
1303*cda5da8dSAndroid Build Coastguard Worker        """
1304*cda5da8dSAndroid Build Coastguard Worker        Initialize the handler with the buffer size.
1305*cda5da8dSAndroid Build Coastguard Worker        """
1306*cda5da8dSAndroid Build Coastguard Worker        logging.Handler.__init__(self)
1307*cda5da8dSAndroid Build Coastguard Worker        self.capacity = capacity
1308*cda5da8dSAndroid Build Coastguard Worker        self.buffer = []
1309*cda5da8dSAndroid Build Coastguard Worker
1310*cda5da8dSAndroid Build Coastguard Worker    def shouldFlush(self, record):
1311*cda5da8dSAndroid Build Coastguard Worker        """
1312*cda5da8dSAndroid Build Coastguard Worker        Should the handler flush its buffer?
1313*cda5da8dSAndroid Build Coastguard Worker
1314*cda5da8dSAndroid Build Coastguard Worker        Returns true if the buffer is up to capacity. This method can be
1315*cda5da8dSAndroid Build Coastguard Worker        overridden to implement custom flushing strategies.
1316*cda5da8dSAndroid Build Coastguard Worker        """
1317*cda5da8dSAndroid Build Coastguard Worker        return (len(self.buffer) >= self.capacity)
1318*cda5da8dSAndroid Build Coastguard Worker
1319*cda5da8dSAndroid Build Coastguard Worker    def emit(self, record):
1320*cda5da8dSAndroid Build Coastguard Worker        """
1321*cda5da8dSAndroid Build Coastguard Worker        Emit a record.
1322*cda5da8dSAndroid Build Coastguard Worker
1323*cda5da8dSAndroid Build Coastguard Worker        Append the record. If shouldFlush() tells us to, call flush() to process
1324*cda5da8dSAndroid Build Coastguard Worker        the buffer.
1325*cda5da8dSAndroid Build Coastguard Worker        """
1326*cda5da8dSAndroid Build Coastguard Worker        self.buffer.append(record)
1327*cda5da8dSAndroid Build Coastguard Worker        if self.shouldFlush(record):
1328*cda5da8dSAndroid Build Coastguard Worker            self.flush()
1329*cda5da8dSAndroid Build Coastguard Worker
1330*cda5da8dSAndroid Build Coastguard Worker    def flush(self):
1331*cda5da8dSAndroid Build Coastguard Worker        """
1332*cda5da8dSAndroid Build Coastguard Worker        Override to implement custom flushing behaviour.
1333*cda5da8dSAndroid Build Coastguard Worker
1334*cda5da8dSAndroid Build Coastguard Worker        This version just zaps the buffer to empty.
1335*cda5da8dSAndroid Build Coastguard Worker        """
1336*cda5da8dSAndroid Build Coastguard Worker        self.acquire()
1337*cda5da8dSAndroid Build Coastguard Worker        try:
1338*cda5da8dSAndroid Build Coastguard Worker            self.buffer.clear()
1339*cda5da8dSAndroid Build Coastguard Worker        finally:
1340*cda5da8dSAndroid Build Coastguard Worker            self.release()
1341*cda5da8dSAndroid Build Coastguard Worker
1342*cda5da8dSAndroid Build Coastguard Worker    def close(self):
1343*cda5da8dSAndroid Build Coastguard Worker        """
1344*cda5da8dSAndroid Build Coastguard Worker        Close the handler.
1345*cda5da8dSAndroid Build Coastguard Worker
1346*cda5da8dSAndroid Build Coastguard Worker        This version just flushes and chains to the parent class' close().
1347*cda5da8dSAndroid Build Coastguard Worker        """
1348*cda5da8dSAndroid Build Coastguard Worker        try:
1349*cda5da8dSAndroid Build Coastguard Worker            self.flush()
1350*cda5da8dSAndroid Build Coastguard Worker        finally:
1351*cda5da8dSAndroid Build Coastguard Worker            logging.Handler.close(self)
1352*cda5da8dSAndroid Build Coastguard Worker
1353*cda5da8dSAndroid Build Coastguard Workerclass MemoryHandler(BufferingHandler):
1354*cda5da8dSAndroid Build Coastguard Worker    """
1355*cda5da8dSAndroid Build Coastguard Worker    A handler class which buffers logging records in memory, periodically
1356*cda5da8dSAndroid Build Coastguard Worker    flushing them to a target handler. Flushing occurs whenever the buffer
1357*cda5da8dSAndroid Build Coastguard Worker    is full, or when an event of a certain severity or greater is seen.
1358*cda5da8dSAndroid Build Coastguard Worker    """
1359*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, capacity, flushLevel=logging.ERROR, target=None,
1360*cda5da8dSAndroid Build Coastguard Worker                 flushOnClose=True):
1361*cda5da8dSAndroid Build Coastguard Worker        """
1362*cda5da8dSAndroid Build Coastguard Worker        Initialize the handler with the buffer size, the level at which
1363*cda5da8dSAndroid Build Coastguard Worker        flushing should occur and an optional target.
1364*cda5da8dSAndroid Build Coastguard Worker
1365*cda5da8dSAndroid Build Coastguard Worker        Note that without a target being set either here or via setTarget(),
1366*cda5da8dSAndroid Build Coastguard Worker        a MemoryHandler is no use to anyone!
1367*cda5da8dSAndroid Build Coastguard Worker
1368*cda5da8dSAndroid Build Coastguard Worker        The ``flushOnClose`` argument is ``True`` for backward compatibility
1369*cda5da8dSAndroid Build Coastguard Worker        reasons - the old behaviour is that when the handler is closed, the
1370*cda5da8dSAndroid Build Coastguard Worker        buffer is flushed, even if the flush level hasn't been exceeded nor the
1371*cda5da8dSAndroid Build Coastguard Worker        capacity exceeded. To prevent this, set ``flushOnClose`` to ``False``.
1372*cda5da8dSAndroid Build Coastguard Worker        """
1373*cda5da8dSAndroid Build Coastguard Worker        BufferingHandler.__init__(self, capacity)
1374*cda5da8dSAndroid Build Coastguard Worker        self.flushLevel = flushLevel
1375*cda5da8dSAndroid Build Coastguard Worker        self.target = target
1376*cda5da8dSAndroid Build Coastguard Worker        # See Issue #26559 for why this has been added
1377*cda5da8dSAndroid Build Coastguard Worker        self.flushOnClose = flushOnClose
1378*cda5da8dSAndroid Build Coastguard Worker
1379*cda5da8dSAndroid Build Coastguard Worker    def shouldFlush(self, record):
1380*cda5da8dSAndroid Build Coastguard Worker        """
1381*cda5da8dSAndroid Build Coastguard Worker        Check for buffer full or a record at the flushLevel or higher.
1382*cda5da8dSAndroid Build Coastguard Worker        """
1383*cda5da8dSAndroid Build Coastguard Worker        return (len(self.buffer) >= self.capacity) or \
1384*cda5da8dSAndroid Build Coastguard Worker                (record.levelno >= self.flushLevel)
1385*cda5da8dSAndroid Build Coastguard Worker
1386*cda5da8dSAndroid Build Coastguard Worker    def setTarget(self, target):
1387*cda5da8dSAndroid Build Coastguard Worker        """
1388*cda5da8dSAndroid Build Coastguard Worker        Set the target handler for this handler.
1389*cda5da8dSAndroid Build Coastguard Worker        """
1390*cda5da8dSAndroid Build Coastguard Worker        self.acquire()
1391*cda5da8dSAndroid Build Coastguard Worker        try:
1392*cda5da8dSAndroid Build Coastguard Worker            self.target = target
1393*cda5da8dSAndroid Build Coastguard Worker        finally:
1394*cda5da8dSAndroid Build Coastguard Worker            self.release()
1395*cda5da8dSAndroid Build Coastguard Worker
1396*cda5da8dSAndroid Build Coastguard Worker    def flush(self):
1397*cda5da8dSAndroid Build Coastguard Worker        """
1398*cda5da8dSAndroid Build Coastguard Worker        For a MemoryHandler, flushing means just sending the buffered
1399*cda5da8dSAndroid Build Coastguard Worker        records to the target, if there is one. Override if you want
1400*cda5da8dSAndroid Build Coastguard Worker        different behaviour.
1401*cda5da8dSAndroid Build Coastguard Worker
1402*cda5da8dSAndroid Build Coastguard Worker        The record buffer is also cleared by this operation.
1403*cda5da8dSAndroid Build Coastguard Worker        """
1404*cda5da8dSAndroid Build Coastguard Worker        self.acquire()
1405*cda5da8dSAndroid Build Coastguard Worker        try:
1406*cda5da8dSAndroid Build Coastguard Worker            if self.target:
1407*cda5da8dSAndroid Build Coastguard Worker                for record in self.buffer:
1408*cda5da8dSAndroid Build Coastguard Worker                    self.target.handle(record)
1409*cda5da8dSAndroid Build Coastguard Worker                self.buffer.clear()
1410*cda5da8dSAndroid Build Coastguard Worker        finally:
1411*cda5da8dSAndroid Build Coastguard Worker            self.release()
1412*cda5da8dSAndroid Build Coastguard Worker
1413*cda5da8dSAndroid Build Coastguard Worker    def close(self):
1414*cda5da8dSAndroid Build Coastguard Worker        """
1415*cda5da8dSAndroid Build Coastguard Worker        Flush, if appropriately configured, set the target to None and lose the
1416*cda5da8dSAndroid Build Coastguard Worker        buffer.
1417*cda5da8dSAndroid Build Coastguard Worker        """
1418*cda5da8dSAndroid Build Coastguard Worker        try:
1419*cda5da8dSAndroid Build Coastguard Worker            if self.flushOnClose:
1420*cda5da8dSAndroid Build Coastguard Worker                self.flush()
1421*cda5da8dSAndroid Build Coastguard Worker        finally:
1422*cda5da8dSAndroid Build Coastguard Worker            self.acquire()
1423*cda5da8dSAndroid Build Coastguard Worker            try:
1424*cda5da8dSAndroid Build Coastguard Worker                self.target = None
1425*cda5da8dSAndroid Build Coastguard Worker                BufferingHandler.close(self)
1426*cda5da8dSAndroid Build Coastguard Worker            finally:
1427*cda5da8dSAndroid Build Coastguard Worker                self.release()
1428*cda5da8dSAndroid Build Coastguard Worker
1429*cda5da8dSAndroid Build Coastguard Worker
1430*cda5da8dSAndroid Build Coastguard Workerclass QueueHandler(logging.Handler):
1431*cda5da8dSAndroid Build Coastguard Worker    """
1432*cda5da8dSAndroid Build Coastguard Worker    This handler sends events to a queue. Typically, it would be used together
1433*cda5da8dSAndroid Build Coastguard Worker    with a multiprocessing Queue to centralise logging to file in one process
1434*cda5da8dSAndroid Build Coastguard Worker    (in a multi-process application), so as to avoid file write contention
1435*cda5da8dSAndroid Build Coastguard Worker    between processes.
1436*cda5da8dSAndroid Build Coastguard Worker
1437*cda5da8dSAndroid Build Coastguard Worker    This code is new in Python 3.2, but this class can be copy pasted into
1438*cda5da8dSAndroid Build Coastguard Worker    user code for use with earlier Python versions.
1439*cda5da8dSAndroid Build Coastguard Worker    """
1440*cda5da8dSAndroid Build Coastguard Worker
1441*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, queue):
1442*cda5da8dSAndroid Build Coastguard Worker        """
1443*cda5da8dSAndroid Build Coastguard Worker        Initialise an instance, using the passed queue.
1444*cda5da8dSAndroid Build Coastguard Worker        """
1445*cda5da8dSAndroid Build Coastguard Worker        logging.Handler.__init__(self)
1446*cda5da8dSAndroid Build Coastguard Worker        self.queue = queue
1447*cda5da8dSAndroid Build Coastguard Worker
1448*cda5da8dSAndroid Build Coastguard Worker    def enqueue(self, record):
1449*cda5da8dSAndroid Build Coastguard Worker        """
1450*cda5da8dSAndroid Build Coastguard Worker        Enqueue a record.
1451*cda5da8dSAndroid Build Coastguard Worker
1452*cda5da8dSAndroid Build Coastguard Worker        The base implementation uses put_nowait. You may want to override
1453*cda5da8dSAndroid Build Coastguard Worker        this method if you want to use blocking, timeouts or custom queue
1454*cda5da8dSAndroid Build Coastguard Worker        implementations.
1455*cda5da8dSAndroid Build Coastguard Worker        """
1456*cda5da8dSAndroid Build Coastguard Worker        self.queue.put_nowait(record)
1457*cda5da8dSAndroid Build Coastguard Worker
1458*cda5da8dSAndroid Build Coastguard Worker    def prepare(self, record):
1459*cda5da8dSAndroid Build Coastguard Worker        """
1460*cda5da8dSAndroid Build Coastguard Worker        Prepare a record for queuing. The object returned by this method is
1461*cda5da8dSAndroid Build Coastguard Worker        enqueued.
1462*cda5da8dSAndroid Build Coastguard Worker
1463*cda5da8dSAndroid Build Coastguard Worker        The base implementation formats the record to merge the message and
1464*cda5da8dSAndroid Build Coastguard Worker        arguments, and removes unpickleable items from the record in-place.
1465*cda5da8dSAndroid Build Coastguard Worker        Specifically, it overwrites the record's `msg` and
1466*cda5da8dSAndroid Build Coastguard Worker        `message` attributes with the merged message (obtained by
1467*cda5da8dSAndroid Build Coastguard Worker        calling the handler's `format` method), and sets the `args`,
1468*cda5da8dSAndroid Build Coastguard Worker        `exc_info` and `exc_text` attributes to None.
1469*cda5da8dSAndroid Build Coastguard Worker
1470*cda5da8dSAndroid Build Coastguard Worker        You might want to override this method if you want to convert
1471*cda5da8dSAndroid Build Coastguard Worker        the record to a dict or JSON string, or send a modified copy
1472*cda5da8dSAndroid Build Coastguard Worker        of the record while leaving the original intact.
1473*cda5da8dSAndroid Build Coastguard Worker        """
1474*cda5da8dSAndroid Build Coastguard Worker        # The format operation gets traceback text into record.exc_text
1475*cda5da8dSAndroid Build Coastguard Worker        # (if there's exception data), and also returns the formatted
1476*cda5da8dSAndroid Build Coastguard Worker        # message. We can then use this to replace the original
1477*cda5da8dSAndroid Build Coastguard Worker        # msg + args, as these might be unpickleable. We also zap the
1478*cda5da8dSAndroid Build Coastguard Worker        # exc_info, exc_text and stack_info attributes, as they are no longer
1479*cda5da8dSAndroid Build Coastguard Worker        # needed and, if not None, will typically not be pickleable.
1480*cda5da8dSAndroid Build Coastguard Worker        msg = self.format(record)
1481*cda5da8dSAndroid Build Coastguard Worker        # bpo-35726: make copy of record to avoid affecting other handlers in the chain.
1482*cda5da8dSAndroid Build Coastguard Worker        record = copy.copy(record)
1483*cda5da8dSAndroid Build Coastguard Worker        record.message = msg
1484*cda5da8dSAndroid Build Coastguard Worker        record.msg = msg
1485*cda5da8dSAndroid Build Coastguard Worker        record.args = None
1486*cda5da8dSAndroid Build Coastguard Worker        record.exc_info = None
1487*cda5da8dSAndroid Build Coastguard Worker        record.exc_text = None
1488*cda5da8dSAndroid Build Coastguard Worker        record.stack_info = None
1489*cda5da8dSAndroid Build Coastguard Worker        return record
1490*cda5da8dSAndroid Build Coastguard Worker
1491*cda5da8dSAndroid Build Coastguard Worker    def emit(self, record):
1492*cda5da8dSAndroid Build Coastguard Worker        """
1493*cda5da8dSAndroid Build Coastguard Worker        Emit a record.
1494*cda5da8dSAndroid Build Coastguard Worker
1495*cda5da8dSAndroid Build Coastguard Worker        Writes the LogRecord to the queue, preparing it for pickling first.
1496*cda5da8dSAndroid Build Coastguard Worker        """
1497*cda5da8dSAndroid Build Coastguard Worker        try:
1498*cda5da8dSAndroid Build Coastguard Worker            self.enqueue(self.prepare(record))
1499*cda5da8dSAndroid Build Coastguard Worker        except Exception:
1500*cda5da8dSAndroid Build Coastguard Worker            self.handleError(record)
1501*cda5da8dSAndroid Build Coastguard Worker
1502*cda5da8dSAndroid Build Coastguard Worker
1503*cda5da8dSAndroid Build Coastguard Workerclass QueueListener(object):
1504*cda5da8dSAndroid Build Coastguard Worker    """
1505*cda5da8dSAndroid Build Coastguard Worker    This class implements an internal threaded listener which watches for
1506*cda5da8dSAndroid Build Coastguard Worker    LogRecords being added to a queue, removes them and passes them to a
1507*cda5da8dSAndroid Build Coastguard Worker    list of handlers for processing.
1508*cda5da8dSAndroid Build Coastguard Worker    """
1509*cda5da8dSAndroid Build Coastguard Worker    _sentinel = None
1510*cda5da8dSAndroid Build Coastguard Worker
1511*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, queue, *handlers, respect_handler_level=False):
1512*cda5da8dSAndroid Build Coastguard Worker        """
1513*cda5da8dSAndroid Build Coastguard Worker        Initialise an instance with the specified queue and
1514*cda5da8dSAndroid Build Coastguard Worker        handlers.
1515*cda5da8dSAndroid Build Coastguard Worker        """
1516*cda5da8dSAndroid Build Coastguard Worker        self.queue = queue
1517*cda5da8dSAndroid Build Coastguard Worker        self.handlers = handlers
1518*cda5da8dSAndroid Build Coastguard Worker        self._thread = None
1519*cda5da8dSAndroid Build Coastguard Worker        self.respect_handler_level = respect_handler_level
1520*cda5da8dSAndroid Build Coastguard Worker
1521*cda5da8dSAndroid Build Coastguard Worker    def dequeue(self, block):
1522*cda5da8dSAndroid Build Coastguard Worker        """
1523*cda5da8dSAndroid Build Coastguard Worker        Dequeue a record and return it, optionally blocking.
1524*cda5da8dSAndroid Build Coastguard Worker
1525*cda5da8dSAndroid Build Coastguard Worker        The base implementation uses get. You may want to override this method
1526*cda5da8dSAndroid Build Coastguard Worker        if you want to use timeouts or work with custom queue implementations.
1527*cda5da8dSAndroid Build Coastguard Worker        """
1528*cda5da8dSAndroid Build Coastguard Worker        return self.queue.get(block)
1529*cda5da8dSAndroid Build Coastguard Worker
1530*cda5da8dSAndroid Build Coastguard Worker    def start(self):
1531*cda5da8dSAndroid Build Coastguard Worker        """
1532*cda5da8dSAndroid Build Coastguard Worker        Start the listener.
1533*cda5da8dSAndroid Build Coastguard Worker
1534*cda5da8dSAndroid Build Coastguard Worker        This starts up a background thread to monitor the queue for
1535*cda5da8dSAndroid Build Coastguard Worker        LogRecords to process.
1536*cda5da8dSAndroid Build Coastguard Worker        """
1537*cda5da8dSAndroid Build Coastguard Worker        self._thread = t = threading.Thread(target=self._monitor)
1538*cda5da8dSAndroid Build Coastguard Worker        t.daemon = True
1539*cda5da8dSAndroid Build Coastguard Worker        t.start()
1540*cda5da8dSAndroid Build Coastguard Worker
1541*cda5da8dSAndroid Build Coastguard Worker    def prepare(self, record):
1542*cda5da8dSAndroid Build Coastguard Worker        """
1543*cda5da8dSAndroid Build Coastguard Worker        Prepare a record for handling.
1544*cda5da8dSAndroid Build Coastguard Worker
1545*cda5da8dSAndroid Build Coastguard Worker        This method just returns the passed-in record. You may want to
1546*cda5da8dSAndroid Build Coastguard Worker        override this method if you need to do any custom marshalling or
1547*cda5da8dSAndroid Build Coastguard Worker        manipulation of the record before passing it to the handlers.
1548*cda5da8dSAndroid Build Coastguard Worker        """
1549*cda5da8dSAndroid Build Coastguard Worker        return record
1550*cda5da8dSAndroid Build Coastguard Worker
1551*cda5da8dSAndroid Build Coastguard Worker    def handle(self, record):
1552*cda5da8dSAndroid Build Coastguard Worker        """
1553*cda5da8dSAndroid Build Coastguard Worker        Handle a record.
1554*cda5da8dSAndroid Build Coastguard Worker
1555*cda5da8dSAndroid Build Coastguard Worker        This just loops through the handlers offering them the record
1556*cda5da8dSAndroid Build Coastguard Worker        to handle.
1557*cda5da8dSAndroid Build Coastguard Worker        """
1558*cda5da8dSAndroid Build Coastguard Worker        record = self.prepare(record)
1559*cda5da8dSAndroid Build Coastguard Worker        for handler in self.handlers:
1560*cda5da8dSAndroid Build Coastguard Worker            if not self.respect_handler_level:
1561*cda5da8dSAndroid Build Coastguard Worker                process = True
1562*cda5da8dSAndroid Build Coastguard Worker            else:
1563*cda5da8dSAndroid Build Coastguard Worker                process = record.levelno >= handler.level
1564*cda5da8dSAndroid Build Coastguard Worker            if process:
1565*cda5da8dSAndroid Build Coastguard Worker                handler.handle(record)
1566*cda5da8dSAndroid Build Coastguard Worker
1567*cda5da8dSAndroid Build Coastguard Worker    def _monitor(self):
1568*cda5da8dSAndroid Build Coastguard Worker        """
1569*cda5da8dSAndroid Build Coastguard Worker        Monitor the queue for records, and ask the handler
1570*cda5da8dSAndroid Build Coastguard Worker        to deal with them.
1571*cda5da8dSAndroid Build Coastguard Worker
1572*cda5da8dSAndroid Build Coastguard Worker        This method runs on a separate, internal thread.
1573*cda5da8dSAndroid Build Coastguard Worker        The thread will terminate if it sees a sentinel object in the queue.
1574*cda5da8dSAndroid Build Coastguard Worker        """
1575*cda5da8dSAndroid Build Coastguard Worker        q = self.queue
1576*cda5da8dSAndroid Build Coastguard Worker        has_task_done = hasattr(q, 'task_done')
1577*cda5da8dSAndroid Build Coastguard Worker        while True:
1578*cda5da8dSAndroid Build Coastguard Worker            try:
1579*cda5da8dSAndroid Build Coastguard Worker                record = self.dequeue(True)
1580*cda5da8dSAndroid Build Coastguard Worker                if record is self._sentinel:
1581*cda5da8dSAndroid Build Coastguard Worker                    if has_task_done:
1582*cda5da8dSAndroid Build Coastguard Worker                        q.task_done()
1583*cda5da8dSAndroid Build Coastguard Worker                    break
1584*cda5da8dSAndroid Build Coastguard Worker                self.handle(record)
1585*cda5da8dSAndroid Build Coastguard Worker                if has_task_done:
1586*cda5da8dSAndroid Build Coastguard Worker                    q.task_done()
1587*cda5da8dSAndroid Build Coastguard Worker            except queue.Empty:
1588*cda5da8dSAndroid Build Coastguard Worker                break
1589*cda5da8dSAndroid Build Coastguard Worker
1590*cda5da8dSAndroid Build Coastguard Worker    def enqueue_sentinel(self):
1591*cda5da8dSAndroid Build Coastguard Worker        """
1592*cda5da8dSAndroid Build Coastguard Worker        This is used to enqueue the sentinel record.
1593*cda5da8dSAndroid Build Coastguard Worker
1594*cda5da8dSAndroid Build Coastguard Worker        The base implementation uses put_nowait. You may want to override this
1595*cda5da8dSAndroid Build Coastguard Worker        method if you want to use timeouts or work with custom queue
1596*cda5da8dSAndroid Build Coastguard Worker        implementations.
1597*cda5da8dSAndroid Build Coastguard Worker        """
1598*cda5da8dSAndroid Build Coastguard Worker        self.queue.put_nowait(self._sentinel)
1599*cda5da8dSAndroid Build Coastguard Worker
1600*cda5da8dSAndroid Build Coastguard Worker    def stop(self):
1601*cda5da8dSAndroid Build Coastguard Worker        """
1602*cda5da8dSAndroid Build Coastguard Worker        Stop the listener.
1603*cda5da8dSAndroid Build Coastguard Worker
1604*cda5da8dSAndroid Build Coastguard Worker        This asks the thread to terminate, and then waits for it to do so.
1605*cda5da8dSAndroid Build Coastguard Worker        Note that if you don't call this before your application exits, there
1606*cda5da8dSAndroid Build Coastguard Worker        may be some records still left on the queue, which won't be processed.
1607*cda5da8dSAndroid Build Coastguard Worker        """
1608*cda5da8dSAndroid Build Coastguard Worker        self.enqueue_sentinel()
1609*cda5da8dSAndroid Build Coastguard Worker        self._thread.join()
1610*cda5da8dSAndroid Build Coastguard Worker        self._thread = None
1611