Skip to content

Commit 4de4d0a

Browse files
committed
Adds honeybadger support.
The Dockerfile is required to be in a non-slim image because honeybadger introduces a dependency that is natively built. We will likely run into these things, anyway. Adds the `honeybadger` Python library to `requirements.txt` New configuration option via env to provide the honeybadger project key within the `HONEYBADGER_API_KEY` variable. Sets it up to log all exceptions that are unhandled within the app. Sets it up to log all CRITICAL logs that happen in the app. Sets it up to log all ERROR logs (that aren't exceptions) in the app.
1 parent c74151f commit 4de4d0a

File tree

6 files changed

+61
-5
lines changed

6 files changed

+61
-5
lines changed

Dockerfile

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
FROM python:3.11-slim
2-
3-
RUN pip install Flask
1+
FROM python:3.11
2+
# Note: We cannot use a '3.x-slim' image because we want 'gcc' installed for
3+
# certain packages. For instance, 'honeybadger' requires gcc via a
4+
# dependency on 'psutil'.
45

56
WORKDIR /app
67
COPY requirements.txt .

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ to `DEBUG`, `INFO`, `WARNING`, `ERROR`, or `CRITICAL`. The `DEBUG` setting is th
2525
most permissive and shows all logging text. The `CRITICAL` prevents most logging
2626
from happening. Most logging happens at `INFO`, which is the default setting.
2727

28+
To enable Honeybadger reporting for events in the application, provide the
29+
`HONEYBADGER_API_KEY` within the configuration or as an environment variable. When
30+
enabled, the application will notify on Exceptions raised and any `error` or `critical`
31+
logs.
32+
2833
## Local Development
2934

3035
All of our server code is written using [Flask](https://flask.palletsprojects.com/en/2.3.x/).

config.txt.sample

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
OPENAI_API_KEY=
22
LOG_LEVEL=INFO
3+
#HONEYBADGER_API_KEY=hbp_xxx

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ numpy
22
openai
33
flask
44
waitress
5+
honeybadger

src/__init__.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
# Flask
1313
from flask import Flask
1414

15-
# OpenAI library
16-
import openai
15+
# Honeybadger support
16+
from honeybadger.contrib import FlaskHoneybadger
17+
from honeybadger.contrib.logger import HoneybadgerHandler
1718

1819
def create_app(test_config=None):
1920
# create and configure the app
@@ -42,6 +43,35 @@ def create_app(test_config=None):
4243
logging.log(100, f"Setting up application. Logging level={log_level}")
4344
logging.basicConfig(format='%(asctime)s: %(levelname)s:%(name)s:%(message)s', level=log_level)
4445

46+
# Add Honeybadger support
47+
if os.getenv('HONEYBADGER_API_KEY'):
48+
logging.info('Setting up Honeybadger configuration')
49+
50+
# I need to patch Flask in order for Honeybadger to load
51+
# The honeybadger library uses this deprecated attribute
52+
# It was deprecated because it is now always 'True'.
53+
# See: https://github.com/pallets/flask/commit/04994df59f2f642e52ba46ca656088bcdb931262
54+
from flask import signals
55+
setattr(signals, 'signals_available', True)
56+
57+
# Log exceptions to Honeybadger
58+
app.config['HONEYBADGER_API_KEY'] = os.getenv('HONEYBADGER_API_KEY')
59+
app.config['HONEYBADGER_PARAMS_FILTERS'] = 'password, secret, openai_api_key, api_key'
60+
app.config['HONEYBADGER_ENVIRONMENT'] = os.getenv('FLASK_ENV')
61+
FlaskHoneybadger(app, report_exceptions=True)
62+
63+
# Also log ERROR/CRITICAL logs to Honeybadger
64+
class NoExceptionErrorFilter(logging.Filter):
65+
def filter(self, record):
66+
# But ignore Python logging exceptions on 'ERROR'
67+
return not record.getMessage().startswith('Exception on ')
68+
69+
hb_handler = HoneybadgerHandler(api_key=os.getenv('HONEYBADGER_API_KEY'))
70+
hb_handler.setLevel(logging.ERROR)
71+
hb_handler.addFilter(NoExceptionErrorFilter())
72+
logger = logging.getLogger()
73+
logger.addHandler(hb_handler)
74+
4575
# Index (a simple HTML response that will always succeed)
4676
@app.route('/')
4777
def root():

src/test.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,24 @@ def index():
1717
def test():
1818
return {}
1919

20+
# A simple failing request
21+
@test_routes.route('/test/exception')
22+
def test_exception():
23+
raise Exception("This is a test")
24+
return {}
25+
26+
# A simple post of an error message.
27+
@test_routes.route('/test/error')
28+
def test_error():
29+
logging.error("This is an error log.")
30+
return {}
31+
32+
# A simple post of a critical message.
33+
@test_routes.route('/test/critical')
34+
def test_critical():
35+
logging.critical("This is a critical log.")
36+
return {}
37+
2038
# Test numpy integration
2139
@test_routes.route('/test/numpy')
2240
def test_numpy():

0 commit comments

Comments
 (0)