Connexion: How do I access the logger?

Created on 2 May 2018  路  6Comments  路  Source: zalando/connexion

Hi, I couldn't find any information in the documentation.
How can I access the logger, e.g. to add a handler? I would like to write the output to a file.

I have a bit experience with flask so I tried to access the flask logger

#!/usr/bin/env python3

import connexion
import logging
from logging.handlers import WatchedFileHandler

from swagger_server import encoder
from swagger_server.database import init_db, db_session
from swagger_server.tools import create_path


def main():
    app.run(port=8080)


logging.basicConfig(level=logging.INFO)
init_db()

app = connexion.App(__name__, specification_dir='./swagger/')
app.app.json_encoder = encoder.JSONEncoder
app.add_api('swagger.yaml', arguments={'title': 'P7 Renderservice'})

application = app.app

logPath = './data/logs/service.log'
create_path(logPath)
handler = WatchedFileHandler(logPath)
handler.setLevel(logging.DEBUG)
application.logger.addHandler(handler)


@application.teardown_appcontext
def shutdown_session(exception=None):
    db_session.remove()


if __name__ == '__main__':
    main()

-> https://github.com/padok/REST-Event-API-example/blob/master/swagger_server/__main__.py

but my file remains empty

I want to save or modify what the app already print to stdout; for example

172.17.0.1 - - [02/May/2018 03:02:46] "GET /v1/event HTTP/1.1" 200 -
172.17.0.1 - - [02/May/2018 03:02:46] "GET /v1/event HTTP/1.1" 200 -
172.17.0.1 - - [02/May/2018 03:02:46] "GET /v1/event HTTP/1.1" 200 -
172.17.0.1 - - [02/May/2018 03:02:47] "GET /v1/event HTTP/1.1" 200 -

Thanks for your help!

question

Most helpful comment

exactly

event_api.app.logger.addHandler(log_handler)
event_api.app.logger.setLevel(logging.ERROR)

in your validator class, use
`` from flask import current_app current_app.logger.info("flask logger: foo") ... instead ofapp = Flask(__name__)`

All 6 comments

you did more or less correct.
Please use application factory: http://flask.pocoo.org/docs/0.12/patterns/appfactories/

I use a custom extension for logging, but the essential is:
'''
handler = logging.StreamHandler()
handler.setLevel(config['LOGGING_LEVEL'])
handler.setFormatter(logging.Formatter(config['LOGGING_FORMAT']))
app.logger.addHandler(handler)
app.logger.setLevel(app.config['LOGGING_LEVEL'])
'''

after you use the the logger with the correct level.

Instead of StreamHandler it could be any other handler. Or it could be even proxy.

Do you have an example @roman-telepathy-ai ?

logging example is above. a note here: if accessing connexion app, then use app.app.

regarding - App factories just have a look at docs or search for "flask tutorial" (miguel will be on top).

I have figured this out. I'll explain now. I didn't use the app factory pattern though but hopefully my code is clear enough.

I have a special validator class. The code is as follows:
```#!/usr/bin/env python3

import datetime
from connexion.decorators.validation import RequestBodyValidator
from jsonschema import ValidationError
from connexion import problem
from flask import Flask

app = Flask(__name__)
BAD_REQUEST = 'Bad Request'

class RequestBodyValidatorVerboseErrorLogging(RequestBodyValidator):

def validate_schema(self, data, url):
    if self.is_null_value_valid and is_null(data):
        return None

    try:
        self.validator.validate(data)
    except ValidationError as exception:
        app.logger.error("{timestamp} {url} VALIDATION_ERROR: {error} REQUEST_BODY: {request_body}".format(timestamp=datetime.datetime.utcnow().isoformat(),url=url, error=exception.message, request_body=data))
        return problem(400, BAD_REQUEST, str(exception.message))

    return None
I want to log the error messages of this class to a rotating file. Earlier, I was using the common logger namespace convention but my suspicion was that the Flask application was taking precedence. I changed the logging to use `app.logger.error` instead of `logger.error`. Notice my import above.

My main API file is as follows:

!/usr/bin/env python3

import connexion
import logging
import sys
from event_api_validators import RequestBodyValidatorVerboseErrorLogging
from logging.handlers import RotatingFileHandler

SWAGGER_PATH = '/event_api/'
LOG_PATH = '/error_logs/event_api_error_log.log'
RESOLVED_SWAGGER_FILE = 'api_index_resolved.json'

log_handler = RotatingFileHandler(LOG_PATH, mode='a', maxBytes=10010241024,
backupCount=10, encoding=None, delay=False)
log_handler.setLevel(logging.ERROR)

validator_map = {
'body': RequestBodyValidatorVerboseErrorLogging
}

event_api = connexion.App(__name__, validator_map=validator_map)
event_api.app.logger.addHandler(log_handler)
event_api.app.logger.setLevel(logging.ERROR)
event_api.add_api(RESOLVED_SWAGGER_FILE, swagger_path=SWAGGER_PATH)

if __name__ == '__main__':
event_api.run(port=80)
```

This works with the RotatingFileHandler. Additionally, I still write to stream with the default log handler as well.

exactly

event_api.app.logger.addHandler(log_handler)
event_api.app.logger.setLevel(logging.ERROR)

in your validator class, use
`` from flask import current_app current_app.logger.info("flask logger: foo") ... instead ofapp = Flask(__name__)`

Thanks! Much cleaner.

Was this page helpful?
0 / 5 - 0 ratings