Create simple flask error application to log exceptions - python

I've uploaded some code into a server. The code was working locally but when I upload it to the server it gives me an Internal Server Error. The website is running with wsgi and the code is:
try:
from decksite import main, APP as application
except Exception as e:
from shared import repo
repo.create_issue('Error starting website', exception=e)
if __name__ == '__main__':
print('Running manually. Is something wrong?')
application.run(host='0.0.0.0', debug=False)
So both the try and the except are failing. I want to add a second exception and pass it all to a simple flask application that would output both exceptions to the browser and log them to a file. The problem is that I don't know how to pass the exception to the error_app flask app and that it breaks in the line where I set the logging config. Here is what I've done. I'm only getting NoneType: None instead of the full exception.
import os, sys
sys.path.append("/home/myuser/public_html/flask");
try:
from decksite import main, APP as application
except Exception as error:
#from shared import repo
#repo.create_issue('Error starting decksite', exception=error)
#sys.path.insert(0, os.path.dirname(__file__))
#from error_app import app as application
# This is the code that goes into the error flask application
import logging
import traceback
from flask import Flask, __version__
app = Flask(__name__)
application = app
#app.route("/")
def hello():
return traceback.format_exc()
# The next line gives Internal Server Error
logging.basicConfig(filename='example.log', level=logging.DEBUG)
logging.exception(error)
return traceback.format_exc()
if __name__ == '__main__':
print('Running manually. Is something wrong?')
application.run(host='0.0.0.0', debug=False)
I don't have sudo in the server and can't ssh to it so unless I'm able to log the errors I'm not going to be able to fix anything.
Edit: I've almost got it as I want:
.htaccess
website.wsgi
error_app.py
website/init.py
website/main.py

Create a custom 500 handler and print out the trackback
import traceback
#app.errorhandler(500)
def internal_server_error(e):
return render_template('500_error.html', traceback=traceback.format_exc())
Have your '500_error.html' template show you the traceback.

You mentioned 500 Internal Server Error is coming. Things are proper in your local but fail on server. Since you don't have ssh access, it might be tough to debug. If you use something like Docker or Kubernetes to build and deploy it can be useful. I can suggest you some ways to debug. The code is not going to try except and failing, the possible reason is the server itself not starting due to missing requirements say some import or it could be anything.
Debug Steps
Create a virtual environment and re-install requirements in it similar to your server. This will help you to identify if there is a missing requirement.
if you are environment is not production and you are testing the application in the server then put debug = True. It will show an error on the front end. This is definitely not a recommended approach. I am suggesting since you don't have ssh access.
If possible create a simple route say /hello and in that just return hello, and check whether it is returning you the right result or not. This will let you know whether your server is starting or not. Even this is not recommendable for production.
You can also check the flask app before request and after request. This might also be useful
Hopefully, 1st step debugging will help you a lot and you might not need to go to step 2 and step 3. I gave you for the worst-case scenario

Related

How to use only 'flask run' command in terminal and add default config variables in code instead?

