Repository: scoutapp/scout_apm_python
Pull request #742 (2022-07-22 17:36:01)

If core agent raises a sigterm or sigquit log at debug level.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2d6a275..28894c1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,8 @@
 - Added Django 4.1 to the testing matrix.
 
 ### Fixed
+- Catch SIGQUIT and SIGTERM errors when running core agent. They will now
+  be logged as debug messages rather than exceptions.
 
 ## [2.25.0] 2022-05-12
 
diff --git a/src/scout_apm/core/agent/manager.py b/src/scout_apm/core/agent/manager.py
index 6c1a137..6258058 100644
--- a/src/scout_apm/core/agent/manager.py
+++ b/src/scout_apm/core/agent/manager.py
@@ -6,6 +6,7 @@ import hashlib
 import json
 import logging
 import os
+import signal
 import subprocess
 import tarfile
 import time
@@ -72,6 +73,12 @@ class CoreAgentManager(object):
                     close_fds=True,
                     stdout=devnull,
                 )
+        except subprocess.CalledProcessError as err:
+            if err.returncode in [signal.SIGTERM, signal.SIGQUIT]:
+                logger.debug("Core agent returned signal: {}".format(err.returncode))
+            else:
+                logger.exception("CalledProcessError running Core Agent")
+            return False
         except Exception:
             # TODO detect failure of launch properly
             logger.exception("Error running Core Agent")


Test patch:
diff --git a/tests/integration/core/agent/test_manager.py b/tests/integration/core/agent/test_manager.py
index 9b982dc..7b059ba 100644
--- a/tests/integration/core/agent/test_manager.py
+++ b/tests/integration/core/agent/test_manager.py
@@ -2,6 +2,8 @@
 from __future__ import absolute_import, division, print_function, unicode_literals
 
 import logging
+import signal
+import subprocess
 import time
 
 import pytest
@@ -124,3 +126,42 @@ def test_launch_error(caplog, core_agent_manager):
         ("scout_apm.core.agent.manager", logging.ERROR, "Error running Core Agent")
     ]
     assert caplog.records[0].exc_info[1] is exception
+
+
+@pytest.mark.parametrize(["signal_code"], [[signal.SIGQUIT], [signal.SIGTERM]])
+def test_launch_expected_signal_error(signal_code, caplog, core_agent_manager):
+    caplog.set_level(logging.ERROR)
+    exception = subprocess.CalledProcessError(signal_code, "err")
+    with mock.patch.object(
+        manager.CoreAgentManager,
+        "agent_binary",
+        side_effect=exception,
+    ):
+        result = core_agent_manager.launch()
+
+    assert not result
+    assert not core_agent_is_running()
+    # Caplog doesn't contain debug messages
+    assert caplog.record_tuples == []
+
+
+def test_launch_unexpected_signal_error(caplog, core_agent_manager):
+    caplog.set_level(logging.ERROR)
+    exception = subprocess.CalledProcessError(signal.SIGINT, "err")
+    with mock.patch.object(
+        manager.CoreAgentManager,
+        "agent_binary",
+        side_effect=exception,
+    ):
+        result = core_agent_manager.launch()
+
+    assert not result
+    assert not core_agent_is_running()
+    assert caplog.record_tuples == [
+        (
+            "scout_apm.core.agent.manager",
+            logging.ERROR,
+            "CalledProcessError running Core Agent",
+        )
+    ]
+    assert caplog.records[0].exc_info[1] is exception