20012021 by vinay sajip permission to use copy modify and distribute this software and its documentation for any purpose and without fee is hereby granted provided that the above notice appear in all copies and that both that notice and this permission notice appear in supporting documentation and that the name of vinay sajip not be used in advertising or publicity pertaining to distribution of the software without specific written prior permission vinay sajip disclaims all warranties with regard to this software including all implied warranties of merchantability and fitness in no event shall vinay sajip be liable for any special indirect or consequential damages or any damages whatsoever resulting from loss of use data or profits whether in an action of contract negligence or other tortious action arising out of or in connection with the use or performance of this software additional handlers for the logging package for python the core package is based on pep 282 and comments thereto in comp lang python c 20012021 vinay sajip to use simply import logging handlers and log away some constants base class for handlers that rotate log files at a certain point not meant to be instantiated directly instead use rotatingfilehandler or timedrotatingfilehandler use the specified filename for streamed logging emit a record output the record to the file catering for rollover as described in dorollover modify the filename of a log file when rotating this is provided so that a custom filename can be provided the default implementation calls the namer attribute of the handler if it s callable passing the default name to it if the attribute isn t callable the default is none the name is returned unchanged param defaultname the default name for the log file when rotating rotate the current log the default implementation calls the rotator attribute of the handler if it s callable passing the source and dest arguments to it if the attribute isn t callable the default is none the source is simply renamed to the destination param source the source filename this is normally the base filename e g test log param dest the destination filename this is normally what the source is rotated to e g test log 1 issue 18940 a file may not have been created if delay is true handler for logging to a set of files which switches from one file to the next when the current file reaches a certain size open the specified file and use it as the stream for logging by default the file grows indefinitely you can specify particular values of maxbytes and backupcount to allow the file to rollover at a predetermined size rollover occurs whenever the current log file is nearly maxbytes in length if backupcount is 1 the system will successively create new files with the same pathname as the base file but with extensions 1 2 etc appended to it for example with a backupcount of 5 and a base file name of app log you would get app log app log 1 app log 2 through to app log 5 the file being written to is always app log when it gets filled up it is closed and renamed to app log 1 and if files app log 1 app log 2 etc exist then they are renamed to app log 2 app log 3 etc respectively if maxbytes is zero rollover never occurs if rotationrollover is wanted it doesn t make sense to use another mode if for example w were specified then if there were multiple runs of the calling application the logs from previous runs would be lost if the w is respected because the log file would be truncated on each run do a rollover as described in init determine if rollover should occur basically see if the supplied record would cause the file to exceed the size limit we have see bpo45401 never rollover anything other than regular files handler for logging to a file rotating the log file at certain timed intervals if backupcount is 0 when rollover is done no more than backupcount files are kept the oldest ones are deleted calculate the real rollover interval which is just the number of seconds between rollovers also set the filename suffix used when a rollover occurs current when events supported s seconds m minutes h hours d days midnight roll over at midnight w06 roll over on a certain day 0 monday case of the when specifier is not important lower or upper case will work the following line added because the filename passed in could be a path object see issue 27493 but self basefilename will be a string work out the rollover time based on the specified time if we are rolling over at midnight or weekly then the interval is already known what we need to figure out is when the next interval is in other words if you are rolling over at midnight then your base interval is 1 day but you want to start that one day clock at midnight not now so we have to fudge the rolloverat value in order to trigger the first rollover at the right time after that the regular interval will take care of the rest note that this code doesn t care about leap seconds this could be done with less code but i wanted it to be clear r is the number of seconds left between now and the next rotation rotate time is before the current time for example when self rotateat is 13 45 and it now 14 15 rotation is tomorrow if we are rolling over on a certain day add in the number of days until the next rollover but offset by 1 since we just calculated the time until the next day starts there are three cases case 1 the day to rollover is today in this case do nothing case 2 the day to rollover is further in the interval i e today is day 2 wednesday and rollover is on day 6 sunday days to next rollover is simply 6 2 1 or 3 case 3 the day to rollover is behind us in the interval i e today is day 5 saturday and rollover is on day 3 thursday days to rollover is 6 5 3 or 4 in this case it s the number of days left in the current week 1 plus the number of days in the next week until the rollover day 3 the calculations described in 2 and 3 above need to have a day added this is because the above time calculation takes us to midnight on this day i e the start of the next day determine if rollover should occur record is not used as we are just comparing times but it is needed so the method signatures are the same see 89564 never rollover anything other than regular files the file is not a regular file so do not rollover but do set the next rollover time to avoid repeated checks determine the files to delete when rolling over more specific than the earlier method which just used glob glob see bpo44753 don t use the extension when computing the prefix our files will always start with basename our files could be just about anything after custom naming but likely candidates are of the form foo log datetimesuffix or foo datetimesuffix log see bpo45628 the datetime suffix could be anywhere in the filename do a rollover in this case a datetime stamp is appended to the filename when the rollover happens however you want the file to be named for the start of the interval not the current time if there is a backup count then we have to get a list of matching filenames sort them and remove the one with the oldest suffix get the time that this sequence started at and make it a timetuple if dst changes and midnight or weekly rollover adjust for this a handler for logging to a file which watches the file to see if it has changed while in use this can happen because of usage of programs such as newsyslog and logrotate which perform log file rotation this handler intended for use under unix watches the file to see if it has changed since the last emit a file has changed if its device or inode have changed if it has changed the old file stream is closed and the file opened to get a new stream this handler is not appropriate for use under windows because under windows open files cannot be moved or renamed logging opens the files with exclusive locks and so there is no need for such a handler furthermore stino is not supported under windows stat always returns zero for this value this handler is based on a suggestion and patch by chad j schroeder reopen log file if needed checks if the underlying file has changed and if it has close the old stream and reopen the file to get the current stream reduce the chance of race conditions by stat ing by path only once and then fstat ing our new fd if we opened a new log stream see issue 14632 thanks to john mulligan for the problem report and patch stat the file by path checking for existence compare file system stat with that of our stream file handle we have an open file handle clean it up open a new file handle and get new stat info from that fd emit a record if underlying file has changed reopen the file before emitting the record to it a handler class which writes logging records in pickle format to a streaming socket the socket is kept open across logging calls if the peer resets it an attempt is made to reconnect on the next call the pickle which is sent is that of the logrecord s attribute dictionary dict so that the receiver does not need to have the logging module installed in order to process the logging event to unpickle the record at the receiving end into a logrecord use the makelogrecord function initializes the handler with a specific host address and port when the attribute closeonerror is set to true if a socket error occurs the socket is silently closed and then reopened on the next logging call exponential backoff parameters a factory method which allows subclasses to define the precise type of socket they want try to create a socket using an exponential backoff with a max retry time thanks to robert olson for the original patch sf 815911 which has been slightly refactored either retrytime is none in which case this is the first time back after a disconnect or we ve waited long enough creation failed so set the retry time and return send a pickled string to the socket this function allows for partial sends which can happen when the network is busy self sock can be none either because we haven t reached the retry time yet or because we have reached the retry time and retried but are still unable to connect pickles the record in binary format with a length prefix and returns it ready for transmission across the socket just to get traceback text into record exctext see issue 14436 if msg or args are objects they may not be available on the receiving end so we convert the msg args to a string save it as msg and zap the args issue 25685 delete message if present redundant with msg handle an error during logging an error has occurred during logging most likely cause connection lost close the socket so that we can retry on the next event emit a record pickles the record and writes it to the socket in binary format if there is an error with the socket silently drop the packet if there was a problem with the socket reestablishes the socket closes the socket a handler class which writes logging records in pickle format to a datagram socket the pickle which is sent is that of the logrecord s attribute dictionary dict so that the receiver does not need to have the logging module installed in order to process the logging event to unpickle the record at the receiving end into a logrecord use the makelogrecord function initializes the handler with a specific host address and port the factory method of sockethandler is here overridden to create a udp socket sockdgram send a pickled string to a socket this function no longer allows for partial sends which can happen when the network is busy udp does not guarantee delivery and can deliver packets out of sequence a handler class which sends formatted logging records to a syslog server based on sam rushing s syslog module http www nightmare comsquirlpythonextmiscsyslog py contributed by nicolas untz after which minor refactoring changes have been made from linuxsyssyslog h prioritiesfacilities are encoded into a single 32bit quantity where the bottom 3 bits are the priority 07 and the top 28 bits are the facility 0big number both the priorities and the facilities map roughly onetoone to strings in the syslogd8 source code this mapping is included in this file priorities these are ordered facility codes other codes through 15 reserved for system use originally added to work around gh43683 unnecessary since gh50043 but kept for backwards compatibility initialize a handler if address is specified as a string a unix socket is used to log to a local syslogd sysloghandleraddressdevlog can be used if facility is not specified loguser is used if socktype is specified as socket sockdgram or socket sockstream that specific socket type will be used for unix sockets you can also specify a socktype of none in which case socket sockdgram will be used falling back to socket sockstream it worked so set self socktype to the used type user didn t specify falling back so fail it worked so set self socktype to the used type try to create a socket and if it s not a datagram socket connect it to the other end this method is called during handler initialization but it s not regarded as an error if the other end isn t listening yet the method will be called again when emitting an event if there is no socket at that point syslog server may be unavailable during handler initialisation c s openlog function also ignores connection errors moreover we ignore these errors while logging so it s not worse to ignore it also here encode the facility and priority you can pass in strings or integers if strings are passed the facilitynames and prioritynames mapping dictionaries are used to convert them to integers closes the socket map a logging level name to a key in the prioritynames map this is useful in two scenarios when custom levels are being used and in the case where you can t do a straightforward mapping by lowercasing the logging level name because of locale specific issues see sf 1524081 emit a record the record is formatted and then sent to the syslog server if exception information is present it is not sent to the server we need to convert record level to lowercase maybe this will change in the future message is a string convert to bytes as required by rfc 5424 a handler class which sends an smtp email for each logging event initialize the handler initialize the instance with the from and to addresses and subject line of the email to specify a nonstandard smtp port use the host port tuple format for the mailhost argument to specify authentication credentials supply a username password tuple for the credentials argument to specify the use of a secure protocol tls pass in a tuple for the secure argument this will only be used when authentication credentials are supplied the tuple will be either an empty tuple or a singlevalue tuple with the name of a keyfile or a 2value tuple with the names of the keyfile and certificate file this tuple is passed to the starttls method a timeout in seconds can be specified for the smtp connection the default is one second determine the subject for the email if you want to specify a subject line which is recorddependent override this method emit a record format the record and send it to the specified addressees a handler class which sends events to the nt event log adds a registry entry for the specified application name if no dllname is provided win32service pyd which contains some basic message placeholders is used note that use of these placeholders will make your event logs big as the entire message source is held in the log if you want slimmer logs you have to pass in the name of your own dll which contains the message definitions you want to use in the event log administrative privileges are required to add a source to the registry this may not be available for a user that just wants to add to an existing source handle this specific case this will probably be a pywintypes error only raise if it s not an access denied error else let it pass return the message id for the event record if you are using your own messages you could do this by having the msg passed to the logger being an id rather than a formatting string then in here you could use a dictionary lookup to get the message id this version returns 1 which is the base message id in win32service pyd return the event category for the record override this if you want to specify your own categories this version returns 0 return the event type for the record override this if you want to specify your own types this version does a mapping using the handler s typemap attribute which is set up in init to a dictionary which contains mappings for debug info warning error and critical if you are using your own levels you will either need to override this method or place a suitable dictionary in the handler s typemap attribute emit a record determine the message id event category and event type then log the message in the nt event log clean up this handler you can remove the application name from the registry as a source of event log entries however if you do this you will not be able to see the events as you intended in the event log viewer it needs to be able to access the registry to get the dll name self welu removesourcefromregistryself appname self logtype a class which sends records to a web server using either get or post semantics initialize the instance with the host the request url and the method get or post default implementation of mapping the log record into a dict that is sent as the cgi data overwrite in your class contributed by franz glasner get a httpsconnection override when a custom connection is required for example if there is a proxy emit a record send the record to the web server as a percentencoded dictionary support multiple hosts on one ip address need to strip optional port from host if present see issue 30904 putrequest call above already adds this header on python 3 x h putheaderhost host a handler class which buffers logging records in memory whenever each record is added to the buffer a check is made to see if the buffer should be flushed if it should then flush is expected to do what s needed initialize the handler with the buffer size should the handler flush its buffer returns true if the buffer is up to capacity this method can be overridden to implement custom flushing strategies emit a record append the record if shouldflush tells us to call flush to process the buffer override to implement custom flushing behaviour this version just zaps the buffer to empty close the handler this version just flushes and chains to the parent class close a handler class which buffers logging records in memory periodically flushing them to a target handler flushing occurs whenever the buffer is full or when an event of a certain severity or greater is seen initialize the handler with the buffer size the level at which flushing should occur and an optional target note that without a target being set either here or via settarget a memoryhandler is no use to anyone the flushonclose argument is true for backward compatibility reasons the old behaviour is that when the handler is closed the buffer is flushed even if the flush level hasn t been exceeded nor the capacity exceeded to prevent this set flushonclose to false see issue 26559 for why this has been added check for buffer full or a record at the flushlevel or higher set the target handler for this handler for a memoryhandler flushing means just sending the buffered records to the target if there is one override if you want different behaviour the record buffer is only cleared if a target has been set flush if appropriately configured set the target to none and lose the buffer this handler sends events to a queue typically it would be used together with a multiprocessing queue to centralise logging to file in one process in a multiprocess application so as to avoid file write contention between processes this code is new in python 3 2 but this class can be copy pasted into user code for use with earlier python versions initialise an instance using the passed queue enqueue a record the base implementation uses putnowait you may want to override this method if you want to use blocking timeouts or custom queue implementations prepare a record for queuing the object returned by this method is enqueued the base implementation formats the record to merge the message and arguments and removes unpickleable items from the record inplace specifically it overwrites the record s msg and message attributes with the merged message obtained by calling the handler s format method and sets the args excinfo and exctext attributes to none you might want to override this method if you want to convert the record to a dict or json string or send a modified copy of the record while leaving the original intact the format operation gets traceback text into record exctext if there s exception data and also returns the formatted message we can then use this to replace the original msg args as these might be unpickleable we also zap the excinfo exctext and stackinfo attributes as they are no longer needed and if not none will typically not be pickleable bpo35726 make copy of record to avoid affecting other handlers in the chain emit a record writes the logrecord to the queue preparing it for pickling first this class implements an internal threaded listener which watches for logrecords being added to a queue removes them and passes them to a list of handlers for processing initialise an instance with the specified queue and handlers dequeue a record and return it optionally blocking the base implementation uses get you may want to override this method if you want to use timeouts or work with custom queue implementations start the listener this starts up a background thread to monitor the queue for logrecords to process prepare a record for handling this method just returns the passedin record you may want to override this method if you need to do any custom marshalling or manipulation of the record before passing it to the handlers handle a record this just loops through the handlers offering them the record to handle monitor the queue for records and ask the handler to deal with them this method runs on a separate internal thread the thread will terminate if it sees a sentinel object in the queue this is used to enqueue the sentinel record the base implementation uses putnowait you may want to override this method if you want to use timeouts or work with custom queue implementations stop the listener this asks the thread to terminate and then waits for it to do so note that if you don t call this before your application exits there may be some records still left on the queue which won t be processed 2001 2021 by vinay sajip permission to use copy modify and distribute this software and its documentation for any purpose and without fee is hereby granted provided that the above notice appear in all copies and that both that notice and this permission notice appear in supporting documentation and that the name of vinay sajip not be used in advertising or publicity pertaining to distribution of the software without specific written prior permission vinay sajip disclaims all warranties with regard to this software including all implied warranties of merchantability and fitness in no event shall vinay sajip be liable for any special indirect or consequential damages or any damages whatsoever resulting from loss of use data or profits whether in an action of contract negligence or other tortious action arising out of or in connection with the use or performance of this software additional handlers for the logging package for python the core package is based on pep 282 and comments thereto in comp lang python c 2001 2021 vinay sajip to use simply import logging handlers and log away some constants number of seconds in a day base class for handlers that rotate log files at a certain point not meant to be instantiated directly instead use rotatingfilehandler or timedrotatingfilehandler use the specified filename for streamed logging emit a record output the record to the file catering for rollover as described in dorollover modify the filename of a log file when rotating this is provided so that a custom filename can be provided the default implementation calls the namer attribute of the handler if it s callable passing the default name to it if the attribute isn t callable the default is none the name is returned unchanged param default_name the default name for the log file when rotating rotate the current log the default implementation calls the rotator attribute of the handler if it s callable passing the source and dest arguments to it if the attribute isn t callable the default is none the source is simply renamed to the destination param source the source filename this is normally the base filename e g test log param dest the destination filename this is normally what the source is rotated to e g test log 1 issue 18940 a file may not have been created if delay is true handler for logging to a set of files which switches from one file to the next when the current file reaches a certain size open the specified file and use it as the stream for logging by default the file grows indefinitely you can specify particular values of maxbytes and backupcount to allow the file to rollover at a predetermined size rollover occurs whenever the current log file is nearly maxbytes in length if backupcount is 1 the system will successively create new files with the same pathname as the base file but with extensions 1 2 etc appended to it for example with a backupcount of 5 and a base file name of app log you would get app log app log 1 app log 2 through to app log 5 the file being written to is always app log when it gets filled up it is closed and renamed to app log 1 and if files app log 1 app log 2 etc exist then they are renamed to app log 2 app log 3 etc respectively if maxbytes is zero rollover never occurs if rotation rollover is wanted it doesn t make sense to use another mode if for example w were specified then if there were multiple runs of the calling application the logs from previous runs would be lost if the w is respected because the log file would be truncated on each run do a rollover as described in __init__ determine if rollover should occur basically see if the supplied record would cause the file to exceed the size limit we have see bpo 45401 never rollover anything other than regular files delay was set are we rolling over due to non posix compliant windows feature handler for logging to a file rotating the log file at certain timed intervals if backupcount is 0 when rollover is done no more than backupcount files are kept the oldest ones are deleted calculate the real rollover interval which is just the number of seconds between rollovers also set the filename suffix used when a rollover occurs current when events supported s seconds m minutes h hours d days midnight roll over at midnight w 0 6 roll over on a certain day 0 monday case of the when specifier is not important lower or upper case will work one second one minute one hour one day one week multiply by units requested the following line added because the filename passed in could be a path object see issue 27493 but self basefilename will be a string work out the rollover time based on the specified time if we are rolling over at midnight or weekly then the interval is already known what we need to figure out is when the next interval is in other words if you are rolling over at midnight then your base interval is 1 day but you want to start that one day clock at midnight not now so we have to fudge the rolloverat value in order to trigger the first rollover at the right time after that the regular interval will take care of the rest note that this code doesn t care about leap seconds this could be done with less code but i wanted it to be clear r is the number of seconds left between now and the next rotation rotate time is before the current time for example when self rotateat is 13 45 and it now 14 15 rotation is tomorrow if we are rolling over on a certain day add in the number of days until the next rollover but offset by 1 since we just calculated the time until the next day starts there are three cases case 1 the day to rollover is today in this case do nothing case 2 the day to rollover is further in the interval i e today is day 2 wednesday and rollover is on day 6 sunday days to next rollover is simply 6 2 1 or 3 case 3 the day to rollover is behind us in the interval i e today is day 5 saturday and rollover is on day 3 thursday days to rollover is 6 5 3 or 4 in this case it s the number of days left in the current week 1 plus the number of days in the next week until the rollover day 3 the calculations described in 2 and 3 above need to have a day added this is because the above time calculation takes us to midnight on this day i e the start of the next day 0 is monday dst kicks in before next rollover so we need to deduct an hour dst bows out before next rollover so we need to add an hour determine if rollover should occur record is not used as we are just comparing times but it is needed so the method signatures are the same see 89564 never rollover anything other than regular files the file is not a regular file so do not rollover but do set the next rollover time to avoid repeated checks determine the files to delete when rolling over more specific than the earlier method which just used glob glob see bpo 44753 don t use the extension when computing the prefix our files will always start with basename our files could be just about anything after custom naming but likely candidates are of the form foo log datetime_suffix or foo datetime_suffix log see bpo 45628 the date time suffix could be anywhere in the filename do a rollover in this case a date time stamp is appended to the filename when the rollover happens however you want the file to be named for the start of the interval not the current time if there is a backup count then we have to get a list of matching filenames sort them and remove the one with the oldest suffix get the time that this sequence started at and make it a timetuple if dst changes and midnight or weekly rollover adjust for this dst kicks in before next rollover so we need to deduct an hour dst bows out before next rollover so we need to add an hour a handler for logging to a file which watches the file to see if it has changed while in use this can happen because of usage of programs such as newsyslog and logrotate which perform log file rotation this handler intended for use under unix watches the file to see if it has changed since the last emit a file has changed if its device or inode have changed if it has changed the old file stream is closed and the file opened to get a new stream this handler is not appropriate for use under windows because under windows open files cannot be moved or renamed logging opens the files with exclusive locks and so there is no need for such a handler furthermore st_ino is not supported under windows stat always returns zero for this value this handler is based on a suggestion and patch by chad j schroeder reopen log file if needed checks if the underlying file has changed and if it has close the old stream and reopen the file to get the current stream reduce the chance of race conditions by stat ing by path only once and then fstat ing our new fd if we opened a new log stream see issue 14632 thanks to john mulligan for the problem report and patch stat the file by path checking for existence compare file system stat with that of our stream file handle we have an open file handle clean it up see issue 21742 _open might fail open a new file handle and get new stat info from that fd emit a record if underlying file has changed reopen the file before emitting the record to it a handler class which writes logging records in pickle format to a streaming socket the socket is kept open across logging calls if the peer resets it an attempt is made to reconnect on the next call the pickle which is sent is that of the logrecord s attribute dictionary __dict__ so that the receiver does not need to have the logging module installed in order to process the logging event to unpickle the record at the receiving end into a logrecord use the makelogrecord function initializes the handler with a specific host address and port when the attribute closeonerror is set to true if a socket error occurs the socket is silently closed and then reopened on the next logging call exponential backoff parameters a factory method which allows subclasses to define the precise type of socket they want issue 19182 try to create a socket using an exponential backoff with a max retry time thanks to robert olson for the original patch sf 815911 which has been slightly refactored either retrytime is none in which case this is the first time back after a disconnect or we ve waited long enough next time no delay before trying creation failed so set the retry time and return send a pickled string to the socket this function allows for partial sends which can happen when the network is busy self sock can be none either because we haven t reached the retry time yet or because we have reached the retry time and retried but are still unable to connect pragma no cover so we can call createsocket next time pickles the record in binary format with a length prefix and returns it ready for transmission across the socket just to get traceback text into record exc_text see issue 14436 if msg or args are objects they may not be available on the receiving end so we convert the msg args to a string save it as msg and zap the args issue 25685 delete message if present redundant with msg handle an error during logging an error has occurred during logging most likely cause connection lost close the socket so that we can retry on the next event try to reconnect next time emit a record pickles the record and writes it to the socket in binary format if there is an error with the socket silently drop the packet if there was a problem with the socket re establishes the socket closes the socket a handler class which writes logging records in pickle format to a datagram socket the pickle which is sent is that of the logrecord s attribute dictionary __dict__ so that the receiver does not need to have the logging module installed in order to process the logging event to unpickle the record at the receiving end into a logrecord use the makelogrecord function initializes the handler with a specific host address and port the factory method of sockethandler is here overridden to create a udp socket sock_dgram send a pickled string to a socket this function no longer allows for partial sends which can happen when the network is busy udp does not guarantee delivery and can deliver packets out of sequence a handler class which sends formatted logging records to a syslog server based on sam rushing s syslog module http www nightmare com squirl python ext misc syslog py contributed by nicolas untz after which minor refactoring changes have been made from linux sys syslog h priorities facilities are encoded into a single 32 bit quantity where the bottom 3 bits are the priority 0 7 and the top 28 bits are the facility 0 big number both the priorities and the facilities map roughly one to one to strings in the syslogd 8 source code this mapping is included in this file priorities these are ordered system is unusable action must be taken immediately critical conditions error conditions warning conditions normal but significant condition informational debug level messages facility codes kernel messages random user level messages mail system system daemons security ization messages messages generated internally by syslogd line printer subsystem network news subsystem uucp subsystem clock daemon security ization messages private ftp daemon ntp subsystem log audit log alert scheduling daemon solaris other codes through 15 reserved for system use reserved for local use reserved for local use reserved for local use reserved for local use reserved for local use reserved for local use reserved for local use reserved for local use deprecated deprecated deprecated originally added to work around gh 43683 unnecessary since gh 50043 but kept for backwards compatibility initialize a handler if address is specified as a string a unix socket is used to log to a local syslogd sysloghandler address dev log can be used if facility is not specified log_user is used if socktype is specified as socket sock_dgram or socket sock_stream that specific socket type will be used for unix sockets you can also specify a socktype of none in which case socket sock_dgram will be used falling back to socket sock_stream it worked so set self socktype to the used type user didn t specify falling back so fail it worked so set self socktype to the used type try to create a socket and if it s not a datagram socket connect it to the other end this method is called during handler initialization but it s not regarded as an error if the other end isn t listening yet the method will be called again when emitting an event if there is no socket at that point syslog server may be unavailable during handler initialisation c s openlog function also ignores connection errors moreover we ignore these errors while logging so it s not worse to ignore it also here encode the facility and priority you can pass in strings or integers if strings are passed the facility_names and priority_names mapping dictionaries are used to convert them to integers closes the socket map a logging level name to a key in the priority_names map this is useful in two scenarios when custom levels are being used and in the case where you can t do a straightforward mapping by lowercasing the logging level name because of locale specific issues see sf 1524081 prepended to all messages some old syslog daemons expect a nul terminator emit a record the record is formatted and then sent to the syslog server if exception information is present it is not sent to the server we need to convert record level to lowercase maybe this will change in the future message is a string convert to bytes as required by rfc 5424 a handler class which sends an smtp email for each logging event initialize the handler initialize the instance with the from and to addresses and subject line of the email to specify a non standard smtp port use the host port tuple format for the mailhost argument to specify authentication credentials supply a username password tuple for the credentials argument to specify the use of a secure protocol tls pass in a tuple for the secure argument this will only be used when authentication credentials are supplied the tuple will be either an empty tuple or a single value tuple with the name of a keyfile or a 2 value tuple with the names of the keyfile and certificate file this tuple is passed to the starttls method a timeout in seconds can be specified for the smtp connection the default is one second determine the subject for the email if you want to specify a subject line which is record dependent override this method emit a record format the record and send it to the specified addressees a handler class which sends events to the nt event log adds a registry entry for the specified application name if no dllname is provided win32service pyd which contains some basic message placeholders is used note that use of these placeholders will make your event logs big as the entire message source is held in the log if you want slimmer logs you have to pass in the name of your own dll which contains the message definitions you want to use in the event log administrative privileges are required to add a source to the registry this may not be available for a user that just wants to add to an existing source handle this specific case this will probably be a pywintypes error only raise if it s not an access denied error else let it pass not access denied return the message id for the event record if you are using your own messages you could do this by having the msg passed to the logger being an id rather than a formatting string then in here you could use a dictionary lookup to get the message id this version returns 1 which is the base message id in win32service pyd return the event category for the record override this if you want to specify your own categories this version returns 0 return the event type for the record override this if you want to specify your own types this version does a mapping using the handler s typemap attribute which is set up in __init__ to a dictionary which contains mappings for debug info warning error and critical if you are using your own levels you will either need to override this method or place a suitable dictionary in the handler s typemap attribute emit a record determine the message id event category and event type then log the message in the nt event log clean up this handler you can remove the application name from the registry as a source of event log entries however if you do this you will not be able to see the events as you intended in the event log viewer it needs to be able to access the registry to get the dll name self _welu removesourcefromregistry self appname self logtype a class which sends records to a web server using either get or post semantics initialize the instance with the host the request url and the method get or post default implementation of mapping the log record into a dict that is sent as the cgi data overwrite in your class contributed by franz glasner get a http s connection override when a custom connection is required for example if there is a proxy emit a record send the record to the web server as a percent encoded dictionary support multiple hosts on one ip address need to strip optional port from host if present see issue 30904 putrequest call above already adds this header on python 3 x h putheader host host can t do anything with the result a handler class which buffers logging records in memory whenever each record is added to the buffer a check is made to see if the buffer should be flushed if it should then flush is expected to do what s needed initialize the handler with the buffer size should the handler flush its buffer returns true if the buffer is up to capacity this method can be overridden to implement custom flushing strategies emit a record append the record if shouldflush tells us to call flush to process the buffer override to implement custom flushing behaviour this version just zaps the buffer to empty close the handler this version just flushes and chains to the parent class close a handler class which buffers logging records in memory periodically flushing them to a target handler flushing occurs whenever the buffer is full or when an event of a certain severity or greater is seen initialize the handler with the buffer size the level at which flushing should occur and an optional target note that without a target being set either here or via settarget a memoryhandler is no use to anyone the flushonclose argument is true for backward compatibility reasons the old behaviour is that when the handler is closed the buffer is flushed even if the flush level hasn t been exceeded nor the capacity exceeded to prevent this set flushonclose to false see issue 26559 for why this has been added check for buffer full or a record at the flushlevel or higher set the target handler for this handler for a memoryhandler flushing means just sending the buffered records to the target if there is one override if you want different behaviour the record buffer is only cleared if a target has been set flush if appropriately configured set the target to none and lose the buffer this handler sends events to a queue typically it would be used together with a multiprocessing queue to centralise logging to file in one process in a multi process application so as to avoid file write contention between processes this code is new in python 3 2 but this class can be copy pasted into user code for use with earlier python versions initialise an instance using the passed queue will be set to listener if configured via dictconfig enqueue a record the base implementation uses put_nowait you may want to override this method if you want to use blocking timeouts or custom queue implementations prepare a record for queuing the object returned by this method is enqueued the base implementation formats the record to merge the message and arguments and removes unpickleable items from the record in place specifically it overwrites the record s msg and message attributes with the merged message obtained by calling the handler s format method and sets the args exc_info and exc_text attributes to none you might want to override this method if you want to convert the record to a dict or json string or send a modified copy of the record while leaving the original intact the format operation gets traceback text into record exc_text if there s exception data and also returns the formatted message we can then use this to replace the original msg args as these might be unpickleable we also zap the exc_info exc_text and stack_info attributes as they are no longer needed and if not none will typically not be pickleable bpo 35726 make copy of record to avoid affecting other handlers in the chain emit a record writes the logrecord to the queue preparing it for pickling first this class implements an internal threaded listener which watches for logrecords being added to a queue removes them and passes them to a list of handlers for processing initialise an instance with the specified queue and handlers dequeue a record and return it optionally blocking the base implementation uses get you may want to override this method if you want to use timeouts or work with custom queue implementations start the listener this starts up a background thread to monitor the queue for logrecords to process prepare a record for handling this method just returns the passed in record you may want to override this method if you need to do any custom marshalling or manipulation of the record before passing it to the handlers handle a record this just loops through the handlers offering them the record to handle monitor the queue for records and ask the handler to deal with them this method runs on a separate internal thread the thread will terminate if it sees a sentinel object in the queue this is used to enqueue the sentinel record the base implementation uses put_nowait you may want to override this method if you want to use timeouts or work with custom queue implementations stop the listener this asks the thread to terminate and then waits for it to do so note that if you don t call this before your application exits there may be some records still left on the queue which won t be processed
import io, logging, socket, os, pickle, struct, time, re
from stat import ST_DEV, ST_INO, ST_MTIME
import queue
import threading
import copy





