Repository: scoutapp/scout_apm_python

Issue:
Support Queue timing in Python agent
Checking the request headers for officially supported frameworks like Django and Flask should be straight forward.

We should also have a generic API interface for recording Queue time in other cases.

Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ac97f7e..1ec6555 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@
 ### Fixed
 
 - Track path and user IP on Django < 1.10
+- The undocumented `core-agent-manager` CLI command works again
 
 ## [2.1.0] 2019-06-25
 
diff --git a/README.md b/README.md
index b9c3955..c1c5ba7 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,10 @@
 # Scout Python APM Agent
 
+[![travis](https://img.shields.io/travis/scoutapp/scout_apm_python/master.svg)](https://travis-ci.org/scoutapp/scout_apm_python)
+[![pypi](https://img.shields.io/pypi/v/scout-apm.svg)](https://pypi.python.org/pypi/scout-apm)
+[![docs](https://img.shields.io/badge/docs-read%20online-green.svg)](https://docs.scoutapm.com/#python-agent)
+[![black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/python/black)
+
 Monitor the performance of Python Django apps, Flask apps, and Celery workers with Scout's [Python APM Agent](https://www.scoutapm.com). Detailed performance metrics and transaction traces are collected once the `scout-apm` package is installed and configured.
 
 ![screenshot](https://s3-us-west-1.amazonaws.com/scout-blog/python_monitoring_release/python_monitoring_screenshot.png)
diff --git a/setup.cfg b/setup.cfg
index 1fee903..eaec295 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -11,9 +11,7 @@ ignore =
 
 [coverage:run]
 branch = True
-omit =
-    src/scout_apm/core/cli/core_agent_manager.py
-    src/scout_apm/core/monkey.py
+omit = src/scout_apm/core/monkey.py
 
 [flake8]
 # core
diff --git a/src/scout_apm/core/cli/core_agent_manager.py b/src/scout_apm/core/cli/core_agent_manager.py
index 98b9829..608ad1e 100755
--- a/src/scout_apm/core/cli/core_agent_manager.py
+++ b/src/scout_apm/core/cli/core_agent_manager.py
@@ -4,38 +4,31 @@ from __future__ import absolute_import, division, print_function, unicode_litera
 import argparse
 import logging
 
+from scout_apm.core import AgentContext, CoreAgentManager
 
-def download(**kwargs):
-    from scout_apm.core import CoreAgentManager
-
-    core_agent_manager = CoreAgentManager()
-    core_agent_manager.download()
-
-
-def launch(**kwargs):
-    from scout_apm.core import CoreAgentManager
-
-    core_agent_manager = CoreAgentManager()
-    core_agent_manager.launch()
+logger = logging.getLogger(__name__)
 
 
-def main(**kwargs):
+def main(argv=None):
     parser = argparse.ArgumentParser()
     parser.add_argument(
         "-v", "--verbose", help="increase output verbosity", action="count"
     )
 
-    subparsers = parser.add_subparsers(dest="subparser")
+    subparsers = parser.add_subparsers(
+        title="subcommands", description="valid subcommands", dest="subparser"
+    )
     subparsers.add_parser("download")
     subparsers.add_parser("launch")
 
-    args = parser.parse_args()
+    args = parser.parse_args(argv)
 
     if args.verbose is not None:
         if args.verbose >= 2:
-            logging.basicConfig(level=getattr(logging, "DEBUG", None))
-        elif args.verbose == 1:
-            logging.basicConfig(level=getattr(logging, "INFO", None))
+            logging.basicConfig(level=logging.DEBUG)
+        else:
+            logging.basicConfig(level=logging.INFO)
 
-    kwargs = vars(args)
-    globals()[kwargs.pop("subparser")](**kwargs)
+    AgentContext.build()
+    core_agent_manager = CoreAgentManager()
+    getattr(core_agent_manager, args.subparser)()


Test patch:
diff --git a/tests/unit/core/cli/test_core_agent_manager.py b/tests/unit/core/cli/test_core_agent_manager.py
new file mode 100644
index 0000000..313d5fe
--- /dev/null
+++ b/tests/unit/core/cli/test_core_agent_manager.py
@@ -0,0 +1,39 @@
+# coding=utf-8
+from __future__ import absolute_import, division, print_function, unicode_literals
+
+import logging
+
+import pytest
+
+from scout_apm.core.cli.core_agent_manager import main
+from tests.compat import mock
+
+
+@pytest.fixture(autouse=True)
+def mock_CoreAgentManager():
+    # Always mock out the actual CoreAgentManager class for these tests, to
+    # keep them quick
+    path = "scout_apm.core.cli.core_agent_manager.CoreAgentManager"
+    with mock.patch(path) as mock_obj:
+        yield mock_obj
+
+
+@mock.patch("scout_apm.core.cli.core_agent_manager.logging.basicConfig")
+@pytest.mark.parametrize(
+    "args, expected_level", [(["-v"], logging.INFO), (["-v", "-v"], logging.DEBUG)]
+)
+def test_logging_verbose(mock_basicConfig, args, expected_level):
+    # Have to use a mock for basicConfig since logging is already configured
+    # during tests
+    main(args + ["download"])
+
+    mock_basicConfig.assert_called_with(level=expected_level)
+
+
+@pytest.mark.parametrize("command", ["download", "launch"])
+def test_command(mock_CoreAgentManager, command):
+    main([command])
+
+    instance = mock_CoreAgentManager.return_value
+    method = getattr(instance, command)
+    method.assert_called_with()