'Python flask - Log to 2 different destinations with different log error levels
I am having a python flask app. We have used local logger with file handler and stream handler for logging messages. Handler levels INFO
fh.setLevel(logging.INFO)
ch.setLevel(logging.INFO)
Then we have added one more logger for elastic search. Only error logs should be sent to this elastic search logger.
apm = ElasticAPM(app, logging=True)
handler = LoggingHandler(client=apm.client)
handler.setLevel(logging.ERROR)
app.logger.addHandler(handler)
But after inclusion of elastic search handler, INFO messages from local logger are also sent to elastic search. This fills the elastic search with unimportant logs.
How to send only error logs to elastic search while sending INFO logs to local file and local stream handlers?
Attached the python flask code with the above mentioned loggers.
import datetime
import logging
from elasticapm.contrib.flask import ElasticAPM
from elasticapm.handlers.logging import LoggingHandler
from flask import Flask
from flask import request, Blueprint, current_app
app = Flask("app_name")
LOGGING_LOCATION = "D:/logs/es"
secret_token = "abc"
elastic_search_url = "https://aaaaaaa.apm.westus.azure.elastic-cloud.com"
app.config['ELASTIC_APM'] = {
'SERVICE_NAME': 'test_error_logs',
'SECRET_TOKEN': secret_token,
'SERVER_URL': elastic_search_url
}
# Creating handler for elastic search logs and adding to flask app's logger
apm = ElasticAPM(app, logging=True)
handler = LoggingHandler(client=apm.client)
handler.setLevel(logging.ERROR)
app.logger.addHandler(handler)
bp1 = Blueprint('app', __name__)
def create_logger(_app_name):
_logging_location = LOGGING_LOCATION
logger = logging.getLogger(_app_name)
print("Logger: {}".format(logger))
# If the logger has handlers, it means that logger is already created
has_local_logger = False
print("logger.handlers: {}".format(logger.handlers))
if len(logger.handlers) > 0:
for lh in logger.handlers:
handler_type = str(type(lh))
print(handler_type)
if "StreamHandler" in handler_type or "FileHandler" in handler_type:
has_local_logger = True
if has_local_logger:
print("Returning...")
return logger
_logfile = _logging_location + _app_name + '_' + "test_es.log"
logger = logging.getLogger(_app_name)
logger.setLevel(logging.ERROR)
fh = logging.FileHandler(_logfile)
fh.setLevel(logging.INFO)
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
formatter = logging.Formatter(
"%(asctime)s - [%(filename)s - %(funcName)10s():%(lineno)s ] - %(levelname)s - %(message)s",
datefmt='%Y-%m-%d %H:%M:%S')
ch.setFormatter(formatter)
fh.setFormatter(formatter)
logger.addHandler(ch)
logger.addHandler(fh)
# logger.propagate = False
print('New logger')
return logger
local_logger = create_logger("local_log")
@bp1.route('/test', methods=['GET'])
def url_test_api():
print("Handlers: {} ".format(local_logger.handlers))
print("App Handlers: {} ".format(current_app.logger.handlers))
curr = datetime.datetime.utcnow()
val = request.args.get('val')
if val == "a":
# This logger to send to local file handler and local stream handler
local_logger.info("Test log 1: @ {} ".format(curr))
return "Correct"
# This logger to send to elastic search
current_app.logger.error("Error value {} @ {}".format(val, curr), exc_info=True)
return "Incorrect"
app.register_blueprint(bp1)
app.run(port=3002)
Code for making API calls to above server
import requests
res = requests.get("http://localhost:3002/test?val=a")
print(res.text)
Python 3.7 Flask=1.1.1 elastic-apm=5.10.0
Solution 1:[1]
import logging
from elasticapm.contrib.flask import ElasticAPM
apm = ElasticAPM(app, logging=logging.ERROR)
you will be able to control via logging=logging.ERROR
Source Documentation
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Garvit Jain |