DEFAULT_TCP_LOGGING_PORT    = 9020
DEFAULT_UDP_LOGGING_PORT    = 9021
DEFAULT_HTTP_LOGGING_PORT   = 9022
DEFAULT_SOAP_LOGGING_PORT   = 9023
SYSLOG_UDP_PORT             = 514
SYSLOG_TCP_PORT             = 514

_MIDNIGHT = 24 * 60 * 60  

class BaseRotatingHandler(logging.FileHandler):
    
    namer = None
    rotator = None

    def __init__(self, filename, mode, encoding=None, delay=False, errors=None):
        
        logging.FileHandler.__init__(self, filename, mode=mode,
                                     encoding=encoding, delay=delay,
                                     errors=errors)
        self.mode = mode
        self.encoding = encoding
        self.errors = errors

    def emit(self, record):
        
        try:
            if self.shouldRollover(record):
                self.doRollover()
            logging.FileHandler.emit(self, record)
        except Exception:
            self.handleError(record)

    def rotation_filename(self, default_name):
        
        if not callable(self.namer):
            result = default_name
        else:
            result = self.namer(default_name)
        return result

    def rotate(self, source, dest):
        
        if not callable(self.rotator):
            
            if os.path.exists(source):
                os.rename(source, dest)
        else:
            self.rotator(source, dest)

