Skip to content

Commit 383a088

Browse files
authored
catch and log exceptions in the interval timer function (#1145)
Instead of letting the thread die, we log the exception with a stack trace to ease debugging.
1 parent 3a50962 commit 383a088

File tree

2 files changed

+26
-5
lines changed

2 files changed

+26
-5
lines changed

elasticapm/utils/threading.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,13 @@
3030

3131
from __future__ import absolute_import
3232

33+
import logging
3334
import os
3435
import threading
3536
from timeit import default_timer
3637

38+
logger = logging.getLogger("elasticapm.utils.threading")
39+
3740

3841
class IntervalTimer(threading.Thread):
3942
"""
@@ -77,11 +80,15 @@ def run(self):
7780
# we've been cancelled, time to go home
7881
return
7982
start = default_timer()
80-
rval = self._function(*self._args, **self._kwargs)
81-
if self._evaluate_function_interval and isinstance(rval, (int, float)):
82-
interval_override = rval
83-
else:
84-
interval_override = None
83+
try:
84+
rval = self._function(*self._args, **self._kwargs)
85+
if self._evaluate_function_interval and isinstance(rval, (int, float)):
86+
interval_override = rval
87+
else:
88+
interval_override = None
89+
except Exception:
90+
logger.error("Exception in interval timer function", exc_info=True)
91+
8592
execution_time = default_timer() - start
8693

8794
def cancel(self):

tests/utils/threading_tests.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import mock
3333

3434
from elasticapm.utils.threading import IntervalTimer
35+
from tests.utils import assert_any_record_contains
3536

3637

3738
def test_interval_timer():
@@ -75,3 +76,16 @@ def test_interval_timer_interval_override_non_number():
7576
timer.cancel()
7677
time.sleep(0.05)
7778
assert not timer.is_alive()
79+
80+
81+
def test_interval_timer_exception(caplog):
82+
def my_func():
83+
return 1 / 0
84+
85+
with caplog.at_level("ERROR", "elasticapm.utils.threading"):
86+
timer = IntervalTimer(function=my_func, interval=0.1)
87+
timer.start()
88+
time.sleep(0.25)
89+
assert timer.is_alive()
90+
timer.cancel()
91+
assert_any_record_contains(caplog.records, "Exception in interval timer function")

0 commit comments

Comments
 (0)