使用 Plotly 仪表板时 Flask 日志条目重复
Flask log entries duplicated when using Plotly dashboards
我在将 Plotly 仪表板引入我的 Flask 应用程序时看到了意外行为。每个 Plotly 仪表板都会导致 Flask 日志条目被复制。
例如,如果我将两个 Plotly 仪表板附加到我的 Flask 应用程序,日志条目(例如 current_app.logger.info('hi')
)将在我的日志中出现三次。如果我删除 Plotly 仪表板,日志条目会出现一次,这是预期的行为。
我尝试通过 app.logger.handlers.clear()
删除我的日志配置代码中的现有处理程序,并将 dictConfig
的 disable_existing_loggers
设置为 True
,这两种操作都会导致没有被记录。我也尝试过使用单例方法来配置记录器(再次使用 dictConfig
),但我仍然看到日志条目重复多次。
如何防止 Plotly 仪表板导致重复的日志条目?
更新:
这是 Dash 应用程序初始化方式的简化版本:
def register_dashapp(app):
from dashboards.dash_files.my_dash import (
define_layout,
define_callbacks,
)
my_dashapp = dash.Dash(__name__,
server=app,
url_base_pathname='/my_dash/',
assets_folder="../dashboards/foo/bar/assets",
)
with app.app_context():
my_dashapp.title = "Test"
define_layout(my_dashapp)
define_callbacks(my_dashapp)
def create_app():
app = Flask(__name__, instance_relative_config=False)
app.config.from_object('config.Config')
with app.app_context():
register_extensions(app)
app.register_blueprint(main)
register_dash_app(app)
return app
您似乎多次使用日志记录实例声明您的应用,导致重复。
第一个应用程序实例是您传递给此函数的应用程序对象:
def register_dashapp(app):
# foo
第二种情况是您从第一个应用创建应用:
dash.Dash(__name__,
server=app,
url_base_pathname='/my_dash/',
assets_folder="../dashboards/foo/bar/assets"
)
第三个是创建 Flask 实例时:
app = Flask(__name__, instance_relative_config=False)
这里共有3个应用。
要解决这个问题,我建议在您的 dash 应用程序中使用一个 flask 服务器,然后像添加普通 flask 应用程序一样添加您的 flask 扩展。
我可以通过删除 the logging handler added by the Dash library.
来解决这个问题
my_dash = dash.Dash(__name__,
server=app,
url_base_pathname='/my_dash/',
assets_folder="../dashboards/foo/bar/assets"
)
if (my_dash.logger.hasHandlers()):
my_dash.logger.handlers.clear()
这样做似乎没有任何缺点,但我可能忽略了一些东西,我很想看看是否有其他人有更好的方法。我将推迟几天再接受我自己的回答。
在相关说明中,我认为这可以通过 Dash 构造函数进行配置。我也很想知道是否有人对此有想法。我可能会和项目一起开票,看看他们对这种可能性的看法。
我遇到了日志重复问题并使用相同的 HasHandlers 逻辑解决了它,但是我调用日志的方式略有不同。这需要 python 箭头库,我发现它在大多数用例中优于 datetime。
我在主 app.py 或 _init_.py 文件中定义了 site_logger。
# define logger
def site_logger(log_name):
now = arrow.now('US/Eastern').format('YYYY_MM_DD')
handler = logging.FileHandler('logs/' + log_name + '_' + now + '.log')
formatter = logging.Formatter('%(asctime)s %(levelname)s %(name)s: %(message)s')
handler.setFormatter(formatter)
logger = logging.getLogger(log_name)
logger.setLevel("DEBUG")
if logger.hasHandlers():
logger.handlers.clear()
logger.addHandler(handler)
logger.propagate = False
return logger
然后我在任何 views.py 文件或函数中按以下方式调用记录器,您也可以将记录器传递给您在 views.py 中调用的函数,记录函数的结果在调用它的正确页面文件中。
from app import site_logger
logger = site_logger('page_name')
然后我可以用通常的方式记录事件。下面是两个示例,在记录器中使用 f 字符串是将变量轻松传递到日志数据的好方法。
logger.info(f'{user} logged in successfully')
logger.warning(f'{user} password failure!')
这将提供统一命名的日志处理程序和日志文件,您可以更轻松地追溯到所进行的页面或函数调用。当 arrow.now('timezome') 值轮换到第二天时,日期格式的文件应该自动轮换。
if not DashboardDAO.validate_create_title(dashboard_title, unique()):
exceptions.append(DashboardTitleExistsValidationError())
我在将 Plotly 仪表板引入我的 Flask 应用程序时看到了意外行为。每个 Plotly 仪表板都会导致 Flask 日志条目被复制。
例如,如果我将两个 Plotly 仪表板附加到我的 Flask 应用程序,日志条目(例如 current_app.logger.info('hi')
)将在我的日志中出现三次。如果我删除 Plotly 仪表板,日志条目会出现一次,这是预期的行为。
我尝试通过 app.logger.handlers.clear()
删除我的日志配置代码中的现有处理程序,并将 dictConfig
的 disable_existing_loggers
设置为 True
,这两种操作都会导致没有被记录。我也尝试过使用单例方法来配置记录器(再次使用 dictConfig
),但我仍然看到日志条目重复多次。
如何防止 Plotly 仪表板导致重复的日志条目?
更新:
这是 Dash 应用程序初始化方式的简化版本:
def register_dashapp(app):
from dashboards.dash_files.my_dash import (
define_layout,
define_callbacks,
)
my_dashapp = dash.Dash(__name__,
server=app,
url_base_pathname='/my_dash/',
assets_folder="../dashboards/foo/bar/assets",
)
with app.app_context():
my_dashapp.title = "Test"
define_layout(my_dashapp)
define_callbacks(my_dashapp)
def create_app():
app = Flask(__name__, instance_relative_config=False)
app.config.from_object('config.Config')
with app.app_context():
register_extensions(app)
app.register_blueprint(main)
register_dash_app(app)
return app
您似乎多次使用日志记录实例声明您的应用,导致重复。
第一个应用程序实例是您传递给此函数的应用程序对象:
def register_dashapp(app):
# foo
第二种情况是您从第一个应用创建应用:
dash.Dash(__name__,
server=app,
url_base_pathname='/my_dash/',
assets_folder="../dashboards/foo/bar/assets"
)
第三个是创建 Flask 实例时:
app = Flask(__name__, instance_relative_config=False)
这里共有3个应用。
要解决这个问题,我建议在您的 dash 应用程序中使用一个 flask 服务器,然后像添加普通 flask 应用程序一样添加您的 flask 扩展。
我可以通过删除 the logging handler added by the Dash library.
来解决这个问题my_dash = dash.Dash(__name__,
server=app,
url_base_pathname='/my_dash/',
assets_folder="../dashboards/foo/bar/assets"
)
if (my_dash.logger.hasHandlers()):
my_dash.logger.handlers.clear()
这样做似乎没有任何缺点,但我可能忽略了一些东西,我很想看看是否有其他人有更好的方法。我将推迟几天再接受我自己的回答。
在相关说明中,我认为这可以通过 Dash 构造函数进行配置。我也很想知道是否有人对此有想法。我可能会和项目一起开票,看看他们对这种可能性的看法。
我遇到了日志重复问题并使用相同的 HasHandlers 逻辑解决了它,但是我调用日志的方式略有不同。这需要 python 箭头库,我发现它在大多数用例中优于 datetime。
我在主 app.py 或 _init_.py 文件中定义了 site_logger。
# define logger
def site_logger(log_name):
now = arrow.now('US/Eastern').format('YYYY_MM_DD')
handler = logging.FileHandler('logs/' + log_name + '_' + now + '.log')
formatter = logging.Formatter('%(asctime)s %(levelname)s %(name)s: %(message)s')
handler.setFormatter(formatter)
logger = logging.getLogger(log_name)
logger.setLevel("DEBUG")
if logger.hasHandlers():
logger.handlers.clear()
logger.addHandler(handler)
logger.propagate = False
return logger
然后我在任何 views.py 文件或函数中按以下方式调用记录器,您也可以将记录器传递给您在 views.py 中调用的函数,记录函数的结果在调用它的正确页面文件中。
from app import site_logger
logger = site_logger('page_name')
然后我可以用通常的方式记录事件。下面是两个示例,在记录器中使用 f 字符串是将变量轻松传递到日志数据的好方法。
logger.info(f'{user} logged in successfully')
logger.warning(f'{user} password failure!')
这将提供统一命名的日志处理程序和日志文件,您可以更轻松地追溯到所进行的页面或函数调用。当 arrow.now('timezome') 值轮换到第二天时,日期格式的文件应该自动轮换。
if not DashboardDAO.validate_create_title(dashboard_title, unique()):
exceptions.append(DashboardTitleExistsValidationError())