Arne
Arne

Reputation: 20117

Log all http responses with an error code >=400

The application in question uses connexion, which wraps flask, to take care of the web-server. The API is specified with swagger. Is there an easy and straight forward way to get somewhere into the code where http responses are formulated from the web-server?

If possible, I would like to avoid writing 200 errorhandlers, or the 10 most popular and crossing my fingers.

api.py

import connexion
app = connexion.App(__name__,
                specification_dir='../swagger/',
                swagger_ui=False,
                validator_map={
                    'body': connexion.decorators.validation.RequestBodyValidator
                })
app.add_api('swagger.yml', strict_validation=True)

# If I had to use app.error_handler decorators to implement the special
# treatment of http responses with error codes, I would put it here

swagger.yml

swagger: '2.0'
info:
  title: My Minimal Working Example
consumes:

  - application/json
produces:
  - application/json

basePath: /api/v1
paths:
  '/do_something':
    post:
      tags:
        - MyTag
      operationId: entrypoint.do_something
      summary: Do something on request
      parameters:
        - name: data
          in: body
          schema:
            $ref: '#/definitions/data'
      responses:
        '200':
          description: Success!
          schema:
            $ref: '#/definitions/Response'
        '400':
          description: Error!
          schema:
            $ref: '#/definitions/Response'
        '403':
          description: Not Authorized
          schema:
            $ref: '#/definitions/Response'    
# a lot more stuff and "definitions"

Upvotes: 0

Views: 946

Answers (1)

Arne
Arne

Reputation: 20117

I solved the problem by subclassing the Flask object, as davidism suggested. The short version is this:

app.py

import logging.config
import yaml

logging.config.dictConfig(yaml.load(open('logging.conf', 'r')))
logger = logging.getLogger("mainLogger")


class LoggingFlask(Flask):
    def make_response(self, rv):
        rv = super(LoggingFlask, self).make_response(rv)
        if int(rv.status_code) >= 300:
            logger.warn("Request failed with error code %s." % rv.status_code)
        return rv


app = LoggingFlask(__name__)

session.log

./app.py 
[2017-10-10 11:38:19,564 - werkzeug - INFO]:  * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
[2017-10-10 11:38:19,566 - werkzeug - INFO]:  * Restarting with stat
[2017-10-10 11:38:19,690 - werkzeug - WARNING]:  * Debugger is active!
[2017-10-10 11:38:19,691 - werkzeug - INFO]:  * Debugger PIN: 211-310-838

# issues a good request
[2017-10-10 11:38:25,179 - werkzeug - INFO]: 127.0.0.1 - - [10/Oct/2017 11:38:25] "GET /todo/api/v1.0/tasks HTTP/1.1" 200 -

# issued a bad request
[2017-10-10 11:38:28,646 - mainLogger - WARNING]: Request failed with error code 404.
[2017-10-10 11:38:28,646 - mainLogger - WARNING]: Request failed with error code 404.
[2017-10-10 11:38:28,647 - werkzeug - INFO]: 127.0.0.1 - - [10/Oct/2017 11:38:28] "GET /todo/api/v1.0/task HTTP/1.1" 404 -

If someone knows how to access the request that triggered the current response, feel free to drop a comment so that I can include it in this answer as well.

Upvotes: 3

Related Questions