Развертывание Zappa не выполняется из-за ошибки в обработчике журналов, но работает локально - PullRequest
0 голосов
/ 03 октября 2019

Я пишу свое первое приложение Flask и пытаюсь развернуть его с помощью Zappa. Он продолжает работать из-за невозможности настроить обработчики журналов, но когда я запускаю сервер локально, он работает без проблем.

Модуль ведения журнала:

import logging

# Filter classes for logging
# Does not allow 'exceptions' through
class NoExceptionFilter(logging.Filter):
    def filter(self, record):
        return not (record.name == "exception")

# Does not allow messages from the root logger through        
class NoRootFilter(logging.Filter):
    def filter(self, record):
        return not (record.name == "root")

# Only allows messages from werkzeug through. Also, changes the message so that it only logs ip address and actions
class OnlyWerkzeugFilter(logging.Filter):
    def filter(self, record):
        msgSplit = record.msg.split()
        ipAddr = msgSplit[0]
        if (record.name == "werkzeug" and ipAddr.count(".") == 3):
            requestString = " ".join(msgSplit[5:9])
            record.msg = "%s %s" % (ipAddr, requestString)
            return True
        else:
            return False
        #return (record.name == "werkzeug")

# Does not allow messages from werkzeug through
class NoWerkzeugFilter(logging.Filter):
    def filter(self, record):
        return not (record.name == "werkzeug")

# Does not allow *anything* through. For disabling logging when debugging
class NothingAllowedFilter(logging.Filter):
    def filter(self, record):
        return not (record.levelname == "EXCEPTION" or record.levelname == "INFO" or record.levelname == "ERROR")

# LOGGING
# Formatters
DEFAULT_FORMATTER = {"format": "(%(levelname)s,%(name)s) - %(asctime)s: %(message)s", "datefmt": "%d/%m/%Y %I:%M:%S %p"}
MESSAGE_ONLY = {"format": "%(message)s"}

# Filters
NO_EXCEPTION = {"()": NoExceptionFilter}
NO_ROOT = {"()": NoRootFilter}
NO_WERKZEUG = {"()": NoWerkzeugFilter}
ONLY_WERKZEUG = {"()": OnlyWerkzeugFilter}
NOTHING_ALLOWED = {"()": NothingAllowedFilter}

# Handlers
ROOT_HANDLER = {"class": "logging.FileHandler", "formatter": "default", "filename": "server.log", "mode": "a", "encoding": "utf-8", "filters": ["no_exception", "no_werkzeug"]}
EXCEPTION_HANDLER = {"class": "logging.FileHandler", "formatter": "default", "filename": "stack_trace.log", "mode": "a", "encoding": "utf-8", "filters": ["no_werkzeug"]}
WERKZEUG_HANDLER = {"class": "logging.FileHandler", "formatter": "default", "filename": "request.log", "mode": "a", "encoding": "utf-8", "filters": ["only_werkzeug"]}

# Sets up the basic configuration for the logging program. 
LOGGING =\
            {
                "appName": "",
                "version": 1,
                "formatters": {"default": DEFAULT_FORMATTER, "msg_only": MESSAGE_ONLY},
                "filters":
                            {
                                "no_exception": NO_EXCEPTION,
                                "no_root": NO_ROOT,
                                "no_werkzeug": NO_WERKZEUG,
                                "only_werkzeug": ONLY_WERKZEUG,
                                "nothing_allowed": NOTHING_ALLOWED
                            },
                "handlers": { "root_handler": ROOT_HANDLER, "exception_handler": EXCEPTION_HANDLER, "werkzeug_handler": WERKZEUG_HANDLER},
                "loggers":
                            {
                                "exception": 
                                            {
                                                "level": "ERROR",
                                                "handlers": ["exception_handler"],
                                                "propagate": 0
                                            },
                                "werkzeug":
                                            {
                                                "level": "INFO",
                                                "handlers": ["werkzeug_handler"]
                                            }
                            },
                "root": 
                        {
                            "level": "INFO",
                            "handlers": ["root_handler"]
                        }
            }

И модуль сервера:

import flask
import logging
import os
import sys
import mas_searches as mas
import mas_database as mas_d
from mas_api_check_form import *
from mas_api_logging import *
from flask import request, jsonify, Flask
from flask_script import Manager, Server
from logging.config import dictConfig
#from werkzeug.middleware.proxy_fix import ProxyFix

# Class for running code at the start of the server
class CustomServer(Server):
    def __call__(self, app, *args, **kwargs):
        LogServerStart()
        #Hint: Here you could manipulate app
        return Server.__call__(self, app, *args, **kwargs)

def LogServerStart():
    appLogger.info("Server has started")

def LogPOSTError(ipAddr, errMsgs):
    logMessage = "%s - error in POST data (%s)" % (ipAddr, ", ".join(errMsgs))
    appLogger.info(logMessage)
    print(logMessage)

def LogUserSearch(ipAddr, searchTypes, textToSearch, lang):
    logMessage = "%s - requested [%s] search(es) for '%s' (language: '%s')" % (ipAddr, 
        ",".join(searchTypes), textToSearch, lang)
    appLogger.info(logMessage)
    print(logMessage)

# START
appName = "Mispelled Author Search" # Set app name