class RotatingFileHandler(BaseRotatingHandler):
    
    def __init__(self, filename, mode='a', maxBytes=0, backupCount=0,
                 encoding=None, delay=False, errors=None):
        
        
        
        
        
        
        if maxBytes > 0:
            mode = 'a'
        if "b" not in mode:
            encoding = io.text_encoding(encoding)
        BaseRotatingHandler.__init__(self, filename, mode, encoding=encoding,
                                     delay=delay, errors=errors)
        self.maxBytes = maxBytes
        self.backupCount = backupCount

    def doRollover(self):
        
        if self.stream:
            self.stream.close()
            self.stream = None
        if self.backupCount > 0:
            for i in range(self.backupCount - 1, 0, -1):
                sfn = self.rotation_filename("%s.%d" % (self.baseFilename, i))
                dfn = self.rotation_filename("%s.%d" % (self.baseFilename,
                                                        i + 1))
                if os.path.exists(sfn):
                    if os.path.exists(dfn):
                        os.remove(dfn)
                    os.rename(sfn, dfn)
            dfn = self.rotation_filename(self.baseFilename + ".1")
            if os.path.exists(dfn):
                os.remove(dfn)
            self.rotate(self.baseFilename, dfn)
        if not self.delay:
            self.stream = self._open()

    def shouldRollover(self, record):
        
        
        if os.path.exists(self.baseFilename) and not os.path.isfile(self.baseFilename):
            return False
        if self.stream is None:                 
            self.stream = self._open()
        if self.maxBytes > 0:                   
            msg = "%s\n" % self.format(record)
            self.stream.seek(0, 2)  
            if self.stream.tell() + len(msg) >= self.maxBytes:
                return True
        return False

