1

I am trying to use an FTP server stub during tests. I don't want the console output, but I would like to capture the logging to a file.

I want the FTP server to run in a different process, so I use multiprocessing.

My code as follows sets all logging to level WARNING:

from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import FTPServer
import pyftpdlib.log as pyftpdliblog
import os
import logging
import multiprocessing as mp

authorizer = DummyAuthorizer()
authorizer.add_user('user', '12345', '.', perm='elradfmwM')
handler = FTPHandler
handler.authorizer = authorizer

pyftpdliblog.LEVEL = logging.WARNING
logging.basicConfig(filename='pyftpd.log', level=logging.INFO)
server = FTPServer(('', 2121), handler)

def main():
    p = mp.Process(target=server.serve_forever)
    p.start()


if __name__ == '__main__':
    main()

How do I set only the console logging to level WARNING, or even better, completely shutdown without giving up the file logging?

oz123
  • 27,559
  • 27
  • 125
  • 187

2 Answers2

1

So, after digging inside the code, I found out the following hint:

# This is a method of FTPServer and it is called before 
# server.serve_forever
def _log_start(self):
    if not logging.getLogger('pyftpdlib').handlers:
        # If we get to this point it means the user hasn't
        # configured logger. We want to log by default so
        # we configure logging ourselves so that it will
        # print to stderr.
        from pyftpdlib.ioloop import _config_logging
        _config_logging()

So, all I had to do is to define my own appropriate handlers:

logger = logging.getLogger('pyftpdlib')
logger.setLevel(logging.INFO)
hdlr = logging.FileHandler('pyftpd.log' )
logger.addHandler(hdlr)

Now, there is file logging, but console logging will not start.

oz123
  • 27,559
  • 27
  • 125
  • 187
0

Something like this:

import logging

date_format = "%Y/%m/%d %H:%M:%S"
log_file_path = "my_file.txt"

root_logger = logging.getLogger()
root_logger.setLevel(logging.DEBUG)

# own_module_logger = logging.getLogger(__name__)
pyftpdlib_logger = logging.getLogger("pyftpdlib")

# Setup logging to file (Only pyftpdlib)
filehandler = logging.FileHandler(filename = log_file_path)
filehandler.setLevel(logging.DEBUG)
fileformatter = logging.Formatter(fmt = "%(asctime)s - %(levelname)-8s - %(name)s.%(funcName)s - %(message)s",
                                  datefmt = date_format)
filehandler.setFormatter(fileformatter)
pyftpdlib_logger.addHandler(filehandler)
pyftpdlib_logger.propagate = False

# Setup logging to console (All other)
console = logging.StreamHandler()
console.setLevel(logging.INFO)
consoleformatter = logging.Formatter(fmt = "%(asctime)s - %(levelname)-8s - %(name)s.%(funcName)s - %(message)s",
                                     datefmt = date_format)
console.setFormatter(consoleformatter)
root_logger.addHandler(console)

# Do your loggings
a = logging.getLogger()
a.info('root I')
a.debug('root D')

b = logging.getLogger("pyftpdlib")
b.info('P I')
b.debug('P D')

logging.shutdown()

So loggings of pyftpdlib go to file. Everything from your module to console. One of the key thing here is the propagate!

RvdK
  • 19,580
  • 4
  • 64
  • 107
  • I don't want to change the logging from my module, because it's inside `unittest.TestCase`. – oz123 Mar 09 '15 at 15:14
  • I don't understand what you mean. If you call the part of setting up the filehandler from my code, before you call anything from the pyftpdlib module, it should be working. – RvdK Mar 09 '15 at 16:27
  • See my answer below. Principally your solution works, but with my overhead. When I posted my solution, I didn't see yours. – oz123 Mar 09 '15 at 18:57