Mercer
Mercer

Reputation: 9986

Python log rotation and compression

My script allows me to import photos into a specific folder and update my database MongoDB via a JSON file import.

I set up a logging system with log rotation and compression.

I have different problems:

enter image description here

python script:

def moveFTPFiles(serverName,userName,passWord,remotePath,localPath,deleteRemoteFiles=False,onlyDiff=False):
    """Connect to an FTP server and bring down files to a local directory"""
    import os
    import sys
    import glob
    from sets import Set
    import ftplib 

    logger.info(' Deleting Files ')

    os.chdir(localDirectoryPath)
    files=glob.glob('*.*')
    for filename in files:
        os.unlink(filename)

    logger.info(' Retreiving Files ')

    try:
        ftp = ftplib.FTP(serverName)
        ftp.login(userName,passWord)
        ftp.cwd(remotePath)
        logger.info(' Connecting ')
        if onlyDiff:
            lFileSet = Set(os.listdir(localPath))
            rFileSet = Set(ftp.nlst())
            transferList = list(rFileSet - lFileSet)
            logger.info(' Missing ' + str(len(transferList)))
        else:
            transferList = ftp.nlst()
        delMsg = "" 
        filesMoved = 0
        for fl in transferList:
            # create a full local filepath
            localFile = localPath + fl
            # print "Create a full local filepath: " + localFile
            grabFile = True
            if grabFile:                
                #open a the local file
                fileObj = open(localFile, 'wb')
                # Download the file a chunk at a time using RETR
                ftp.retrbinary('RETR ' + fl, fileObj.write)
                # Close the file
                # print "Close the file "
                fileObj.close()
                filesMoved += 1
                #print "Uploaded: " + str(filesMoved)
                #sys.stdout.write(str(filesMoved)+' ')
                #sys.stdout.flush()

            # Delete the remote file if requested
            if deleteRemoteFiles:
                ftp.delete(fl)
                delMsg = " and Deleted"         

        logger.info('Files Moved' + delMsg + ': ' + str(filesMoved) + ' on ' + timeStamp())
    except ftplib.all_errors as e:
        logger.error('We have a problem on moveFTPFiles' + '%s' % e)
    ftp.close() # Close FTP connection
    ftp = None

def timeStamp():
    """returns a formatted current time/date"""
    import time
    return str(time.strftime("%a %d %b %Y %I:%M:%S %p"))

def importData(serverName,userName,passWord,directory,filematch,source,destination):
    import socket
    import ftplib
    import os
    import subprocess
    import json

    try:
        ftp = ftplib.FTP(serverName)
        ftp.login(userName,passWord)
        ftp.cwd(directory)
        logger.info(' Connecting ')
        # Loop through matching files and download each one individually
        for filename in ftp.nlst(filematch):
            fhandle = open(filename, 'wb')
            logger.info(' Getting ' + filename)
            ftp.retrbinary('RETR ' + filename, fhandle.write)
            fhandle.close()
        #convert xml to json
        logger.info(' Convert ' + filename + ' to .json ')
        subprocess.call('xml2json -t xml2json -o stockvo.json stockvo.xml --strip_text', shell=True)
        #remove xml file
        logger.info(' Delete ' + filename)
        os.unlink(source+'stockvo.xml')
        #modify json file
        logger.info(' Modify .json file')
        data = json.loads(open("stockvo.json").read())
        with open("stockvo.json", "w") as outfile:
                json.dump(data["Stock"]["Vehicule"], outfile)

        #import json file to MongoDB
        logger.info(' Import json file to MongoDB')
        subprocess.call('mongoimport --db AutoPrivilege -c cars stockvo.json --jsonArray --upsert --drop',shell=True)

        #remove old json file
        logger.info('Delete old .json file')
        ## if file exists, delete it ##
        myfile=destination+"stockvo.json"
        if os.path.isfile(myfile):
            os.remove(myfile)
        #os.unlink(destination+'stockvo.json')

        #move json file
        logger.info('Move .json')
        os.system('mv %s %s' % (source+'stockvo.json', destination+'stockvo.json'))

    except ftplib.all_errors as e:
        logger.error('We have a problem on importData' + '%s' % e)
    ftp.close() # Close FTP connection
    ftp = None

