NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

__init__.py (4256B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\beeline\middleware\flask\__init__.py
      2 import datetime
      3 import threading
      4 import beeline
      5 import flask
      6 from beeline.propagation import Request
      7 from flask import current_app, signals
      8 from werkzeug.wrappers import Request
      9 from beeline.middleware.wsgi import WSGIRequest
     10 
     11 class HoneyMiddleware(object):
     12 
     13     def __init__(self, app, db_events = True):
     14         self.app = app
     15         self.app.before_request(self._before_request)
     16         if signals.signals_available:
     17             self.app.teardown_request(self._teardown_request)
     18         app.wsgi_app = HoneyWSGIMiddleware(app.wsgi_app)
     19         if db_events:
     20             app = HoneyDBMiddleware(app)
     21 
     22     def _before_request(self):
     23         beeline.add_field('request.route', flask.request.endpoint)
     24 
     25     def _teardown_request(self, exception):
     26         if exception:
     27             beeline.add_field('request.error_detail', beeline.internal.stringify_exception(exception))
     28             beeline.add_field('request.error', str(type(exception)))
     29             beeline.internal.send_event()
     30 
     31 
     32 class HoneyWSGIMiddleware(object):
     33 
     34     def __init__(self, app):
     35         self.app = app
     36 
     37     def __call__(self, environ, start_response):
     38         req = Request(environ, shallow=True)
     39         wr = WSGIRequest('flask', environ)
     40         root_span = beeline.propagate_and_start_trace(wr.request_context(), wr)
     41 
     42         def _start_response(status, headers, *args):
     43             status_code = int(status[0:4])
     44             beeline.add_context_field('response.status_code', status_code)
     45             if status_code != 500:
     46                 beeline.finish_trace(root_span)
     47             elif status_code == 500 and not signals.signals_available:
     48                 beeline.finish_trace(root_span)
     49             return start_response(status, headers, *args)
     50 
     51         return self.app(environ, _start_response)
     52 
     53 
     54 class HoneyDBMiddleware(object):
     55 
     56     def __init__(self, app = None):
     57         self.app = app
     58         if app is not None:
     59             self.init_app(app)
     60         self.state = threading.local()
     61         self.state.span = None
     62 
     63     def init_app(self, app):
     64         try:
     65             from sqlalchemy.engine import Engine
     66             from sqlalchemy.event import listen
     67             listen(Engine, 'before_cursor_execute', self.before_cursor_execute)
     68             listen(Engine, 'after_cursor_execute', self.after_cursor_execute)
     69             listen(Engine, 'handle_error', self.handle_error)
     70         except ImportError:
     71             pass
     72 
     73     def before_cursor_execute(self, conn, cursor, statement, parameters, context, executemany):
     74         if not current_app:
     75             return
     76         params = []
     77         if type(parameters) == tuple or type(parameters) == list:
     78             for param in parameters:
     79                 if type(param) == datetime.datetime:
     80                     param = param.isoformat()
     81                 params.append(param)
     82 
     83         elif type(parameters) == dict:
     84             for k, v in parameters.items():
     85                 param = '%s=' % k
     86                 if type(v) == datetime.datetime:
     87                     v = v.isoformat()
     88                 param += '%s' % v
     89                 params.append(param)
     90 
     91         self.state.span = beeline.start_span(context={'name': 'flask_db_query',
     92          'type': 'db',
     93          'db.query': statement,
     94          'db.query_args': params})
     95         self.query_start_time = datetime.datetime.now()
     96 
     97     def after_cursor_execute(self, conn, cursor, statement, parameters, context, executemany):
     98         if not current_app:
     99             return
    100         query_duration = datetime.datetime.now() - self.query_start_time
    101         beeline.add_context({'db.duration': query_duration.total_seconds() * 1000,
    102          'db.last_insert_id': getattr(cursor, 'lastrowid', None),
    103          'db.rows_affected': cursor.rowcount})
    104         if self.state.span:
    105             beeline.finish_span(self.state.span)
    106         self.state.span = None
    107 
    108     def handle_error(self, context):
    109         if not current_app:
    110             return
    111         beeline.add_context_field('db.error', beeline.internal.stringify_exception(context.original_exception))
    112         if self.state.span:
    113             beeline.finish_span(self.state.span)
    114         self.state.span = None