|
| 1 | +title: How to Monitor Python Web Applications |
| 2 | +slug: monitor-python-web-applications |
| 3 | +meta: Learn how to add monitoring to a Python web application using a hosted monitoring service such as Rollbar. |
| 4 | +category: post |
| 5 | +date: 2017-09-26 |
| 6 | +modified: 2017-09-26 |
| 7 | +headerimage: /img/170926-monitor-python-web-apps/header.jpg |
| 8 | +headeralt: Python, Rollbar and Bottle logos, copyright their respective owners. |
| 9 | + |
| 10 | + |
| 11 | +A quick way to check for errors and issues in your operational |
| 12 | +[Python web application](/web-development.html) is to drop-in one of many |
| 13 | +awesome hosted [monitoring](/monitoring.html) tools. |
| 14 | + |
| 15 | +Let's learn to quickly add [Rollbar monitoring](https://rollbar.com) |
| 16 | +to a web app to visualize when our application is running properly and |
| 17 | +when it has issues. This tutorial will use [Bottle](/bottle.html) as the |
| 18 | +example [web framework](/web-frameworks.html) along with Rollbar as the |
| 19 | +monitoring service but you can also check out the list of other tools |
| 20 | +on the [monitoring page](/monitoring.html). |
| 21 | + |
| 22 | + |
| 23 | +## Our Tools |
| 24 | +We can use either [Python 2 or 3](/python-2-or-3.html) to build this |
| 25 | +tutorial, but Python 3 is *strongly* recommended for all new applications. |
| 26 | +[Python 3.6.2](https://www.python.org/downloads/release/python-362/) to |
| 27 | +was used to build this tutorial. We will also use the following |
| 28 | +[application dependencies](/application-dependencies.html) throughout |
| 29 | +the post: |
| 30 | + |
| 31 | +* [pip](https://pip.pypa.io/en/stable/) and |
| 32 | + [virtualenv](https://virtualenv.pypa.io/en/latest/), which come installed |
| 33 | + with Python 3, to install and isolate the Bottle and Rollbar libraries |
| 34 | + from your other projects |
| 35 | +* [Bottle](/bottle.html) web framework, |
| 36 | + [version 0.12.13](https://bottlepy.org/docs/0.12/) |
| 37 | +* [pyrollbar](https://rollbar.com/docs/notifier/pyrollbar/) monitoring |
| 38 | + instrumentation library, |
| 39 | + [version 0.13.13](https://github.com/rollbar/pyrollbar/tree/v0.13.13) |
| 40 | + in Bottle applications so pyrollbar can report on all errors |
| 41 | +* A [free Rollbar account](https://rollbar.com/) where we will send error |
| 42 | + data and view it when it is captured |
| 43 | + |
| 44 | +If you need help getting your |
| 45 | +[development environment](/development-environments.html) configured |
| 46 | +before running this code, take a look at |
| 47 | +[this guide for setting up Python 3 and Bottle on Ubuntu 16.04 LTS](/blog/python-3-bottle-green-unicorn-ubuntu-1604-xenial-xerus.html). |
| 48 | + |
| 49 | +All code in this blog post is available open source under the MIT license |
| 50 | +on GitHub under the |
| 51 | +[monitor-python-bottle-apps directory of the blog-code-examples repository](https://github.com/fullstackpython/blog-code-examples). |
| 52 | +Use and abuse the source code as you desire for your own applications. |
| 53 | + |
| 54 | + |
| 55 | +## Installing Dependencies |
| 56 | +Create a new virtual environment for this project using the following |
| 57 | +command. I recommend keeping a separate directory for virtualenvs under |
| 58 | +`~/Envs/` so you will know where all your project virtualenvs are located. |
| 59 | + |
| 60 | +```bash |
| 61 | +python3 -m venv monitorpython |
| 62 | +``` |
| 63 | + |
| 64 | +Activate the virtualenv with the `activate` shell script: |
| 65 | + |
| 66 | +```bash |
| 67 | +source monitorpython/bin/activate |
| 68 | +``` |
| 69 | + |
| 70 | +The command prompt will change after activating the virtualenv: |
| 71 | + |
| 72 | +<img src="/img/170926-monitor-python-web-apps/activate-python-virtualenv.png" width="100%" class="technical-diagram img-rounded" style="border:1px solid #ccc" alt="Activating our Python virtual environment on the command line."> |
| 73 | + |
| 74 | +Remember that you need to activate your virtualenv in every new terminal |
| 75 | +window where you want to use the virtualenv to run the project. |
| 76 | + |
| 77 | +We can now install Bottle and Rollbar into the activated |
| 78 | +virtualenv. |
| 79 | + |
| 80 | +``` |
| 81 | +pip install bottle==0.12.13 rollbar==0.13.13 |
| 82 | +``` |
| 83 | + |
| 84 | +Look for output like the following to confirm the |
| 85 | +dependencies installed correctly. |
| 86 | + |
| 87 | +``` |
| 88 | +Installing collected packages: bottle, urllib3, certifi, idna, chardet, requests, six, rollbar |
| 89 | + Running setup.py install for bottle ... done |
| 90 | + Running setup.py install for rollbar ... done |
| 91 | + Successfully installed bottle-0.12.13 certifi-2017.7.27.1 chardet-3.0.4 idna-2.6 requests-2.18.4 rollbar-0.13.13 six-1.11.0 urllib3-1.22 |
| 92 | +``` |
| 93 | + |
| 94 | +We have our dependencies ready to go so now we can build |
| 95 | +our Python web application. |
| 96 | + |
| 97 | + |
| 98 | +## Our Python Web App |
| 99 | +Create a folder for your project named `monitor-python-apps`. `cd` into |
| 100 | +the folder and then create a file named `app.py` with the following |
| 101 | +code. |
| 102 | + |
| 103 | +```python |
| 104 | +import bottle |
| 105 | +import os |
| 106 | +import re |
| 107 | +from bottle import route, template |
| 108 | + |
| 109 | + |
| 110 | +TEMPLATE_STRING = """ |
| 111 | +<html> |
| 112 | + <head> |
| 113 | + <title>Full Stack Python Web App</title> |
| 114 | + </head> |
| 115 | + <body> |
| 116 | + <h1>{{ h1 }}</h1> |
| 117 | + </body> |
| 118 | +</html> |
| 119 | +""" |
| 120 | + |
| 121 | +MIN_MSG_LENGTH = 2 |
| 122 | + |
| 123 | + |
| 124 | +@route("/<msg>/") |
| 125 | +def show_message(msg): |
| 126 | + """Display a message if the msg value is greater than 2 characters |
| 127 | + in the path. |
| 128 | + """ |
| 129 | + valid_length = len(msg) >= MIN_MSG_LENGTH |
| 130 | + valid_name = re.match('^[a-z\-]+$', msg.lower()) is not None |
| 131 | + if valid_length and valid_name: |
| 132 | + return template(TEMPLATE_STRING, h1=msg) |
| 133 | + else: |
| 134 | + error_msg = "Sorry, only alpha characters and hyphens allowed." |
| 135 | + raise Exception(error_msg) |
| 136 | + |
| 137 | + |
| 138 | +if __name__ == "__main__": |
| 139 | + bottle.run(host='localhost', port=8080) |
| 140 | +``` |
| 141 | + |
| 142 | +The above application code has a few standard Bottle imports so we can |
| 143 | +create a Bottle web app and handle URL routes. |
| 144 | + |
| 145 | +We have a single function, `show_message`, that handles a single Bottle |
| 146 | +URL route. `show_message` checks if the URL path contains only alphabetic |
| 147 | +characters and hyphens for a message to display. If the message passes |
| 148 | +the conditions then a page is rendered with that message |
| 149 | +in an `h1` element. If `msg` does not pass the condition test then an |
| 150 | +exception is thrown that only alpha characters and hyphens are allowed. |
| 151 | + |
| 152 | +Save `app.py` and we can run our code. Execute `app.py` using the `python` |
| 153 | +command as follows (make sure your virtualenv is still activated in the |
| 154 | +terminal where you are running this command): |
| 155 | + |
| 156 | +```bash |
| 157 | +python app.py |
| 158 | +``` |
| 159 | + |
| 160 | +The Bottle development server should start up and display a few lines |
| 161 | +of output. |
| 162 | + |
| 163 | +<img src="/img/170926-monitor-python-web-apps/run-bottle-app.png" width="100%" class="technical-diagram img-rounded" style="border:1px solid #ccc" alt="Run the local Bottle development server."> |
| 164 | + |
| 165 | +What if we try to access the application running on |
| 166 | +[localhost port 8080](http://localhost:8080)? |
| 167 | + |
| 168 | +<img src="/img/170926-monitor-python-web-apps/localhost-404.png" width="100%" class="technical-diagram img-rounded" style="border:1px solid #ccc" alt="Testing our Bottle web app at the base URL gets an HTTP 404 error."> |
| 169 | + |
| 170 | +HTTP status 404 page not found, which is what we expected because we only |
| 171 | +defined a single route and it did not live at the base path. |
| 172 | + |
| 173 | +Try a URL with a path that contains only alphabetic characters and hyphens, |
| 174 | +such as |
| 175 | +[localhost:8080/hello-world/](http://localhost:8080/hello-world/). |
| 176 | + |
| 177 | +<img src="/img/170926-monitor-python-web-apps/localhost-hello-world.png" width="100%" class="technical-diagram img-rounded" style="border:1px solid #ccc" alt="Testing at /hello-world/ returns an HTTP 200 response."> |
| 178 | + |
| 179 | +The application was successful in displaying "hello-world" but what if we |
| 180 | +try a URL that contains numbers in addition to the alphabetic characters, |
| 181 | +such as |
| 182 | +[localhost:8080/fullstackpython123/](http://localhost:8080/fullstackpython/)? |
| 183 | + |
| 184 | +<img src="/img/170926-monitor-python-web-apps/localhost-500.png" width="100%" class="technical-diagram img-rounded" style="border:1px solid #ccc" alt="We receive a 500 error when numbers are added to the URL."> |
| 185 | + |
| 186 | +An HTTP 500 error. That is surely not a good user experience. |
| 187 | + |
| 188 | +The 500 error is obvious to us right now because we are |
| 189 | +testing the application locally during development. However, what happens |
| 190 | +when the app is deployed and a user gets the error in their own web |
| 191 | +browser? They will likely quit out of frustration and you will never |
| 192 | +know what happened unless you add some error tracking and application |
| 193 | +monitoring. |
| 194 | + |
| 195 | +Time to modify our code to add Rollbar to report errors that occur. |
| 196 | + |
| 197 | + |
| 198 | +## Monitoring for Errors with Rollbar |
| 199 | +Go to the [Rollbar homepage in your browser](https://rollbar.com/) |
| 200 | +to add their tool to our Bottle app. |
| 201 | + |
| 202 | +<img src="/img/170926-monitor-python-web-apps/rollbar-homepage.jpg" width="100%" class="technical-diagram img-rounded" style="border:1px solid #ccc" alt="The Rollbar homepage in the Chrome web browser."> |
| 203 | + |
| 204 | +Click the "Sign Up" button in the upper right-hand corner. Enter your |
| 205 | +email address, a username and the password you want on the sign up page. |
| 206 | + |
| 207 | +<img src="/img/170926-monitor-python-web-apps/sign-up-page.jpg" width="100%" class="technical-diagram img-rounded" style="border:1px solid #ccc" alt="Enter your account information on the sign up page."> |
| 208 | + |
| 209 | +After the sign up page you will see the onboarding flow where you can |
| 210 | +enter a project name and select a programming language. For the project |
| 211 | +name type in "Full Stack Python" then select that you are monitoring a |
| 212 | +Python app. |
| 213 | + |
| 214 | +<img src="/img/170926-monitor-python-web-apps/create-new-project.jpg" width="100%" class="technical-diagram img-rounded" style="border:1px solid #ccc" alt="Create a new project named 'Battlegrounds' and select Python as the programming language."> |
| 215 | + |
| 216 | +Press the "Continue" button at the bottom to move along. The next |
| 217 | +screen shows us a few instructions to add monitoring to a Python |
| 218 | +application. |
| 219 | + |
| 220 | +<img src="/img/170723-monitor-flask-apps/project-setup.jpg" width="100%" class="technical-diagram img-rounded" style="border:1px solid #ccc" alt="Set up your project using your server-side access token."> |
| 221 | + |
| 222 | +Let's change our Bottle code to let Rollbar collect and aggregate the |
| 223 | +errors that pop up in our application. Modify `app.py` to include the |
| 224 | +following highlighted lines. |
| 225 | + |
| 226 | +```python |
| 227 | +import bottle |
| 228 | +import os |
| 229 | +import re |
| 230 | +from bottle import route, template |
| 231 | +~~from rollbar.contrib.bottle import RollbarBottleReporter |
| 232 | + |
| 233 | + |
| 234 | +TEMPLATE_STRING = """ |
| 235 | +<html> |
| 236 | + <head> |
| 237 | + <title>Full Stack Python Web App</title> |
| 238 | + </head> |
| 239 | + <body> |
| 240 | + <h1>{{ h1 }}</h1> |
| 241 | + </body> |
| 242 | +</html> |
| 243 | +""" |
| 244 | + |
| 245 | +MIN_MSG_LENGTH = 2 |
| 246 | +~~ROLLBAR_SECRET = os.environ.get("ROLLBAR_SECRET") |
| 247 | +~~ |
| 248 | +~~rb_monitor = RollbarBottleReporter(access_token=ROLLBAR_SECRET, |
| 249 | +~~ environment='production') |
| 250 | +~~bottle.install(rb_monitor) |
| 251 | + |
| 252 | + |
| 253 | +@route("/<msg>/") |
| 254 | +def show_message(msg): |
| 255 | + """Display a message if the msg value is greater than 2 characters |
| 256 | + in the path. |
| 257 | + """ |
| 258 | + valid_length = len(msg) >= MIN_MSG_LENGTH |
| 259 | + valid_name = re.match('^[a-z\-]+$', msg.lower()) is not None |
| 260 | + if valid_length and valid_name: |
| 261 | + return template(TEMPLATE_STRING, h1=msg) |
| 262 | + else: |
| 263 | + error_msg = "Sorry, only alpha characters and hyphens allowed." |
| 264 | + raise Exception(error_msg) |
| 265 | + |
| 266 | + |
| 267 | +if __name__ == "__main__": |
| 268 | + bottle.run(host='localhost', port=8080) |
| 269 | +``` |
| 270 | + |
| 271 | +A new import `from rollbar.contrib.bottle import RollbarBottleReporter` |
| 272 | +is our conduit between the application and the Rollbar server. `rollbar` |
| 273 | +is the library we installed earlier. |
| 274 | + |
| 275 | +The `ROLLBAR_SECRET` token needs to be set in an environment variable. |
| 276 | +Save and quit `app.py`. Run the following command in the terminal where your |
| 277 | +virtualenv is activated: |
| 278 | + |
| 279 | +```bash |
| 280 | +export ROLLBAR_SECRET='token here' |
| 281 | +``` |
| 282 | + |
| 283 | +If you are uncertain about what your secret token is, it can be found on |
| 284 | +the Rollbar onboarding screen. |
| 285 | + |
| 286 | +Note that I typically store all my environment variables in a `.env` |
| 287 | +file and use a |
| 288 | +[template.env](https://github.com/fullstackpython/blog-code-examples/blob/master/monitor-flask-apps/template.env) |
| 289 | +as a template for what I should fill into `.env`. `.env` can be invoked |
| 290 | +from the terminal using the `. .env` command. Make sure to *never* commit |
| 291 | +your secret tokens to a source control repository though, especially if |
| 292 | +the repository is public! |
| 293 | + |
| 294 | +After exporting your `ROLLBAR_SECRET` key as an environment variable |
| 295 | +we can test that Rollbar is working as we run our application. Run it |
| 296 | +now using `python`: |
| 297 | + |
| 298 | +```bash |
| 299 | +python app.py |
| 300 | +``` |
| 301 | + |
| 302 | +Back in your web browser press the "Done! Go to Dashboard" button. |
| 303 | + |
| 304 | +If an event hasn't been reported yet we'll see a waiting screen like this |
| 305 | +one: |
| 306 | + |
| 307 | +<img src="/img/170926-monitor-python-web-apps/waiting.jpg" width="100%" class="technical-diagram img-rounded" style="border:1px solid #ccc" alt="Waiting for data on the Rollbar dashboard."> |
| 308 | + |
| 309 | +Make sure your Bottle development server is running and try to go to |
| 310 | +[localhost:8080/fullstackpython123/](http://localhost:8080/fullstackpython123/). |
| 311 | +A 500 server error is immediately reported on the dashboard: |
| 312 | + |
| 313 | +<img src="/img/170926-monitor-python-web-apps/exception-reported.jpg" width="100%" class="technical-diagram img-rounded" style="border:1px solid #ccc" alt="Viewing the 500 errors reported in the Rollbar dashboard."> |
| 314 | + |
| 315 | +We even get an email with the error (which can also be turned off if you |
| 316 | +don't want emails for every error): |
| 317 | + |
| 318 | +<img src="/img/170926-monitor-python-web-apps/email-error-report.jpg" width="100%" class="technical-diagram img-rounded" style="border:1px solid #ccc" alt="Email with the Rollbar error report."> |
| 319 | + |
| 320 | +Nice, with just a few lines of code we now have our Bottle app reporting |
| 321 | +errors for any user that's working with our application. |
| 322 | + |
| 323 | + |
| 324 | +## What now? |
| 325 | +We just learned how to catch and handle errors with Rollbar as a hosted |
| 326 | +monitoring platform in a simple example |
| 327 | +[Bottle application](/bottle.html). Next you will want to |
| 328 | +add [monitoring](/monitoring.html) to more complicated web apps, including |
| 329 | +ones that use [Django](/django.html) or [Flask](/flask.html). You can also |
| 330 | +try Rollbar's more advanced features to: |
| 331 | + |
| 332 | +* [set up rules to group errors](https://rollbar.com/docs/custom-grouping/) |
| 333 | +* [debug and track deployment issues](https://rollbar.com/docs/deploy-tracking/) |
| 334 | +* [sort and view errors by user](https://rollbar.com/docs/person-tracking/) |
| 335 | + |
| 336 | +There is plenty more to learn about in the areas of |
| 337 | +[web development](/web-development.html) and |
| 338 | +[deployments](/deployments.html) so keep learning by reading |
| 339 | +about [web frameworks](/web-frameworks.html). You can also learn more |
| 340 | +about integrating Rollbar with Python applications via |
| 341 | +[their Python documentation](https://rollbar.com/docs/notifier/pyrollbar/). |
| 342 | + |
| 343 | +Questions? Let me know via |
| 344 | +[a GitHub issue ticket on the Full Stack Python repository](https://github.com/mattmakai/fullstackpython.com/issues), |
| 345 | +on Twitter |
| 346 | +[@fullstackpython](https://twitter.com/fullstackpython) |
| 347 | +or [@mattmakai](https://twitter.com/mattmakai). |
| 348 | + |
| 349 | +Do you see a typo, syntax issue or just something that's confusing in this |
| 350 | +blog post? Fork |
| 351 | +[this page's source on GitHub](https://github.com/mattmakai/fullstackpython.com/blob/master/content/posts/170926-monitor-python-web-apps.markdown) |
| 352 | +and submit a pull request with a fix or |
| 353 | +[file an issue ticket on GitHub](https://github.com/mattmakai/fullstackpython.com/issues). |
0 commit comments