fbence
fbence

Reputation: 2153

python logging only to file

I have a cronjob running a python script which I added a logging to, but since it's a daily job it is really annoying that I get daily emails of it's function, but I can't seem to find a setting, that will make it log only into the logfile.

#!/usr/bin/python
import logging, logging.handlers
LOGFILENAME = "log.log" 
logging.basicConfig()
log = logging.getLogger("nameoflog")
log.setLevel(logging.DEBUG) 
handler = logging.handlers.WatchedFileHandler(LOGFILENAME)
handler.setLevel(logging.DEBUG)
handler.setFormatter(logging.Formatter("%(asctime)-15s %(levelname)-8s %(name)s %(message)s")) 
log.addHandler(handler)
log.info("something happening")

How is it possible to make logging only write to a file and not to file and STDOUT?

Upvotes: 10

Views: 17140

Answers (3)

kappa101
kappa101

Reputation: 81

Logging in Python can be complex, and the default logging module has some limitations esp because stream handler is attached to the root logger. It doesn't provide a straightforward way to log messages exclusively to a file without logging them to the console. The FileLogger class presented here extends the built-in logging functionality to overcome this limitation, allowing you to log messages to both a file and the console, or exclusively to a file if desired.

class FileLogger(logging.Logger):
def __init__(self, name, filename, mode='a', level=logging.INFO, fformatter=None, log_to_console=False, sformatter=None):
    super().__init__(name, level)

    # Create a custom file handler
    self.file_handler = logging.FileHandler(filename=filename, mode=mode)

    # Set the formatter for the file handler
    if fformatter is not None:
        self.file_handler.setFormatter(fformatter)

    # Add the file handler to the logger
    self.addHandler(self.file_handler)

    if log_to_console:
        # Create a console handler
        self.console_handler = logging.StreamHandler()  # Prints to the console

        # Set the formatter for the console handler
        if not sformatter:
            sformatter = fformatter
        self.console_handler.setFormatter(sformatter)

        # Add the console handler to the logger
        self.addHandler(self.console_handler)


def fdebug(self, msg, pre_msg=''):
    if pre_msg:
        print(pre_msg)
    self.debug(msg)

def finfo(self, msg):
    self.info(msg)

def fwarn(self, msg):
    self.warning(msg)

def ferror(self, msg):
    self.error(msg)

def fcritical(self, msg):
    self.critical(msg)



# Test the logging
if __name__ == '__main__':
    s_log_level = logging.CRITICAL
    file_log_level = logging.WARN
    log_format = "[%(asctime)s.%(msecs)03d] %(message)s"
    log_fp = f'tmp.log'

    logging.basicConfig(format=log_format, level=s_log_level, datefmt="%H:%M:%S")

    # Create an instance of the custom logger
    formatter = logging.Formatter(log_format, "%H:%M:%S")
    fLogger = FileLogger(__name__, log_fp, mode='a', level=file_log_level, fformatter=formatter)
    
    fLogger.fdebug("This will be logged to file with DEBUG level")
    fLogger.finfo("This will be logged to file with INFO level")
    fLogger.fwarn("This will be logged to file with WARNING level")
    fLogger.ferror("This will be logged to file with ERROR level")
    fLogger.fcritical("This will be logged to file with CRITICAL level")

    logging.debug("This Debug will be logged to console")
    logging.info("This info will be logged to console")
    logging.warning("This warning also be logged to console")
    logging.critical("This critical also be logged to console")

In this solution, the FileLogger class extends the logging.Logger class and provides the ability to log messages exclusively to a file. The constructor of the FileLogger class accepts parameters for the log file name (filename) and mode (mode), allowing customization of the log file behavior.

To use this solution, simply create an instance of the FileLogger class and call the logging methods (info, debug, warning, etc.) on the logger instance. The log messages will be written only to the specified log file.

Remember to adjust the filename parameter to set the desired log file name, and you can change the mode parameter to control the behavior of the log file (e.g., 'a' for append, 'w' for overwrite).

Upvotes: 1

tdelaney
tdelaney

Reputation: 77347

The problem is that you call logging.basicConfig() which sets up logging to stdout. basicConfig is just a helper method used when you don't want to make more detailed logging calls. Since you setup the methods yourself, you should not call basicConfig.

Upvotes: 9

labheshr
labheshr

Reputation: 3056

Here's an example that works for me (it does not print the message to stdout, but only to example.log):

def logToFile():
    import logging
    logging.basicConfig(filename='example.log',level=logging.DEBUG)
    logging.info("trying to log to file")

logToFile()

Upvotes: 3

Related Questions