Я пишу свое первое приложение 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
Я попытался удалить обработчик исключения, но он просто выдает еще одну ошибку для корневого обработчика. Что я делаю не так?