I would like to start my Flask application with just flask run with these config informations: host = 0.0.0.0, port = 443 & cert = adhoc. If I wanted to run this through command I would have executed the code below instead:
flask run --host=0.0.0.0 --port=443 --cert=adhoc
But then I have to tell all my group mates and my professor to do it too when they check on my code. So I tried to work around this by using the code below in my app:
werkzeug.serving.run_simple("0.0.0.0", 443, app, ssl_context='adhoc')
However when I try to close my server with CTRL+C, it starts another server that actually would start if I didn't have any config informations. So I was wondering is there any way to go around this? Either it is to continue using werkzeug or to change it to something else.
Here is a shorten version of my code that includes how I have built my app. Tried to include what's just needed. If there's anything I should include more just tell me. Any help is appreciated. Thank you!
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
SECRET_KEY='env',
DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
)
app.app_context().push()
if test_config is None:
# load the instance config, if it exists, when not testing
app.config.from_pyfile('config.py', silent=True)
else:
# load the test config if passed in
app.config.from_mapping(test_config)
# ensure the instance folder exists
try:
os.makedirs(app.instance_path)
except OSError:
pass
serving.run_simple("0.0.0.0", 443, app, ssl_context='adhoc')
return app
Environment variables would probably be the correct way to provide these values to the flask run command.
You never mentioned your platform, but on Linux, something like:
export FLASK_RUN_PORT=9999
Causes the dev sever to launch on port 9999 when launched with just flask run
You could also put these values in the file .flaskenv:
FLASK_RUN_PORT=9999
FLASK_RUN_HOST=0.0.0.0
flask run should then autoload these values.
By the way official documentation misses these values out, I had to look on issue 2661
Seems FLASK_RUN_CERT=adhoc is also a valid one, as per issue 3105.
Not sure if there's an extensive list of these anywhere.

Using Requests library with WSGI

I'm creating a GroupMe bot that's hosted on Heroku with Gunicorn as the WSGI server.
When I try deploying the app, I get a failed to find object 'app' in 'MODULE_NAME' error, I think because I don't have a WSGI callable.
Here's what I have:
def app():
while True:
rqResponse = requests.get('https://api.groupme.com/v3/groups/' + groupID +'/messages', params = requestParams)
# Pings the gm-membot Heroku app so it doesn't idle.
requests.get('http://gm-bot.herokuapp.com')
if rqResponse.status_code == 200:
gotten = rqResponse.json()['response']['messages']
for message in gotten:
messageText = message['text'].lower()
if (messageText in bot_reply.staticTriggers) or (messageText in bot_reply.dynamicTriggers):
bot_reply.botReply(message)
requestParams['since_id'] = message['id']
else:
raise Exception('error')
break
time.sleep(5)
My Procfile output:
web: gunicorn MODULE_NAME:app --workers=1
However, After looking at the documentation for Gunicorn and WSGI, I can't figure out how to mesh it with the code I already have written using the Requests library. Is there any way I can get Gunicorn to work without a lot of rewriting? Also, I'm very new to this, so I apologize if there's an obvious answer.
(P.S. everything works fine if I just host the app on my latptop!)
I found two answers: first and second, though I think it's the memory leak on server (cause you said hosted local everything works).
Try and let me know

How to integrate Sentry with Huey workers / consumers

I'd like to integrate Sentry with Huey task queue's workers / consumers.
I've seen an issue in both Sentry and Huey's GitHub issues, but I found no definite answer about how to integrate them.
I've read that one way to integrate them is via logging, however I'm storing my API key in the database and loading it from Python code, not from a hard-coded ini file (as is recommended).
Here is how I load Sentry in my main (Pyramid) app:
app = config.make_wsgi_app()
if get_siteconfig(dbsession)['sentry_key_backend']:
try:
from raven import Client
from raven.middleware import Sentry
client = Client(get_siteconfig(dbsession)['sentry_key_backend'])
app = Sentry(app, client=client)
except Exception:
print('SENTRY init error')
Wheres my huey_worker.py is just a bunch of import statement and database setup lines, without an actual app or a function which I could wrap in a try - except block.
What is the recommended way to integrate Sentry in this case?

Replacing flask internal web server with Apache

