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