Using Logbook with Codenvy


 

Logbook tutorial with Codenvy IDE

What is Logbook

Logbook is a logging sytem for Python that replaces the standard library’s logging module. It was designed with both complex and simple applications in mind. If properly configured, Logbook’s logging calls will be very cheap and provide a great performance improvement over an equivalent configuration of the standard library’s logging module.

It also supports the ability to inject additional information for all logging calls happening in a specific thread or for the whole application. For example, this makes it possible for a web application to add request-specific information to each log record such as remote address, request URL, HTTP method and more.

And this is what we will do. Add request logging to our simple web-app from the Werkzeug Tutorial.

Lets start a python project

First of all create a new python project using the Codenvy IDE. Select from menu ‘Project’, New->Create Project. new_project Name your new application accordingly, select Python as the project type, and leave PaaS as None. new_project-2 Next select the ‘simple python project’ and click finish.

The sample ‘Simple python application’ is based on bottle, but as Werkzeug and bottle functionality overlap, replace “bottle” with “werkzeug” in the requirements.txt file to make the python environment to install Werkzeug. Also add a new line with “Logbook” to install Logbook.

After this we are ready to copy over our files from the Werkzeug tutorial. If you haven’t read it, and you don’t understand what’s going on, please go take a look, it’s really simple.

Another way to copy the werkzeug project is to clone the repository through menu->git->clone. As a project url you should put the url returned from menu->git->GIT URL(read only) while you have opened the project you want cloned.

Initial Configuration

Create a new file named logger.py

new_file

And add this code:

#logger.py

from logbook import FileHandler, Logger

handler = FileHandler('app.log')
ilogger = Logger('APPNAME')

handler.push_application()

ilogger.info('Logging system ready:')

This is enough to bootstrap our logging system.
We create a FileHandler and a Logger. After the call push_application the FileHandler is the default handler application wide.

Connect with werkzeug

We are trying to log the requests for our werkzeug app. The best spot to do this is inside the wsgi_app function in the Hello class, as it has access to both the request and the response objects.

#hello.py

from logger import ilogger    #Add this line

class Hello(object):

    def __init__(self):

        self.url_map = Map([
            Rule('/', endpoint='root'),
            Rule('/hello', endpoint='hello'),
            Rule('/helloargs', endpoint='hello_args'),
            Rule('/hello/<user_name>', endpoint='hello_dynamic'),
            Rule('/hellodb/<user_id>', endpoint='hello_datastore'),
            Rule('/records', endpoint='show_records')              #Add this line
        ])
        self.database = kvstore
        self.log = ilogger         #Add this line

    def wsgi_app(self, environ, start_response):
        request = Request(environ)
        response = self.dispatch_request(request)
        # We are calling our logger after dispatch_request to get access to the response status
        self.log.info('Request for:%s from %s status:%s'%(request.full_path,
                                                request.remote_addr,
                                                response.status_code)
                      )
        return response(environ, start_response)

    def __call__(self, environ, start_response):
        return self.wsgi_app(environ, start_response)

    def dispatch_request(self, request):
        adapter = self.url_map.bind_to_environ(request.environ)
        try:
            endpoint, values = adapter.match()
            return getattr(self, 'on_' + endpoint)(request, **values)
        except HTTPException, e:
            return e

    def on_root(self, request):
        return Response(tmpl.root, mimetype='text/html')

    # More code here. Removed for brevity

First we import our logger from the logger package we created in the previous step.
Notice that we connect the logger with our hello class in the constructor.

After this we are ready to call our logger from anywhere inside our Hello class. We have added the call inside the wsgi_app function after we get the response so that we have access to the status code.

Add a new View

Notice that we additionally have added the ‘/records’ Rule inside our url_map. This rule has an endpoint of ‘show_records’ so lest add a new function called on_show_records.

#hello.py - Hello class

    def on_show_records(self, request, **keys):
        records = []
        for line in open('app.log','r'):
            records.append('<br/>'+line)
        return Response(tmpl.html%(''.join(records)), mimetype='text/html')

We are using a new template from the templates file. Let’s add that too:

#templates.py

html = """<html>
              <body>
                %s
              </body>
           </html> """

Start the application and browse around, then visit ‘/records’ to view the log file