import time
import re
import os
import stat
import logging
import logging.handlers as handlers

class SizedTimedRotatingFileHandler(handlers.TimedRotatingFileHandler):
    """
    Handler for logging to a set of files, which switches from one file
    to the next when the current file reaches a certain size, or at certain
    timed intervals
    """
    def __init__(self, filename, mode='a', maxBytes=0, backupCount=0, encoding=None,
                 delay=0, when='h', interval=1, utc=False):
        # 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.
        if maxBytes > 0:
            mode = 'a'
        handlers.TimedRotatingFileHandler.__init__(
            self, filename, when, interval, backupCount, encoding, delay, utc)
        self.maxBytes = maxBytes

    def shouldRollover(self, record):
        """
        Determine if rollover should occur.

        Basically, see if the supplied record would cause the file to exceed
        the size limit we have.
        """
        if self.stream is None:                 # delay was set...
            self.stream = self._open()
        if self.maxBytes > 0:                   # are we rolling over?
            msg = "%s\n" % self.format(record)
            self.stream.seek(0, 2)  #due to non-posix-compliant Windows feature
            if self.stream.tell() + len(msg) >= self.maxBytes:
                return 1
        t = int(time.time())
        if t >= self.rolloverAt:
            return 1
        return 0

if __name__ == '__main__':      

    #log to a file
    log_filename='/opt/log/importData.log'
    logger=logging.getLogger('importData')
    logger.setLevel(logging.DEBUG)
    handler=SizedTimedRotatingFileHandler(
        log_filename, maxBytes=100, backupCount=5,
        when='s',interval=10,
        # encoding='bz2',  # uncomment for bz2 compression
    )
    formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
    handler.setFormatter(formatter)
    logger.addHandler(handler)

    #--- constant connection values
    ftpServerName = "xxxxx.xxxxxx"
    ftpU = "xxxxxxxx"
    ftpP = "xxxxxx"
    remoteDirectoryPath = "/xxxxxx/xxxxxx/xxxxxx/xxxxxxx/"
    localDirectoryPath = "/xxxxx/xxxxxxxxx/xxxxxxxx/xxxxxxx/"

    directory = '/xxxxxxx/'
    filematch = '*.xml'
    source='/xxxxxx/xxxxxxxx/'
    destination='/xxxxxxxx/xxxxxx/'

    deleteAfterCopy = False     #set to true if you want to clean out the remote directory
    onlyNewFiles = True         #set to true to grab & overwrite all files locally
    importData(ftpServerName,ftpU,ftpP,directory,filematch,source,destination)
    moveFTPFiles(ftpServerName,ftpU,ftpP,remoteDirectoryPath,localDirectoryPath,deleteAfterCopy,onlyNewFiles)

importData.log:

2015-04-23 11:33:57,408 INFO Files Moved: 1145 on Thu 23 Apr 2015 11:33:57 AM

importData.log.2015-04-23_11-33-40:

2015-04-23 11:33:40,896 INFO Deleting Files 2015-04-23 11:33:40,956 INFO Retreiving Files

importData.log2015-04-23_11-33-41:

2015-04-23 11:33:41,386 INFO Connecting 2015-04-23 11:33:41,825 INFO Missing 1145

Can anyone suggest a way in python to solve my problems .?

Upvotes: 0

Views: 1069

Answers (1)

viraptor
viraptor

Reputation: 34205

SizedTimedRotatingFileHandler(log_filename, maxBytes=100, ...

Does exactly what it's configured to do - a maximum of 100 bytes will be logged into one file. Increase the max size to a few (hundred?) megabytes and you'll get infrequent rotation.

Regarding only partial logging to the file, you define the handler only for the 'importData' module. Other modules will write to the default handler (likely the console).

Regarding the subprocess.call() itself, it's not actually logging anything. Unless you capture the output using the stdout argument, the output will be printed to the normal stdout. You need to setup a pipe and read from it into the logger instead.

Upvotes: 1

Related Questions