14dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip# Copyright 2001-2013 by Vinay Sajip. All Rights Reserved. 257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum# 357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum# Permission to use, copy, modify, and distribute this software and its 457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum# documentation for any purpose and without fee is hereby granted, 557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum# provided that the above copyright notice appear in all copies and that 657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum# both that copyright notice and this permission notice appear in 757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum# supporting documentation, and that the name of Vinay Sajip 857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum# not be used in advertising or publicity pertaining to distribution 957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum# of the software without specific, written prior permission. 1057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 1157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 1257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 1357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 1457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 1557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 1757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum""" 183f74284e1baef338b34ed9a17a7b46e9607ccd5dVinay SajipAdditional handlers for the logging package for Python. The core package is 1916f6a29be8fe709c133f07150c1326451139faaeVinay Sajipbased on PEP 282 and comments thereto in comp.lang.python. 2057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 214dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay SajipCopyright (C) 2001-2013 Vinay Sajip. All Rights Reserved. 2257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 23aecf36a0b532260d38297e323c978bf6f0be2c83Vinay SajipTo use, simply 'import logging.handlers' and log away! 2457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum""" 2557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 26885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajipimport errno, logging, socket, os, cPickle, struct, time, re 279098ee43607340769d1dddf88522cc1bf9b1788fVinay Sajipfrom stat import ST_DEV, ST_INO, ST_MTIME 2857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 294600f11a0772d826c89ff67643ce04ca3c5b2c38Vinay Sajiptry: 304600f11a0772d826c89ff67643ce04ca3c5b2c38Vinay Sajip import codecs 314600f11a0772d826c89ff67643ce04ca3c5b2c38Vinay Sajipexcept ImportError: 324600f11a0772d826c89ff67643ce04ca3c5b2c38Vinay Sajip codecs = None 335ac6528b91382e218332d367c98f06a5ed8670ffVinay Sajiptry: 345ac6528b91382e218332d367c98f06a5ed8670ffVinay Sajip unicode 355ac6528b91382e218332d367c98f06a5ed8670ffVinay Sajip _unicode = True 365ac6528b91382e218332d367c98f06a5ed8670ffVinay Sajipexcept NameError: 375ac6528b91382e218332d367c98f06a5ed8670ffVinay Sajip _unicode = False 384600f11a0772d826c89ff67643ce04ca3c5b2c38Vinay Sajip 3957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum# 4057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum# Some constants... 4157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum# 4257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 4357102f861d506b6c2d2215d100dac9143574fa77Guido van RossumDEFAULT_TCP_LOGGING_PORT = 9020 4457102f861d506b6c2d2215d100dac9143574fa77Guido van RossumDEFAULT_UDP_LOGGING_PORT = 9021 4557102f861d506b6c2d2215d100dac9143574fa77Guido van RossumDEFAULT_HTTP_LOGGING_PORT = 9022 4657102f861d506b6c2d2215d100dac9143574fa77Guido van RossumDEFAULT_SOAP_LOGGING_PORT = 9023 4757102f861d506b6c2d2215d100dac9143574fa77Guido van RossumSYSLOG_UDP_PORT = 514 481c77b7f84c5fca050980854a677539ba377439ddVinay SajipSYSLOG_TCP_PORT = 514 4957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 504b4a63e30a8f300e545f2c44b4c456c74718aa79Vinay Sajip_MIDNIGHT = 24 * 60 * 60 # number of seconds in a day 514b4a63e30a8f300e545f2c44b4c456c74718aa79Vinay Sajip 5217c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajipclass BaseRotatingHandler(logging.FileHandler): 5317c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip """ 5417c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip Base class for handlers that rotate log files at a certain point. 5517c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip Not meant to be instantiated directly. Instead, use RotatingFileHandler 5617c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip or TimedRotatingFileHandler. 5717c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip """ 5892aa2f8d6bfe3088d3f1b322cdf546997eaaff71Vinay Sajip def __init__(self, filename, mode, encoding=None, delay=0): 5917c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip """ 6017c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip Use the specified filename for streamed logging 6117c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip """ 624600f11a0772d826c89ff67643ce04ca3c5b2c38Vinay Sajip if codecs is None: 634600f11a0772d826c89ff67643ce04ca3c5b2c38Vinay Sajip encoding = None 6492aa2f8d6bfe3088d3f1b322cdf546997eaaff71Vinay Sajip logging.FileHandler.__init__(self, filename, mode, encoding, delay) 654600f11a0772d826c89ff67643ce04ca3c5b2c38Vinay Sajip self.mode = mode 664600f11a0772d826c89ff67643ce04ca3c5b2c38Vinay Sajip self.encoding = encoding 6757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 6817c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip def emit(self, record): 6917c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip """ 7017c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip Emit a record. 7117c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip 7217c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip Output the record to the file, catering for rollover as described 7317c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip in doRollover(). 7417c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip """ 753970c11157e985966744cea2960964f5a3144f53Vinay Sajip try: 763970c11157e985966744cea2960964f5a3144f53Vinay Sajip if self.shouldRollover(record): 773970c11157e985966744cea2960964f5a3144f53Vinay Sajip self.doRollover() 783970c11157e985966744cea2960964f5a3144f53Vinay Sajip logging.FileHandler.emit(self, record) 7985c1909a78c97745cd41a56be7bce372b7d60d64Vinay Sajip except (KeyboardInterrupt, SystemExit): 8085c1909a78c97745cd41a56be7bce372b7d60d64Vinay Sajip raise 813970c11157e985966744cea2960964f5a3144f53Vinay Sajip except: 823970c11157e985966744cea2960964f5a3144f53Vinay Sajip self.handleError(record) 8317c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip 8417c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajipclass RotatingFileHandler(BaseRotatingHandler): 8517c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip """ 8617c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip Handler for logging to a set of files, which switches from one file 8717c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip to the next when the current file reaches a certain size. 8817c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip """ 8992aa2f8d6bfe3088d3f1b322cdf546997eaaff71Vinay Sajip def __init__(self, filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=0): 9057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 9157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Open the specified file and use it as the stream for logging. 9257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 9357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum By default, the file grows indefinitely. You can specify particular 9457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum values of maxBytes and backupCount to allow the file to rollover at 9557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum a predetermined size. 9657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 9757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Rollover occurs whenever the current log file is nearly maxBytes in 9857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum length. If backupCount is >= 1, the system will successively create 9957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum new files with the same pathname as the base file, but with extensions 10057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum ".1", ".2" etc. appended to it. For example, with a backupCount of 5 10157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum and a base file name of "app.log", you would get "app.log", 10257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "app.log.1", "app.log.2", ... through to "app.log.5". The file being 10357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum written to is always "app.log" - when it gets filled up, it is closed 10457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum and renamed to "app.log.1", and if files "app.log.1", "app.log.2" etc. 10557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum exist, then they are renamed to "app.log.2", "app.log.3" etc. 10657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum respectively. 10757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 10857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum If maxBytes is zero, rollover never occurs. 10957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 110e8b1eafd8819bcc98d38a93a9ecfe76066c370a1Vinay Sajip # If rotation/rollover is wanted, it doesn't make sense to use another 111e8b1eafd8819bcc98d38a93a9ecfe76066c370a1Vinay Sajip # mode. If for example 'w' were specified, then if there were multiple 112e8b1eafd8819bcc98d38a93a9ecfe76066c370a1Vinay Sajip # runs of the calling application, the logs from previous runs would be 113e8b1eafd8819bcc98d38a93a9ecfe76066c370a1Vinay Sajip # lost if the 'w' is respected, because the log file would be truncated 114e8b1eafd8819bcc98d38a93a9ecfe76066c370a1Vinay Sajip # on each run. 11517c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip if maxBytes > 0: 116e8b1eafd8819bcc98d38a93a9ecfe76066c370a1Vinay Sajip mode = 'a' 11792aa2f8d6bfe3088d3f1b322cdf546997eaaff71Vinay Sajip BaseRotatingHandler.__init__(self, filename, mode, encoding, delay) 11857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.maxBytes = maxBytes 11957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.backupCount = backupCount 12057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 12157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def doRollover(self): 12257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 12357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Do a rollover, as described in __init__(). 12457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 125aecf36a0b532260d38297e323c978bf6f0be2c83Vinay Sajip if self.stream: 126aecf36a0b532260d38297e323c978bf6f0be2c83Vinay Sajip self.stream.close() 127cdb8388cad74e0f2910d5b43531daf6271467292Vinay Sajip self.stream = None 12857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum if self.backupCount > 0: 12957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum for i in range(self.backupCount - 1, 0, -1): 13057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum sfn = "%s.%d" % (self.baseFilename, i) 13157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum dfn = "%s.%d" % (self.baseFilename, i + 1) 13257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum if os.path.exists(sfn): 13357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum #print "%s -> %s" % (sfn, dfn) 13457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum if os.path.exists(dfn): 13557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum os.remove(dfn) 13657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum os.rename(sfn, dfn) 13757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum dfn = self.baseFilename + ".1" 13857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum if os.path.exists(dfn): 13957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum os.remove(dfn) 1406d7e29651cf6a2232d66e47974c522cc2927a6c2Vinay Sajip # Issue 18940: A file may not have been created if delay is True. 1416d7e29651cf6a2232d66e47974c522cc2927a6c2Vinay Sajip if os.path.exists(self.baseFilename): 1426d7e29651cf6a2232d66e47974c522cc2927a6c2Vinay Sajip os.rename(self.baseFilename, dfn) 143fb03696fdabeb850cdc714cd1abb45f6d93fcdf6Vinay Sajip if not self.delay: 144fb03696fdabeb850cdc714cd1abb45f6d93fcdf6Vinay Sajip self.stream = self._open() 14557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 14617c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip def shouldRollover(self, record): 14757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 14817c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip Determine if rollover should occur. 14957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 15017c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip Basically, see if the supplied record would cause the file to exceed 15117c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip the size limit we have. 15257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 153aecf36a0b532260d38297e323c978bf6f0be2c83Vinay Sajip if self.stream is None: # delay was set... 154aecf36a0b532260d38297e323c978bf6f0be2c83Vinay Sajip self.stream = self._open() 15557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum if self.maxBytes > 0: # are we rolling over? 15657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum msg = "%s\n" % self.format(record) 1576fa635df7aa88ae9fd8b41ae42743341316c90f7Neal Norwitz self.stream.seek(0, 2) #due to non-posix-compliant Windows feature 15857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum if self.stream.tell() + len(msg) >= self.maxBytes: 15917c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip return 1 16017c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip return 0 16117c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip 16217c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajipclass TimedRotatingFileHandler(BaseRotatingHandler): 16317c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip """ 16417c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip Handler for logging to a file, rotating the log file at certain timed 16517c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip intervals. 16617c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip 16717c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip If backupCount is > 0, when rollover is done, no more than backupCount 16817c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip files are kept - the oldest ones are deleted. 16917c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip """ 1701c77b7f84c5fca050980854a677539ba377439ddVinay Sajip def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False): 17192aa2f8d6bfe3088d3f1b322cdf546997eaaff71Vinay Sajip BaseRotatingHandler.__init__(self, filename, 'a', encoding, delay) 1721c77b7f84c5fca050980854a677539ba377439ddVinay Sajip self.when = when.upper() 17317c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip self.backupCount = backupCount 174a12da73c468ca08a15671dc9a69bee3bb745cb4fVinay Sajip self.utc = utc 17517c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # Calculate the real rollover interval, which is just the number of 17617c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # seconds between rollovers. Also set the filename suffix used when 17717c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # a rollover occurs. Current 'when' events supported: 17817c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # S - Seconds 17917c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # M - Minutes 18017c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # H - Hours 18117c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # D - Days 18217c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # midnight - roll over at midnight 18317c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # W{0-6} - roll over on a certain day; 0 - Monday 18417c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # 18517c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # Case of the 'when' specifier is not important; lower or upper case 18617c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # will work. 18717c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip if self.when == 'S': 18817c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip self.interval = 1 # one second 18917c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip self.suffix = "%Y-%m-%d_%H-%M-%S" 190e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}$" 19117c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip elif self.when == 'M': 19217c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip self.interval = 60 # one minute 19317c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip self.suffix = "%Y-%m-%d_%H-%M" 194e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}$" 19517c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip elif self.when == 'H': 19617c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip self.interval = 60 * 60 # one hour 19717c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip self.suffix = "%Y-%m-%d_%H" 198e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}$" 19917c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip elif self.when == 'D' or self.when == 'MIDNIGHT': 20017c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip self.interval = 60 * 60 * 24 # one day 20117c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip self.suffix = "%Y-%m-%d" 202e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip self.extMatch = r"^\d{4}-\d{2}-\d{2}$" 20317c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip elif self.when.startswith('W'): 20417c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip self.interval = 60 * 60 * 24 * 7 # one week 20517c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip if len(self.when) != 2: 20617c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip raise ValueError("You must specify a day for weekly rollover from 0 to 6 (0 is Monday): %s" % self.when) 20717c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip if self.when[1] < '0' or self.when[1] > '6': 20817c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip raise ValueError("Invalid day specified for weekly rollover: %s" % self.when) 20917c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip self.dayOfWeek = int(self.when[1]) 21017c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip self.suffix = "%Y-%m-%d" 211e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip self.extMatch = r"^\d{4}-\d{2}-\d{2}$" 21217c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip else: 21317c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip raise ValueError("Invalid rollover interval specified: %s" % self.when) 21417c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip 215e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip self.extMatch = re.compile(self.extMatch) 216e7d4066cdf1868a31f3ad5c6a271df045abe8255Vinay Sajip self.interval = self.interval * interval # multiply by units requested 2179098ee43607340769d1dddf88522cc1bf9b1788fVinay Sajip if os.path.exists(filename): 2189098ee43607340769d1dddf88522cc1bf9b1788fVinay Sajip t = os.stat(filename)[ST_MTIME] 2199098ee43607340769d1dddf88522cc1bf9b1788fVinay Sajip else: 2209098ee43607340769d1dddf88522cc1bf9b1788fVinay Sajip t = int(time.time()) 2219098ee43607340769d1dddf88522cc1bf9b1788fVinay Sajip self.rolloverAt = self.computeRollover(t) 22283da034c9af59b73aa4f175eaebdc5f39d461656Vinay Sajip 22391290b5f53c1ddc81f30eacf6cf93d087b7c74eeVinay Sajip def computeRollover(self, currentTime): 22491290b5f53c1ddc81f30eacf6cf93d087b7c74eeVinay Sajip """ 22591290b5f53c1ddc81f30eacf6cf93d087b7c74eeVinay Sajip Work out the rollover time based on the specified time. 22691290b5f53c1ddc81f30eacf6cf93d087b7c74eeVinay Sajip """ 22791290b5f53c1ddc81f30eacf6cf93d087b7c74eeVinay Sajip result = currentTime + self.interval 22817c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # If we are rolling over at midnight or weekly, then the interval is already known. 22917c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # What we need to figure out is WHEN the next interval is. In other words, 23017c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # if you are rolling over at midnight, then your base interval is 1 day, 23117c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # but you want to start that one day clock at midnight, not now. So, we 23217c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # have to fudge the rolloverAt value in order to trigger the first rollover 23317c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # at the right time. After that, the regular interval will take care of 23417c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # the rest. Note that this code doesn't care about leap seconds. :) 23517c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip if self.when == 'MIDNIGHT' or self.when.startswith('W'): 23617c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # This could be done with less code, but I wanted it to be clear 23783da034c9af59b73aa4f175eaebdc5f39d461656Vinay Sajip if self.utc: 238a12da73c468ca08a15671dc9a69bee3bb745cb4fVinay Sajip t = time.gmtime(currentTime) 239a12da73c468ca08a15671dc9a69bee3bb745cb4fVinay Sajip else: 240a12da73c468ca08a15671dc9a69bee3bb745cb4fVinay Sajip t = time.localtime(currentTime) 24117c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip currentHour = t[3] 24217c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip currentMinute = t[4] 24317c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip currentSecond = t[5] 24417c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # r is the number of seconds left between now and midnight 2454b4a63e30a8f300e545f2c44b4c456c74718aa79Vinay Sajip r = _MIDNIGHT - ((currentHour * 60 + currentMinute) * 60 + 2464b4a63e30a8f300e545f2c44b4c456c74718aa79Vinay Sajip currentSecond) 24791290b5f53c1ddc81f30eacf6cf93d087b7c74eeVinay Sajip result = currentTime + r 24817c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # If we are rolling over on a certain day, add in the number of days until 24917c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # the next rollover, but offset by 1 since we just calculated the time 25017c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # until the next day starts. There are three cases: 25117c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # Case 1) The day to rollover is today; in this case, do nothing 25217c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # Case 2) The day to rollover is further in the interval (i.e., today is 25317c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # day 2 (Wednesday) and rollover is on day 6 (Sunday). Days to 25417c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # next rollover is simply 6 - 2 - 1, or 3. 25517c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # Case 3) The day to rollover is behind us in the interval (i.e., today 25617c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # is day 5 (Saturday) and rollover is on day 3 (Thursday). 25717c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # Days to rollover is 6 - 5 + 3, or 4. In this case, it's the 25817c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # number of days left in the current week (1) plus the number 25917c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # of days in the next week until the rollover day (3). 260ae747dccab69cb3828a3d51fafe41021f50882c9Vinay Sajip # The calculations described in 2) and 3) above need to have a day added. 261ae747dccab69cb3828a3d51fafe41021f50882c9Vinay Sajip # This is because the above time calculation takes us to midnight on this 262ae747dccab69cb3828a3d51fafe41021f50882c9Vinay Sajip # day, i.e. the start of the next day. 26383da034c9af59b73aa4f175eaebdc5f39d461656Vinay Sajip if self.when.startswith('W'): 26417c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip day = t[6] # 0 is Monday 265bababa3eccbff2d7c2c8bf3fc5730cf90825d300Vinay Sajip if day != self.dayOfWeek: 266bababa3eccbff2d7c2c8bf3fc5730cf90825d300Vinay Sajip if day < self.dayOfWeek: 267ae747dccab69cb3828a3d51fafe41021f50882c9Vinay Sajip daysToWait = self.dayOfWeek - day 268bababa3eccbff2d7c2c8bf3fc5730cf90825d300Vinay Sajip else: 269ae747dccab69cb3828a3d51fafe41021f50882c9Vinay Sajip daysToWait = 6 - day + self.dayOfWeek + 1 27091290b5f53c1ddc81f30eacf6cf93d087b7c74eeVinay Sajip newRolloverAt = result + (daysToWait * (60 * 60 * 24)) 27183da034c9af59b73aa4f175eaebdc5f39d461656Vinay Sajip if not self.utc: 272a12da73c468ca08a15671dc9a69bee3bb745cb4fVinay Sajip dstNow = t[-1] 273a12da73c468ca08a15671dc9a69bee3bb745cb4fVinay Sajip dstAtRollover = time.localtime(newRolloverAt)[-1] 274a12da73c468ca08a15671dc9a69bee3bb745cb4fVinay Sajip if dstNow != dstAtRollover: 275a12da73c468ca08a15671dc9a69bee3bb745cb4fVinay Sajip if not dstNow: # DST kicks in before next rollover, so we need to deduct an hour 2769790e083a5330ab0f46dd0c9371ddc25cdeb9735Vinay Sajip addend = -3600 277a12da73c468ca08a15671dc9a69bee3bb745cb4fVinay Sajip else: # DST bows out before next rollover, so we need to add an hour 2789790e083a5330ab0f46dd0c9371ddc25cdeb9735Vinay Sajip addend = 3600 2799790e083a5330ab0f46dd0c9371ddc25cdeb9735Vinay Sajip newRolloverAt += addend 28091290b5f53c1ddc81f30eacf6cf93d087b7c74eeVinay Sajip result = newRolloverAt 28191290b5f53c1ddc81f30eacf6cf93d087b7c74eeVinay Sajip return result 28217c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip 28317c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip def shouldRollover(self, record): 28417c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip """ 285e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip Determine if rollover should occur. 28617c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip 28717c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip record is not used, as we are just comparing times, but it is needed so 288e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip the method signatures are the same 28917c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip """ 29017c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip t = int(time.time()) 29117c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip if t >= self.rolloverAt: 29217c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip return 1 2935e9e9e19f7fae86e5d234a5cd8386bc6e34a36abVinay Sajip #print "No need to rollover: %d, %d" % (t, self.rolloverAt) 29417c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip return 0 29517c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip 296e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip def getFilesToDelete(self): 297e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip """ 298e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip Determine the files to delete when rolling over. 299e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip 300e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip More specific than the earlier method, which just used glob.glob(). 301e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip """ 302e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip dirName, baseName = os.path.split(self.baseFilename) 303e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip fileNames = os.listdir(dirName) 304e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip result = [] 305e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip prefix = baseName + "." 306e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip plen = len(prefix) 307e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip for fileName in fileNames: 308e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip if fileName[:plen] == prefix: 309e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip suffix = fileName[plen:] 310e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip if self.extMatch.match(suffix): 311a12da73c468ca08a15671dc9a69bee3bb745cb4fVinay Sajip result.append(os.path.join(dirName, fileName)) 312e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip result.sort() 313e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip if len(result) < self.backupCount: 314e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip result = [] 315e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip else: 316e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip result = result[:len(result) - self.backupCount] 317e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip return result 318e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip 31917c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip def doRollover(self): 32017c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip """ 32117c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip do a rollover; in this case, a date/time stamp is appended to the filename 32217c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip when the rollover happens. However, you want the file to be named for the 32317c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip start of the interval, not the current time. If there is a backup count, 32417c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip then we have to get a list of matching filenames, sort them and remove 32517c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip the one with the oldest suffix. 32617c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip """ 327aecf36a0b532260d38297e323c978bf6f0be2c83Vinay Sajip if self.stream: 328aecf36a0b532260d38297e323c978bf6f0be2c83Vinay Sajip self.stream.close() 329cdb8388cad74e0f2910d5b43531daf6271467292Vinay Sajip self.stream = None 33017c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip # get the time that this sequence started at and make it a TimeTuple 3319790e083a5330ab0f46dd0c9371ddc25cdeb9735Vinay Sajip currentTime = int(time.time()) 3329790e083a5330ab0f46dd0c9371ddc25cdeb9735Vinay Sajip dstNow = time.localtime(currentTime)[-1] 33317c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip t = self.rolloverAt - self.interval 334a12da73c468ca08a15671dc9a69bee3bb745cb4fVinay Sajip if self.utc: 335a12da73c468ca08a15671dc9a69bee3bb745cb4fVinay Sajip timeTuple = time.gmtime(t) 336a12da73c468ca08a15671dc9a69bee3bb745cb4fVinay Sajip else: 337a12da73c468ca08a15671dc9a69bee3bb745cb4fVinay Sajip timeTuple = time.localtime(t) 3389790e083a5330ab0f46dd0c9371ddc25cdeb9735Vinay Sajip dstThen = timeTuple[-1] 3399790e083a5330ab0f46dd0c9371ddc25cdeb9735Vinay Sajip if dstNow != dstThen: 3409790e083a5330ab0f46dd0c9371ddc25cdeb9735Vinay Sajip if dstNow: 3419790e083a5330ab0f46dd0c9371ddc25cdeb9735Vinay Sajip addend = 3600 3429790e083a5330ab0f46dd0c9371ddc25cdeb9735Vinay Sajip else: 3439790e083a5330ab0f46dd0c9371ddc25cdeb9735Vinay Sajip addend = -3600 3449790e083a5330ab0f46dd0c9371ddc25cdeb9735Vinay Sajip timeTuple = time.localtime(t + addend) 34517c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip dfn = self.baseFilename + "." + time.strftime(self.suffix, timeTuple) 34617c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip if os.path.exists(dfn): 34717c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip os.remove(dfn) 3486d7e29651cf6a2232d66e47974c522cc2927a6c2Vinay Sajip # Issue 18940: A file may not have been created if delay is True. 3496d7e29651cf6a2232d66e47974c522cc2927a6c2Vinay Sajip if os.path.exists(self.baseFilename): 3506d7e29651cf6a2232d66e47974c522cc2927a6c2Vinay Sajip os.rename(self.baseFilename, dfn) 35117c52d84934ff85efc26db3a040ce85cfb154488Vinay Sajip if self.backupCount > 0: 352e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip for s in self.getFilesToDelete(): 353e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip os.remove(s) 354fb03696fdabeb850cdc714cd1abb45f6d93fcdf6Vinay Sajip if not self.delay: 355fb03696fdabeb850cdc714cd1abb45f6d93fcdf6Vinay Sajip self.stream = self._open() 35691290b5f53c1ddc81f30eacf6cf93d087b7c74eeVinay Sajip newRolloverAt = self.computeRollover(currentTime) 357e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip while newRolloverAt <= currentTime: 358e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip newRolloverAt = newRolloverAt + self.interval 359e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip #If DST changes and midnight or weekly rollover, adjust for this. 360a12da73c468ca08a15671dc9a69bee3bb745cb4fVinay Sajip if (self.when == 'MIDNIGHT' or self.when.startswith('W')) and not self.utc: 361e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip dstAtRollover = time.localtime(newRolloverAt)[-1] 362e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip if dstNow != dstAtRollover: 363e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip if not dstNow: # DST kicks in before next rollover, so we need to deduct an hour 3649790e083a5330ab0f46dd0c9371ddc25cdeb9735Vinay Sajip addend = -3600 365e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip else: # DST bows out before next rollover, so we need to add an hour 3669790e083a5330ab0f46dd0c9371ddc25cdeb9735Vinay Sajip addend = 3600 3679790e083a5330ab0f46dd0c9371ddc25cdeb9735Vinay Sajip newRolloverAt += addend 368e5aefa0b303b3146df931bab692d0758c1aa725fVinay Sajip self.rolloverAt = newRolloverAt 36957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 37073306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajipclass WatchedFileHandler(logging.FileHandler): 37173306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip """ 37273306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip A handler for logging to a file, which watches the file 37373306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip to see if it has changed while in use. This can happen because of 37473306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip usage of programs such as newsyslog and logrotate which perform 37573306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip log file rotation. This handler, intended for use under Unix, 37673306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip watches the file to see if it has changed since the last emit. 37773306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip (A file has changed if its device or inode have changed.) 37873306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip If it has changed, the old file stream is closed, and the file 37973306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip opened to get a new stream. 38073306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip 38173306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip This handler is not appropriate for use under Windows, because 38273306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip under Windows open files cannot be moved or renamed - logging 38373306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip opens the files with exclusive locks - and so there is no need 38473306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip for such a handler. Furthermore, ST_INO is not supported under 38573306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip Windows; stat always returns zero for this value. 38673306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip 38773306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip This handler is based on a suggestion and patch by Chad J. 38873306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip Schroeder. 38973306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip """ 39092aa2f8d6bfe3088d3f1b322cdf546997eaaff71Vinay Sajip def __init__(self, filename, mode='a', encoding=None, delay=0): 39192aa2f8d6bfe3088d3f1b322cdf546997eaaff71Vinay Sajip logging.FileHandler.__init__(self, filename, mode, encoding, delay) 392885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip self.dev, self.ino = -1, -1 393885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip self._statstream() 394885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip 395885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip def _statstream(self): 396885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip if self.stream: 397885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip sres = os.fstat(self.stream.fileno()) 398885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip self.dev, self.ino = sres[ST_DEV], sres[ST_INO] 39973306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip 40073306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip def emit(self, record): 40173306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip """ 40273306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip Emit a record. 40373306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip 40473306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip First check if the underlying file has changed, and if it 40573306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip has, close the old stream and reopen the file to get the 40673306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip current stream. 40773306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip """ 408885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip # Reduce the chance of race conditions by stat'ing by path only 409885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip # once and then fstat'ing our new fd if we opened a new log stream. 410885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip # See issue #14632: Thanks to John Mulligan for the problem report 411885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip # and patch. 412885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip try: 413885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip # stat the file by path, checking for existence 414885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip sres = os.stat(self.baseFilename) 415885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip except OSError as err: 416885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip if err.errno == errno.ENOENT: 417885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip sres = None 418885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip else: 419885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip raise 420885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip # compare file system stat with that of our stream file handle 421885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip if not sres or sres[ST_DEV] != self.dev or sres[ST_INO] != self.ino: 422885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip if self.stream is not None: 423885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip # we have an open file handle, clean it up 424885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip self.stream.flush() 425885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip self.stream.close() 426ce817cb36d7e8764b5ddecadea4b02276879d631Vinay Sajip self.stream = None # See Issue #21742: _open () might fail. 427885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip # open a new file handle and get new stat info from that fd 428885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip self.stream = self._open() 429885f6fd472342795d54fae3309c10f87cadceec0Vinay Sajip self._statstream() 43073306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip logging.FileHandler.emit(self, record) 43173306b07edda7e922d8f90f14dd97ec390467f1bVinay Sajip 43257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossumclass SocketHandler(logging.Handler): 43357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 43457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum A handler class which writes logging records, in pickle format, to 43557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum a streaming socket. The socket is kept open across logging calls. 43657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum If the peer resets it, an attempt is made to reconnect on the next call. 4376f3eaa67e51ed0c1b493a26afdf4417d4105d96dRaymond Hettinger The pickle which is sent is that of the LogRecord's attribute dictionary 4386f3eaa67e51ed0c1b493a26afdf4417d4105d96dRaymond Hettinger (__dict__), so that the receiver does not need to have the logging module 4396f3eaa67e51ed0c1b493a26afdf4417d4105d96dRaymond Hettinger installed in order to process the logging event. 4406f3eaa67e51ed0c1b493a26afdf4417d4105d96dRaymond Hettinger 4416f3eaa67e51ed0c1b493a26afdf4417d4105d96dRaymond Hettinger To unpickle the record at the receiving end into a LogRecord, use the 4426f3eaa67e51ed0c1b493a26afdf4417d4105d96dRaymond Hettinger makeLogRecord function. 44357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 44457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 44557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def __init__(self, host, port): 44657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 44757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Initializes the handler with a specific host address and port. 44857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 44957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum The attribute 'closeOnError' is set to 1 - which means that if 45057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum a socket error occurs, the socket is silently closed and then 45157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum reopened on the next logging call. 45257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 45357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum logging.Handler.__init__(self) 45457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.host = host 45557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.port = port 45657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.sock = None 45757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.closeOnError = 0 45848cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip self.retryTime = None 45948cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip # 46048cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip # Exponential backoff parameters. 46148cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip # 46248cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip self.retryStart = 1.0 46348cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip self.retryMax = 30.0 46448cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip self.retryFactor = 2.0 46557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 466aa7b16a888eb53fdc4d7f194f3d49e6e8fe3ac24Vinay Sajip def makeSocket(self, timeout=1): 46757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 46857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum A factory method which allows subclasses to define the precise 46957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum type of socket they want. 47057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 47157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 472aa7b16a888eb53fdc4d7f194f3d49e6e8fe3ac24Vinay Sajip if hasattr(s, 'settimeout'): 473aa7b16a888eb53fdc4d7f194f3d49e6e8fe3ac24Vinay Sajip s.settimeout(timeout) 47457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum s.connect((self.host, self.port)) 47557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum return s 47657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 47748cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip def createSocket(self): 47848cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip """ 47948cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip Try to create a socket, using an exponential backoff with 48048cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip a max retry time. Thanks to Robert Olson for the original patch 48148cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip (SF #815911) which has been slightly refactored. 48248cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip """ 48348cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip now = time.time() 48448cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip # Either retryTime is None, in which case this 48548cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip # is the first time back after a disconnect, or 48648cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip # we've waited long enough. 48748cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip if self.retryTime is None: 4884e0e1b6a540e664e89739456db4c706701bf062bTim Peters attempt = 1 48948cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip else: 4904e0e1b6a540e664e89739456db4c706701bf062bTim Peters attempt = (now >= self.retryTime) 49148cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip if attempt: 49248cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip try: 49348cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip self.sock = self.makeSocket() 49448cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip self.retryTime = None # next time, no delay before trying 495c683a87ca6d026e33c07758bf4802c009727b5f2Vinay Sajip except socket.error: 49648cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip #Creation failed, so set the retry time and return. 49748cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip if self.retryTime is None: 49848cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip self.retryPeriod = self.retryStart 49948cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip else: 50048cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip self.retryPeriod = self.retryPeriod * self.retryFactor 50148cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip if self.retryPeriod > self.retryMax: 50248cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip self.retryPeriod = self.retryMax 50348cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip self.retryTime = now + self.retryPeriod 50448cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip 50557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def send(self, s): 50657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 50757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Send a pickled string to the socket. 50857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 50957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum This function allows for partial sends which can happen when the 51057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum network is busy. 51157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 51248cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip if self.sock is None: 51348cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip self.createSocket() 51448cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip #self.sock can be None either because we haven't reached the retry 51548cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip #time yet, or because we have reached the retry time and retried, 51648cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip #but are still unable to connect. 51748cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip if self.sock: 51848cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip try: 51948cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip if hasattr(self.sock, "sendall"): 52048cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip self.sock.sendall(s) 52148cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip else: 52248cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip sentsofar = 0 52348cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip left = len(s) 52448cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip while left > 0: 52548cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip sent = self.sock.send(s[sentsofar:]) 52648cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip sentsofar = sentsofar + sent 52748cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip left = left - sent 52848cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip except socket.error: 52948cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip self.sock.close() 53048cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip self.sock = None # so we can call createSocket next time 53157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 53257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def makePickle(self, record): 53357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 53457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Pickles the record in binary format with a length prefix, and 53557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum returns it ready for transmission across the socket. 53657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 53748cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip ei = record.exc_info 53848cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip if ei: 5397ce9bda575313b66ca0a5cbcf6d6d30f9546a894Vinay Sajip # just to get traceback text into record.exc_text ... 5407ce9bda575313b66ca0a5cbcf6d6d30f9546a894Vinay Sajip dummy = self.format(record) 5414e0e1b6a540e664e89739456db4c706701bf062bTim Peters record.exc_info = None # to avoid Unpickleable error 5427ce9bda575313b66ca0a5cbcf6d6d30f9546a894Vinay Sajip # See issue #14436: If msg or args are objects, they may not be 5437ce9bda575313b66ca0a5cbcf6d6d30f9546a894Vinay Sajip # available on the receiving end. So we convert the msg % args 5447ce9bda575313b66ca0a5cbcf6d6d30f9546a894Vinay Sajip # to a string, save it as msg and zap the args. 5457ce9bda575313b66ca0a5cbcf6d6d30f9546a894Vinay Sajip d = dict(record.__dict__) 5467ce9bda575313b66ca0a5cbcf6d6d30f9546a894Vinay Sajip d['msg'] = record.getMessage() 5477ce9bda575313b66ca0a5cbcf6d6d30f9546a894Vinay Sajip d['args'] = None 5487ce9bda575313b66ca0a5cbcf6d6d30f9546a894Vinay Sajip s = cPickle.dumps(d, 1) 54948cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip if ei: 5504e0e1b6a540e664e89739456db4c706701bf062bTim Peters record.exc_info = ei # for next handler 55157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum slen = struct.pack(">L", len(s)) 55257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum return slen + s 55357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 5546fa635df7aa88ae9fd8b41ae42743341316c90f7Neal Norwitz def handleError(self, record): 55557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 55657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Handle an error during logging. 55757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 55857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum An error has occurred during logging. Most likely cause - 55957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum connection lost. Close the socket so that we can retry on the 56057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum next event. 56157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 56257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum if self.closeOnError and self.sock: 56357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.sock.close() 56457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.sock = None #try to reconnect next time 56557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum else: 5666fa635df7aa88ae9fd8b41ae42743341316c90f7Neal Norwitz logging.Handler.handleError(self, record) 56757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 56857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def emit(self, record): 56957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 57057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Emit a record. 57157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 57257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Pickles the record and writes it to the socket in binary format. 57357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum If there is an error with the socket, silently drop the packet. 57457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum If there was a problem with the socket, re-establishes the 57557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum socket. 57657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 57757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum try: 57857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum s = self.makePickle(record) 57957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.send(s) 58085c1909a78c97745cd41a56be7bce372b7d60d64Vinay Sajip except (KeyboardInterrupt, SystemExit): 58185c1909a78c97745cd41a56be7bce372b7d60d64Vinay Sajip raise 58257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum except: 5836fa635df7aa88ae9fd8b41ae42743341316c90f7Neal Norwitz self.handleError(record) 58457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 58557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def close(self): 58657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 58757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Closes the socket. 58857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 589501982226a175a9e7eeaee597e25ee6319815b7eVinay Sajip self.acquire() 590501982226a175a9e7eeaee597e25ee6319815b7eVinay Sajip try: 5911aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka sock = self.sock 5921aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka if sock: 593d23845e2701c72bf064e508af2012a1a5d342ddaVinay Sajip self.sock = None 5941aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka sock.close() 595501982226a175a9e7eeaee597e25ee6319815b7eVinay Sajip finally: 596501982226a175a9e7eeaee597e25ee6319815b7eVinay Sajip self.release() 59748cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip logging.Handler.close(self) 59857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 59957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossumclass DatagramHandler(SocketHandler): 60057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 60157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum A handler class which writes logging records, in pickle format, to 6026f3eaa67e51ed0c1b493a26afdf4417d4105d96dRaymond Hettinger a datagram socket. The pickle which is sent is that of the LogRecord's 6036f3eaa67e51ed0c1b493a26afdf4417d4105d96dRaymond Hettinger attribute dictionary (__dict__), so that the receiver does not need to 6046f3eaa67e51ed0c1b493a26afdf4417d4105d96dRaymond Hettinger have the logging module installed in order to process the logging event. 6056f3eaa67e51ed0c1b493a26afdf4417d4105d96dRaymond Hettinger 6066f3eaa67e51ed0c1b493a26afdf4417d4105d96dRaymond Hettinger To unpickle the record at the receiving end into a LogRecord, use the 6076f3eaa67e51ed0c1b493a26afdf4417d4105d96dRaymond Hettinger makeLogRecord function. 60857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 60957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 61057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def __init__(self, host, port): 61157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 61257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Initializes the handler with a specific host address and port. 61357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 61457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum SocketHandler.__init__(self, host, port) 61557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.closeOnError = 0 61657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 61757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def makeSocket(self): 61857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 61957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum The factory method of SocketHandler is here overridden to create 62057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum a UDP socket (SOCK_DGRAM). 62157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 62257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 62357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum return s 62457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 62557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def send(self, s): 62657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 62757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Send a pickled string to a socket. 62857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 62957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum This function no longer allows for partial sends which can happen 63057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum when the network is busy - UDP does not guarantee delivery and 63157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum can deliver packets out of sequence. 63257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 633fb154171c4ace44dec817a3e52a0b83bbbb0f4f5Vinay Sajip if self.sock is None: 634fb154171c4ace44dec817a3e52a0b83bbbb0f4f5Vinay Sajip self.createSocket() 63557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.sock.sendto(s, (self.host, self.port)) 63657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 63757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossumclass SysLogHandler(logging.Handler): 63857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 63957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum A handler class which sends formatted logging records to a syslog 64057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum server. Based on Sam Rushing's syslog module: 64157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum http://www.nightmare.com/squirl/python-ext/misc/syslog.py 64257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Contributed by Nicolas Untz (after which minor refactoring changes 64357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum have been made). 64457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 64557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 64657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum # from <linux/sys/syslog.h>: 64757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum # ====================================================================== 64857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum # priorities/facilities are encoded into a single 32-bit quantity, where 64957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum # the bottom 3 bits are the priority (0-7) and the top 28 bits are the 65057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum # facility (0-big number). Both the priorities and the facilities map 65157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum # roughly one-to-one to strings in the syslogd(8) source code. This 65257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum # mapping is included in this file. 65357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum # 65457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum # priorities (these are ordered) 65557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 65657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_EMERG = 0 # system is unusable 65757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_ALERT = 1 # action must be taken immediately 65857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_CRIT = 2 # critical conditions 65957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_ERR = 3 # error conditions 66057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_WARNING = 4 # warning conditions 66157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_NOTICE = 5 # normal but significant condition 66257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_INFO = 6 # informational 66357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_DEBUG = 7 # debug-level messages 66457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 66557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum # facility codes 66657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_KERN = 0 # kernel messages 66757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_USER = 1 # random user-level messages 66857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_MAIL = 2 # mail system 66957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_DAEMON = 3 # system daemons 67057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_AUTH = 4 # security/authorization messages 67157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_SYSLOG = 5 # messages generated internally by syslogd 67257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_LPR = 6 # line printer subsystem 67357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_NEWS = 7 # network news subsystem 67457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_UUCP = 8 # UUCP subsystem 67557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_CRON = 9 # clock daemon 676b0623d64a8a689ace0d0fbdc0227f363b5c1af1fVinay Sajip LOG_AUTHPRIV = 10 # security/authorization messages (private) 677b0623d64a8a689ace0d0fbdc0227f363b5c1af1fVinay Sajip LOG_FTP = 11 # FTP daemon 67857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 67957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum # other codes through 15 reserved for system use 68057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_LOCAL0 = 16 # reserved for local use 68157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_LOCAL1 = 17 # reserved for local use 68257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_LOCAL2 = 18 # reserved for local use 68357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_LOCAL3 = 19 # reserved for local use 68457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_LOCAL4 = 20 # reserved for local use 68557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_LOCAL5 = 21 # reserved for local use 68657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_LOCAL6 = 22 # reserved for local use 68757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum LOG_LOCAL7 = 23 # reserved for local use 68857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 68957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum priority_names = { 69057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "alert": LOG_ALERT, 69157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "crit": LOG_CRIT, 69257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "critical": LOG_CRIT, 69357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "debug": LOG_DEBUG, 69457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "emerg": LOG_EMERG, 69557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "err": LOG_ERR, 69657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "error": LOG_ERR, # DEPRECATED 69757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "info": LOG_INFO, 69857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "notice": LOG_NOTICE, 69957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "panic": LOG_EMERG, # DEPRECATED 70057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "warn": LOG_WARNING, # DEPRECATED 70157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "warning": LOG_WARNING, 70257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum } 70357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 70457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum facility_names = { 70557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "auth": LOG_AUTH, 70657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "authpriv": LOG_AUTHPRIV, 70757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "cron": LOG_CRON, 70857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "daemon": LOG_DAEMON, 709b0623d64a8a689ace0d0fbdc0227f363b5c1af1fVinay Sajip "ftp": LOG_FTP, 71057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "kern": LOG_KERN, 71157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "lpr": LOG_LPR, 71257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "mail": LOG_MAIL, 71357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "news": LOG_NEWS, 71457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "security": LOG_AUTH, # DEPRECATED 71557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "syslog": LOG_SYSLOG, 71657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "user": LOG_USER, 71757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "uucp": LOG_UUCP, 71857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "local0": LOG_LOCAL0, 71957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "local1": LOG_LOCAL1, 72057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "local2": LOG_LOCAL2, 72157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "local3": LOG_LOCAL3, 72257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "local4": LOG_LOCAL4, 72357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "local5": LOG_LOCAL5, 72457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "local6": LOG_LOCAL6, 72557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum "local7": LOG_LOCAL7, 72657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum } 72757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 728dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip #The map below appears to be trivially lowercasing the key. However, 729dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip #there's more to it than meets the eye - in some locales, lowercasing 730dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip #gives unexpected results. See SF #1524081: in the Turkish locale, 731dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip #"INFO".lower() != "info" 732dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip priority_map = { 733dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip "DEBUG" : "debug", 734dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip "INFO" : "info", 735dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip "WARNING" : "warning", 736dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip "ERROR" : "error", 737dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip "CRITICAL" : "critical" 738dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip } 739dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip 7401c77b7f84c5fca050980854a677539ba377439ddVinay Sajip def __init__(self, address=('localhost', SYSLOG_UDP_PORT), 7414dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip facility=LOG_USER, socktype=None): 74257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 74357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Initialize a handler. 74457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 745754a5fb640237a7b6c89bacf7c1c304273b0fd6bVinay Sajip If address is specified as a string, a UNIX socket is used. To log to a 746754a5fb640237a7b6c89bacf7c1c304273b0fd6bVinay Sajip local syslogd, "SysLogHandler(address="/dev/log")" can be used. 7474dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip If facility is not specified, LOG_USER is used. If socktype is 7484dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip specified as socket.SOCK_DGRAM or socket.SOCK_STREAM, that specific 7494dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip socket type will be used. For Unix sockets, you can also specify a 7504dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip socktype of None, in which case socket.SOCK_DGRAM will be used, falling 7514dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip back to socket.SOCK_STREAM. 75257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 75357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum logging.Handler.__init__(self) 75457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 75557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.address = address 75657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.facility = facility 7571c77b7f84c5fca050980854a677539ba377439ddVinay Sajip self.socktype = socktype 7581c77b7f84c5fca050980854a677539ba377439ddVinay Sajip 7591c77b7f84c5fca050980854a677539ba377439ddVinay Sajip if isinstance(address, basestring): 76057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.unixsocket = 1 7615492e1722af1ce85b8248e30cf35e957429d161dVinay Sajip self._connect_unixsocket(address) 76257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum else: 76357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.unixsocket = 0 7644dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip if socktype is None: 7654dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip socktype = socket.SOCK_DGRAM 7661c77b7f84c5fca050980854a677539ba377439ddVinay Sajip self.socket = socket.socket(socket.AF_INET, socktype) 7671c77b7f84c5fca050980854a677539ba377439ddVinay Sajip if socktype == socket.SOCK_STREAM: 7681c77b7f84c5fca050980854a677539ba377439ddVinay Sajip self.socket.connect(address) 7694dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip self.socktype = socktype 77057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.formatter = None 77157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 772a1974c1459a424fdc9d8bbce55500f6006d0297dVinay Sajip def _connect_unixsocket(self, address): 7734dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip use_socktype = self.socktype 7744dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip if use_socktype is None: 7754dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip use_socktype = socket.SOCK_DGRAM 7764dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip self.socket = socket.socket(socket.AF_UNIX, use_socktype) 777a1974c1459a424fdc9d8bbce55500f6006d0297dVinay Sajip try: 778a1974c1459a424fdc9d8bbce55500f6006d0297dVinay Sajip self.socket.connect(address) 7794dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip # it worked, so set self.socktype to the used type 7804dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip self.socktype = use_socktype 781a1974c1459a424fdc9d8bbce55500f6006d0297dVinay Sajip except socket.error: 782a1974c1459a424fdc9d8bbce55500f6006d0297dVinay Sajip self.socket.close() 7834dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip if self.socktype is not None: 7844dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip # user didn't specify falling back, so fail 7854dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip raise 7864dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip use_socktype = socket.SOCK_STREAM 7874dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip self.socket = socket.socket(socket.AF_UNIX, use_socktype) 7884dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip try: 7894dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip self.socket.connect(address) 7904dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip # it worked, so set self.socktype to the used type 7914dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip self.socktype = use_socktype 7924dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip except socket.error: 7934dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip self.socket.close() 7944dc385b4e3a9f7c140ac9725f85d0e60ccce66e6Vinay Sajip raise 795a1974c1459a424fdc9d8bbce55500f6006d0297dVinay Sajip 79657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum # curious: when talking to the unix-domain '/dev/log' socket, a 79757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum # zero-terminator seems to be required. this string is placed 79857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum # into a class variable so that it can be overridden if 79957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum # necessary. 80057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum log_format_string = '<%d>%s\000' 80157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 802dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip def encodePriority(self, facility, priority): 80357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 80457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Encode the facility and priority. You can pass in strings or 80557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum integers - if strings are passed, the facility_names and 80657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum priority_names mapping dictionaries are used to convert them to 80757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum integers. 80857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 8091c77b7f84c5fca050980854a677539ba377439ddVinay Sajip if isinstance(facility, basestring): 81057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum facility = self.facility_names[facility] 8111c77b7f84c5fca050980854a677539ba377439ddVinay Sajip if isinstance(priority, basestring): 81257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum priority = self.priority_names[priority] 81357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum return (facility << 3) | priority 81457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 81557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def close (self): 81657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 81757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Closes the socket. 81857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 819501982226a175a9e7eeaee597e25ee6319815b7eVinay Sajip self.acquire() 820501982226a175a9e7eeaee597e25ee6319815b7eVinay Sajip try: 821d23845e2701c72bf064e508af2012a1a5d342ddaVinay Sajip if self.unixsocket: 822d23845e2701c72bf064e508af2012a1a5d342ddaVinay Sajip self.socket.close() 823501982226a175a9e7eeaee597e25ee6319815b7eVinay Sajip finally: 824501982226a175a9e7eeaee597e25ee6319815b7eVinay Sajip self.release() 82548cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip logging.Handler.close(self) 82657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 827dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip def mapPriority(self, levelName): 828dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip """ 829dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip Map a logging level name to a key in the priority_names map. 830dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip This is useful in two scenarios: when custom levels are being 831dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip used, and in the case where you can't do a straightforward 832dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip mapping by lowercasing the logging level name because of locale- 833dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip specific issues (see SF #1524081). 834dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip """ 835dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip return self.priority_map.get(levelName, "warning") 836dc57936b63043ad4f1bbb85e91399b02b7b22f21Vinay Sajip 83757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def emit(self, record): 83857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 83957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Emit a record. 84057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 84157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum The record is formatted, and then sent to the syslog server. If 84257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum exception information is present, it is NOT sent to the server. 84357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 84457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum try: 845a79d6f40dfa6dc0df03db489e27532a5a1b644ccVinay Sajip msg = self.format(record) + '\000' 846a79d6f40dfa6dc0df03db489e27532a5a1b644ccVinay Sajip """ 847a79d6f40dfa6dc0df03db489e27532a5a1b644ccVinay Sajip We need to convert record level to lowercase, maybe this will 848a79d6f40dfa6dc0df03db489e27532a5a1b644ccVinay Sajip change in the future. 849a79d6f40dfa6dc0df03db489e27532a5a1b644ccVinay Sajip """ 850a79d6f40dfa6dc0df03db489e27532a5a1b644ccVinay Sajip prio = '<%d>' % self.encodePriority(self.facility, 851a79d6f40dfa6dc0df03db489e27532a5a1b644ccVinay Sajip self.mapPriority(record.levelname)) 852a79d6f40dfa6dc0df03db489e27532a5a1b644ccVinay Sajip # Message is a string. Convert to bytes as required by RFC 5424 853a79d6f40dfa6dc0df03db489e27532a5a1b644ccVinay Sajip if type(msg) is unicode: 854a79d6f40dfa6dc0df03db489e27532a5a1b644ccVinay Sajip msg = msg.encode('utf-8') 855a79d6f40dfa6dc0df03db489e27532a5a1b644ccVinay Sajip msg = prio + msg 85657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum if self.unixsocket: 857a1974c1459a424fdc9d8bbce55500f6006d0297dVinay Sajip try: 858a1974c1459a424fdc9d8bbce55500f6006d0297dVinay Sajip self.socket.send(msg) 859a1974c1459a424fdc9d8bbce55500f6006d0297dVinay Sajip except socket.error: 860bb6b51ca2543967d0cbc5398500eee5a0826b3eaVinay Sajip self.socket.close() # See issue 17981 861a1974c1459a424fdc9d8bbce55500f6006d0297dVinay Sajip self._connect_unixsocket(self.address) 862a1974c1459a424fdc9d8bbce55500f6006d0297dVinay Sajip self.socket.send(msg) 8631c77b7f84c5fca050980854a677539ba377439ddVinay Sajip elif self.socktype == socket.SOCK_DGRAM: 86457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.socket.sendto(msg, self.address) 8651c77b7f84c5fca050980854a677539ba377439ddVinay Sajip else: 8661c77b7f84c5fca050980854a677539ba377439ddVinay Sajip self.socket.sendall(msg) 86785c1909a78c97745cd41a56be7bce372b7d60d64Vinay Sajip except (KeyboardInterrupt, SystemExit): 86885c1909a78c97745cd41a56be7bce372b7d60d64Vinay Sajip raise 86957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum except: 8706fa635df7aa88ae9fd8b41ae42743341316c90f7Neal Norwitz self.handleError(record) 87157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 87257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossumclass SMTPHandler(logging.Handler): 87357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 87457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum A handler class which sends an SMTP email for each logging event. 87557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 876483056675169a004a221e21036ed8224dbab8d19Vinay Sajip def __init__(self, mailhost, fromaddr, toaddrs, subject, 877bd1094a4a506e7444350c822a700c82dc91d7728Vinay Sajip credentials=None, secure=None): 87857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 87957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Initialize the handler. 88057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 88157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Initialize the instance with the from and to addresses and subject 88257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum line of the email. To specify a non-standard SMTP port, use the 88370c8e8b8613c2af0025d5c950e0be8d1b6296294Vinay Sajip (host, port) tuple format for the mailhost argument. To specify 88470c8e8b8613c2af0025d5c950e0be8d1b6296294Vinay Sajip authentication credentials, supply a (username, password) tuple 885483056675169a004a221e21036ed8224dbab8d19Vinay Sajip for the credentials argument. To specify the use of a secure 886bd1094a4a506e7444350c822a700c82dc91d7728Vinay Sajip protocol (TLS), pass in a tuple for the secure argument. This will 887bd1094a4a506e7444350c822a700c82dc91d7728Vinay Sajip only be used when authentication credentials are supplied. The tuple 888bd1094a4a506e7444350c822a700c82dc91d7728Vinay Sajip will be either an empty tuple, or a single-value tuple with the name 889bd1094a4a506e7444350c822a700c82dc91d7728Vinay Sajip of a keyfile, or a 2-value tuple with the names of the keyfile and 890bd1094a4a506e7444350c822a700c82dc91d7728Vinay Sajip certificate file. (This tuple is passed to the `starttls` method). 89157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 89257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum logging.Handler.__init__(self) 8930746b002880ef22385135c85e03ddc3d1570a411Vinay Sajip if isinstance(mailhost, (list, tuple)): 89470c8e8b8613c2af0025d5c950e0be8d1b6296294Vinay Sajip self.mailhost, self.mailport = mailhost 89557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum else: 89670c8e8b8613c2af0025d5c950e0be8d1b6296294Vinay Sajip self.mailhost, self.mailport = mailhost, None 8970746b002880ef22385135c85e03ddc3d1570a411Vinay Sajip if isinstance(credentials, (list, tuple)): 89870c8e8b8613c2af0025d5c950e0be8d1b6296294Vinay Sajip self.username, self.password = credentials 89970c8e8b8613c2af0025d5c950e0be8d1b6296294Vinay Sajip else: 90070c8e8b8613c2af0025d5c950e0be8d1b6296294Vinay Sajip self.username = None 90157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.fromaddr = fromaddr 9021c77b7f84c5fca050980854a677539ba377439ddVinay Sajip if isinstance(toaddrs, basestring): 9036fa635df7aa88ae9fd8b41ae42743341316c90f7Neal Norwitz toaddrs = [toaddrs] 90457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.toaddrs = toaddrs 90557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.subject = subject 906483056675169a004a221e21036ed8224dbab8d19Vinay Sajip self.secure = secure 90750d6f54b1aae4aadf6f080148ec2858663312cd7Vinay Sajip self._timeout = 5.0 90857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 90957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def getSubject(self, record): 91057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 91157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Determine the subject for the email. 91257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 91357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum If you want to specify a subject line which is record-dependent, 91457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum override this method. 91557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 91657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum return self.subject 91757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 91857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def emit(self, record): 91957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 92057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Emit a record. 92157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 92257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Format the record and send it to the specified addressees. 92357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 92457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum try: 92557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum import smtplib 9267ce5c831ccde730a201a9b7a95e5d54cd9b98285Vinay Sajip from email.utils import formatdate 92757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum port = self.mailport 92857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum if not port: 92957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum port = smtplib.SMTP_PORT 93050d6f54b1aae4aadf6f080148ec2858663312cd7Vinay Sajip smtp = smtplib.SMTP(self.mailhost, port, timeout=self._timeout) 93157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum msg = self.format(record) 932f297bd1937f1fb73c7f734f6410e294da8dad12dNeal Norwitz msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\nDate: %s\r\n\r\n%s" % ( 93357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.fromaddr, 9341c77b7f84c5fca050980854a677539ba377439ddVinay Sajip ",".join(self.toaddrs), 935f297bd1937f1fb73c7f734f6410e294da8dad12dNeal Norwitz self.getSubject(record), 936318a12eb0129bd75754cb3cc68076cc3b737074fMartin v. Löwis formatdate(), msg) 93770c8e8b8613c2af0025d5c950e0be8d1b6296294Vinay Sajip if self.username: 938bd1094a4a506e7444350c822a700c82dc91d7728Vinay Sajip if self.secure is not None: 939483056675169a004a221e21036ed8224dbab8d19Vinay Sajip smtp.ehlo() 940bd1094a4a506e7444350c822a700c82dc91d7728Vinay Sajip smtp.starttls(*self.secure) 941483056675169a004a221e21036ed8224dbab8d19Vinay Sajip smtp.ehlo() 94270c8e8b8613c2af0025d5c950e0be8d1b6296294Vinay Sajip smtp.login(self.username, self.password) 94357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum smtp.sendmail(self.fromaddr, self.toaddrs, msg) 94457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum smtp.quit() 945245a5ab31bbaa48776736bdd101b0df7164125c9Vinay Sajip except (KeyboardInterrupt, SystemExit): 946245a5ab31bbaa48776736bdd101b0df7164125c9Vinay Sajip raise 94757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum except: 9486fa635df7aa88ae9fd8b41ae42743341316c90f7Neal Norwitz self.handleError(record) 94957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 95057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossumclass NTEventLogHandler(logging.Handler): 95157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 95257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum A handler class which sends events to the NT Event Log. Adds a 95357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum registry entry for the specified application name. If no dllname is 95457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum provided, win32service.pyd (which contains some basic message 95557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum placeholders) is used. Note that use of these placeholders will make 95657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum your event logs big, as the entire message source is held in the log. 95757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum If you want slimmer logs, you have to pass in the name of your own DLL 95857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum which contains the message definitions you want to use in the event log. 95957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 96057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def __init__(self, appname, dllname=None, logtype="Application"): 96157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum logging.Handler.__init__(self) 96257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum try: 96357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum import win32evtlogutil, win32evtlog 96457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.appname = appname 96557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self._welu = win32evtlogutil 96657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum if not dllname: 96757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum dllname = os.path.split(self._welu.__file__) 96857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum dllname = os.path.split(dllname[0]) 96957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum dllname = os.path.join(dllname[0], r'win32service.pyd') 97057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.dllname = dllname 97157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.logtype = logtype 97257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self._welu.AddSourceToRegistry(appname, dllname, logtype) 97357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.deftype = win32evtlog.EVENTLOG_ERROR_TYPE 97457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.typemap = { 97557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum logging.DEBUG : win32evtlog.EVENTLOG_INFORMATION_TYPE, 97657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum logging.INFO : win32evtlog.EVENTLOG_INFORMATION_TYPE, 9776fa635df7aa88ae9fd8b41ae42743341316c90f7Neal Norwitz logging.WARNING : win32evtlog.EVENTLOG_WARNING_TYPE, 97857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum logging.ERROR : win32evtlog.EVENTLOG_ERROR_TYPE, 97957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum logging.CRITICAL: win32evtlog.EVENTLOG_ERROR_TYPE, 98057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum } 98157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum except ImportError: 9821c77b7f84c5fca050980854a677539ba377439ddVinay Sajip print("The Python Win32 extensions for NT (service, event "\ 9831c77b7f84c5fca050980854a677539ba377439ddVinay Sajip "logging) appear not to be available.") 98457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self._welu = None 98557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 98657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def getMessageID(self, record): 98757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 98857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Return the message ID for the event record. If you are using your 98957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum own messages, you could do this by having the msg passed to the 99057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum logger being an ID rather than a formatting string. Then, in here, 99157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum you could use a dictionary lookup to get the message ID. This 99257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum version returns 1, which is the base message ID in win32service.pyd. 99357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 99457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum return 1 99557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 99657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def getEventCategory(self, record): 99757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 99857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Return the event category for the record. 99957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 100057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Override this if you want to specify your own categories. This version 100157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum returns 0. 100257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 100357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum return 0 100457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 100557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def getEventType(self, record): 100657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 100757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Return the event type for the record. 100857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 100957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Override this if you want to specify your own types. This version does 101057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum a mapping using the handler's typemap attribute, which is set up in 101157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum __init__() to a dictionary which contains mappings for DEBUG, INFO, 10126fa635df7aa88ae9fd8b41ae42743341316c90f7Neal Norwitz WARNING, ERROR and CRITICAL. If you are using your own levels you will 101357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum either need to override this method or place a suitable dictionary in 101457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum the handler's typemap attribute. 101557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 101657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum return self.typemap.get(record.levelno, self.deftype) 101757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 101857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def emit(self, record): 101957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 102057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Emit a record. 102157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 102257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Determine the message ID, event category and event type. Then 102357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum log the message in the NT event log. 102457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 102557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum if self._welu: 102657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum try: 102757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum id = self.getMessageID(record) 102857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum cat = self.getEventCategory(record) 102957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum type = self.getEventType(record) 103057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum msg = self.format(record) 103157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self._welu.ReportEvent(self.appname, id, cat, type, [msg]) 1032245a5ab31bbaa48776736bdd101b0df7164125c9Vinay Sajip except (KeyboardInterrupt, SystemExit): 1033245a5ab31bbaa48776736bdd101b0df7164125c9Vinay Sajip raise 103457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum except: 10356fa635df7aa88ae9fd8b41ae42743341316c90f7Neal Norwitz self.handleError(record) 103657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 103757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def close(self): 103857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 103957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Clean up this handler. 104057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 104157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum You can remove the application name from the registry as a 104257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum source of event log entries. However, if you do this, you will 104357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum not be able to see the events as you intended in the Event Log 104457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Viewer - it needs to be able to access the registry to get the 104557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum DLL name. 104657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 104757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum #self._welu.RemoveSourceFromRegistry(self.appname, self.logtype) 104848cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip logging.Handler.close(self) 104957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 105057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossumclass HTTPHandler(logging.Handler): 105157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 105257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum A class which sends records to a Web server, using either GET or 105357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum POST semantics. 105457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 105557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def __init__(self, host, url, method="GET"): 105657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 105757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Initialize the instance with the host, the request URL, and the method 105857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum ("GET" or "POST") 105957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 106057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum logging.Handler.__init__(self) 10611c77b7f84c5fca050980854a677539ba377439ddVinay Sajip method = method.upper() 106257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum if method not in ["GET", "POST"]: 10631c77b7f84c5fca050980854a677539ba377439ddVinay Sajip raise ValueError("method must be GET or POST") 106457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.host = host 106557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.url = url 106657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.method = method 106757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 1068f297bd1937f1fb73c7f734f6410e294da8dad12dNeal Norwitz def mapLogRecord(self, record): 1069f297bd1937f1fb73c7f734f6410e294da8dad12dNeal Norwitz """ 1070f297bd1937f1fb73c7f734f6410e294da8dad12dNeal Norwitz Default implementation of mapping the log record into a dict 107148cfe38e799394e2fdf81d95af3bdbfaf8e01360Vinay Sajip that is sent as the CGI data. Overwrite in your class. 1072ab2db5815c28314d3b7bd3d7c3d2e1b5932ea524Vinay Sajip Contributed by Franz Glasner. 1073f297bd1937f1fb73c7f734f6410e294da8dad12dNeal Norwitz """ 1074f297bd1937f1fb73c7f734f6410e294da8dad12dNeal Norwitz return record.__dict__ 1075f297bd1937f1fb73c7f734f6410e294da8dad12dNeal Norwitz 107657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def emit(self, record): 107757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 107857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Emit a record. 107957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 1080a5ba05cd31134287f7016cd66898c861f80256c0Senthil Kumaran Send the record to the Web server as a percent-encoded dictionary 108157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 108257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum try: 108357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum import httplib, urllib 1084b79350601bc3faea4ca97d537ba887810daf0ba0Vinay Sajip host = self.host 1085b79350601bc3faea4ca97d537ba887810daf0ba0Vinay Sajip h = httplib.HTTP(host) 108657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum url = self.url 1087f297bd1937f1fb73c7f734f6410e294da8dad12dNeal Norwitz data = urllib.urlencode(self.mapLogRecord(record)) 108857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum if self.method == "GET": 10891c77b7f84c5fca050980854a677539ba377439ddVinay Sajip if (url.find('?') >= 0): 109057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum sep = '&' 109157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum else: 109257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum sep = '?' 109357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum url = url + "%c%s" % (sep, data) 109457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum h.putrequest(self.method, url) 1095b79350601bc3faea4ca97d537ba887810daf0ba0Vinay Sajip # support multiple hosts on one IP address... 1096b79350601bc3faea4ca97d537ba887810daf0ba0Vinay Sajip # need to strip optional :port from host, if present 10971c77b7f84c5fca050980854a677539ba377439ddVinay Sajip i = host.find(":") 1098b79350601bc3faea4ca97d537ba887810daf0ba0Vinay Sajip if i >= 0: 1099b79350601bc3faea4ca97d537ba887810daf0ba0Vinay Sajip host = host[:i] 1100b79350601bc3faea4ca97d537ba887810daf0ba0Vinay Sajip h.putheader("Host", host) 110157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum if self.method == "POST": 1102b79350601bc3faea4ca97d537ba887810daf0ba0Vinay Sajip h.putheader("Content-type", 1103b79350601bc3faea4ca97d537ba887810daf0ba0Vinay Sajip "application/x-www-form-urlencoded") 110457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum h.putheader("Content-length", str(len(data))) 110584040dbe8170864ba673321ec7568974bdabf5a4Kristján Valur Jónsson h.endheaders(data if self.method == "POST" else None) 110657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum h.getreply() #can't do anything with the result 1107245a5ab31bbaa48776736bdd101b0df7164125c9Vinay Sajip except (KeyboardInterrupt, SystemExit): 1108245a5ab31bbaa48776736bdd101b0df7164125c9Vinay Sajip raise 110957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum except: 11106fa635df7aa88ae9fd8b41ae42743341316c90f7Neal Norwitz self.handleError(record) 111157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 111257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossumclass BufferingHandler(logging.Handler): 111357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 111457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum A handler class which buffers logging records in memory. Whenever each 111557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum record is added to the buffer, a check is made to see if the buffer should 111657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum be flushed. If it should, then flush() is expected to do what's needed. 111757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 111857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def __init__(self, capacity): 111957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 112057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Initialize the handler with the buffer size. 112157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 112257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum logging.Handler.__init__(self) 112357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.capacity = capacity 112457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.buffer = [] 112557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 112657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def shouldFlush(self, record): 112757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 112857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Should the handler flush its buffer? 112957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 113057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Returns true if the buffer is up to capacity. This method can be 113157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum overridden to implement custom flushing strategies. 113257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 113357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum return (len(self.buffer) >= self.capacity) 113457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 113557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def emit(self, record): 113657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 113757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Emit a record. 113857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 113957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Append the record. If shouldFlush() tells us to, call flush() to process 114057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum the buffer. 114157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 114257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.buffer.append(record) 114357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum if self.shouldFlush(record): 114457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.flush() 114557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 114657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def flush(self): 114757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 114857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Override to implement custom flushing behaviour. 114957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 115057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum This version just zaps the buffer to empty. 115157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 1152501982226a175a9e7eeaee597e25ee6319815b7eVinay Sajip self.acquire() 1153501982226a175a9e7eeaee597e25ee6319815b7eVinay Sajip try: 1154d23845e2701c72bf064e508af2012a1a5d342ddaVinay Sajip self.buffer = [] 1155501982226a175a9e7eeaee597e25ee6319815b7eVinay Sajip finally: 1156501982226a175a9e7eeaee597e25ee6319815b7eVinay Sajip self.release() 115757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 1158f42d95ebd167b4a0b0edfdfc6f15bd8c5cec799bVinay Sajip def close(self): 1159f42d95ebd167b4a0b0edfdfc6f15bd8c5cec799bVinay Sajip """ 1160f42d95ebd167b4a0b0edfdfc6f15bd8c5cec799bVinay Sajip Close the handler. 1161f42d95ebd167b4a0b0edfdfc6f15bd8c5cec799bVinay Sajip 1162f42d95ebd167b4a0b0edfdfc6f15bd8c5cec799bVinay Sajip This version just flushes and chains to the parent class' close(). 1163f42d95ebd167b4a0b0edfdfc6f15bd8c5cec799bVinay Sajip """ 11641aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka try: 11651aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka self.flush() 11661aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka finally: 11671aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka logging.Handler.close(self) 1168f42d95ebd167b4a0b0edfdfc6f15bd8c5cec799bVinay Sajip 116957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossumclass MemoryHandler(BufferingHandler): 117057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 117157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum A handler class which buffers logging records in memory, periodically 117257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum flushing them to a target handler. Flushing occurs whenever the buffer 117357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum is full, or when an event of a certain severity or greater is seen. 117457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 117557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def __init__(self, capacity, flushLevel=logging.ERROR, target=None): 117657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 117757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Initialize the handler with the buffer size, the level at which 117857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum flushing should occur and an optional target. 117957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 118057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Note that without a target being set either here or via setTarget(), 118157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum a MemoryHandler is no use to anyone! 118257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 118357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum BufferingHandler.__init__(self, capacity) 118457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.flushLevel = flushLevel 118557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.target = target 118657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 118757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def shouldFlush(self, record): 118857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 118957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Check for buffer full or a record at the flushLevel or higher. 119057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 119157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum return (len(self.buffer) >= self.capacity) or \ 119257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum (record.levelno >= self.flushLevel) 119357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 119457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def setTarget(self, target): 119557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 119657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Set the target handler for this handler. 119757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 119857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum self.target = target 119957102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 120057102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def flush(self): 120157102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 120257102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum For a MemoryHandler, flushing means just sending the buffered 120357102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum records to the target, if there is one. Override if you want 120457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum different behaviour. 120557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 1206501982226a175a9e7eeaee597e25ee6319815b7eVinay Sajip self.acquire() 1207501982226a175a9e7eeaee597e25ee6319815b7eVinay Sajip try: 1208d23845e2701c72bf064e508af2012a1a5d342ddaVinay Sajip if self.target: 1209d23845e2701c72bf064e508af2012a1a5d342ddaVinay Sajip for record in self.buffer: 1210d23845e2701c72bf064e508af2012a1a5d342ddaVinay Sajip self.target.handle(record) 1211d23845e2701c72bf064e508af2012a1a5d342ddaVinay Sajip self.buffer = [] 1212501982226a175a9e7eeaee597e25ee6319815b7eVinay Sajip finally: 1213501982226a175a9e7eeaee597e25ee6319815b7eVinay Sajip self.release() 121457102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum 121557102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum def close(self): 121657102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 121757102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum Flush, set the target to None and lose the buffer. 121857102f861d506b6c2d2215d100dac9143574fa77Guido van Rossum """ 1219501982226a175a9e7eeaee597e25ee6319815b7eVinay Sajip try: 12201aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka self.flush() 1221501982226a175a9e7eeaee597e25ee6319815b7eVinay Sajip finally: 12221aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka self.acquire() 12231aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka try: 12241aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka self.target = None 12251aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka BufferingHandler.close(self) 12261aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka finally: 12271aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka self.release() 1228