Current File : /home/jvzmxxx/wiki/extensions/EventLogging/server/bin/eventlogging-devserver
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
  eventlogging-devserver
  ----------------------
  Invoking this command-line tool will spawn a web server that can serve
  as a test logging endpoint. Events logged against this server will be
  validated verbosely and pretty-printed to the terminal.

  To use this, you probably want to set '$wgEventLoggingBaseUri' on your
  test wiki to point at the host and port of this web server. The value
  '//localhost:8080/event.gif' should work.

  Example:
    event : {"wiki": "devwiki", "schema": "TrackedPageContentSaveComplete", "revision": 7872558, "event": {"revId": 10, "token": "foobar"}}
    url : http://localhost:8080/event.gif?%7B%22wiki%22%3A+%22devwiki%22%2C+%22schema%22%3A+%22TrackedPageContentSaveComplete%22%2C+%22revision%22%3A+7872558%2C+%22event%22%3A+%7B%22revId%22%3A+10%2C+%22token%22%3A+%22foobar%22%7D%7D


  usage: eventlogging-devserver [-h] [--host HOST] [--port PORT]

  optional arguments:
    -h, --help        show this help message and exit
    --host HOST       server host (default: 'localhost')
    --port PORT       server port (default: 8080)
    --append-to PATH  file to append to (default: stdout)
    --verbose         print pretty colors to stderr

  :copyright: (c) 2012 by Ori Livneh <ori@wikimedia.org>
  :license: GNU General Public Licence 2.0 or later

"""  # noqa
# pylint: disable=E0611
from __future__ import print_function, unicode_literals

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

import argparse
import itertools

from wsgiref.simple_server import make_server, WSGIRequestHandler

import eventlogging
import jsonschema

from pygments import formatters, highlight, lexers
from pygments.console import ansiformat


argparser = argparse.ArgumentParser(fromfile_prefix_chars='@')
argparser.add_argument('--host', default='localhost',
                       help='server host (default: localhost)')
argparser.add_argument('--port', default=8080, type=int,
                       help='server port (default: 8080)')
argparser.add_argument('--append-to', type=argparse.FileType('a'),
                       default=sys.stdout,
                       help='file to append to (optional)')
argparser.add_argument('--verbose', action='store_true',
                       help='print out events to stderr as they come in')
args = argparser.parse_args()

formatter = formatters.get_formatter_by_name('256', style='rrt')
colorize = ansiformat

json_lexer = lexers.get_lexer_by_name('json')
php_lexer = lexers.get_lexer_by_name('php', startinline=True)

server_software = 'EventLogging/%s' % eventlogging.__version__

seq_ids = itertools.count()
parser = eventlogging.LogParser('%q %{recvFrom}s %{seqId}d %t %h')
log_fmt = ('?%(QUERY_STRING)s %(SERVER_NAME)s '
           '%(SEQ_ID)d %(TIME)s %(REMOTE_ADDR)s')

max_qs_size = 900


def heading(caption=None):
    if caption is None:
        return 74 * '-'
    return '-- {:-<95}'.format(colorize('*yellow*', caption) + ' ')


def prepare_response(status, headers):
    """Encode a dictionary of HTTP headers to a list of tuples
    containing bytes."""
    if eventlogging.compat.PY3:
        return status, list(headers.items())
    status = status.encode('utf-8')
    headers = [(k.encode('utf-8'), v.encode('utf-8')) for k, v in
               headers.iteritems()]
    return status, headers


class EventLoggingHandler(WSGIRequestHandler):
    """WSGI request handler; annotates environ dict with seq ID and
    timestamp in NCSA Common Log Format."""

    def get_environ(self):
        environ = WSGIRequestHandler.get_environ(self)
        environ.update(SEQ_ID=next(seq_ids), TIME=eventlogging.ncsa_utcnow())
        return environ

    def log_message(self, format, *args):  # pylint: disable=W0621
        pass  # We'll handle logging in the WSGI app.


def validate(log_line):
    """Parse and validate a log line containing an encapsulated event.
    Returns a tuple of (event, errors). If no object was decoded,
    'event' will be None."""
    try:
        event = parser.parse(log_line)
    except ValueError as err:
        return None, [err]

    try:
        scid = event['schema'], event['revision']
    except KeyError as err:
        return event, [err]

    try:
        schema = eventlogging.get_schema(scid, encapsulate=True)
    except jsonschema.SchemaError as err:
        return event, [err]

    validator = jsonschema.Draft3Validator(schema)
    return event, list(validator.iter_errors(event))


def validate_size(environ):
    """Check whether the query string respects the maximum size.
    Returns a list with a ValueError if the size exceeds the maximum.
    Returns an empty list otherwise."""
    if 'QUERY_STRING' in environ:
        qs_size = len(environ['QUERY_STRING'])
        if qs_size > max_qs_size:
            return [ValueError(
                'Query string size (%d) is greater than max size (%d)' %
                (qs_size, max_qs_size))]
    return []


def handle_event(environ, start_response):
    """WSGI app; parses, validates and pretty-prints incoming event
    requests."""
    log_line = log_fmt % environ
    event, errors = validate(log_line)
    errors.extend(validate_size(environ))

    headers = {
        'Server': server_software,
        'Requested-Event-Valid': str(int(not errors))
    }

    for i, error in enumerate(errors):
        headers['Validation-Error-%d' % (i + 1)] = str(error)
    status, headers = prepare_response('204 No Content', headers)
    start_response(status, headers)

    args.append_to.write(eventlogging.json.dumps(event) + "\n")

    if args.verbose:
        print(heading('request'))
        print(log_line)

        print(heading('event'))
        pretty_json = eventlogging.json.dumps(event, indent=2, sort_keys=True)
        print(highlight(pretty_json, json_lexer, formatter), end='')

        print(heading('validation'))
        for error in errors:
            print(colorize('_red_', 'Error:'), error)

        if not errors:
            print(colorize('_green_', 'Valid.'))

        print(heading())

    return []


httpd = make_server(args.host, args.port, handle_event,
                    handler_class=EventLoggingHandler)

sys.stderr.write('''
   ___                        _
  / (_)                    \_|_)                 o
  \__        _   _  _  _|_   |     __   __,  __,     _  _    __,
  /    |  |_|/  / |/ |  |   _|    /  \_/  | /  | |  / |/ |  /  |
  \___/ \/  |__/  |  |_/|_/(/\___/\__/ \_/|/\_/|/|_/  |  |_/\_/|/
-----------------------------------------/|---/|--------------/|----------
  (C) Wikimedia Foundation, 2013         \|   \|              \|

''' + highlight('''
# Ensure the following values are set in LocalSettings.php:
require_once "$IP/extensions/EventLogging/EventLogging.php";
$wgEventLoggingSchemaApiUri = 'https://meta.wikimedia.org/w/api.php';

# Listening to events.\n''', php_lexer, formatter))

try:
    httpd.serve_forever()
except KeyboardInterrupt:
    pass