I have been given a requirement to log a python application that runs continuously, to a logfile on an SMB share.
The issue is if there is ever a reason for that SMB share to go offline (patching/network issue etc) whilst the python app is still running, a stream error is raised (due to the file being missing), the filehandler does not recover once the file becomes available once again, therefore no further logs are written.
Error trace
--- Logging error ---
Traceback (most recent call last):
File "C:\Program Files (x86)\Python38-32\lib\logging\handlers.py", line 69, in emit
if self.shouldRollover(record):
File "C:\Program Files (x86)\Python38-32\lib\logging\handlers.py", line 186, in shouldRollover
self.stream.seek(0, 2) #due to non-posix-compliant Windows feature
PermissionError: [Errno 13] Permission denied
Question
Is it possible to capture the failed state, wait some time, then request the handler to re-open the logfile?
I have simulated the state by pointing the filehandler to a USB drive (D:/) which is removed then re-inserted:
import logging,time,datetime
from logging.handlers import RotatingFileHandler
def configure_logging(processName):
MAX_BYTES = 500000
BACKUP_COUNT = 5
logger = logging.getLogger("testLogger")
logger.setLevel(logging.INFO)
log_format = logging.Formatter('%(asctime)s %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
stream_handler = logging.StreamHandler()
stream_handler.setFormatter(log_format)
stream_handler.setLevel(logging.INFO)
logger.addHandler(stream_handler)
info_handler = RotatingFileHandler('D:/info.log', maxBytes=MAX_BYTES, backupCount=BACKUP_COUNT)
info_handler.setFormatter(log_format)
info_handler.setLevel(logging.INFO)
logger.addHandler(info_handler)
error_handler = RotatingFileHandler('C:/temp/error.log', maxBytes=MAX_BYTES, backupCount=BACKUP_COUNT)
error_handler.setFormatter(log_format)
error_handler.setLevel(logging.ERROR)
logger.addHandler(error_handler)
return(logger)
def looper():
while 1:
logger = logging.getLogger("testLogger")
logger.info('Remote message')
logger.error('Local Message')
print('i looped')
time.sleep(1)
if __name__ == "__main__":
processName = 'TestLogger'
logger = configure_logging(processName)
looper()
Logs are still written to the local C:/ drive from logger.error, as this is performed by the second filehandler, but the log file at D:/info.log is no longer written to once the file becomes available once again.