class TimedRotatingFileHandler(BaseRotatingHandler):
    
    def __init__(self, filename, when='h', interval=1, backupCount=0,
                 encoding=None, delay=False, utc=False, atTime=None,
                 errors=None):
        encoding = io.text_encoding(encoding)
        BaseRotatingHandler.__init__(self, filename, 'a', encoding=encoding,
                                     delay=delay, errors=errors)
        self.when = when.upper()
        self.backupCount = backupCount
        self.utc = utc
        self.atTime = atTime
        
        
        
        
        
        
        
        
        
        
        
        
        if self.when == 'S':
            self.interval = 1 
            self.suffix = "%Y-%m-%d_%H-%M-%S"
            self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}(\.\w+)?$"
        elif self.when == 'M':
            self.interval = 60 
            self.suffix = "%Y-%m-%d_%H-%M"
            self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}(\.\w+)?$"
        elif self.when == 'H':
            self.interval = 60 * 60 
            self.suffix = "%Y-%m-%d_%H"
            self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}(\.\w+)?$"
        elif self.when == 'D' or self.when == 'MIDNIGHT':
            self.interval = 60 * 60 * 24 
            self.suffix = "%Y-%m-%d"
            self.extMatch = r"^\d{4}-\d{2}-\d{2}(\.\w+)?$"
        elif self.when.startswith('W'):
            self.interval = 60 * 60 * 24 * 7 
            if len(self.when) != 2:
                raise ValueError("You must specify a day for weekly rollover from 0 to 6 (0 is Monday): %s" % self.when)
            if self.when[1] < '0' or self.when[1] > '6':
                raise ValueError("Invalid day specified for weekly rollover: %s" % self.when)
            self.dayOfWeek = int(self.when[1])
            self.suffix = "%Y-%m-%d"
            self.extMatch = r"^\d{4}-\d{2}-\d{2}(\.\w+)?$"
        else:
            raise ValueError("Invalid rollover interval specified: %s" % self.when)

        self.extMatch = re.compile(self.extMatch, re.ASCII)
        self.interval = self.interval * interval 
        
        
        filename = self.baseFilename
        if os.path.exists(filename):
            t = os.stat(filename)[ST_MTIME]
        else:
            t = int(time.time())
        self.rolloverAt = self.computeRollover(t)

    def computeRollover(self, currentTime):
        
        result = currentTime + self.interval
        
        
        
        
        
        
        
        if self.when == 'MIDNIGHT' or self.when.startswith('W'):
            
            if self.utc:
                t = time.gmtime(currentTime)
            else:
                t = time.localtime(currentTime)
            currentHour = t[3]
            currentMinute = t[4]
            currentSecond = t[5]
            currentDay = t[6]
            
            if self.atTime is None:
                rotate_ts = _MIDNIGHT
            else:
                rotate_ts = ((self.atTime.hour * 60 + self.atTime.minute)*60 +
                    self.atTime.second)

            r = rotate_ts - ((currentHour * 60 + currentMinute) * 60 +
                currentSecond)
            if r < 0:
                
                
                
                r += _MIDNIGHT
                currentDay = (currentDay + 1) % 7
            result = currentTime + r
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            if self.when.startswith('W'):
                day = currentDay 
                if day != self.dayOfWeek:
                    if day < self.dayOfWeek:
                        daysToWait = self.dayOfWeek - day
                    else:
                        daysToWait = 6 - day + self.dayOfWeek + 1
                    newRolloverAt = result + (daysToWait * (60 * 60 * 24))
                    if not self.utc:
                        dstNow = t[-1]
                        dstAtRollover = time.localtime(newRolloverAt)[-1]
                        if dstNow != dstAtRollover:
                            if not dstNow:  
                                addend = -3600
                            else:           
                                addend = 3600
                            newRolloverAt += addend
                    result = newRolloverAt
        return result

    def shouldRollover(self, record):
        
        t = int(time.time())
        if t >= self.rolloverAt:
            
            if os.path.exists(self.baseFilename) and not os.path.isfile(self.baseFilename):
                
                
                self.rolloverAt = self.computeRollover(t)
                return False

            return True
        return False

    def getFilesToDelete(self):
        
        dirName, baseName = os.path.split(self.baseFilename)
        fileNames = os.listdir(dirName)
        result = []
        
        n, e = os.path.splitext(baseName)
        prefix = n + '.'
        plen = len(prefix)
        for fileName in fileNames:
            if self.namer is None:
                
                if not fileName.startswith(baseName):
                    continue
            else:
                
                
                
                if (not fileName.startswith(baseName) and fileName.endswith(e) and
                    len(fileName) > (plen + 1) and not fileName[plen+1].isdigit()):
                    continue

            if fileName[:plen] == prefix:
                suffix = fileName[plen:]
                
                
                parts = suffix.split('.')
                for part in parts:
                    if self.extMatch.match(part):
                        result.append(os.path.join(dirName, fileName))
                        break
        if len(result) < self.backupCount:
            result = []
        else:
            result.sort()
            result = result[:len(result) - self.backupCount]
        return result

    def doRollover(self):
        
        if self.stream:
            self.stream.close()
            self.stream = None
        
        currentTime = int(time.time())
        dstNow = time.localtime(currentTime)[-1]
        t = self.rolloverAt - self.interval
        if self.utc:
            timeTuple = time.gmtime(t)
        else:
            timeTuple = time.localtime(t)
            dstThen = timeTuple[-1]
            if dstNow != dstThen:
                if dstNow:
                    addend = 3600
                else:
                    addend = -3600
                timeTuple = time.localtime(t + addend)
        dfn = self.rotation_filename(self.baseFilename + "." +
                                     time.strftime(self.suffix, timeTuple))
        if os.path.exists(dfn):
            os.remove(dfn)
        self.rotate(self.baseFilename, dfn)
        if self.backupCount > 0:
            for s in self.getFilesToDelete():
                os.remove(s)
        if not self.delay:
            self.stream = self._open()
        newRolloverAt = self.computeRollover(currentTime)
        while newRolloverAt <= currentTime:
            newRolloverAt = newRolloverAt + self.interval
        
        if (self.when == 'MIDNIGHT' or self.when.startswith('W')) and not self.utc:
            dstAtRollover = time.localtime(newRolloverAt)[-1]
            if dstNow != dstAtRollover:
                if not dstNow:  
                    addend = -3600
                else:           
                    addend = 3600
                newRolloverAt += addend
        self.rolloverAt = newRolloverAt

