Search code examples
pythonfile-descriptor

Get fileno() for a file opened by current pid using filename?


I have a third-party module that opens a file using logging.FileHandler, I want to know how can I find out its fileno from the filename.

third_party.py:

def setup_loging(logfile):
    logFormatter = logging.Formatter(
        "%(asctime)s [%(process)d] [%(name)-12.12s] "
        "[%(levelname)-5.5s]  %(message)s")
    rootLogger = logging.getLogger()
    rootLogger.setLevel(logging.NOTSET)
    if logfile:
        fileHandler = logging.FileHandler(logfile, mode="wt", encoding="utf-8")
        fileHandler.setFormatter(logFormatter)
        fileHandler.setLevel(logging.NOTSET)
        rootLogger.addHandler(fileHandler)

    consoleHandler = logging.StreamHandler(sys.stdout)
    if verbose:
        consoleHandler.setLevel(logging.DEBUG)
    else:
        consoleHandler.setLevel(logging.INFO)
    consolelogFormatter = logging.Formatter(
        "[%(name)-12.12s] [%(levelname)-5.5s]  %(message)s")
    consoleHandler.setFormatter(consolelogFormatter)
    rootLogger.addHandler(consoleHandler)

my_script.py:

from third_party import setup_loging
setup_loging(logfile='/tmp/foo.log')

# How do I get the fileno for file /tmp/foo.log ?
# only way i know is doing: lsof /tmp/foo.log
print get_fileno_from_filename('/tmp/foo.log')

Solution

  • Try snatching the stream property from your FileHandler, and then its stream to get to the file object:

    def setup_loging(logfile):
        # your code...
        if logfile:
            return fileHandler
    
    logging_handler = setup_loging(logfile='/tmp/foo.log')
    if logging_handler:
        print("fileno: {}".format(logging_handler.stream.stream.fileno()))
    

    A bit hackish, but gets the job done ;)

    P.S. If you can't modify the script in any way, you can always get all root logging handlers (logging.getLogger().handlers) and sift through them until you find a FileHandler, but there might be more than one so be sure to check the name property of the extracted file object before getting its fileno(). Something like:

    import os
    
    your_log_file = "/tmp/foo.log"
    log_file_path = os.path.realpath(your_log_file) # make sure we have a full path
    
    setup_loging(log_file_path) # call the third party
    
    for handler in logging.getLogger().handlers:
        if isinstance(handler, logging.FileHandler):
            if handler.stream.stream.name == log_file_path:
                print("{}, fileno: {}".format(log_file_path, handler.stream.stream.fileno()))
                break