A wrapper around the Tornado web framework that supports logs with traceId.
Project description
================================================
_____ _
|_ _| _ _ __ | |__ based on Tornado
| || | | | '_ \| '_ \ / _ \ / _ \| '_ \
| || |_| | |_) | | | | (_) | (_) | | | |
|_| \__, | .__/|_| |_|\___/ \___/|_| |_|
|___/|_|
================================================
Typhoon is a wrapper around the Tornado web framework. It offers the ability to attach log records with a trace id, which is used to trace individual HTTP requests. By default Typhoon obtains trace id from the request's header X-TRACEID
. To change this behavior, subclass typhoon.web.Application
and overwrite the get_trace_id
method.
Requirements
- tornado >= 5.1
Installation
- Use pip:
pip install typhoon-web pip install typhoon-web --upgrade
- Clone repository and install with:
python setup.py install
Hello, world
Here is a simple “Hello, world” example web app for Typhoon:
import logging
import time
import tornado.ioloop
import typhoon.web
import typhoon.log
class MainHandler(typhoon.web.RequestHandler):
@typhoon.web.run_in_executor
def process(self):
logging.info('go to sleep')
time.sleep(3)
logging.info('wake up')
return 'Hello, world'
async def get(self):
result = await self.process()
self.write(result)
# Native coroutine (using async def and await) was introduced in Python 3.5.
# For previous version, use generator-based coroutine.
# For example:
#
# @tornado.gen.coroutine
# def get(self):
# result = yield self.process()
# self.write(result)
def make_app():
return typhoon.web.Application([
(r'/', MainHandler),
])
if __name__ == '__main__':
typhoon.log.configure(log_path='/home/logs')
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
In this example, three different log files will be generated in the log_path:
- access.log records summaries of each http request.
- stats.log records messages for statistics and analysis.
- app.log contains all logs that are neither access logs nor stats logs.
To log to stats.log, use an instance of typhoon.log.StatsLogger
:
import typhoon.log
stats_log = typhoon.log.StatsLogger()
stats_log.info({'user_count': 100})
stats_log.info({'job_register': 20}, topic='register')
Notice that logging methods of StatsLogger
only accept a dict
object as message.
Trace id
By default trace id is automatically obtained and handled by Typhoon only when the client sends a request with a header X-TRACEID: some-value
:
$ curl -H "X-TRACEID: ceon1haa6cau1dung1" http://127.0.0.1:8888
To customize the way trace id is passed, subclass typhoon.web.Application
and overwrite the get_trace_id
method.
import typhoon.web
class MyApplication(typhoon.web.Application):
def get_trace_id(self, handler):
# obtain trace id from URL Parameter.
return handler.get_argument('traceId', '-')
In the above example, trace id is passed through an URL parameter:
$ curl http://127.0.0.1:8888?traceId=ceon1haa6cau1dung1
You may have to call another service and pass down the trace id. In this case, use typhoon.log.TRACE_ID()
to obtain current trace id:
import requests
import typhoon.web
import typhoon.log
class MainHandler(typhoon.web.RequestHandler):
@typhoon.web.run_in_executor
def process(self):
# call another service and pass down current trace id.
r = request.get('http://127.0.0.1:9990/hello', header={'X-TRACEID': typhoon.log.TRACE_ID()})
if r.status_code == 200:
return 'Hello, world'
else:
return 'oops!'
async def get(self):
result = await self.process()
self.write(result)
<font color='green'>[new]</font> High-Level API
For those who are not familiar with Tornado, Typhoon provides high-level api since v1.0.2.
Neither RequestHandler
, nor Application
. Just subclass typhoon.rest.RestControler
, and decorated method with typhoon.rest.route
decorator.
Here is a “Hello, world” example.
from typhoon.rest import RestController, RestResult, route, start_server
from typhoon.status import OK
class Controller(RestController):
@route(uri=r'/hello', method='get')
def greet(self, user=None):
if user is not None:
content = f'Hello, {user}'
else:
content = 'Hello, world'
return RestResult(status=OK, content=content)
if __name__ == '__main__':
start_server(
controller = Controller(),
port=8888
)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.