class WatchedFileHandler(logging.FileHandler):
    
    def __init__(self, filename, mode='a', encoding=None, delay=False,
                 errors=None):
        if "b" not in mode:
            encoding = io.text_encoding(encoding)
        logging.FileHandler.__init__(self, filename, mode=mode,
                                     encoding=encoding, delay=delay,
                                     errors=errors)
        self.dev, self.ino = -1, -1
        self._statstream()

    def _statstream(self):
        if self.stream:
            sres = os.fstat(self.stream.fileno())
            self.dev, self.ino = sres[ST_DEV], sres[ST_INO]

    def reopenIfNeeded(self):
        
        
        
        
        
        try:
            
            sres = os.stat(self.baseFilename)
        except FileNotFoundError:
            sres = None
        
        if not sres or sres[ST_DEV] != self.dev or sres[ST_INO] != self.ino:
            if self.stream is not None:
                
                self.stream.flush()
                self.stream.close()
                self.stream = None  
                
                self.stream = self._open()
                self._statstream()

    def emit(self, record):
        
        self.reopenIfNeeded()
        logging.FileHandler.emit(self, record)


class SocketHandler(logging.Handler):
    

    def __init__(self, host, port):
        
        logging.Handler.__init__(self)
        self.host = host
        self.port = port
        if port is None:
            self.address = host
        else:
            self.address = (host, port)
        self.sock = None
        self.closeOnError = False
        self.retryTime = None
        
        
        
        self.retryStart = 1.0
        self.retryMax = 30.0
        self.retryFactor = 2.0

    def makeSocket(self, timeout=1):
        
        if self.port is not None:
            result = socket.create_connection(self.address, timeout=timeout)
        else:
            result = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
            result.settimeout(timeout)
            try:
                result.connect(self.address)
            except OSError:
                result.close()  
                raise
        return result

    def createSocket(self):
        
        now = time.time()
        
        
        
        if self.retryTime is None:
            attempt = True
        else:
            attempt = (now >= self.retryTime)
        if attempt:
            try:
                self.sock = self.makeSocket()
                self.retryTime = None 
            except OSError:
                
                if self.retryTime is None:
                    self.retryPeriod = self.retryStart
                else:
                    self.retryPeriod = self.retryPeriod * self.retryFactor
                    if self.retryPeriod > self.retryMax:
                        self.retryPeriod = self.retryMax
                self.retryTime = now + self.retryPeriod

    def send(self, s):
        
        if self.sock is None:
            self.createSocket()
        
        
        
        if self.sock:
            try:
                self.sock.sendall(s)
            except OSError: 
                self.sock.close()
                self.sock = None  

    def makePickle(self, record):
        
        ei = record.exc_info
        if ei:
            
            dummy = self.format(record)
        
        
        
        d = dict(record.__dict__)
        d['msg'] = record.getMessage()
        d['args'] = None
        d['exc_info'] = None
        
        d.pop('message', None)
        s = pickle.dumps(d, 1)
        slen = struct.pack(">L", len(s))
        return slen + s

    def handleError(self, record):
        
        if self.closeOnError and self.sock:
            self.sock.close()
            self.sock = None        
        else:
            logging.Handler.handleError(self, record)

    def emit(self, record):
        
        try:
            s = self.makePickle(record)
            self.send(s)
        except Exception:
            self.handleError(record)

    def close(self):
        
        with self.lock:
            sock = self.sock
            if sock:
                self.sock = None
                sock.close()
            logging.Handler.close(self)