I have written a single user application that currently works with Flask internal web server. It does not seem to be very robust and it crashes with all sorts of socket errors as soon as a page takes a long time to load and the user navigates elsewhere while waiting. So I thought to replace it with Apache.
The problem is, my current code is a single program that first launches about ten threads to do stuff, for example set up ssh tunnels to remote servers and zmq connections to communicate with a database located there. Finally it enters run() loop to start the internal server.
I followed all sorts of instructions and managed to get Apache service the initial page. However, everything goes wrong as I now don't have any worker threads available, nor any globally initialised classes, and none of my global variables holding interfaces to communicate with these threads do not exist.
Obviously I am not a web developer.
How badly "wrong" my current code is? Is there any way to make that work with Apache with a reasonable amount of work? Can I have Apache just replace the run() part and have a running application, with which Apache communicates? My current app in a very simplified form (without data processing threads) is something like this:
comm=None
app = Flask(__name__)
class CommsHandler(object):
__init__(self):
*Init communication links to external servers and databases*
def request_data(self, request):
*Use initialised links to request something*
return result
#app.route("/", methods=["GET"]):
def mainpage():
return render_template("main.html")
#app.route("/foo", methods=["GET"]):
def foo():
a=comm.request_data("xyzzy")
return render_template("foo.html", data=a)
comm = CommsHandler()
app.run()
Or have I done this completely wrong? Now when I remove app.run and just import app class to wsgi script, I do get a response from the main page as it does not need reference to global variable comm.
/foo does not work, as "comm" is an uninitialised variable. And I can see why, of course. I just never thought this would need to be exported to Apache or any other web server.
So the question is, can I launch this application somehow in a rc script at boot, set up its communication links and everyhing, and have Apache/wsgi just call function of the running application instead of launching a new one?
Hannu
This is the simple app with flask run on internal server:
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
To run it on apache server Check out fastCGI doc :
from flup.server.fcgi import WSGIServer
from yourapplication import app
if __name__ == '__main__':
WSGIServer(app).run()

Is there any way of detecting an automatic reload in flask's debug mode?

I have a flask app where I'd like to execute some code on the first time the app is run, not on the automatic reloads triggered by the debug mode. Is there any way of detecting when a reload is triggered so that I can do this?
To give an example, I might want to open a web browser every time I run the app from sublime text, but not when I subsequently edit the files, like so:
import webbrowser
if __name__ == '__main__':
webbrowser.open('http://localhost:5000')
app.run(host='localhost', port=5000, debug=True)
You can set an environment variable.
import os
if 'WERKZEUG_LOADED' in os.environ:
print 'Reloading...'
else:
print 'Starting...'
os.environ['WERKZEUG_LOADED']='TRUE'
I still don't know how to persist a reference that survives the reloading, though.
What about using Flask-Script to kick off a process before you start your server? Something like this (cribbed from their documentation and edited slightly):
# run_devserver.py
import webbrowser
from flask.ext.script import Manager
from myapp import app
manager = Manager(app)
if __name__ == "__main__":
webbrowser.open('http://localhost:5000')
manager.run(host='localhost', port=5000, debug=True)
I have a Flask app where it's not really practical to change the DEBUG flag or disable reloading, and the app is spun up in a more complex way than just flask run.
#osa's solution didn't work for me with flask debug on, because it doesn't have enough finesse to pick out the werkzeug watcher process from the worker process that gets reloaded.
I have this code in my main package's __init__.py (the package that defines the flask app). This code is run by another small module which has from <the_package_name> import app followed by app.run(debug=True, host='0.0.0.0', port=5000). Therefore this code is executed before the app starts.
import ptvsd
import os
my_pid = os.getpid()
if os.environ.get('PPID') == str(os.getppid()):
logger.debug('Reloading...')
logger.debug(f"Current process ID: {my_pid}")
try:
port = 5678
ptvsd.enable_attach(address=('0.0.0.0', port))
logger.debug(f'========================== PTVSD waiting on port {port} ==========================')
# ptvsd.wait_for_attach() # Not necessary for my app; YMMV
except Exception as ex:
logger.debug(f'PTVSD raised {ex}')
else:
logger.debug('Starting...')
os.environ['PPID'] = str(my_pid)
logger.debug(f"First process ID: {my_pid}")
NB: note the difference between os.getpid() and os.getppid() (the latter gets the parent process's ID).
I can attach at any point and it works great, even if the app has reloaded already before I attach. I can detach and re-attach. The debugger survives a reload.

Categories

Resources