david
david

Reputation: 1077

Log only to a file and not to screen for logging.DEBUG

I have the following script that I want only the "DEBUG" log messages to be logged to the file, and nothing to the screen.

from flask import Flask, request, jsonify
from gevent.pywsgi import WSGIServer
import usaddress
app = Flask(__name__)

from logging.handlers import RotatingFileHandler
import logging
#logging.basicConfig(filename='error.log',level=logging.DEBUG)


# create a file to store weblogs
log = open('error.log', 'w'); log.seek(0); log.truncate();
log.write("Web Application Log\n"); log.close();

log_handler = RotatingFileHandler('error.log', maxBytes =1000000, backupCount=1)

formatter = logging.Formatter(
    "[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s"
    )
log_handler.setFormatter(formatter)
app.logger.setLevel(logging.DEBUG)
app.logger.addHandler(log_handler)

@app.route('/')
def hello():
  return "Hello World!"

@app.route("/parseAddress", methods=["POST"])
def parseAddress():
  address = request.form['address']
  return jsonify(usaddress.tag(address)), 200

if __name__ == '__main__':
#  app.run(host='0.0.0.0')
  http_server = WSGIServer(('', 5000), app, log=app.logger)
  http_server.serve_forever()

But right now even "INFO" messages are being logged to the file and to the screen. How can I have only the "DEBUG" messages logged to the file and nothing to the screen?

Upvotes: 2

Views: 2690

Answers (2)

Rozy Mahsun
Rozy Mahsun

Reputation: 363

def setup_logger(modes, logger_name, log_file, level=logging.INFO):
    l = logging.getLogger(logger_name)
    l.setLevel(level)
    print(modes)
    if(modes == 2):
        formatterTwo = logging.Formatter('%(asctime)s [%(levelname)s] %(message)s')
        fileHandler = logging.FileHandler(log_file, mode='a')
        fileHandler.setFormatter(formatterTwo)
        streamHandler = logging.StreamHandler()
        streamHandler.setFormatter(formatterTwo)
        l.addHandler(fileHandler)
        l.addHandler(streamHandler)
    else:
        formatterOne = logging.Formatter('%(message)s')
        fileHandler = logging.FileHandler(log_file, mode='a')
        fileHandler.setFormatter(formatterOne)
        streamHandler = logging.StreamHandler()
        streamHandler.setFormatter(formatterOne)
        l.setLevel(logging.DEBUG)
        l.addHandler(fileHandler)


setup_logger(2,'log1', "logFile_With_output_to_file_and_screen.log")
setup_logger(1,'log2', "logFile_Only_no_output_to_screen.log")
loggerOne = logging.getLogger('log1')
loggerTwo = logging.getLogger('log2')


loggerOne.info("This will output to Screen and File")
loggerTwo.debug("This will output to File ONLY")

**Notes : modes 1: Only File, 2 File and Screen

Upvotes: 0

RafalS
RafalS

Reputation: 6344

I did some interactive testing and it looks like app.logger is a logger named with python file

print(app.logger.name) # filename

and it has one handler

print(app.logger.handlers) # [<StreamHandler <stderr> (NOTSET)>]

A handler with level logging.NOTSET processes all messages (from all logging levels). So when you set app.logger.setLevel(logging.DEBUG) then all debug and higher logs will be passed to handlers and all of them will appear on stderr.

To log absolutely nothing on the screen you have to manually remove StreamHandler:

app.logger.handlers.pop(0)

and to log DEBUG and higher to the file set logging level also on the handler

log_handler.setLevel(logging.DEBUG)

Python logging is quite complicated. See this logging flow chart for better understanding what is going on :)

EDIT: to log only one specific level you need custom Filter object:

class LevelFilter:
    def __init__(self, level):
        self._level = level

    def filter(self, log_record):
        return log_record.levelno == self._level

log_handler.setLevel(logging.DEBUG)
log_handler.addFilter(LevelFilter(logging.DEBUG))

Upvotes: 3

Related Questions