class DatagramHandler(SocketHandler):
    
    def __init__(self, host, port):
        
        SocketHandler.__init__(self, host, port)
        self.closeOnError = False

    def makeSocket(self):
        
        if self.port is None:
            family = socket.AF_UNIX
        else:
            family = socket.AF_INET
        s = socket.socket(family, socket.SOCK_DGRAM)
        return s

    def send(self, s):
        
        if self.sock is None:
            self.createSocket()
        self.sock.sendto(s, self.address)

class SysLogHandler(logging.Handler):
    

    
    
    
    
    
    
    
    
    

    LOG_EMERG     = 0       
    LOG_ALERT     = 1       
    LOG_CRIT      = 2       
    LOG_ERR       = 3       
    LOG_WARNING   = 4       
    LOG_NOTICE    = 5       
    LOG_INFO      = 6       
    LOG_DEBUG     = 7       

    
    LOG_KERN      = 0       
    LOG_USER      = 1       
    LOG_MAIL      = 2       
    LOG_DAEMON    = 3       
    LOG_AUTH      = 4       
    LOG_SYSLOG    = 5       
    LOG_LPR       = 6       
    LOG_NEWS      = 7       
    LOG_UUCP      = 8       
    LOG_CRON      = 9       
    LOG_AUTHPRIV  = 10      
    LOG_FTP       = 11      
    LOG_NTP       = 12      
    LOG_SECURITY  = 13      
    LOG_CONSOLE   = 14      
    LOG_SOLCRON   = 15      

    
    LOG_LOCAL0    = 16      
    LOG_LOCAL1    = 17      
    LOG_LOCAL2    = 18      
    LOG_LOCAL3    = 19      
    LOG_LOCAL4    = 20      
    LOG_LOCAL5    = 21      
    LOG_LOCAL6    = 22      
    LOG_LOCAL7    = 23      

    priority_names = {
        "alert":    LOG_ALERT,
        "crit":     LOG_CRIT,
        "critical": LOG_CRIT,
        "debug":    LOG_DEBUG,
        "emerg":    LOG_EMERG,
        "err":      LOG_ERR,
        "error":    LOG_ERR,        
        "info":     LOG_INFO,
        "notice":   LOG_NOTICE,
        "panic":    LOG_EMERG,      
        "warn":     LOG_WARNING,    
        "warning":  LOG_WARNING,
        }

    facility_names = {
        "auth":         LOG_AUTH,
        "authpriv":     LOG_AUTHPRIV,
        "console":      LOG_CONSOLE,
        "cron":         LOG_CRON,
        "daemon":       LOG_DAEMON,
        "ftp":          LOG_FTP,
        "kern":         LOG_KERN,
        "lpr":          LOG_LPR,
        "mail":         LOG_MAIL,
        "news":         LOG_NEWS,
        "ntp":          LOG_NTP,
        "security":     LOG_SECURITY,
        "solaris-cron": LOG_SOLCRON,
        "syslog":       LOG_SYSLOG,
        "user":         LOG_USER,
        "uucp":         LOG_UUCP,
        "local0":       LOG_LOCAL0,
        "local1":       LOG_LOCAL1,
        "local2":       LOG_LOCAL2,
        "local3":       LOG_LOCAL3,
        "local4":       LOG_LOCAL4,
        "local5":       LOG_LOCAL5,
        "local6":       LOG_LOCAL6,
        "local7":       LOG_LOCAL7,
        }

    
    
    priority_map = {
        "DEBUG" : "debug",
        "INFO" : "info",
        "WARNING" : "warning",
        "ERROR" : "error",
        "CRITICAL" : "critical"
    }

    def __init__(self, address=('localhost', SYSLOG_UDP_PORT),
                 facility=LOG_USER, socktype=None):
        
        logging.Handler.__init__(self)

        self.address = address
        self.facility = facility
        self.socktype = socktype
        self.socket = None
        self.createSocket()

    def _connect_unixsocket(self, address):
        use_socktype = self.socktype
        if use_socktype is None:
            use_socktype = socket.SOCK_DGRAM
        self.socket = socket.socket(socket.AF_UNIX, use_socktype)
        try:
            self.socket.connect(address)
            
            self.socktype = use_socktype
        except OSError:
            self.socket.close()
            if self.socktype is not None:
                
                raise
            use_socktype = socket.SOCK_STREAM
            self.socket = socket.socket(socket.AF_UNIX, use_socktype)
            try:
                self.socket.connect(address)
                
                self.socktype = use_socktype
            except OSError:
                self.socket.close()
                raise

    def createSocket(self):
        
        address = self.address
        socktype = self.socktype

        if isinstance(address, str):
            self.unixsocket = True
            
            
            
            
            try:
                self._connect_unixsocket(address)
            except OSError:
                pass
        else:
            self.unixsocket = False
            if socktype is None:
                socktype = socket.SOCK_DGRAM
            host, port = address
            ress = socket.getaddrinfo(host, port, 0, socktype)
            if not ress:
                raise OSError("getaddrinfo returns an empty list")
            for res in ress:
                af, socktype, proto, _, sa = res
                err = sock = None
                try:
                    sock = socket.socket(af, socktype, proto)
                    if socktype == socket.SOCK_STREAM:
                        sock.connect(sa)
                    break
                except OSError as exc:
                    err = exc
                    if sock is not None:
                        sock.close()
            if err is not None:
                raise err
            self.socket = sock
            self.socktype = socktype

    def encodePriority(self, facility, priority):
        
        if isinstance(facility, str):
            facility = self.facility_names[facility]
        if isinstance(priority, str):
            priority = self.priority_names[priority]
        return (facility << 3) | priority

    def close(self):
        
        with self.lock:
            sock = self.socket
            if sock:
                self.socket = None
                sock.close()
            logging.Handler.close(self)

    def mapPriority(self, levelName):
        
        return self.priority_map.get(levelName, "warning")

    ident = ''          
    append_nul = True   

    def emit(self, record):
        
        try:
            msg = self.format(record)
            if self.ident:
                msg = self.ident + msg
            if self.append_nul:
                msg += '\000'

            
            
            prio = '<%d>' % self.encodePriority(self.facility,
                                                self.mapPriority(record.levelname))
            prio = prio.encode('utf-8')
            
            msg = msg.encode('utf-8')
            msg = prio + msg

            if not self.socket:
                self.createSocket()

            if self.unixsocket:
                try:
                    self.socket.send(msg)
                except OSError:
                    self.socket.close()
                    self._connect_unixsocket(self.address)
                    self.socket.send(msg)
            elif self.socktype == socket.SOCK_DGRAM:
                self.socket.sendto(msg, self.address)
            else:
                self.socket.sendall(msg)
        except Exception:
            self.handleError(record)

