【问题标题】:Flask log entries duplicated when using Plotly dashboards使用 Plotly 仪表板时重复的烧瓶日志条目
【发布时间】:2020-01-16 19:54:24
【问题描述】:

在我的 Flask 应用程序中引入 Plotly 仪表板时,我看到了意外行为。每个 Plotly 仪表板都会导致 Flask 日志条目重复。

例如,如果我将两个 Plotly 仪表板附加到我的 Flask 应用程序,日志条目(例如 current_app.logger.info('hi'))将在我的日志中出现 3 次。如果我删除 Plotly 仪表板,日志条目会出现一次,这是预期的行为。

我尝试通过app.logger.handlers.clear() 删除我的日志记录配置代码中的现有处理程序,并将dictConfigdisable_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

【问题讨论】:

  • app.run_server 的代码是什么样的?
  • 另外,您的记录器上的配置代码是什么?
  • 我正在使用this 方法进行日志配置,但我仍然看到这个问题根本没有配置日志记录。我没有使用run_server,但我会在我的问题中添加一个基本版本的 Dash 初始化。

标签: python flask plotly-dash


【解决方案1】:

我遇到了一个日志重复问题,并使用相同的 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')

然后我可以用通常的方式记录事件。下面是两个示例,在 logger 中使用 f 字符串是一种轻松将 vars 传递到日志数据的好方法。

logger.info(f'{user} logged in successfully')
logger.warning(f'{user} password failure!')

这将提供统一命名的日志处理程序和日志文件,您可以更轻松地追溯到页面或进行的函数调用。当 arrow.now('timezome') 值旋转到下一天时,日期格式的文件应该自动旋转。

【讨论】:

    【解决方案2】:

    我可以通过删除 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 构造函数进行配置。我也很想知道是否有人对此有想法。我可能会为该项目开一张票,看看他们对这种可能性的看法。

    【讨论】:

      【解决方案3】:

      您似乎多次使用日志记录实例声明您的应用,从而导致重复。

      第一个应用实例是您传递给此函数的应用对象:

      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 应用中使用烧瓶服务器,然后像添加普通烧瓶应用一样添加烧瓶扩展。

      【讨论】:

      • 这些“三个实例”都是作为参数传递的同一个应用程序实例。 (是否有一些我不知道的隐含发生的事情?)您是否有“在您的仪表板应用程序中使用烧瓶服务器”的文档链接?我查看了 Plotly 文档和源代码,看起来您可以将 Flask 实例作为 server kwarg (就像我在这里所做的那样)或布尔值传递。
      • 类似这样的东西@pdoherty926 dash.plot.ly/integrating-dash
      • 这看起来就是我正在做的事情。我的下一步是创建一个新的 POC 应用程序以确定我是否看到相同的行为。如果我发现任何相关的东西,我会跟进。感谢您的回答和反馈!
      【解决方案4】:
      if not DashboardDAO.validate_create_title(dashboard_title, unique()):
            exceptions.append(DashboardTitleExistsValidationError())
         
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-03-25
        • 2013-12-25
        • 2016-01-28
        • 2013-08-31
        • 1970-01-01
        • 2019-01-27
        • 1970-01-01
        相关资源
        最近更新 更多