1ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot# Copyright 2001-2013 by Vinay Sajip. All Rights Reserved.
2ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot#
3ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot# Permission to use, copy, modify, and distribute this software and its
4ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot# documentation for any purpose and without fee is hereby granted,
5ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot# provided that the above copyright notice appear in all copies and that
6ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot# both that copyright notice and this permission notice appear in
7ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot# supporting documentation, and that the name of Vinay Sajip
8ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot# not be used in advertising or publicity pertaining to distribution
9ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot# of the software without specific, written prior permission.
10ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
11ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
12ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
13ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
14ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
17ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot"""
18ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team RobotAdditional handlers for the logging package for Python. The core package is
19ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotbased on PEP 282 and comments thereto in comp.lang.python.
20ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
21ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team RobotCopyright (C) 2001-2013 Vinay Sajip. All Rights Reserved.
22ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
23ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team RobotTo use, simply 'import logging.handlers' and log away!
24ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot"""
25ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
26ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotimport errno, logging, socket, os, cPickle, struct, time, re
27ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotfrom stat import ST_DEV, ST_INO, ST_MTIME
28ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
29ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robottry:
30ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    import codecs
31ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotexcept ImportError:
32ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    codecs = None
33ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robottry:
34ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    unicode
35ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    _unicode = True
36ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotexcept NameError:
37ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    _unicode = False
38ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
39ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot#
40ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot# Some constants...
41ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot#
42ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
43ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team RobotDEFAULT_TCP_LOGGING_PORT    = 9020
44ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team RobotDEFAULT_UDP_LOGGING_PORT    = 9021
45ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team RobotDEFAULT_HTTP_LOGGING_PORT   = 9022
46ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team RobotDEFAULT_SOAP_LOGGING_PORT   = 9023
47ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team RobotSYSLOG_UDP_PORT             = 514
48ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team RobotSYSLOG_TCP_PORT             = 514
49ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
50ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot_MIDNIGHT = 24 * 60 * 60  # number of seconds in a day
51ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
52ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotclass BaseRotatingHandler(logging.FileHandler):
53ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
54ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    Base class for handlers that rotate log files at a certain point.
55ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    Not meant to be instantiated directly.  Instead, use RotatingFileHandler
56ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    or TimedRotatingFileHandler.
57ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
58ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def __init__(self, filename, mode, encoding=None, delay=0):
59ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
60ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Use the specified filename for streamed logging
61ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
62ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if codecs is None:
63ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            encoding = None
64ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        logging.FileHandler.__init__(self, filename, mode, encoding, delay)
65ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.mode = mode
66ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.encoding = encoding
67ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
68ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def emit(self, record):
69ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
70ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Emit a record.
71ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
72ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Output the record to the file, catering for rollover as described
73ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        in doRollover().
74ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
75ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        try:
76ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if self.shouldRollover(record):
77ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                self.doRollover()
78ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            logging.FileHandler.emit(self, record)
79ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        except (KeyboardInterrupt, SystemExit):
80ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            raise
81ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        except:
82ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.handleError(record)
83ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
84ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotclass RotatingFileHandler(BaseRotatingHandler):
85ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
86ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    Handler for logging to a set of files, which switches from one file
87ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    to the next when the current file reaches a certain size.
88ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
89ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def __init__(self, filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=0):
90ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
91ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Open the specified file and use it as the stream for logging.
92ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
93ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        By default, the file grows indefinitely. You can specify particular
94ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        values of maxBytes and backupCount to allow the file to rollover at
95ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        a predetermined size.
96ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
97ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Rollover occurs whenever the current log file is nearly maxBytes in
98ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        length. If backupCount is >= 1, the system will successively create
99ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        new files with the same pathname as the base file, but with extensions
100ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        ".1", ".2" etc. appended to it. For example, with a backupCount of 5
101ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        and a base file name of "app.log", you would get "app.log",
102ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "app.log.1", "app.log.2", ... through to "app.log.5". The file being
103ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        written to is always "app.log" - when it gets filled up, it is closed
104ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        and renamed to "app.log.1", and if files "app.log.1", "app.log.2" etc.
105ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        exist, then they are renamed to "app.log.2", "app.log.3" etc.
106ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        respectively.
107ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
108ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        If maxBytes is zero, rollover never occurs.
109ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
110ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # If rotation/rollover is wanted, it doesn't make sense to use another
111ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # mode. If for example 'w' were specified, then if there were multiple
112ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # runs of the calling application, the logs from previous runs would be
113ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # lost if the 'w' is respected, because the log file would be truncated
114ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # on each run.
115ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if maxBytes > 0:
116ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            mode = 'a'
117ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        BaseRotatingHandler.__init__(self, filename, mode, encoding, delay)
118ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.maxBytes = maxBytes
119ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.backupCount = backupCount
120ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
121ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def doRollover(self):
122ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
123ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Do a rollover, as described in __init__().
124ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
125ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if self.stream:
126ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.stream.close()
127ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.stream = None
128ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if self.backupCount > 0:
129ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            for i in range(self.backupCount - 1, 0, -1):
130ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                sfn = "%s.%d" % (self.baseFilename, i)
131ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                dfn = "%s.%d" % (self.baseFilename, i + 1)
132ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                if os.path.exists(sfn):
133ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    #print "%s -> %s" % (sfn, dfn)
134ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    if os.path.exists(dfn):
135ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                        os.remove(dfn)
136ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    os.rename(sfn, dfn)
137ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            dfn = self.baseFilename + ".1"
138ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if os.path.exists(dfn):
139ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                os.remove(dfn)
140ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            os.rename(self.baseFilename, dfn)
141ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            #print "%s -> %s" % (self.baseFilename, dfn)
142ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.stream = self._open()
143ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
144ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def shouldRollover(self, record):
145ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
146ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Determine if rollover should occur.
147ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
148ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Basically, see if the supplied record would cause the file to exceed
149ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        the size limit we have.
150ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
151ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if self.stream is None:                 # delay was set...
152ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.stream = self._open()
153ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if self.maxBytes > 0:                   # are we rolling over?
154ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            msg = "%s\n" % self.format(record)
155ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.stream.seek(0, 2)  #due to non-posix-compliant Windows feature
156ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if self.stream.tell() + len(msg) >= self.maxBytes:
157ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                return 1
158ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        return 0
159ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
160ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotclass TimedRotatingFileHandler(BaseRotatingHandler):
161ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
162ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    Handler for logging to a file, rotating the log file at certain timed
163ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    intervals.
164ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
165ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    If backupCount is > 0, when rollover is done, no more than backupCount
166ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    files are kept - the oldest ones are deleted.
167ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
168ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False):
169ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        BaseRotatingHandler.__init__(self, filename, 'a', encoding, delay)
170ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.when = when.upper()
171ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.backupCount = backupCount
172ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.utc = utc
173ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # Calculate the real rollover interval, which is just the number of
174ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # seconds between rollovers.  Also set the filename suffix used when
175ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # a rollover occurs.  Current 'when' events supported:
176ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # S - Seconds
177ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # M - Minutes
178ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # H - Hours
179ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # D - Days
180ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # midnight - roll over at midnight
181ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # W{0-6} - roll over on a certain day; 0 - Monday
182ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        #
183ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # Case of the 'when' specifier is not important; lower or upper case
184ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # will work.
185ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if self.when == 'S':
186ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.interval = 1 # one second
187ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.suffix = "%Y-%m-%d_%H-%M-%S"
188ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}$"
189ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        elif self.when == 'M':
190ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.interval = 60 # one minute
191ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.suffix = "%Y-%m-%d_%H-%M"
192ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}$"
193ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        elif self.when == 'H':
194ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.interval = 60 * 60 # one hour
195ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.suffix = "%Y-%m-%d_%H"
196ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}$"
197ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        elif self.when == 'D' or self.when == 'MIDNIGHT':
198ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.interval = 60 * 60 * 24 # one day
199ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.suffix = "%Y-%m-%d"
200ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.extMatch = r"^\d{4}-\d{2}-\d{2}$"
201ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        elif self.when.startswith('W'):
202ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.interval = 60 * 60 * 24 * 7 # one week
203ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if len(self.when) != 2:
204ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                raise ValueError("You must specify a day for weekly rollover from 0 to 6 (0 is Monday): %s" % self.when)
205ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if self.when[1] < '0' or self.when[1] > '6':
206ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                raise ValueError("Invalid day specified for weekly rollover: %s" % self.when)
207ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.dayOfWeek = int(self.when[1])
208ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.suffix = "%Y-%m-%d"
209ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.extMatch = r"^\d{4}-\d{2}-\d{2}$"
210ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        else:
211ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            raise ValueError("Invalid rollover interval specified: %s" % self.when)
212ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
213ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.extMatch = re.compile(self.extMatch)
214ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.interval = self.interval * interval # multiply by units requested
215ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if os.path.exists(filename):
216ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            t = os.stat(filename)[ST_MTIME]
217ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        else:
218ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            t = int(time.time())
219ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.rolloverAt = self.computeRollover(t)
220ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
221ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def computeRollover(self, currentTime):
222ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
223ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Work out the rollover time based on the specified time.
224ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
225ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        result = currentTime + self.interval
226ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # If we are rolling over at midnight or weekly, then the interval is already known.
227ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # What we need to figure out is WHEN the next interval is.  In other words,
228ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # if you are rolling over at midnight, then your base interval is 1 day,
229ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # but you want to start that one day clock at midnight, not now.  So, we
230ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # have to fudge the rolloverAt value in order to trigger the first rollover
231ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # at the right time.  After that, the regular interval will take care of
232ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # the rest.  Note that this code doesn't care about leap seconds. :)
233ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if self.when == 'MIDNIGHT' or self.when.startswith('W'):
234ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            # This could be done with less code, but I wanted it to be clear
235ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if self.utc:
236ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                t = time.gmtime(currentTime)
237ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            else:
238ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                t = time.localtime(currentTime)
239ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            currentHour = t[3]
240ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            currentMinute = t[4]
241ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            currentSecond = t[5]
242ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            # r is the number of seconds left between now and midnight
243ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            r = _MIDNIGHT - ((currentHour * 60 + currentMinute) * 60 +
244ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    currentSecond)
245ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            result = currentTime + r
246ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            # If we are rolling over on a certain day, add in the number of days until
247ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            # the next rollover, but offset by 1 since we just calculated the time
248ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            # until the next day starts.  There are three cases:
249ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            # Case 1) The day to rollover is today; in this case, do nothing
250ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            # Case 2) The day to rollover is further in the interval (i.e., today is
251ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            #         day 2 (Wednesday) and rollover is on day 6 (Sunday).  Days to
252ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            #         next rollover is simply 6 - 2 - 1, or 3.
253ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            # Case 3) The day to rollover is behind us in the interval (i.e., today
254ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            #         is day 5 (Saturday) and rollover is on day 3 (Thursday).
255ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            #         Days to rollover is 6 - 5 + 3, or 4.  In this case, it's the
256ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            #         number of days left in the current week (1) plus the number
257ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            #         of days in the next week until the rollover day (3).
258ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            # The calculations described in 2) and 3) above need to have a day added.
259ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            # This is because the above time calculation takes us to midnight on this
260ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            # day, i.e. the start of the next day.
261ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if self.when.startswith('W'):
262ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                day = t[6] # 0 is Monday
263ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                if day != self.dayOfWeek:
264ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    if day < self.dayOfWeek:
265ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                        daysToWait = self.dayOfWeek - day
266ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    else:
267ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                        daysToWait = 6 - day + self.dayOfWeek + 1
268ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    newRolloverAt = result + (daysToWait * (60 * 60 * 24))
269ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    if not self.utc:
270ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                        dstNow = t[-1]
271ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                        dstAtRollover = time.localtime(newRolloverAt)[-1]
272ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                        if dstNow != dstAtRollover:
273ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                            if not dstNow:  # DST kicks in before next rollover, so we need to deduct an hour
274ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                                addend = -3600
275ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                            else:           # DST bows out before next rollover, so we need to add an hour
276ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                                addend = 3600
277ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                            newRolloverAt += addend
278ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    result = newRolloverAt
279ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        return result
280ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
281ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def shouldRollover(self, record):
282ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
283ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Determine if rollover should occur.
284ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
285ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        record is not used, as we are just comparing times, but it is needed so
286ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        the method signatures are the same
287ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
288ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        t = int(time.time())
289ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if t >= self.rolloverAt:
290ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            return 1
291ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        #print "No need to rollover: %d, %d" % (t, self.rolloverAt)
292ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        return 0
293ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
294ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def getFilesToDelete(self):
295ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
296ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Determine the files to delete when rolling over.
297ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
298ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        More specific than the earlier method, which just used glob.glob().
299ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
300ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        dirName, baseName = os.path.split(self.baseFilename)
301ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        fileNames = os.listdir(dirName)
302ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        result = []
303ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        prefix = baseName + "."
304ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        plen = len(prefix)
305ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        for fileName in fileNames:
306ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if fileName[:plen] == prefix:
307ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                suffix = fileName[plen:]
308ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                if self.extMatch.match(suffix):
309ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    result.append(os.path.join(dirName, fileName))
310ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        result.sort()
311ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if len(result) < self.backupCount:
312ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            result = []
313ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        else:
314ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            result = result[:len(result) - self.backupCount]
315ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        return result
316ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
317ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def doRollover(self):
318ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
319ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        do a rollover; in this case, a date/time stamp is appended to the filename
320ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        when the rollover happens.  However, you want the file to be named for the
321ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        start of the interval, not the current time.  If there is a backup count,
322ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        then we have to get a list of matching filenames, sort them and remove
323ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        the one with the oldest suffix.
324ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
325ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if self.stream:
326ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.stream.close()
327ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.stream = None
328ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # get the time that this sequence started at and make it a TimeTuple
329ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        currentTime = int(time.time())
330ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        dstNow = time.localtime(currentTime)[-1]
331ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        t = self.rolloverAt - self.interval
332ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if self.utc:
333ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            timeTuple = time.gmtime(t)
334ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        else:
335ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            timeTuple = time.localtime(t)
336ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            dstThen = timeTuple[-1]
337ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if dstNow != dstThen:
338ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                if dstNow:
339ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    addend = 3600
340ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                else:
341ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    addend = -3600
342ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                timeTuple = time.localtime(t + addend)
343ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        dfn = self.baseFilename + "." + time.strftime(self.suffix, timeTuple)
344ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if os.path.exists(dfn):
345ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            os.remove(dfn)
346ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        os.rename(self.baseFilename, dfn)
347ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if self.backupCount > 0:
348ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            # find the oldest log file and delete it
349ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            #s = glob.glob(self.baseFilename + ".20*")
350ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            #if len(s) > self.backupCount:
351ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            #    s.sort()
352ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            #    os.remove(s[0])
353ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            for s in self.getFilesToDelete():
354ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                os.remove(s)
355ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        #print "%s -> %s" % (self.baseFilename, dfn)
356ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.stream = self._open()
357ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        newRolloverAt = self.computeRollover(currentTime)
358ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        while newRolloverAt <= currentTime:
359ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            newRolloverAt = newRolloverAt + self.interval
360ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        #If DST changes and midnight or weekly rollover, adjust for this.
361ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if (self.when == 'MIDNIGHT' or self.when.startswith('W')) and not self.utc:
362ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            dstAtRollover = time.localtime(newRolloverAt)[-1]
363ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if dstNow != dstAtRollover:
364ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                if not dstNow:  # DST kicks in before next rollover, so we need to deduct an hour
365ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    addend = -3600
366ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                else:           # DST bows out before next rollover, so we need to add an hour
367ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    addend = 3600
368ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                newRolloverAt += addend
369ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.rolloverAt = newRolloverAt
370ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
371ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotclass WatchedFileHandler(logging.FileHandler):
372ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
373ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    A handler for logging to a file, which watches the file
374ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    to see if it has changed while in use. This can happen because of
375ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    usage of programs such as newsyslog and logrotate which perform
376ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    log file rotation. This handler, intended for use under Unix,
377ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    watches the file to see if it has changed since the last emit.
378ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    (A file has changed if its device or inode have changed.)
379ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    If it has changed, the old file stream is closed, and the file
380ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    opened to get a new stream.
381ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
382ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    This handler is not appropriate for use under Windows, because
383ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    under Windows open files cannot be moved or renamed - logging
384ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    opens the files with exclusive locks - and so there is no need
385ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    for such a handler. Furthermore, ST_INO is not supported under
386ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    Windows; stat always returns zero for this value.
387ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
388ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    This handler is based on a suggestion and patch by Chad J.
389ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    Schroeder.
390ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
391ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def __init__(self, filename, mode='a', encoding=None, delay=0):
392ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        logging.FileHandler.__init__(self, filename, mode, encoding, delay)
393ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.dev, self.ino = -1, -1
394ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self._statstream()
395ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
396ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def _statstream(self):
397ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if self.stream:
398ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            sres = os.fstat(self.stream.fileno())
399ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.dev, self.ino = sres[ST_DEV], sres[ST_INO]
400ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
401ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def emit(self, record):
402ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
403ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Emit a record.
404ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
405ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        First check if the underlying file has changed, and if it
406ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        has, close the old stream and reopen the file to get the
407ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        current stream.
408ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
409ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # Reduce the chance of race conditions by stat'ing by path only
410ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # once and then fstat'ing our new fd if we opened a new log stream.
411ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # See issue #14632: Thanks to John Mulligan for the problem report
412ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # and patch.
413ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        try:
414ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            # stat the file by path, checking for existence
415ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            sres = os.stat(self.baseFilename)
416ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        except OSError as err:
417ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if err.errno == errno.ENOENT:
418ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                sres = None
419ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            else:
420ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                raise
421ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # compare file system stat with that of our stream file handle
422ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if not sres or sres[ST_DEV] != self.dev or sres[ST_INO] != self.ino:
423ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if self.stream is not None:
424ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                # we have an open file handle, clean it up
425ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                self.stream.flush()
426ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                self.stream.close()
427ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                # open a new file handle and get new stat info from that fd
428ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                self.stream = self._open()
429ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                self._statstream()
430ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        logging.FileHandler.emit(self, record)
431ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
432ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotclass SocketHandler(logging.Handler):
433ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
434ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    A handler class which writes logging records, in pickle format, to
435ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    a streaming socket. The socket is kept open across logging calls.
436ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    If the peer resets it, an attempt is made to reconnect on the next call.
437ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    The pickle which is sent is that of the LogRecord's attribute dictionary
438ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    (__dict__), so that the receiver does not need to have the logging module
439ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    installed in order to process the logging event.
440ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
441ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    To unpickle the record at the receiving end into a LogRecord, use the
442ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    makeLogRecord function.
443ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
444ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
445ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def __init__(self, host, port):
446ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
447ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Initializes the handler with a specific host address and port.
448ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
449ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        The attribute 'closeOnError' is set to 1 - which means that if
450ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        a socket error occurs, the socket is silently closed and then
451ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        reopened on the next logging call.
452ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
453ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        logging.Handler.__init__(self)
454ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.host = host
455ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.port = port
456ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.sock = None
457ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.closeOnError = 0
458ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.retryTime = None
459ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        #
460ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # Exponential backoff parameters.
461ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        #
462ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.retryStart = 1.0
463ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.retryMax = 30.0
464ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.retryFactor = 2.0
465ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
466ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def makeSocket(self, timeout=1):
467ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
468ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        A factory method which allows subclasses to define the precise
469ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        type of socket they want.
470ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
471ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
472ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if hasattr(s, 'settimeout'):
473ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            s.settimeout(timeout)
474ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        s.connect((self.host, self.port))
475ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        return s
476ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
477ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def createSocket(self):
478ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
479ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Try to create a socket, using an exponential backoff with
480ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        a max retry time. Thanks to Robert Olson for the original patch
481ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        (SF #815911) which has been slightly refactored.
482ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
483ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        now = time.time()
484ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # Either retryTime is None, in which case this
485ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # is the first time back after a disconnect, or
486ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # we've waited long enough.
487ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if self.retryTime is None:
488ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            attempt = 1
489ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        else:
490ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            attempt = (now >= self.retryTime)
491ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if attempt:
492ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            try:
493ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                self.sock = self.makeSocket()
494ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                self.retryTime = None # next time, no delay before trying
495ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            except socket.error:
496ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                #Creation failed, so set the retry time and return.
497ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                if self.retryTime is None:
498ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    self.retryPeriod = self.retryStart
499ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                else:
500ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    self.retryPeriod = self.retryPeriod * self.retryFactor
501ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    if self.retryPeriod > self.retryMax:
502ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                        self.retryPeriod = self.retryMax
503ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                self.retryTime = now + self.retryPeriod
504ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
505ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def send(self, s):
506ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
507ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Send a pickled string to the socket.
508ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
509ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        This function allows for partial sends which can happen when the
510ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        network is busy.
511ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
512ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if self.sock is None:
513ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.createSocket()
514ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        #self.sock can be None either because we haven't reached the retry
515ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        #time yet, or because we have reached the retry time and retried,
516ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        #but are still unable to connect.
517ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if self.sock:
518ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            try:
519ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                if hasattr(self.sock, "sendall"):
520ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    self.sock.sendall(s)
521ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                else:
522ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    sentsofar = 0
523ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    left = len(s)
524ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    while left > 0:
525ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                        sent = self.sock.send(s[sentsofar:])
526ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                        sentsofar = sentsofar + sent
527ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                        left = left - sent
528ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            except socket.error:
529ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                self.sock.close()
530ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                self.sock = None  # so we can call createSocket next time
531ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
532ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def makePickle(self, record):
533ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
534ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Pickles the record in binary format with a length prefix, and
535ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        returns it ready for transmission across the socket.
536ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
537ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        ei = record.exc_info
538ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if ei:
539ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            # just to get traceback text into record.exc_text ...
540ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            dummy = self.format(record)
541ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            record.exc_info = None  # to avoid Unpickleable error
542ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # See issue #14436: If msg or args are objects, they may not be
543ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # available on the receiving end. So we convert the msg % args
544ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # to a string, save it as msg and zap the args.
545ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        d = dict(record.__dict__)
546ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        d['msg'] = record.getMessage()
547ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        d['args'] = None
548ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        s = cPickle.dumps(d, 1)
549ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if ei:
550ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            record.exc_info = ei  # for next handler
551ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        slen = struct.pack(">L", len(s))
552ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        return slen + s
553ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
554ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def handleError(self, record):
555ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
556ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Handle an error during logging.
557ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
558ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        An error has occurred during logging. Most likely cause -
559ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        connection lost. Close the socket so that we can retry on the
560ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        next event.
561ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
562ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if self.closeOnError and self.sock:
563ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.sock.close()
564ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.sock = None        #try to reconnect next time
565ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        else:
566ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            logging.Handler.handleError(self, record)
567ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
568ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def emit(self, record):
569ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
570ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Emit a record.
571ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
572ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Pickles the record and writes it to the socket in binary format.
573ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        If there is an error with the socket, silently drop the packet.
574ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        If there was a problem with the socket, re-establishes the
575ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        socket.
576ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
577ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        try:
578ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            s = self.makePickle(record)
579ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.send(s)
580ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        except (KeyboardInterrupt, SystemExit):
581ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            raise
582ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        except:
583ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.handleError(record)
584ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
585ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def close(self):
586ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
587ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Closes the socket.
588ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
589ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.acquire()
590ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        try:
591ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if self.sock:
592ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                self.sock.close()
593ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                self.sock = None
594ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        finally:
595ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.release()
596ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        logging.Handler.close(self)
597ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
598ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotclass DatagramHandler(SocketHandler):
599ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
600ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    A handler class which writes logging records, in pickle format, to
601ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    a datagram socket.  The pickle which is sent is that of the LogRecord's
602ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    attribute dictionary (__dict__), so that the receiver does not need to
603ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    have the logging module installed in order to process the logging event.
604ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
605ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    To unpickle the record at the receiving end into a LogRecord, use the
606ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    makeLogRecord function.
607ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
608ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
609ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def __init__(self, host, port):
610ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
611ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Initializes the handler with a specific host address and port.
612ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
613ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        SocketHandler.__init__(self, host, port)
614ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.closeOnError = 0
615ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
616ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def makeSocket(self):
617ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
618ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        The factory method of SocketHandler is here overridden to create
619ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        a UDP socket (SOCK_DGRAM).
620ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
621ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
622ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        return s
623ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
624ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def send(self, s):
625ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
626ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Send a pickled string to a socket.
627ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
628ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        This function no longer allows for partial sends which can happen
629ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        when the network is busy - UDP does not guarantee delivery and
630ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        can deliver packets out of sequence.
631ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
632ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if self.sock is None:
633ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.createSocket()
634ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.sock.sendto(s, (self.host, self.port))
635ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
636ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotclass SysLogHandler(logging.Handler):
637ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
638ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    A handler class which sends formatted logging records to a syslog
639ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    server. Based on Sam Rushing's syslog module:
640ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    http://www.nightmare.com/squirl/python-ext/misc/syslog.py
641ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    Contributed by Nicolas Untz (after which minor refactoring changes
642ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    have been made).
643ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
644ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
645ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    # from <linux/sys/syslog.h>:
646ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    # ======================================================================
647ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    # priorities/facilities are encoded into a single 32-bit quantity, where
648ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    # the bottom 3 bits are the priority (0-7) and the top 28 bits are the
649ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    # facility (0-big number). Both the priorities and the facilities map
650ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    # roughly one-to-one to strings in the syslogd(8) source code.  This
651ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    # mapping is included in this file.
652ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    #
653ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    # priorities (these are ordered)
654ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
655ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_EMERG     = 0       #  system is unusable
656ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_ALERT     = 1       #  action must be taken immediately
657ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_CRIT      = 2       #  critical conditions
658ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_ERR       = 3       #  error conditions
659ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_WARNING   = 4       #  warning conditions
660ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_NOTICE    = 5       #  normal but significant condition
661ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_INFO      = 6       #  informational
662ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_DEBUG     = 7       #  debug-level messages
663ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
664ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    #  facility codes
665ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_KERN      = 0       #  kernel messages
666ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_USER      = 1       #  random user-level messages
667ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_MAIL      = 2       #  mail system
668ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_DAEMON    = 3       #  system daemons
669ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_AUTH      = 4       #  security/authorization messages
670ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_SYSLOG    = 5       #  messages generated internally by syslogd
671ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_LPR       = 6       #  line printer subsystem
672ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_NEWS      = 7       #  network news subsystem
673ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_UUCP      = 8       #  UUCP subsystem
674ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_CRON      = 9       #  clock daemon
675ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_AUTHPRIV  = 10      #  security/authorization messages (private)
676ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_FTP       = 11      #  FTP daemon
677ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
678ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    #  other codes through 15 reserved for system use
679ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_LOCAL0    = 16      #  reserved for local use
680ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_LOCAL1    = 17      #  reserved for local use
681ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_LOCAL2    = 18      #  reserved for local use
682ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_LOCAL3    = 19      #  reserved for local use
683ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_LOCAL4    = 20      #  reserved for local use
684ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_LOCAL5    = 21      #  reserved for local use
685ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_LOCAL6    = 22      #  reserved for local use
686ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    LOG_LOCAL7    = 23      #  reserved for local use
687ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
688ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    priority_names = {
689ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "alert":    LOG_ALERT,
690ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "crit":     LOG_CRIT,
691ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "critical": LOG_CRIT,
692ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "debug":    LOG_DEBUG,
693ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "emerg":    LOG_EMERG,
694ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "err":      LOG_ERR,
695ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "error":    LOG_ERR,        #  DEPRECATED
696ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "info":     LOG_INFO,
697ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "notice":   LOG_NOTICE,
698ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "panic":    LOG_EMERG,      #  DEPRECATED
699ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "warn":     LOG_WARNING,    #  DEPRECATED
700ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "warning":  LOG_WARNING,
701ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        }
702ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
703ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    facility_names = {
704ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "auth":     LOG_AUTH,
705ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "authpriv": LOG_AUTHPRIV,
706ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "cron":     LOG_CRON,
707ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "daemon":   LOG_DAEMON,
708ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "ftp":      LOG_FTP,
709ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "kern":     LOG_KERN,
710ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "lpr":      LOG_LPR,
711ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "mail":     LOG_MAIL,
712ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "news":     LOG_NEWS,
713ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "security": LOG_AUTH,       #  DEPRECATED
714ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "syslog":   LOG_SYSLOG,
715ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "user":     LOG_USER,
716ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "uucp":     LOG_UUCP,
717ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "local0":   LOG_LOCAL0,
718ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "local1":   LOG_LOCAL1,
719ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "local2":   LOG_LOCAL2,
720ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "local3":   LOG_LOCAL3,
721ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "local4":   LOG_LOCAL4,
722ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "local5":   LOG_LOCAL5,
723ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "local6":   LOG_LOCAL6,
724ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "local7":   LOG_LOCAL7,
725ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        }
726ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
727ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    #The map below appears to be trivially lowercasing the key. However,
728ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    #there's more to it than meets the eye - in some locales, lowercasing
729ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    #gives unexpected results. See SF #1524081: in the Turkish locale,
730ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    #"INFO".lower() != "info"
731ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    priority_map = {
732ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "DEBUG" : "debug",
733ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "INFO" : "info",
734ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "WARNING" : "warning",
735ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "ERROR" : "error",
736ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        "CRITICAL" : "critical"
737ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    }
738ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
739ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def __init__(self, address=('localhost', SYSLOG_UDP_PORT),
740ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                 facility=LOG_USER, socktype=None):
741ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
742ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Initialize a handler.
743ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
744ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        If address is specified as a string, a UNIX socket is used. To log to a
745ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        local syslogd, "SysLogHandler(address="/dev/log")" can be used.
746ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        If facility is not specified, LOG_USER is used. If socktype is
747ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        specified as socket.SOCK_DGRAM or socket.SOCK_STREAM, that specific
748ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        socket type will be used. For Unix sockets, you can also specify a
749ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        socktype of None, in which case socket.SOCK_DGRAM will be used, falling
750ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        back to socket.SOCK_STREAM.
751ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
752ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        logging.Handler.__init__(self)
753ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
754ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.address = address
755ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.facility = facility
756ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.socktype = socktype
757ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
758ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if isinstance(address, basestring):
759ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.unixsocket = 1
760ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self._connect_unixsocket(address)
761ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        else:
762ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.unixsocket = 0
763ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if socktype is None:
764ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                socktype = socket.SOCK_DGRAM
765ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.socket = socket.socket(socket.AF_INET, socktype)
766ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if socktype == socket.SOCK_STREAM:
767ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                self.socket.connect(address)
768ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.socktype = socktype
769ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.formatter = None
770ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
771ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def _connect_unixsocket(self, address):
772ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        use_socktype = self.socktype
773ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if use_socktype is None:
774ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            use_socktype = socket.SOCK_DGRAM
775ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.socket = socket.socket(socket.AF_UNIX, use_socktype)
776ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        try:
777ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.socket.connect(address)
778ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            # it worked, so set self.socktype to the used type
779ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.socktype = use_socktype
780ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        except socket.error:
781ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.socket.close()
782ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if self.socktype is not None:
783ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                # user didn't specify falling back, so fail
784ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                raise
785ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            use_socktype = socket.SOCK_STREAM
786ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.socket = socket.socket(socket.AF_UNIX, use_socktype)
787ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            try:
788ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                self.socket.connect(address)
789ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                # it worked, so set self.socktype to the used type
790ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                self.socktype = use_socktype
791ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            except socket.error:
792ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                self.socket.close()
793ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                raise
794ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
795ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    # curious: when talking to the unix-domain '/dev/log' socket, a
796ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    #   zero-terminator seems to be required.  this string is placed
797ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    #   into a class variable so that it can be overridden if
798ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    #   necessary.
799ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    log_format_string = '<%d>%s\000'
800ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
801ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def encodePriority(self, facility, priority):
802ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
803ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Encode the facility and priority. You can pass in strings or
804ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        integers - if strings are passed, the facility_names and
805ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        priority_names mapping dictionaries are used to convert them to
806ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        integers.
807ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
808ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if isinstance(facility, basestring):
809ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            facility = self.facility_names[facility]
810ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if isinstance(priority, basestring):
811ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            priority = self.priority_names[priority]
812ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        return (facility << 3) | priority
813ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
814ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def close (self):
815ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
816ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Closes the socket.
817ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
818ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.acquire()
819ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        try:
820ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if self.unixsocket:
821ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                self.socket.close()
822ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        finally:
823ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.release()
824ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        logging.Handler.close(self)
825ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
826ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def mapPriority(self, levelName):
827ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
828ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Map a logging level name to a key in the priority_names map.
829ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        This is useful in two scenarios: when custom levels are being
830ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        used, and in the case where you can't do a straightforward
831ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        mapping by lowercasing the logging level name because of locale-
832ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        specific issues (see SF #1524081).
833ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
834ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        return self.priority_map.get(levelName, "warning")
835ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
836ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def emit(self, record):
837ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
838ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Emit a record.
839ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
840ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        The record is formatted, and then sent to the syslog server. If
841ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        exception information is present, it is NOT sent to the server.
842ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
843ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        msg = self.format(record) + '\000'
844ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
845ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        We need to convert record level to lowercase, maybe this will
846ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        change in the future.
847ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
848ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        prio = '<%d>' % self.encodePriority(self.facility,
849ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                                            self.mapPriority(record.levelname))
850ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # Message is a string. Convert to bytes as required by RFC 5424
851ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if type(msg) is unicode:
852ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            msg = msg.encode('utf-8')
853ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        msg = prio + msg
854ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        try:
855ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if self.unixsocket:
856ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                try:
857ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    self.socket.send(msg)
858ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                except socket.error:
859ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    self._connect_unixsocket(self.address)
860ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    self.socket.send(msg)
861ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            elif self.socktype == socket.SOCK_DGRAM:
862ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                self.socket.sendto(msg, self.address)
863ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            else:
864ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                self.socket.sendall(msg)
865ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        except (KeyboardInterrupt, SystemExit):
866ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            raise
867ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        except:
868ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.handleError(record)
869ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
870ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotclass SMTPHandler(logging.Handler):
871ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
872ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    A handler class which sends an SMTP email for each logging event.
873ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
874ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def __init__(self, mailhost, fromaddr, toaddrs, subject,
875ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                 credentials=None, secure=None):
876ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
877ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Initialize the handler.
878ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
879ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Initialize the instance with the from and to addresses and subject
880ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        line of the email. To specify a non-standard SMTP port, use the
881ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        (host, port) tuple format for the mailhost argument. To specify
882ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        authentication credentials, supply a (username, password) tuple
883ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        for the credentials argument. To specify the use of a secure
884ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        protocol (TLS), pass in a tuple for the secure argument. This will
885ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        only be used when authentication credentials are supplied. The tuple
886ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        will be either an empty tuple, or a single-value tuple with the name
887ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        of a keyfile, or a 2-value tuple with the names of the keyfile and
888ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        certificate file. (This tuple is passed to the `starttls` method).
889ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
890ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        logging.Handler.__init__(self)
891ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if isinstance(mailhost, tuple):
892ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.mailhost, self.mailport = mailhost
893ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        else:
894ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.mailhost, self.mailport = mailhost, None
895ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if isinstance(credentials, tuple):
896ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.username, self.password = credentials
897ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        else:
898ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.username = None
899ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.fromaddr = fromaddr
900ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if isinstance(toaddrs, basestring):
901ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            toaddrs = [toaddrs]
902ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.toaddrs = toaddrs
903ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.subject = subject
904ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.secure = secure
905ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self._timeout = 5.0
906ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
907ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def getSubject(self, record):
908ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
909ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Determine the subject for the email.
910ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
911ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        If you want to specify a subject line which is record-dependent,
912ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        override this method.
913ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
914ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        return self.subject
915ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
916ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def emit(self, record):
917ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
918ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Emit a record.
919ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
920ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Format the record and send it to the specified addressees.
921ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
922ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        try:
923ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            import smtplib
924ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            from email.utils import formatdate
925ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            port = self.mailport
926ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if not port:
927ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                port = smtplib.SMTP_PORT
928ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            smtp = smtplib.SMTP(self.mailhost, port, timeout=self._timeout)
929ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            msg = self.format(record)
930ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\nDate: %s\r\n\r\n%s" % (
931ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                            self.fromaddr,
932ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                            ",".join(self.toaddrs),
933ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                            self.getSubject(record),
934ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                            formatdate(), msg)
935ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if self.username:
936ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                if self.secure is not None:
937ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    smtp.ehlo()
938ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    smtp.starttls(*self.secure)
939ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    smtp.ehlo()
940ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                smtp.login(self.username, self.password)
941ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            smtp.sendmail(self.fromaddr, self.toaddrs, msg)
942ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            smtp.quit()
943ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        except (KeyboardInterrupt, SystemExit):
944ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            raise
945ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        except:
946ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.handleError(record)
947ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
948ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotclass NTEventLogHandler(logging.Handler):
949ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
950ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    A handler class which sends events to the NT Event Log. Adds a
951ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    registry entry for the specified application name. If no dllname is
952ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    provided, win32service.pyd (which contains some basic message
953ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    placeholders) is used. Note that use of these placeholders will make
954ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    your event logs big, as the entire message source is held in the log.
955ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    If you want slimmer logs, you have to pass in the name of your own DLL
956ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    which contains the message definitions you want to use in the event log.
957ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
958ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def __init__(self, appname, dllname=None, logtype="Application"):
959ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        logging.Handler.__init__(self)
960ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        try:
961ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            import win32evtlogutil, win32evtlog
962ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.appname = appname
963ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self._welu = win32evtlogutil
964ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if not dllname:
965ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                dllname = os.path.split(self._welu.__file__)
966ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                dllname = os.path.split(dllname[0])
967ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                dllname = os.path.join(dllname[0], r'win32service.pyd')
968ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.dllname = dllname
969ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.logtype = logtype
970ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self._welu.AddSourceToRegistry(appname, dllname, logtype)
971ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.deftype = win32evtlog.EVENTLOG_ERROR_TYPE
972ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.typemap = {
973ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                logging.DEBUG   : win32evtlog.EVENTLOG_INFORMATION_TYPE,
974ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                logging.INFO    : win32evtlog.EVENTLOG_INFORMATION_TYPE,
975ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                logging.WARNING : win32evtlog.EVENTLOG_WARNING_TYPE,
976ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                logging.ERROR   : win32evtlog.EVENTLOG_ERROR_TYPE,
977ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                logging.CRITICAL: win32evtlog.EVENTLOG_ERROR_TYPE,
978ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot         }
979ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        except ImportError:
980ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            print("The Python Win32 extensions for NT (service, event "\
981ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                        "logging) appear not to be available.")
982ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self._welu = None
983ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
984ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def getMessageID(self, record):
985ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
986ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Return the message ID for the event record. If you are using your
987ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        own messages, you could do this by having the msg passed to the
988ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        logger being an ID rather than a formatting string. Then, in here,
989ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        you could use a dictionary lookup to get the message ID. This
990ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        version returns 1, which is the base message ID in win32service.pyd.
991ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
992ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        return 1
993ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
994ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def getEventCategory(self, record):
995ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
996ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Return the event category for the record.
997ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
998ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Override this if you want to specify your own categories. This version
999ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        returns 0.
1000ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1001ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        return 0
1002ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1003ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def getEventType(self, record):
1004ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1005ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Return the event type for the record.
1006ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1007ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Override this if you want to specify your own types. This version does
1008ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        a mapping using the handler's typemap attribute, which is set up in
1009ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        __init__() to a dictionary which contains mappings for DEBUG, INFO,
1010ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        WARNING, ERROR and CRITICAL. If you are using your own levels you will
1011ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        either need to override this method or place a suitable dictionary in
1012ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        the handler's typemap attribute.
1013ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1014ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        return self.typemap.get(record.levelno, self.deftype)
1015ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1016ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def emit(self, record):
1017ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1018ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Emit a record.
1019ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1020ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Determine the message ID, event category and event type. Then
1021ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        log the message in the NT event log.
1022ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1023ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if self._welu:
1024ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            try:
1025ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                id = self.getMessageID(record)
1026ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                cat = self.getEventCategory(record)
1027ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                type = self.getEventType(record)
1028ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                msg = self.format(record)
1029ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                self._welu.ReportEvent(self.appname, id, cat, type, [msg])
1030ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            except (KeyboardInterrupt, SystemExit):
1031ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                raise
1032ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            except:
1033ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                self.handleError(record)
1034ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1035ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def close(self):
1036ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1037ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Clean up this handler.
1038ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1039ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        You can remove the application name from the registry as a
1040ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        source of event log entries. However, if you do this, you will
1041ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        not be able to see the events as you intended in the Event Log
1042ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Viewer - it needs to be able to access the registry to get the
1043ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        DLL name.
1044ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1045ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        #self._welu.RemoveSourceFromRegistry(self.appname, self.logtype)
1046ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        logging.Handler.close(self)
1047ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1048ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotclass HTTPHandler(logging.Handler):
1049ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
1050ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    A class which sends records to a Web server, using either GET or
1051ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    POST semantics.
1052ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
1053ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def __init__(self, host, url, method="GET"):
1054ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1055ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Initialize the instance with the host, the request URL, and the method
1056ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        ("GET" or "POST")
1057ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1058ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        logging.Handler.__init__(self)
1059ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        method = method.upper()
1060ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if method not in ["GET", "POST"]:
1061ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            raise ValueError("method must be GET or POST")
1062ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.host = host
1063ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.url = url
1064ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.method = method
1065ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1066ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def mapLogRecord(self, record):
1067ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1068ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Default implementation of mapping the log record into a dict
1069ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        that is sent as the CGI data. Overwrite in your class.
1070ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Contributed by Franz  Glasner.
1071ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1072ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        return record.__dict__
1073ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1074ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def emit(self, record):
1075ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1076ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Emit a record.
1077ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1078ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Send the record to the Web server as a percent-encoded dictionary
1079ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1080ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        try:
1081ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            import httplib, urllib
1082ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            host = self.host
1083ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            h = httplib.HTTP(host)
1084ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            url = self.url
1085ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            data = urllib.urlencode(self.mapLogRecord(record))
1086ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if self.method == "GET":
1087ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                if (url.find('?') >= 0):
1088ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    sep = '&'
1089ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                else:
1090ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    sep = '?'
1091ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                url = url + "%c%s" % (sep, data)
1092ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            h.putrequest(self.method, url)
1093ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            # support multiple hosts on one IP address...
1094ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            # need to strip optional :port from host, if present
1095ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            i = host.find(":")
1096ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if i >= 0:
1097ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                host = host[:i]
1098ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            h.putheader("Host", host)
1099ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if self.method == "POST":
1100ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                h.putheader("Content-type",
1101ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                            "application/x-www-form-urlencoded")
1102ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                h.putheader("Content-length", str(len(data)))
1103ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            h.endheaders(data if self.method == "POST" else None)
1104ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            h.getreply()    #can't do anything with the result
1105ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        except (KeyboardInterrupt, SystemExit):
1106ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            raise
1107ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        except:
1108ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.handleError(record)
1109ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1110ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotclass BufferingHandler(logging.Handler):
1111ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
1112ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot  A handler class which buffers logging records in memory. Whenever each
1113ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot  record is added to the buffer, a check is made to see if the buffer should
1114ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot  be flushed. If it should, then flush() is expected to do what's needed.
1115ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
1116ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def __init__(self, capacity):
1117ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1118ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Initialize the handler with the buffer size.
1119ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1120ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        logging.Handler.__init__(self)
1121ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.capacity = capacity
1122ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.buffer = []
1123ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1124ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def shouldFlush(self, record):
1125ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1126ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Should the handler flush its buffer?
1127ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1128ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Returns true if the buffer is up to capacity. This method can be
1129ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        overridden to implement custom flushing strategies.
1130ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1131ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        return (len(self.buffer) >= self.capacity)
1132ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1133ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def emit(self, record):
1134ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1135ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Emit a record.
1136ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1137ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Append the record. If shouldFlush() tells us to, call flush() to process
1138ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        the buffer.
1139ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1140ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.buffer.append(record)
1141ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if self.shouldFlush(record):
1142ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.flush()
1143ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1144ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def flush(self):
1145ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1146ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Override to implement custom flushing behaviour.
1147ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1148ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        This version just zaps the buffer to empty.
1149ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1150ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.acquire()
1151ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        try:
1152ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.buffer = []
1153ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        finally:
1154ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.release()
1155ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1156ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def close(self):
1157ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1158ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Close the handler.
1159ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1160ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        This version just flushes and chains to the parent class' close().
1161ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1162ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.flush()
1163ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        logging.Handler.close(self)
1164ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1165ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotclass MemoryHandler(BufferingHandler):
1166ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
1167ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    A handler class which buffers logging records in memory, periodically
1168ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    flushing them to a target handler. Flushing occurs whenever the buffer
1169ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    is full, or when an event of a certain severity or greater is seen.
1170ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    """
1171ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def __init__(self, capacity, flushLevel=logging.ERROR, target=None):
1172ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1173ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Initialize the handler with the buffer size, the level at which
1174ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        flushing should occur and an optional target.
1175ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1176ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Note that without a target being set either here or via setTarget(),
1177ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        a MemoryHandler is no use to anyone!
1178ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1179ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        BufferingHandler.__init__(self, capacity)
1180ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.flushLevel = flushLevel
1181ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.target = target
1182ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1183ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def shouldFlush(self, record):
1184ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1185ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Check for buffer full or a record at the flushLevel or higher.
1186ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1187ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        return (len(self.buffer) >= self.capacity) or \
1188ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                (record.levelno >= self.flushLevel)
1189ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1190ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def setTarget(self, target):
1191ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1192ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Set the target handler for this handler.
1193ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1194ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.target = target
1195ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1196ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def flush(self):
1197ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1198ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        For a MemoryHandler, flushing means just sending the buffered
1199ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        records to the target, if there is one. Override if you want
1200ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        different behaviour.
1201ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1202ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.acquire()
1203ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        try:
1204ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            if self.target:
1205ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                for record in self.buffer:
1206ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                    self.target.handle(record)
1207ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                self.buffer = []
1208ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        finally:
1209ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.release()
1210ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
1211ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def close(self):
1212ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1213ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        Flush, set the target to None and lose the buffer.
1214ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        """
1215ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.flush()
1216ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.acquire()
1217ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        try:
1218ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.target = None
1219ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            BufferingHandler.close(self)
1220ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        finally:
1221ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.release()
1222