Skip to content

Commit ff37475

Browse files
committed
Revert "contrib/django: remove deprecated LoggingHandler (elastic#2345)"
This reverts commit eb34e89.
1 parent b11d2cb commit ff37475

File tree

3 files changed

+106
-0
lines changed

3 files changed

+106
-0
lines changed

elasticapm/conf/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,11 @@ def setup_logging(handler):
887887
>>> client = ElasticAPM(...)
888888
>>> setup_logging(LoggingHandler(client))
889889
890+
Within Django:
891+
892+
>>> from elasticapm.contrib.django.handlers import LoggingHandler
893+
>>> setup_logging(LoggingHandler())
894+
890895
Returns a boolean based on if logging was configured or not.
891896
"""
892897
# TODO We should probably revisit this. Does it make more sense as

elasticapm/contrib/django/handlers.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,44 @@
3131

3232
from __future__ import absolute_import
3333

34+
import logging
3435
import sys
3536
import warnings
3637

3738
from django.conf import settings as django_settings
3839

40+
from elasticapm import get_client
41+
from elasticapm.handlers.logging import LoggingHandler as BaseLoggingHandler
42+
from elasticapm.utils.logging import get_logger
43+
44+
logger = get_logger("elasticapm.logging")
45+
46+
47+
class LoggingHandler(BaseLoggingHandler):
48+
def __init__(self, level=logging.NOTSET) -> None:
49+
warnings.warn(
50+
"The LoggingHandler is deprecated and will be removed in v7.0 of the agent. "
51+
"Please use `log_ecs_reformatting` and ship the logs with Elastic "
52+
"Agent or Filebeat instead. "
53+
"https://www.elastic.co/guide/en/apm/agent/python/current/logs.html",
54+
DeprecationWarning,
55+
)
56+
# skip initialization of BaseLoggingHandler
57+
logging.Handler.__init__(self, level=level)
58+
59+
@property
60+
def client(self):
61+
return get_client()
62+
63+
def _emit(self, record, **kwargs):
64+
from elasticapm.contrib.django.middleware import LogMiddleware
65+
66+
# Fetch the request from a threadlocal variable, if available
67+
request = getattr(LogMiddleware.thread, "request", None)
68+
request = getattr(record, "request", request)
69+
70+
return super(LoggingHandler, self)._emit(record, request=request, **kwargs)
71+
3972

4073
def exception_handler(client, request=None, **kwargs):
4174
def actually_do_stuff(request=None, **kwargs) -> None:

tests/contrib/django/django_tests.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
from elasticapm.conf.constants import ERROR, SPAN, TRANSACTION
6363
from elasticapm.contrib.django.apps import ElasticAPMConfig
6464
from elasticapm.contrib.django.client import client, get_client
65+
from elasticapm.contrib.django.handlers import LoggingHandler
6566
from elasticapm.contrib.django.middleware.wsgi import ElasticAPM
6667
from elasticapm.utils.disttracing import TraceParent
6768
from tests.contrib.django.conftest import BASE_TEMPLATE_DIR
@@ -409,6 +410,25 @@ def test_ignored_exception_is_ignored(django_elasticapm_client, client):
409410
assert len(django_elasticapm_client.events[ERROR]) == 0
410411

411412

413+
def test_record_none_exc_info(django_elasticapm_client):
414+
# sys.exc_info can return (None, None, None) if no exception is being
415+
# handled anywhere on the stack. See:
416+
# http://docs.python.org/library/sys.html#sys.exc_info
417+
record = logging.LogRecord(
418+
"foo", logging.INFO, pathname=None, lineno=None, msg="test", args=(), exc_info=(None, None, None)
419+
)
420+
handler = LoggingHandler()
421+
handler.emit(record)
422+
423+
assert len(django_elasticapm_client.events[ERROR]) == 1
424+
event = django_elasticapm_client.events[ERROR][0]
425+
426+
assert event["log"]["param_message"] == "test"
427+
assert event["log"]["logger_name"] == "foo"
428+
assert event["log"]["level"] == "info"
429+
assert "exception" not in event
430+
431+
412432
def test_404_middleware(django_elasticapm_client, client):
413433
with override_settings(
414434
**middleware_setting(django.VERSION, ["elasticapm.contrib.django.middleware.Catch404Middleware"])
@@ -1012,6 +1032,54 @@ def test_filter_matches_module_only(django_sending_elasticapm_client):
10121032
assert len(django_sending_elasticapm_client.httpserver.requests) == 1
10131033

10141034

1035+
def test_django_logging_request_kwarg(django_elasticapm_client):
1036+
handler = LoggingHandler()
1037+
1038+
logger = logging.getLogger(__name__)
1039+
logger.handlers = []
1040+
logger.addHandler(handler)
1041+
1042+
logger.error(
1043+
"This is a test error",
1044+
extra={
1045+
"request": WSGIRequest(
1046+
environ={
1047+
"wsgi.input": io.StringIO(),
1048+
"REQUEST_METHOD": "POST",
1049+
"SERVER_NAME": "testserver",
1050+
"SERVER_PORT": "80",
1051+
"CONTENT_TYPE": "application/json",
1052+
"ACCEPT": "application/json",
1053+
}
1054+
)
1055+
},
1056+
)
1057+
1058+
assert len(django_elasticapm_client.events[ERROR]) == 1
1059+
event = django_elasticapm_client.events[ERROR][0]
1060+
assert "request" in event["context"]
1061+
request = event["context"]["request"]
1062+
assert request["method"] == "POST"
1063+
1064+
1065+
def test_django_logging_middleware(django_elasticapm_client, client):
1066+
handler = LoggingHandler()
1067+
1068+
logger = logging.getLogger("logmiddleware")
1069+
logger.handlers = []
1070+
logger.addHandler(handler)
1071+
logger.level = logging.INFO
1072+
1073+
with override_settings(
1074+
**middleware_setting(django.VERSION, ["elasticapm.contrib.django.middleware.LogMiddleware"])
1075+
):
1076+
client.get(reverse("elasticapm-logging"))
1077+
assert len(django_elasticapm_client.events[ERROR]) == 1
1078+
event = django_elasticapm_client.events[ERROR][0]
1079+
assert "request" in event["context"]
1080+
assert event["context"]["request"]["url"]["pathname"] == reverse("elasticapm-logging")
1081+
1082+
10151083
def client_get(client, url):
10161084
return client.get(url)
10171085

0 commit comments

Comments
 (0)