class SMTPHandler(logging.Handler):
    
    def __init__(self, mailhost, fromaddr, toaddrs, subject,
                 credentials=None, secure=None, timeout=5.0):
        
        logging.Handler.__init__(self)
        if isinstance(mailhost, (list, tuple)):
            self.mailhost, self.mailport = mailhost
        else:
            self.mailhost, self.mailport = mailhost, None
        if isinstance(credentials, (list, tuple)):
            self.username, self.password = credentials
        else:
            self.username = None
        self.fromaddr = fromaddr
        if isinstance(toaddrs, str):
            toaddrs = [toaddrs]
        self.toaddrs = toaddrs
        self.subject = subject
        self.secure = secure
        self.timeout = timeout

    def getSubject(self, record):
        
        return self.subject

    def emit(self, record):
        
        try:
            import smtplib
            from email.message import EmailMessage
            import email.utils

            port = self.mailport
            if not port:
                port = smtplib.SMTP_PORT
            smtp = smtplib.SMTP(self.mailhost, port, timeout=self.timeout)
            msg = EmailMessage()
            msg['From'] = self.fromaddr
            msg['To'] = ','.join(self.toaddrs)
            msg['Subject'] = self.getSubject(record)
            msg['Date'] = email.utils.localtime()
            msg.set_content(self.format(record))
            if self.username:
                if self.secure is not None:
                    smtp.ehlo()
                    smtp.starttls(*self.secure)
                    smtp.ehlo()
                smtp.login(self.username, self.password)
            smtp.send_message(msg)
            smtp.quit()
        except Exception:
            self.handleError(record)

