Skip to content

Commit 32f8507

Browse files
ensure extra events are serializable before uploading (#20)
Co-authored-by: Petr Heinz <[email protected]>
1 parent d206a32 commit 32f8507

File tree

2 files changed

+47
-2
lines changed

2 files changed

+47
-2
lines changed

logtail/handler.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# coding: utf-8
22
from __future__ import print_function, unicode_literals
33
import logging
4+
import json
45

56
from .compat import queue
67
from .helpers import DEFAULT_CONTEXT
@@ -60,8 +61,9 @@ def emit(self, record):
6061

6162
message = self.format(record)
6263
frame = create_frame(record, message, self.context, include_extra_attributes=self.include_extra_attributes)
64+
serializable_frame = json.loads(json.dumps(frame, default=str))
6365
try:
64-
self.pipe.put(frame, block=(not self.drop_extra_events))
66+
self.pipe.put(serializable_frame, block=(not self.drop_extra_events))
6567
except queue.Full:
6668
# Only raised when not blocking, which means that extra events
6769
# should be dropped.

tests/test_handler.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import unittest
77
import logging
88

9-
from logtail.handler import LogtailHandler
9+
from logtail import LogtailHandler, context
1010

1111

1212
class TestLogtailHandler(unittest.TestCase):
@@ -138,3 +138,46 @@ def test_error_suppression(self, MockWorker):
138138

139139
handler.raise_exceptions = False
140140
logger.critical('hello')
141+
142+
@mock.patch('logtail.handler.FlushWorker')
143+
def test_can_send_unserializable_extra_data(self, MockWorker):
144+
buffer_capacity = 1
145+
handler = LogtailHandler(
146+
source_token=self.source_token,
147+
buffer_capacity=buffer_capacity
148+
)
149+
150+
logger = logging.getLogger(__name__)
151+
logger.handlers = []
152+
logger.addHandler(handler)
153+
logger.info('hello', extra={'data': {'unserializable': UnserializableObject()}})
154+
155+
log_entry = handler.pipe.get()
156+
157+
self.assertEqual(log_entry['message'], 'hello')
158+
self.assertRegex(log_entry['data']['unserializable'], r'^<tests\.test_handler\.UnserializableObject object at 0x[0-f]+>$')
159+
self.assertTrue(handler.pipe.empty())
160+
161+
@mock.patch('logtail.handler.FlushWorker')
162+
def test_can_send_unserializable_extra_context(self, MockWorker):
163+
buffer_capacity = 1
164+
handler = LogtailHandler(
165+
source_token=self.source_token,
166+
buffer_capacity=buffer_capacity
167+
)
168+
169+
logger = logging.getLogger(__name__)
170+
logger.handlers = []
171+
logger.addHandler(handler)
172+
with context(data={'unserializable': UnserializableObject()}):
173+
logger.info('hello')
174+
175+
log_entry = handler.pipe.get()
176+
177+
self.assertEqual(log_entry['message'], 'hello')
178+
self.assertRegex(log_entry['context']['data']['unserializable'], r'^<tests\.test_handler\.UnserializableObject object at 0x[0-f]+>$')
179+
self.assertTrue(handler.pipe.empty())
180+
181+
182+
class UnserializableObject(object):
183+
""" Because this is a custom class, it cannot be serialized into JSON. """

0 commit comments

Comments
 (0)