Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1162 from openhealthcare/add-elcid-logging-into-opal
Add elcid the elcid loggers into opal.
- Loading branch information
Showing
7 changed files
with
232 additions
and
57 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# opal.core.log.ConfidentialEmailer | ||
|
||
A confidential emailer that does not send the stack trace but provides the | ||
file name and error line that the issue happened. Along with the host name and | ||
user who had the issue. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
""" | ||
Declare our current version string | ||
""" | ||
__version__ = '0.8.2.1' | ||
__version__ = '0.8.2.2' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
from django.utils.log import AdminEmailHandler | ||
from django.conf import settings | ||
|
||
|
||
class ConfidentialEmailer(AdminEmailHandler): | ||
def __init__(self, *args, **kwargs): | ||
super(ConfidentialEmailer, self).__init__(*args, **kwargs) | ||
self.include_html = False | ||
|
||
def get_brand_name(self): | ||
return getattr(settings, "OPAL_BRAND_NAME", "Unnamed Opal app") | ||
|
||
def format_subject(self, subject): | ||
return "{} error".format(self.get_brand_name()) | ||
|
||
def emit(self, record): | ||
record.msg = 'Potentially identifiable data suppressed' | ||
record.args = [] | ||
detail = "" | ||
if hasattr(record, "request") and record.request: | ||
if record.request.user.is_authenticated(): | ||
user = record.request.user.username | ||
else: | ||
user = "anonymous" | ||
|
||
m = "Request to host {0} on application {1} from user {2} with {3}" | ||
|
||
detail = m.format( | ||
record.request.META.get("HTTP_HOST"), | ||
self.get_brand_name(), | ||
user, | ||
record.request.META.get("REQUEST_METHOD"), | ||
) | ||
record.request = None | ||
|
||
record.exc_text = "Exception raised at {0}:{1}".format( | ||
record.filename, | ||
record.lineno | ||
) | ||
|
||
record.exc_text += "\n{}".format(detail) | ||
return super(ConfidentialEmailer, self).emit(record) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import logging | ||
import mock | ||
from django.test import override_settings | ||
from django.conf import settings | ||
from opal.core.test import OpalTestCase | ||
from opal.core.log import ConfidentialEmailer | ||
|
||
|
||
# we mock the stream handler because we don't want | ||
# unnecessary logging critical statements when running tests | ||
@override_settings(DEBUG=False, OPAL_BRAND_NAME="Amazing Opal App") | ||
@mock.patch('logging.StreamHandler.emit') | ||
@mock.patch('django.utils.log.AdminEmailHandler.send_mail') | ||
class LogOutputTestCase(OpalTestCase): | ||
def test_request_logging_critical(self, send_mail, stream_handler): | ||
logger = logging.getLogger('django.request') | ||
logger.error('confidential error') | ||
self.assertTrue(send_mail.called) | ||
expected_subject = "Amazing Opal App error" | ||
expected_body = "Potentially identifiable data suppressed" | ||
call_args = send_mail.call_args | ||
self.assertEqual(expected_subject, call_args[0][0]) | ||
self.assertIn(expected_body, call_args[0][1]) | ||
self.assertEqual(call_args[1]["html_message"], None) | ||
|
||
def test_request_logging_with_arguments(self, send_mail, stream_handler): | ||
logger = logging.getLogger('django.request') | ||
logger.error('%s error', "confidential") | ||
self.assertTrue(send_mail.called) | ||
expected_subject = "Amazing Opal App error" | ||
expected_body = "Potentially identifiable data suppressed" | ||
call_args = send_mail.call_args | ||
self.assertEqual(expected_subject, call_args[0][0]) | ||
self.assertIn(expected_body, call_args[0][1]) | ||
self.assertEqual(call_args[1]["html_message"], None) | ||
|
||
@mock.patch('opal.core.log.AdminEmailHandler.emit') | ||
def test_record_formatting(self, emitter, send_mail, stream_handler): | ||
emailer = ConfidentialEmailer() | ||
record = mock.MagicMock() | ||
record.exc_text = "confidential" | ||
record.args = ["some_args"] | ||
record.filename = "some_file.py" | ||
record.lineno = 20 | ||
request = self.rf.get("/some/url") | ||
request.user = self.user | ||
request.session = {} | ||
record.request = request | ||
emailer.emit(record) | ||
self.assertEqual( | ||
emitter.call_args[0][0].exc_text, | ||
"Exception raised at some_file.py:20\nRequest to host None on application Amazing Opal App from user testuser with GET" | ||
) | ||
|
||
@mock.patch('opal.core.log.AdminEmailHandler.emit') | ||
def test_anonymous_user_record_formatting(self, emitter, send_mail, stream_handler): | ||
emailer = ConfidentialEmailer() | ||
record = mock.MagicMock() | ||
record.exc_text = "confidential" | ||
record.args = ["some_args"] | ||
record.filename = "some_file.py" | ||
record.lineno = 20 | ||
request = self.rf.get("/some/url") | ||
request.user = self.user | ||
|
||
request.session = {} | ||
record.request = request | ||
record.request.META = mock.MagicMock() | ||
mock_meta_dict = dict(HTTP_HOST="somewhere", REQUEST_METHOD="GET") | ||
record.request.META.get.side_effect = lambda x: mock_meta_dict[x] | ||
|
||
with mock.patch.object(request.user, "is_authenticated") as is_authenticated: | ||
is_authenticated.return_value = False | ||
emailer.emit(record) | ||
self.assertEqual( | ||
emitter.call_args[0][0].exc_text, | ||
"Exception raised at some_file.py:20\nRequest to host somewhere on application Amazing Opal App from user anonymous with GET" | ||
) | ||
|
||
def test_no_email_on_info(self, send_mail, stream_handler): | ||
logger = logging.getLogger('django.request') | ||
logger.info('%s error', "confidential") | ||
self.assertFalse(send_mail.called) | ||
|
||
def handle_brand_name(self, emitter, send_mail, stream_handler): | ||
del settings.OPAL_BRAND_NAME | ||
logger = logging.getLogger('django.request') | ||
logger.error('confidential error') | ||
self.assertTrue(send_mail.called) | ||
expected_subject = "unamed opal app error" | ||
call_args = send_mail.call_args | ||
self.assertEqual(expected_subject, call_args[0][0]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters