Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DispatcherMiddleware with different loggers per app in flask 1.0 #2866

Closed
jwldk opened this issue Jul 18, 2018 · 5 comments

Comments

@jwldk
Copy link

commented Jul 18, 2018

After upgrading to flask 1.0 logging from different apps using DispatcherMiddleware, each log emitted is written to all handlers in the different apps. I assume this caused by app.logger always having the name flask.app, maybe?

Here is a example:

from werkzeug.wsgi import DispatcherMiddleware
from flask import Flask
from logging.handlers import RotatingFileHandler


handler1 = RotatingFileHandler('app1.log')
app1 = Flask('app1')
app1.logger.addHandler(handler1)

handler2 = RotatingFileHandler('app2.log')
app2 = Flask('app2')
app2.logger.addHandler(handler2)


@app1.route("/")
def hello():
    app1.logger.error("from app1")
    return ''


@app2.route("/")
def hello2():
    app2.logger.error("from app2")
    return ''


app = DispatcherMiddleware(app1, {
    '/app2': app2
})

Run with

uwsgi --socket 0.0.0.0:8000 --protocol=http -w app --callable app

And then make a request to / and /app2/. Each error log will be written in both logfiles.

Environment

  • Python version: 3.6.5
  • Flask version: 1.0.2
  • Werkzeug version: 0.14.1

My actual app is using current_app.logger with blueprints with the same behaviour, but I assume it the same issue.

@davidism

This comment has been minimized.

Copy link
Member

commented Jul 19, 2018

It logs twice because you're adding two handlers to the same logger. Add one handler to the "flask.app" logger instead.

To get different names, override Flask.logger:

class LoggerFlask(Flask):
    @property
    def logger(self):
        return super().logger.getChild(self.name)

app1 = LoggerFlask("app1")
app2 = LoggerFlask("app2")

Or see the docs on logging for how to inject extra information into log records. In your case you would inject current_app.name.

@davidism davidism closed this Jul 19, 2018

@jwldk

This comment has been minimized.

Copy link
Author

commented Jul 20, 2018

Thanks for the workaround. I can see this is not really a bug per se - just a breaking change for my setup :), but while I can see from PR 2436 that LOGGER_NAME was removed to simply things. However wouldn't it make sense to at least be able to override the default flask.app in the constructor like app = Flask(..., logger_name="myapp") which can then be used by create_logger ? Because another unfortunate side effect I've encountered, is that if you add a Sentry error handler to the logging, the Sentry interface groups errors by logger.name - so if you have a bunch of flask applications, everything is now simply called flask.app.

@davidism davidism reopened this Aug 6, 2018

@davidism davidism added the logging label Aug 6, 2018

@davidism

This comment has been minimized.

Copy link
Member

commented Aug 6, 2018

Since we now use the flask. prefix for logger names, it's easy to autoconfigure a handler just for Flask, rather than interfering with other libraries by messing with the root logger, which was part of the whole original problem.

Multiple apps was an unforseen case, and I understand how this can be inconvenient.

I'm hesitant to make this configurable again. Perhaps a compromise would be f"flask.app:{app.name}" so that it's unique but still under the flask namespace.

@davidism

This comment has been minimized.

Copy link
Member

commented Aug 6, 2018

Or even just hard code using app.name instead of "flask.app". If we can be reasonably sure that it won't cause issues like the previous implementation, I'm fine with changing it.

@chinmayprabhudesai

This comment was marked as resolved.

Copy link

commented Apr 9, 2019

It logs twice because you're adding two handlers to the same logger. Add one handler to the "flask.app" logger instead.

To get different names, override Flask.logger:

class LoggerFlask(Flask):
    @property
    def logger(self):
        return super().logger.getChild(self.name)

app1 = Flask("app1")
app2 = Flask("app2")

Or see the docs on logging for how to inject extra information into log records. In your case you would inject current_app.name.

Here, shouldn't the apps be instantiated with the sub-classed LoggerFlask to use the overridden logger property?

@davidism davidism added this to the 1.1.0 milestone Jun 27, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.