logtail-python 0.4.2__tar.gz → 0.4.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {logtail_python-0.4.2 → logtail_python-0.4.3}/PKG-INFO +2 -2
- {logtail_python-0.4.2 → logtail_python-0.4.3}/logtail/__init__.py +1 -1
- {logtail_python-0.4.2 → logtail_python-0.4.3}/logtail/frame.py +6 -1
- {logtail_python-0.4.2 → logtail_python-0.4.3}/logtail/handler.py +10 -3
- {logtail_python-0.4.2 → logtail_python-0.4.3}/logtail_python.egg-info/PKG-INFO +2 -2
- {logtail_python-0.4.2 → logtail_python-0.4.3}/setup.py +1 -1
- {logtail_python-0.4.2 → logtail_python-0.4.3}/tests/test_frame.py +15 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/tests/test_handler.py +29 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/LICENSE.md +0 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/MANIFEST.in +0 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/README.md +0 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/logtail/compat.py +0 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/logtail/flusher.py +0 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/logtail/formatter.py +0 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/logtail/helpers.py +0 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/logtail/rq.py +0 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/logtail/uploader.py +0 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/logtail_python.egg-info/SOURCES.txt +0 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/logtail_python.egg-info/dependency_links.txt +0 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/logtail_python.egg-info/requires.txt +0 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/logtail_python.egg-info/top_level.txt +0 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/requirements.txt +0 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/setup.cfg +0 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/test-requirements.txt +0 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/tests/__init__.py +0 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/tests/test_flusher.py +0 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/tests/test_formatter.py +0 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/tests/test_helpers.py +0 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/tests/test_rq.py +0 -0
- {logtail_python-0.4.2 → logtail_python-0.4.3}/tests/test_uploader.py +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: logtail-python
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.3
|
|
4
4
|
Summary: Better Stack client library
|
|
5
5
|
Home-page: https://github.com/logtail/logtail-python
|
|
6
|
-
Download-URL: https://github.com/logtail/logtail-python/tarball/0.4.
|
|
6
|
+
Download-URL: https://github.com/logtail/logtail-python/tarball/0.4.3
|
|
7
7
|
Author: Logtail
|
|
8
8
|
Author-email: hello@logtail.com
|
|
9
9
|
License: ISC
|
|
@@ -93,4 +93,9 @@ def _relative_to_main_module_if_possible(pathname):
|
|
|
93
93
|
return _relative_to_main_module(pathname) if has_main_module else pathname
|
|
94
94
|
|
|
95
95
|
def _relative_to_main_module(pathname):
|
|
96
|
-
|
|
96
|
+
try:
|
|
97
|
+
return path.relpath(pathname, path.dirname(__main__.__file__))
|
|
98
|
+
except ValueError:
|
|
99
|
+
# Windows has no relative path between drives, and a PyInstaller build unpacks the
|
|
100
|
+
# script to the system drive while the application may run from another one.
|
|
101
|
+
return pathname
|
|
@@ -95,9 +95,16 @@ class LogtailHandler(logging.Handler):
|
|
|
95
95
|
raise e
|
|
96
96
|
|
|
97
97
|
def flush(self):
|
|
98
|
-
if self.flush_thread and self.flush_thread.is_alive():
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
if not (self.flush_thread and self.flush_thread.is_alive()):
|
|
99
|
+
return
|
|
100
|
+
if logging._lock._is_owned():
|
|
101
|
+
# logging.config.dictConfig() flushes the handlers it replaces while holding the global
|
|
102
|
+
# logging lock, and the worker's upload needs that lock whenever urllib3's logger has a
|
|
103
|
+
# level-cache miss, so waiting here could only deadlock. Nothing is lost: the worker
|
|
104
|
+
# keeps running and sends what is queued as soon as the lock is released.
|
|
105
|
+
return
|
|
106
|
+
if not self.flush_thread.flush(timeout=self.flush_timeout):
|
|
107
|
+
print('Gave up waiting for Better Stack uploads after {}s, logs are still buffered'.format(self.flush_timeout))
|
|
101
108
|
|
|
102
109
|
def _reset_after_fork(self):
|
|
103
110
|
# A forked child inherits the parent's queue with whatever was still buffered in it,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: logtail-python
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.3
|
|
4
4
|
Summary: Better Stack client library
|
|
5
5
|
Home-page: https://github.com/logtail/logtail-python
|
|
6
|
-
Download-URL: https://github.com/logtail/logtail-python/tarball/0.4.
|
|
6
|
+
Download-URL: https://github.com/logtail/logtail-python/tarball/0.4.3
|
|
7
7
|
Author: Logtail
|
|
8
8
|
Author-email: hello@logtail.com
|
|
9
9
|
License: ISC
|
|
@@ -4,9 +4,12 @@ from logtail.frame import create_frame
|
|
|
4
4
|
from logtail.handler import LogtailHandler
|
|
5
5
|
from logtail.helpers import LogtailContext
|
|
6
6
|
import datetime
|
|
7
|
+
import ntpath
|
|
7
8
|
import unittest
|
|
8
9
|
import logging
|
|
9
10
|
|
|
11
|
+
from unittest.mock import patch
|
|
12
|
+
|
|
10
13
|
class TestLogtailLogEntry(unittest.TestCase):
|
|
11
14
|
def test_create_frame_happy_path(self):
|
|
12
15
|
handler = LogtailHandler(source_token="some-source-token")
|
|
@@ -36,3 +39,15 @@ class TestLogtailLogEntry(unittest.TestCase):
|
|
|
36
39
|
|
|
37
40
|
frame = create_frame(log_record, log_record.getMessage(), LogtailContext(), include_extra_attributes=True)
|
|
38
41
|
self.assertIn('non_dict_key', frame)
|
|
42
|
+
|
|
43
|
+
@patch('logtail.frame.path', ntpath)
|
|
44
|
+
@patch('logtail.frame.__main__')
|
|
45
|
+
def test_create_frame_keeps_the_absolute_path_when_the_file_is_on_another_drive(self, main):
|
|
46
|
+
# PyInstaller unpacks the script to the system drive while the application's files stay
|
|
47
|
+
# on the drive it was started from, and Windows has no relative path between drives.
|
|
48
|
+
main.__file__ = 'C:\\Users\\zi\\AppData\\Local\\Temp\\_MEI61722\\main.py'
|
|
49
|
+
log_record = logging.LogRecord("logtail-test", 20, 'D:\\workspace\\app\\main.py', 10, "Some log message", [], None)
|
|
50
|
+
|
|
51
|
+
frame = create_frame(log_record, log_record.getMessage(), LogtailContext())
|
|
52
|
+
|
|
53
|
+
self.assertEqual(frame['context']['runtime']['file'], 'D:\\workspace\\app\\main.py')
|
|
@@ -411,6 +411,35 @@ class TestLogtailHandler(unittest.TestCase):
|
|
|
411
411
|
self.assertEqual(uploads, [['hello']])
|
|
412
412
|
self.assertTrue(handler.pipe.empty())
|
|
413
413
|
|
|
414
|
+
def test_flush_does_not_wait_while_the_caller_holds_the_logging_lock(self):
|
|
415
|
+
# logging.config.dictConfig() flushes the handlers it replaces while holding the global
|
|
416
|
+
# logging lock, and the worker's upload needs that lock whenever urllib3's logger has a
|
|
417
|
+
# level-cache miss, so waiting for the worker there can only deadlock.
|
|
418
|
+
logger = logging.getLogger(__name__)
|
|
419
|
+
logger.handlers = []
|
|
420
|
+
logger.setLevel(logging.INFO)
|
|
421
|
+
handler = LogtailHandler(source_token=self.source_token, flush_interval=0.01, check_interval=0.01, flush_timeout=2)
|
|
422
|
+
uploads = []
|
|
423
|
+
in_upload = threading.Event()
|
|
424
|
+
|
|
425
|
+
def upload(frame):
|
|
426
|
+
in_upload.set()
|
|
427
|
+
with logging._lock: # what urllib3's isEnabledFor() does on a level-cache miss
|
|
428
|
+
uploads.append([f['message'] for f in frame])
|
|
429
|
+
return mock.MagicMock(status_code=202)
|
|
430
|
+
|
|
431
|
+
handler.uploader = upload
|
|
432
|
+
logger.addHandler(handler)
|
|
433
|
+
self.addCleanup(self._stop_flush_worker, handler)
|
|
434
|
+
|
|
435
|
+
with logging._lock:
|
|
436
|
+
logger.info('hello')
|
|
437
|
+
self.assertTrue(in_upload.wait(2))
|
|
438
|
+
started = time.time()
|
|
439
|
+
handler.flush()
|
|
440
|
+
self.assertLess(time.time() - started, 0.5, 'flush() waited for a worker that needs the lock we hold')
|
|
441
|
+
self._wait_until(lambda: uploads == [['hello']])
|
|
442
|
+
|
|
414
443
|
def _wait_until(self, condition):
|
|
415
444
|
deadline = time.time() + 2
|
|
416
445
|
while not condition() and time.time() < deadline:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|