# Setup logging
LOGGING["appName"] = appName
dictConfig(LOGGING)
appLogger = logging.getLogger()
werkzeugLogger = logging.getLogger("werkzeug")
exceptionLogger = logging.getLogger("exception")

# Set app details
app = flask.Flask(appName)
app.config["DEBUG"] = False
#app.wsgi_app = ProxyFix(app.wsgi_app)

# Setup manager to control what happens when the server starts
manager = Manager(app)
manager.add_command("runserver", CustomServer()) # Remeber to add the command to your Manager instance

# Setup database
path = os.getcwd() + "/"
dbFile = "AllFootprintsDataPairedWithHebBib.json.withvariants.json"

# Load JSON file (the 'database') into a dataframe
dbDF = mas_d.LoadDatabaseFromJSON(path, dbFile)

# Create a column for english names of authors, and hebrew names of authors (operations in the function are by reference)
mas_d.PutDictFieldIntoDataframeColumnFromDict(dbDF, "author", "heb_bib_data", "heb_author")
mas_d.PutDictFieldIntoDataframeColumnFromDict(dbDF, "author", "footprints_data", "eng_author")

# Routes
@app.route('/', methods=['GET'])
def home():
    return "There's nothing here."

@app.route("/api/v1/search", methods = ["POST"])
def search():
    try:
        form = request.json

        # Check for errors
        errMsgs = CheckFormData(form)
        if (len(errMsgs) > 0):

            # Log the errors
            LogPOSTError(request.remote_addr, errMsgs)

            return jsonify({"has_error": True, "error_messages": errMsgs}), 500

        # Set POST data to local variables
        textToSearch = form["search_text"]
        lang = form["lang"]
        searchTypes = form["search_types"]
        maxScore = 2.0 if ("max_score" not in form.keys()) else form["max_score"]

        # Log search
        LogUserSearch(request.remote_addr, searchTypes, textToSearch, lang)

        # Get author list
        authorList = mas_d.GetAuthorList(dbDF, lang)

        # List of author names
        names = []

        searchDicts = {"exact": None, "levenshtein": None, "soundex": None}
        # Exact and soundex search
        searchKey = {"exact": mas.EXACT, "levenshtein": mas.LEVENSHTEIN, "soundex": mas.SOUNDEX}
        for searchType in searchTypes:
            if (searchType == "levenshtein"):
                continue

            searchDicts[searchType] = mas.PerformSearch(path, lang, authorList, textToSearch, searchKey[searchType])

        # Levenshtein search
        if ("levenshtein" in searchTypes):
            searchTokenCount = len(textToSearch.split())
            authorScores = mas.LevenshteinSearchByScore(textToSearch, authorList, maxScore)
            authorsUnderThreshold = mas.GetAuthorsUnderScoreThreshold(authorScores, searchTokenCount, maxScore)
            levenList = [author["author"] for author in authorsUnderThreshold if (author["agg_score"] <= maxScore * searchTokenCount)]
            searchDicts["levenshtein"] = {"ix": None, "search_type": "levenshtein", "names_list": levenList}

        # Get final results 
        searches = [searchType for searchName,searchType in searchDicts.items() if (searchType is not None)]
        resultsDict = mas.ConcatenateNames(searches)
        for data in resultsDict["search_data"]:
            if (data["search_type"] == "levenshtein" and "levenshtein" in searchTypes):
                data["other_data"] = authorsUnderThreshold

        # Put results into JSON-like object
        names = resultsDict["final_names_found"]
        names.sort()
        jsonDict = {"final_names_found": names, "search_results_specified": resultsDict["search_data"]}

        return jsonify(jsonDict)
    except Exception as e:
        # Print and log error messages
        errMsg = type(sys.exc_info()[1]).__name__ + ": " + str(e)
        print(errMsg + "\n")
        appLogger.error("%s - %s", request.remote_addr, errMsg)
        exceptionLogger.error("%s", "~" * 80)
        exceptionLogger.exception("%s - %s", request.remote_addr, errMsg)

        # Return an error JSON
        errMsgs = ["Server has run into the following error: %s" % (errMsg)]
        return jsonify({"has_error": True, "error_messages": errMsgs}), 500

# Run server app
if (__name__ == "__main__"):
    manager.run()

И вот ошибка, которую я получаю:

[1570113277111] [ERROR] ValueError: Unable to configure handler 'exception_handler'
Traceback (most recent call last):
  File "/var/task/handler.py", line 602, in lambda_handler
    return LambdaHandler.lambda_handler(event, context)
  File "/var/task/handler.py", line 245, in lambda_handler
    handler = cls()
  File "/var/task/handler.py", line 139, in __init__
    self.app_module = importlib.import_module(self.settings.APP_MODULE)
  File "/var/lang/lib/python3.7/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 728, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/var/task/mas_api.py", line 40, in <module>
    dictConfig(LOGGING)
  File "/var/lang/lib/python3.7/logging/config.py", line 799, in dictConfig
    dictConfigClass(config).configure()
  File "/var/lang/lib/python3.7/logging/config.py", line 570, in configure
    '%r' % name) from e

Я попытался удалить обработчик исключения, но он просто выдает еще одну ошибку для корневого обработчика. Что я делаю не так?

...