class NTEventLogHandler(logging.Handler):
    
    def __init__(self, appname, dllname=None, logtype="Application"):
        logging.Handler.__init__(self)
        try:
            import win32evtlogutil, win32evtlog
            self.appname = appname
            self._welu = win32evtlogutil
            if not dllname:
                dllname = os.path.split(self._welu.__file__)
                dllname = os.path.split(dllname[0])
                dllname = os.path.join(dllname[0], r'win32service.pyd')
            self.dllname = dllname
            self.logtype = logtype
            
            
            
            try:
                self._welu.AddSourceToRegistry(appname, dllname, logtype)
            except Exception as e:
                
                
                if getattr(e, 'winerror', None) != 5:  
                    raise
            self.deftype = win32evtlog.EVENTLOG_ERROR_TYPE
            self.typemap = {
                logging.DEBUG   : win32evtlog.EVENTLOG_INFORMATION_TYPE,
                logging.INFO    : win32evtlog.EVENTLOG_INFORMATION_TYPE,
                logging.WARNING : win32evtlog.EVENTLOG_WARNING_TYPE,
                logging.ERROR   : win32evtlog.EVENTLOG_ERROR_TYPE,
                logging.CRITICAL: win32evtlog.EVENTLOG_ERROR_TYPE,
         }
        except ImportError:
            print("The Python Win32 extensions for NT (service, event "\
                        "logging) appear not to be available.")
            self._welu = None

    def getMessageID(self, record):
        
        return 1

    def getEventCategory(self, record):
        
        return 0

    def getEventType(self, record):
        
        return self.typemap.get(record.levelno, self.deftype)

    def emit(self, record):
        
        if self._welu:
            try:
                id = self.getMessageID(record)
                cat = self.getEventCategory(record)
                type = self.getEventType(record)
                msg = self.format(record)
                self._welu.ReportEvent(self.appname, id, cat, type, [msg])
            except Exception:
                self.handleError(record)

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

class HTTPHandler(logging.Handler):
    
    def __init__(self, host, url, method="GET", secure=False, credentials=None,
                 context=None):
        
        logging.Handler.__init__(self)
        method = method.upper()
        if method not in ["GET", "POST"]:
            raise ValueError("method must be GET or POST")
        if not secure and context is not None:
            raise ValueError("context parameter only makes sense "
                             "with secure=True")
        self.host = host
        self.url = url
        self.method = method
        self.secure = secure
        self.credentials = credentials
        self.context = context

    def mapLogRecord(self, record):
        
        return record.__dict__

    def getConnection(self, host, secure):
        
        import http.client
        if secure:
            connection = http.client.HTTPSConnection(host, context=self.context)
        else:
            connection = http.client.HTTPConnection(host)
        return connection

    def emit(self, record):
        
        try:
            import urllib.parse
            host = self.host
            h = self.getConnection(host, self.secure)
            url = self.url
            data = urllib.parse.urlencode(self.mapLogRecord(record))
            if self.method == "GET":
                if (url.find('?') >= 0):
                    sep = '&'
                else:
                    sep = '?'
                url = url + "%c%s" % (sep, data)
            h.putrequest(self.method, url)
            
            
            i = host.find(":")
            if i >= 0:
                host = host[:i]
            
            
            
            if self.method == "POST":
                h.putheader("Content-type",
                            "application/x-www-form-urlencoded")
                h.putheader("Content-length", str(len(data)))
            if self.credentials:
                import base64
                s = ('%s:%s' % self.credentials).encode('utf-8')
                s = 'Basic ' + base64.b64encode(s).strip().decode('ascii')
                h.putheader('Authorization', s)
            h.endheaders()
            if self.method == "POST":
                h.send(data.encode('utf-8'))
            h.getresponse()    
        except Exception:
            self.handleError(record)

class BufferingHandler(logging.Handler):
    
    def __init__(self, capacity):
        
        logging.Handler.__init__(self)
        self.capacity = capacity
        self.buffer = []

    def shouldFlush(self, record):
        
        return (len(self.buffer) >= self.capacity)

    def emit(self, record):
        
        self.buffer.append(record)
        if self.shouldFlush(record):
            self.flush()

    def flush(self):
        
        with self.lock:
            self.buffer.clear()

    def close(self):
        
        try:
            self.flush()
        finally:
            logging.Handler.close(self)

class MemoryHandler(BufferingHandler):
    
    def __init__(self, capacity, flushLevel=logging.ERROR, target=None,
                 flushOnClose=True):
        
        BufferingHandler.__init__(self, capacity)
        self.flushLevel = flushLevel
        self.target = target
        
        self.flushOnClose = flushOnClose

    def shouldFlush(self, record):
        
        return (len(self.buffer) >= self.capacity) or \
                (record.levelno >= self.flushLevel)

    def setTarget(self, target):
        
        with self.lock:
            self.target = target

    def flush(self):
        
        with self.lock:
            if self.target:
                for record in self.buffer:
                    self.target.handle(record)
                self.buffer.clear()

    def close(self):
        
        try:
            if self.flushOnClose:
                self.flush()
        finally:
            with self.lock:
                self.target = None
                BufferingHandler.close(self)


class QueueHandler(logging.Handler):
    

    def __init__(self, queue):
        
        logging.Handler.__init__(self)
        self.queue = queue
        self.listener = None  

    def enqueue(self, record):
        
        self.queue.put_nowait(record)

    def prepare(self, record):
        
        
        
        
        
        
        
        msg = self.format(record)
        
        record = copy.copy(record)
        record.message = msg
        record.msg = msg
        record.args = None
        record.exc_info = None
        record.exc_text = None
        record.stack_info = None
        return record

    def emit(self, record):
        
        try:
            self.enqueue(self.prepare(record))
        except Exception:
            self.handleError(record)


class QueueListener(object):
    
    _sentinel = None

    def __init__(self, queue, *handlers, respect_handler_level=False):
        
        self.queue = queue
        self.handlers = handlers
        self._thread = None
        self.respect_handler_level = respect_handler_level

    def dequeue(self, block):
        
        return self.queue.get(block)

    def start(self):
        
        self._thread = t = threading.Thread(target=self._monitor)
        t.daemon = True
        t.start()

    def prepare(self, record):
        
        return record

    def handle(self, record):
        
        record = self.prepare(record)
        for handler in self.handlers:
            if not self.respect_handler_level:
                process = True
            else:
                process = record.levelno >= handler.level
            if process:
                handler.handle(record)

    def _monitor(self):
        
        q = self.queue
        has_task_done = hasattr(q, 'task_done')
        while True:
            try:
                record = self.dequeue(True)
                if record is self._sentinel:
                    if has_task_done:
                        q.task_done()
                    break
                self.handle(record)
                if has_task_done:
                    q.task_done()
            except queue.Empty:
                break

    def enqueue_sentinel(self):
        
        self.queue.put_nowait(self._sentinel)

    def stop(self):
        
        self.enqueue_sentinel()
        self._thread.join()
        self._thread = None