some little details about logging errors

This commit is contained in:
Kyle Lahnakoski 2018-05-23 22:56:38 -04:00
Родитель 552750632e
Коммит a2b100ac6c
5 изменённых файлов: 72 добавлений и 106 удалений

4
.gitignore поставляемый
Просмотреть файл

@ -2,10 +2,8 @@
*.iml
*.pyc
src
settings.json
resources/logs
esFrontLine/util/.svn
tests/util/.svn
.svn
build
dist
*.egg-info

Просмотреть файл

@ -1,26 +1,25 @@
# encoding: utf-8
#
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
#
# Author: Kyle Lahnakoski (kyle@lahnakoski.com)
#
import argparse
import codecs
import logging
from logging.handlers import RotatingFileHandler
import os
from __future__ import division
from __future__ import unicode_literals
import random
from flask import Flask, json
import time
import flask
import requests
import time
from flask import Flask, json
from werkzeug.contrib.fixers import HeaderRewriterFix
from werkzeug.exceptions import abort
from auth import HawkAuth, AuthException
import sys # REQUIRED FOR DYNAMIC DEBUG
from esFrontLine.auth import HawkAuth, AuthException, logger
from mo_dots import listwrap
from mo_future import BytesIO
from mo_logs import constants, Log, startup, Except
app = Flask(__name__)
auth = HawkAuth()
@ -34,24 +33,6 @@ def stream(raw_response):
yield block
def listwrap(value):
if value is None:
return []
elif isinstance(value, list):
return value
else:
return [value]
class Except(Exception):
def __init__(self, message):
super(Exception, self).__init__(self, message)
self._message = message
@property
def message(self):
return self._message
@app.route('/', defaults={'path': ''}, methods=['GET', 'HEAD', 'POST'])
@app.route('/<path:path>', methods=['GET', 'HEAD', 'POST'])
def catch_all(path):
@ -70,7 +51,7 @@ def catch_all(path):
#PICK RANDOM ES
es = random.choice(listwrap(settings["elasticsearch"]))
## SEND REQUEST
# SEND REQUEST
headers = {k: v for k, v in flask.request.headers if v is not None and v != "" and v != "null"}
headers['content-type'] = 'application/json'
@ -115,10 +96,10 @@ def catch_all(path):
response_content_length=int(outbound_header["content-length"]) if "content-length" in outbound_header else None
))
## FORWARD RESPONSE
return flask.wrappers.Response(
# FORWARD RESPONSE
return flask.Response(
stream(response.raw),
direct_passthrough=True, #FOR STREAMING
direct_passthrough=True, # FOR STREAMING
status=response.status_code,
headers=outbound_header
)
@ -142,39 +123,38 @@ def filter(method, path_string, query):
if path_string in ["", "/"]:
return # HEAD REQUESTS ARE ALLOWED
else:
raise Except("HEAD requests are generally not allowed")
Log.error("HEAD requests are generally not allowed")
path = path_string.split("/")
## EXPECTING {index_name} "/" {type_name} "/" {_id}
## EXPECTING {index_name} "/" {type_name} "/_search"
## EXPECTING {index_name} "/_search"
# EXPECTING {index_name} "/" {type_name} "/" {_id}
# EXPECTING {index_name} "/" {type_name} "/_search"
# EXPECTING {index_name} "/_search"
es_methods = ["_mapping", "_search", "_count"]
if len(path) == 2:
if path[-1] not in es_methods:
raise Except("request path must end with _mapping or _search")
Log.error("request path must end with _mapping or _search")
elif len(path) == 3:
if path[-1] not in es_methods:
raise Except("request path must end with _mapping or _search")
Log.error("request path must end with _mapping or _search")
else:
raise Except('request must be of form: {index_name} "/" {type_name} "/_search" ')
Log.error('request must be of form: {index_name} "/" {type_name} "/_search" ')
## COMPARE TO WHITE LIST
# COMPARE TO WHITE LIST
if path[0] not in settings["whitelist"]:
raise Except('index not in whitelist: {index_name}'.format({"index_name": path[0]}))
Log.error('index not in whitelist: {{index_name}}', index_name=path[0])
## EXPECTING THE QUERY TO AT LEAST HAVE .query ATTRIBUTE
# EXPECTING THE QUERY TO AT LEAST HAVE .query ATTRIBUTE
if path[-1] == "_search" and json.loads(query).get("query", None) is None:
raise Except("_search must have query")
Log.error("_search must have query")
## NO CONTENT ALLOWED WHEN ASKING FOR MAPPING
# NO CONTENT ALLOWED WHEN ASKING FOR MAPPING
if path[-1] == "_mapping" and len(query) > 0:
raise Except("Can not provide content when requesting _mapping")
Log.error("Can not provide content when requesting _mapping")
except Exception as e:
logger.warning(e.message)
raise Except("Not allowed: {path}:\n{query}".format(path=path_string, query=query))
Log.warning("Not allowed: {{path}}:\n{{query}}", path=path_string, query=query, cause=e)
return path[0]
@ -186,14 +166,13 @@ class WSGICopyBody(object):
self.application = application
def __call__(self, environ, start_response):
from cStringIO import StringIO
length = environ.get('CONTENT_LENGTH', '0')
length = 0 if length == '' else int(length)
body = environ['wsgi.input'].read(length)
environ['body_copy'] = body
environ['wsgi.input'] = StringIO(body)
environ['wsgi.input'] = BytesIO(body)
# Call the wrapped application
app_iter = self.application(environ, self._sr_callback(start_response))
@ -208,58 +187,27 @@ class WSGICopyBody(object):
return callback
settings = None
app.wsgi_app = WSGICopyBody(app.wsgi_app)
logger = None
settings = {}
def main():
global settings
try:
parser = argparse.ArgumentParser()
parser.add_argument(*["--settings", "--settings-file", "--settings_file"], **{
"help": "path to JSON file with settings",
"type": str,
"dest": "filename",
"default": "./settings.json",
"required": False
})
namespace = parser.parse_args()
args = {k: getattr(namespace, k) for k in vars(namespace)}
if not os.path.exists(args["filename"]):
raise Except("Can not file settings file {filename}".format(filename=args["filename"]))
with codecs.open(args["filename"], "r", encoding="utf-8") as file:
json_data = file.read()
globals()["settings"] = json.loads(json_data)
settings["args"] = args
settings["whitelist"] = listwrap(settings.get("whitelist", None))
globals()["logger"] = logging.getLogger('esFrontLine')
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
for d in listwrap(settings["debug"]["log"]):
if d.get("filename", None):
fh = RotatingFileHandler(**d)
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
logger.addHandler(fh)
elif d.get("stream", None) in ("sys.stdout", "sys.stderr"):
ch = logging.StreamHandler(stream=eval(d["stream"]))
ch.setLevel(logging.DEBUG)
ch.setFormatter(formatter)
logger.addHandler(ch)
settings = startup.read_settings()
constants.set(settings.constants)
Log.start(settings.debug)
# Setup auth users
auth.load_users(settings.get('users'))
auth.load_users(settings.users)
HeaderRewriterFix(app, remove_headers=['Date', 'Server'])
app.run(**settings["flask"])
app.run(**settings.flask)
except Exception as e:
print(str(e))
Log.error("Problem with etl", e)
finally:
Log.stop()
if __name__ == '__main__':

Просмотреть файл

@ -1,10 +1,22 @@
# encoding: utf-8
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
#
from __future__ import division
from __future__ import unicode_literals
from mohawk import Receiver
import random
import logging
import time
from mo_logs import Log
logger = logging.getLogger('esFrontLine')
logger.setLevel("DEBUG")
class AuthException(Exception):
'''
@ -37,13 +49,12 @@ class HawkAuth(object):
assert isinstance(resources, list), '"resources" must be JSON list'
assert len(resources) > 0, '"resources" cannot be empty'
assert isinstance(hawk, dict), '"hawk" must be a JSON dictionary'
assert hawk.keys() == ['algorithm', 'id', 'key'], \
'"hawk" can only contains algorithm, id, key.'
assert hawk.keys() == {'algorithm', 'id', 'key'}, '"hawk" can only contains algorithm, id, key.'
self.users[user['hawk']['id']] = user
logger.debug('Validated user {id}'.format(**user['hawk']))
Log.note('Validated user {{user}}', user)
except AssertionError as e:
raise Exception('Error on user #{}: {}'.format(index+1, e))
Log.error('Error on user {{user}}', user=user, cause=e)
logger.info('Loaded {} users'.format(len(self.users)))

Просмотреть файл

@ -1,3 +1,14 @@
# encoding: utf-8
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
#
from __future__ import division
from __future__ import unicode_literals
from collections import Mapping
from mohawk import Sender
from elasticsearch.connection import Urllib3HttpConnection
from elasticsearch.compat import urlencode
@ -12,9 +23,8 @@ class HawkConnection(Urllib3HttpConnection):
super(HawkConnection, self).__init__(*args, **kwargs)
# Save credentials
assert isinstance(hawk_credentials, dict), 'hawk_credentials should be a dict'
assert hawk_credentials.keys() == ['algorithm', 'id', 'key'], \
'hawk_credentials can only contains algorithm, id, key.'
assert isinstance(hawk_credentials, Mapping), 'hawk_credentials should be a dict'
assert hawk_credentials.keys() == {'algorithm', 'id', 'key'}, 'hawk_credentials can only contains algorithm, id, key.'
self._hawk_credentials = hawk_credentials
def perform_request(self, method, url, params, body, headers=None, *args, **kwargs):

5
vendor/mo_threads/multiprocess.py поставляемый
Просмотреть файл

@ -14,7 +14,7 @@ import os
import subprocess
from mo_dots import set_default, NullType
from mo_future import none_type
from mo_future import none_type, binary_type
from mo_logs import Log, strings
from mo_logs.exceptions import Except
from mo_threads.lock import Lock
@ -146,8 +146,7 @@ class Process(object):
if line:
if self.debug:
Log.note("{{process}} (stdin): {{line}}", process=self.name, line=line.rstrip())
pipe.write(line + b"\n")
pipe.close()
pipe.write(line.encode('utf8') + b"\n")
def _kill(self):
try: