2016-09-27 1 views
1

Ich habe eine kleine Flasche App, die wie ein REST-API, die viele Methoden, wie diese implementiert verwendet wird:Wie Logging-Nachrichten mit Anfrage Informationen in Kolben anreichern?

@route('/do/something', methods=['POST']) 
def something(): 
    app.logger.debug("got request to /do/something") 
    result = something_implementation(request.json()) 
    app.logger.debug("result was %s", str(result)) 
    return flask.Response(result) 

ich diese Log-Meldungen automatisch mit Informationen aus dem Request-Objekt bereichern möchte, wie Header-Informationen, Teile der Körper und was sonst noch bequem ist.

Wie mache ich das auf elegante und pythische Weise?

Natürlich könnte ich app.logger einfach in meine eigene Funktion einfügen und das Anfrageobjekt und die Nachricht weiterleiten, aber es muss einen schöneren und einfacheren Weg geben, den ich vermisse.

Antwort

1

ich diese gelöst durch logging.Filter Subklassen und Zugabe zu meinem Handler .

Etwas wie folgt aus:

class ContextFilter(logging.Filter): 
    '''Enhances log messages with contextual information''' 
    def filter(self, record): 
     try: 
      record.rid = request.rid 
     except RuntimeError as exc: 
      if str(exc.message) == 'working outside of request context': 
       record.rid = '' 
      else: 
       raise exc 
     return True 

Die try/except-Klausel ist für Protokollmeldungen außerhalb eines Anforderungskontext nötig zu arbeiten. Und dann verwenden Sie es wie folgt aus:

fileHandler = RotatingFileHandler(app.config['LOGFILE'], maxBytes=20971520, 
            backupCount=5, encoding='utf-8') 
fileHandler.setLevel(logging.DEBUG) 
fileHandler.addFilter(ContextFilter()) 
filefmt = '%(asctime)s [%(filename)s:%(lineno)d] %(rid)s: %(message)s' 
fileFormatter = logging.Formatter(filefmt) 
fileHandler.setFormatter(fileFormatter) 
app.logger.addHandler(fileHandler) 

In Zukunft werde ich mehr Felder in der ContextFilter.filter() Methode hinzufügen und nutzen sie, aber ich in der Formatierungs Konfiguration bitte.

2

I gehören in der Regel so etwas wie dies in meiner app.py Datei Debug-Informationen für jede Anforderung zu protokollieren, zusammen mit dem Umgang mit Standardfehlern:

# Useful debugging interceptor to log all values posted to the endpoint 
@app.before_request 
def before(): 
    values = 'values: ' 
    if len(request.values) == 0: 
     values += '(None)' 
    for key in request.values: 
     values += key + ': ' + request.values[key] + ', ' 
    app.logger.debug(values) 

# Useful debugging interceptor to log all endpoint responses 
@app.after_request 
def after(response): 
    app.logger.debug('response: ' + response.status + ', ' + response.data.decode('utf-8')) 
    return response 

# Default handler for uncaught exceptions in the app 
@app.errorhandler(500) 
def internal_error(exception): 
    app.logger.error(exception) 
    return flask.make_response('server error', 500) 

# Default handler for all bad requests sent to the app 
@app.errorhandler(400) 
def handle_bad_request(e): 
    app.logger.info('Bad request', e) 
    return flask.make_response('bad request', 400)v 
+1

Vielen Dank. Ich habe bereits etwas ähnliches, aber es ist nicht genug, ich muss protokollieren, was während der Bearbeitung der Anfrage passiert. Sieht so aus, als müsste ich einen benutzerdefinierten Filter implementieren: https://docs.python.org/2/howto/logging-cookbook.html#using-filters-to-impart-contextual-information Ich muss nur herausfinden, wie um von diesem Filter auf den aktuellen Anforderungskontext zuzugreifen. – Patrick