We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
AttributeError: 'NPlusOneCallSet' object has no attribute 'should_capture_bracktrace'
When trying to upgrade to 1.1.8, I ran into this exception:

```
   File "celery/app/trace.py", line 374, in trace_task
    R = retval = fun(*args, **kwargs)
  File "myapp/celery/worker.py", line 49, in __call__
    return super().__call__(*args, **kwargs)
  File "celery/app/trace.py", line 629, in __protected_call__
    return self.run(*args, **kwargs)
  File "myapp/celery/tasks.py", line 129, in sync_backend_wagers
    retry = sync.race_wagers_sync(race_id, backend)
  File "myapp/libs/sync.py", line 52, in race_wagers_sync
    race = ents.Race.query.get(race_id)
  File "sqlalchemy/orm/query.py", line 871, in get
    ident, loading.load_on_ident)
  File "sqlalchemy/orm/query.py", line 905, in _get_impl
    return fallback_fn(self, key)
  File "sqlalchemy/orm/loading.py", line 231, in load_on_ident
    return q.one()
  File "sqlalchemy/orm/query.py", line 2837, in one
    ret = self.one_or_none()
  File "sqlalchemy/orm/query.py", line 2807, in one_or_none
    ret = list(self)
  File "sqlalchemy/orm/query.py", line 2878, in __iter__
    return self._execute_and_instances(context)
  File "sqlalchemy/orm/query.py", line 2901, in _execute_and_instances
    result = conn.execute(querycontext.statement, self._params)
  File "sqlalchemy/engine/base.py", line 948, in execute
    return meth(self, multiparams, params)
  File "sqlalchemy/sql/elements.py", line 269, in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
  File "sqlalchemy/engine/base.py", line 1060, in _execute_clauseelement
    compiled_sql, distilled_params
  File "sqlalchemy/engine/base.py", line 1207, in _execute_context
    context.executemany)
  File "sqlalchemy/event/attr.py", line 256, in __call__
    fn(*args, **kw)
  File "scout_apm/sqlalchemy/__init__.py", line 16, in after_cursor_execute
    if tr.callset.should_capture_bracktrace(statement) is True:
  AttributeError: 'NPlusOneCallSet' object has no attribute 'should_capture_bracktrace'
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/scout_apm/sqlalchemy/__init__.py`
Content:
```
1 from scout_apm.core.tracked_request import TrackedRequest
2 
3 from sqlalchemy import event
4 
5 def instrument_sqlalchemy(engine):
6     def before_cursor_execute(conn, cursor, statement, parameters, context, executemany):
7         tr = TrackedRequest.instance()
8         span = tr.start_span(operation='SQL/Query')
9         span.tag('db.statement', statement)
10 
11     def after_cursor_execute(conn, cursor, statement, parameters, context, executemany):
12         tr = TrackedRequest.instance()
13         span = tr.current_span()
14         if span is not None:
15             tr.callset.update(statement, 1, span.duration())
16             if tr.callset.should_capture_bracktrace(statement) is True:
17                 span.capture_backtrace()
18         tr.stop_span()
19 
20     if getattr(engine, "_scout_instrumented", False) != True:
21         event.listen(engine, 'before_cursor_execute', before_cursor_execute)
22         event.listen(engine, 'after_cursor_execute', after_cursor_execute)
23         setattr(engine, "_scout_instrumented", True)
24
```

Path: `setup.py`
Content:
```
1 from glob import glob
2 from os.path import basename, splitext
3 
4 from setuptools import find_packages, setup
5 
6 setup(name='scout_apm',
7       version='1.1.8',
8       description='Scout Application Performance Monitoring Agent',
9       long_description='Scout Application Performance Monitoring Agent',
10       url='https://github.com/scoutapp/scout_apm_python',
11       author='Scout',
12       author_email='support@scoutapp.com',
13       license='MIT',
14       zip_safe=False,
15       python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4',
16       packages=find_packages('src'),
17       package_dir={'': 'src'},
18       py_modules=[splitext(basename(path))[0] for path in glob('src/*.py')],
19       entry_points={
20           'console_scripts': [
21               'core-agent-manager = scout_apm.core.cli.core_agent_manager:main'
22           ]
23       },
24       install_requires=['psutil', 'PyYAML', 'requests'],
25       keywords='apm performance monitoring development',
26       classifiers=[
27         'Development Status :: 3 - Alpha',
28         'Intended Audience :: Developers',
29         'Topic :: System :: Monitoring',
30         'License :: Other/Proprietary License',
31         'Operating System :: MacOS',
32         'Operating System :: POSIX',
33         'Operating System :: POSIX :: Linux',
34         'Programming Language :: Python :: 2',
35         'Programming Language :: Python :: 2.7',
36         'Programming Language :: Python :: 3',
37         'Programming Language :: Python :: 3.4',
38         'Programming Language :: Python :: 3.5',
39         'Programming Language :: Python :: 3.6',
40         'Programming Language :: Python :: 3.7',
41       ])
42
```

Path: `src/scout_apm/core/tracked_request.py`
Content:
```
1 from __future__ import absolute_import
2 
3 import logging
4 from datetime import datetime
5 from uuid import uuid4
6 
7 from scout_apm.core.samplers import Samplers
8 from scout_apm.core.request_manager import RequestManager
9 from scout_apm.core.thread_local import ThreadLocalSingleton
10 from scout_apm.core.n_plus_one_call_set import NPlusOneCallSet
11 import scout_apm.core.backtrace
12 
13 # Logging
14 logger = logging.getLogger(__name__)
15 
16 
17 class TrackedRequest(ThreadLocalSingleton):
18     """
19     This is a container which keeps track of all module instances for a single
20     request. For convenience they are made available as attributes based on
21     their keyname
22     """
23     def __init__(self, *args, **kwargs):
24         self.req_id = 'req-' + str(uuid4())
25         self.start_time = kwargs.get('start_time', datetime.utcnow())
26         self.end_time = kwargs.get('end_time', None)
27         self.active_spans = kwargs.get('active_spans', [])
28         self.complete_spans = kwargs.get('complete_spans', [])
29         self.tags = kwargs.get('tags', {})
30         self.real_request = kwargs.get('real_request', False)
31         self.callset = NPlusOneCallSet()
32         logger.debug('Starting request: %s', self.req_id)
33 
34     def mark_real_request(self):
35         self.real_request = True
36 
37     def is_real_request(self):
38         return self.real_request
39 
40     def tag(self, key, value):
41         if key in self.tags:
42             logger.debug('Overwriting previously set tag for request %s: %s' % self.req_id, key)
43         self.tags[key] = value
44 
45     def start_span(self, operation=None):
46         maybe_parent = self.current_span()
47 
48         if maybe_parent is not None:
49             parent_id = maybe_parent.span_id
50         else:
51             parent_id = None
52 
53         new_span = Span(
54             request_id=self.req_id,
55             operation=operation,
56             parent=parent_id)
57         self.active_spans.append(new_span)
58         return new_span
59 
60     def stop_span(self):
61         stopping_span = None
62         try:
63             stopping_span = self.active_spans.pop()
64         except IndexError as e:
65             logger.debug('Exception when stopping span: %s' % repr(e))
66 
67         if stopping_span is not None:
68             stopping_span.stop()
69             stopping_span.annotate()
70             self.complete_spans.append(stopping_span)
71 
72         if len(self.active_spans) == 0:
73             self.finish()
74 
75     def current_span(self):
76         if len(self.active_spans) > 0:
77             return self.active_spans[-1]
78         else:
79             return None
80 
81     # Request is done, release any info we have about it.
82     def finish(self):
83         logger.debug('Stopping request: %s', self.req_id)
84         if self.end_time is None:
85             self.end_time = datetime.utcnow()
86         RequestManager.instance().add_request(self)
87         if self.is_real_request():
88             Samplers.ensure_running()
89 
90         # This can fail if the Tracked Request was created directly, not through instance()
91         try:
92             self.release()
93         except:
94             pass
95 
96 
97 class Span:
98     def __init__(self, *args, **kwargs):
99         self.span_id = kwargs.get('span_id', 'span-' + str(uuid4()))
100         self.start_time = kwargs.get('start_time', datetime.utcnow())
101         self.end_time = kwargs.get('end_time', None)
102         self.request_id = kwargs.get('request_id', None)
103         self.operation = kwargs.get('operation', None)
104         self.parent = kwargs.get('parent', None)
105         self.tags = kwargs.get('tags', {})
106 
107     def stop(self):
108         self.end_time = datetime.utcnow()
109 
110     def tag(self, key, value):
111         if key in self.tags:
112             logger.debug('Overwriting previously set tag for span %s: %s' % self.span_id, key)
113         self.tags[key] = value
114 
115     # In seconds
116     def duration(self):
117         if self.end_time is not None:
118             return (self.end_time - self.start_time).total_seconds()
119         else:
120             # Current, running duration
121             return (datetime.utcnow() - self.start_time).total_seconds()
122 
123     def duration_in_ms(self):
124         return self.duration() / 1000
125 
126     # Add any interesting annotations to the span. Assumes that we are in the
127     # process of stopping this span.
128     def annotate(self):
129         slow_threshold = 0.500
130         if self.duration() > slow_threshold:
131             self.capture_backtrace()
132 
133     def capture_backtrace(self):
134         stack = scout_apm.core.backtrace.capture()
135         self.tag('stack', stack)
136
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -4,7 +4,7 @@
 from setuptools import find_packages, setup
 
 setup(name='scout_apm',
-      version='1.1.8',
+      version='1.1.9',
       description='Scout Application Performance Monitoring Agent',
       long_description='Scout Application Performance Monitoring Agent',
       url='https://github.com/scoutapp/scout_apm_python',
@@ -12,7 +12,7 @@
       author_email='support@scoutapp.com',
       license='MIT',
       zip_safe=False,
-      python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4',
+      python_requires='>=3.4, <4',
       packages=find_packages('src'),
       package_dir={'': 'src'},
       py_modules=[splitext(basename(path))[0] for path in glob('src/*.py')],
@@ -31,8 +31,6 @@
         'Operating System :: MacOS',
         'Operating System :: POSIX',
         'Operating System :: POSIX :: Linux',
-        'Programming Language :: Python :: 2',
-        'Programming Language :: Python :: 2.7',
         'Programming Language :: Python :: 3',
         'Programming Language :: Python :: 3.4',
         'Programming Language :: Python :: 3.5',
diff --git a/src/scout_apm/core/tracked_request.py b/src/scout_apm/core/tracked_request.py
--- a/src/scout_apm/core/tracked_request.py
+++ b/src/scout_apm/core/tracked_request.py
@@ -39,7 +39,7 @@
 
     def tag(self, key, value):
         if key in self.tags:
-            logger.debug('Overwriting previously set tag for request %s: %s' % self.req_id, key)
+            logger.debug('Overwriting previously set tag for request %s: %s' % (self.req_id, key))
         self.tags[key] = value
 
     def start_span(self, operation=None):
@@ -109,7 +109,7 @@
 
     def tag(self, key, value):
         if key in self.tags:
-            logger.debug('Overwriting previously set tag for span %s: %s' % self.span_id, key)
+            logger.debug('Overwriting previously set tag for span %s: %s' % (self.span_id, key))
         self.tags[key] = value
 
     # In seconds
diff --git a/src/scout_apm/sqlalchemy/__init__.py b/src/scout_apm/sqlalchemy/__init__.py
--- a/src/scout_apm/sqlalchemy/__init__.py
+++ b/src/scout_apm/sqlalchemy/__init__.py
@@ -13,7 +13,7 @@
         span = tr.current_span()
         if span is not None:
             tr.callset.update(statement, 1, span.duration())
-            if tr.callset.should_capture_bracktrace(statement) is True:
+            if tr.callset.should_capture_backtrace(statement) is True:
                 span.capture_backtrace()
         tr.stop_span()

{"golden_diff": "diff --git a/setup.py b/setup.py\n--- a/setup.py\n+++ b/setup.py\n@@ -4,7 +4,7 @@\n from setuptools import find_packages, setup\n \n setup(name='scout_apm',\n-      version='1.1.8',\n+      version='1.1.9',\n       description='Scout Application Performance Monitoring Agent',\n       long_description='Scout Application Performance Monitoring Agent',\n       url='https://github.com/scoutapp/scout_apm_python',\n@@ -12,7 +12,7 @@\n       author_email='support@scoutapp.com',\n       license='MIT',\n       zip_safe=False,\n-      python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4',\n+      python_requires='>=3.4, <4',\n       packages=find_packages('src'),\n       package_dir={'': 'src'},\n       py_modules=[splitext(basename(path))[0] for path in glob('src/*.py')],\n@@ -31,8 +31,6 @@\n         'Operating System :: MacOS',\n         'Operating System :: POSIX',\n         'Operating System :: POSIX :: Linux',\n-        'Programming Language :: Python :: 2',\n-        'Programming Language :: Python :: 2.7',\n         'Programming Language :: Python :: 3',\n         'Programming Language :: Python :: 3.4',\n         'Programming Language :: Python :: 3.5',\ndiff --git a/src/scout_apm/core/tracked_request.py b/src/scout_apm/core/tracked_request.py\n--- a/src/scout_apm/core/tracked_request.py\n+++ b/src/scout_apm/core/tracked_request.py\n@@ -39,7 +39,7 @@\n \n     def tag(self, key, value):\n         if key in self.tags:\n-            logger.debug('Overwriting previously set tag for request %s: %s' % self.req_id, key)\n+            logger.debug('Overwriting previously set tag for request %s: %s' % (self.req_id, key))\n         self.tags[key] = value\n \n     def start_span(self, operation=None):\n@@ -109,7 +109,7 @@\n \n     def tag(self, key, value):\n         if key in self.tags:\n-            logger.debug('Overwriting previously set tag for span %s: %s' % self.span_id, key)\n+            logger.debug('Overwriting previously set tag for span %s: %s' % (self.span_id, key))\n         self.tags[key] = value\n \n     # In seconds\ndiff --git a/src/scout_apm/sqlalchemy/__init__.py b/src/scout_apm/sqlalchemy/__init__.py\n--- a/src/scout_apm/sqlalchemy/__init__.py\n+++ b/src/scout_apm/sqlalchemy/__init__.py\n@@ -13,7 +13,7 @@\n         span = tr.current_span()\n         if span is not None:\n             tr.callset.update(statement, 1, span.duration())\n-            if tr.callset.should_capture_bracktrace(statement) is True:\n+            if tr.callset.should_capture_backtrace(statement) is True:\n                 span.capture_backtrace()\n         tr.stop_span()\n", "issue": "AttributeError: 'NPlusOneCallSet' object has no attribute 'should_capture_bracktrace'\nWhen trying to upgrade to 1.1.8, I ran into this exception:\r\n\r\n```\r\n   File \"celery/app/trace.py\", line 374, in trace_task\r\n    R = retval = fun(*args, **kwargs)\r\n  File \"myapp/celery/worker.py\", line 49, in __call__\r\n    return super().__call__(*args, **kwargs)\r\n  File \"celery/app/trace.py\", line 629, in __protected_call__\r\n    return self.run(*args, **kwargs)\r\n  File \"myapp/celery/tasks.py\", line 129, in sync_backend_wagers\r\n    retry = sync.race_wagers_sync(race_id, backend)\r\n  File \"myapp/libs/sync.py\", line 52, in race_wagers_sync\r\n    race = ents.Race.query.get(race_id)\r\n  File \"sqlalchemy/orm/query.py\", line 871, in get\r\n    ident, loading.load_on_ident)\r\n  File \"sqlalchemy/orm/query.py\", line 905, in _get_impl\r\n    return fallback_fn(self, key)\r\n  File \"sqlalchemy/orm/loading.py\", line 231, in load_on_ident\r\n    return q.one()\r\n  File \"sqlalchemy/orm/query.py\", line 2837, in one\r\n    ret = self.one_or_none()\r\n  File \"sqlalchemy/orm/query.py\", line 2807, in one_or_none\r\n    ret = list(self)\r\n  File \"sqlalchemy/orm/query.py\", line 2878, in __iter__\r\n    return self._execute_and_instances(context)\r\n  File \"sqlalchemy/orm/query.py\", line 2901, in _execute_and_instances\r\n    result = conn.execute(querycontext.statement, self._params)\r\n  File \"sqlalchemy/engine/base.py\", line 948, in execute\r\n    return meth(self, multiparams, params)\r\n  File \"sqlalchemy/sql/elements.py\", line 269, in _execute_on_connection\r\n    return connection._execute_clauseelement(self, multiparams, params)\r\n  File \"sqlalchemy/engine/base.py\", line 1060, in _execute_clauseelement\r\n    compiled_sql, distilled_params\r\n  File \"sqlalchemy/engine/base.py\", line 1207, in _execute_context\r\n    context.executemany)\r\n  File \"sqlalchemy/event/attr.py\", line 256, in __call__\r\n    fn(*args, **kw)\r\n  File \"scout_apm/sqlalchemy/__init__.py\", line 16, in after_cursor_execute\r\n    if tr.callset.should_capture_bracktrace(statement) is True:\r\n  AttributeError: 'NPlusOneCallSet' object has no attribute 'should_capture_bracktrace'\r\n```\n", "before_files": [{"content": "from scout_apm.core.tracked_request import TrackedRequest\n\nfrom sqlalchemy import event\n\ndef instrument_sqlalchemy(engine):\n    def before_cursor_execute(conn, cursor, statement, parameters, context, executemany):\n        tr = TrackedRequest.instance()\n        span = tr.start_span(operation='SQL/Query')\n        span.tag('db.statement', statement)\n\n    def after_cursor_execute(conn, cursor, statement, parameters, context, executemany):\n        tr = TrackedRequest.instance()\n        span = tr.current_span()\n        if span is not None:\n            tr.callset.update(statement, 1, span.duration())\n            if tr.callset.should_capture_bracktrace(statement) is True:\n                span.capture_backtrace()\n        tr.stop_span()\n\n    if getattr(engine, \"_scout_instrumented\", False) != True:\n        event.listen(engine, 'before_cursor_execute', before_cursor_execute)\n        event.listen(engine, 'after_cursor_execute', after_cursor_execute)\n        setattr(engine, \"_scout_instrumented\", True)\n", "path": "src/scout_apm/sqlalchemy/__init__.py"}, {"content": "from glob import glob\nfrom os.path import basename, splitext\n\nfrom setuptools import find_packages, setup\n\nsetup(name='scout_apm',\n      version='1.1.8',\n      description='Scout Application Performance Monitoring Agent',\n      long_description='Scout Application Performance Monitoring Agent',\n      url='https://github.com/scoutapp/scout_apm_python',\n      author='Scout',\n      author_email='support@scoutapp.com',\n      license='MIT',\n      zip_safe=False,\n      python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4',\n      packages=find_packages('src'),\n      package_dir={'': 'src'},\n      py_modules=[splitext(basename(path))[0] for path in glob('src/*.py')],\n      entry_points={\n          'console_scripts': [\n              'core-agent-manager = scout_apm.core.cli.core_agent_manager:main'\n          ]\n      },\n      install_requires=['psutil', 'PyYAML', 'requests'],\n      keywords='apm performance monitoring development',\n      classifiers=[\n        'Development Status :: 3 - Alpha',\n        'Intended Audience :: Developers',\n        'Topic :: System :: Monitoring',\n        'License :: Other/Proprietary License',\n        'Operating System :: MacOS',\n        'Operating System :: POSIX',\n        'Operating System :: POSIX :: Linux',\n        'Programming Language :: Python :: 2',\n        'Programming Language :: Python :: 2.7',\n        'Programming Language :: Python :: 3',\n        'Programming Language :: Python :: 3.4',\n        'Programming Language :: Python :: 3.5',\n        'Programming Language :: Python :: 3.6',\n        'Programming Language :: Python :: 3.7',\n      ])\n", "path": "setup.py"}, {"content": "from __future__ import absolute_import\n\nimport logging\nfrom datetime import datetime\nfrom uuid import uuid4\n\nfrom scout_apm.core.samplers import Samplers\nfrom scout_apm.core.request_manager import RequestManager\nfrom scout_apm.core.thread_local import ThreadLocalSingleton\nfrom scout_apm.core.n_plus_one_call_set import NPlusOneCallSet\nimport scout_apm.core.backtrace\n\n# Logging\nlogger = logging.getLogger(__name__)\n\n\nclass TrackedRequest(ThreadLocalSingleton):\n    \"\"\"\n    This is a container which keeps track of all module instances for a single\n    request. For convenience they are made available as attributes based on\n    their keyname\n    \"\"\"\n    def __init__(self, *args, **kwargs):\n        self.req_id = 'req-' + str(uuid4())\n        self.start_time = kwargs.get('start_time', datetime.utcnow())\n        self.end_time = kwargs.get('end_time', None)\n        self.active_spans = kwargs.get('active_spans', [])\n        self.complete_spans = kwargs.get('complete_spans', [])\n        self.tags = kwargs.get('tags', {})\n        self.real_request = kwargs.get('real_request', False)\n        self.callset = NPlusOneCallSet()\n        logger.debug('Starting request: %s', self.req_id)\n\n    def mark_real_request(self):\n        self.real_request = True\n\n    def is_real_request(self):\n        return self.real_request\n\n    def tag(self, key, value):\n        if key in self.tags:\n            logger.debug('Overwriting previously set tag for request %s: %s' % self.req_id, key)\n        self.tags[key] = value\n\n    def start_span(self, operation=None):\n        maybe_parent = self.current_span()\n\n        if maybe_parent is not None:\n            parent_id = maybe_parent.span_id\n        else:\n            parent_id = None\n\n        new_span = Span(\n            request_id=self.req_id,\n            operation=operation,\n            parent=parent_id)\n        self.active_spans.append(new_span)\n        return new_span\n\n    def stop_span(self):\n        stopping_span = None\n        try:\n            stopping_span = self.active_spans.pop()\n        except IndexError as e:\n            logger.debug('Exception when stopping span: %s' % repr(e))\n\n        if stopping_span is not None:\n            stopping_span.stop()\n            stopping_span.annotate()\n            self.complete_spans.append(stopping_span)\n\n        if len(self.active_spans) == 0:\n            self.finish()\n\n    def current_span(self):\n        if len(self.active_spans) > 0:\n            return self.active_spans[-1]\n        else:\n            return None\n\n    # Request is done, release any info we have about it.\n    def finish(self):\n        logger.debug('Stopping request: %s', self.req_id)\n        if self.end_time is None:\n            self.end_time = datetime.utcnow()\n        RequestManager.instance().add_request(self)\n        if self.is_real_request():\n            Samplers.ensure_running()\n\n        # This can fail if the Tracked Request was created directly, not through instance()\n        try:\n            self.release()\n        except:\n            pass\n\n\nclass Span:\n    def __init__(self, *args, **kwargs):\n        self.span_id = kwargs.get('span_id', 'span-' + str(uuid4()))\n        self.start_time = kwargs.get('start_time', datetime.utcnow())\n        self.end_time = kwargs.get('end_time', None)\n        self.request_id = kwargs.get('request_id', None)\n        self.operation = kwargs.get('operation', None)\n        self.parent = kwargs.get('parent', None)\n        self.tags = kwargs.get('tags', {})\n\n    def stop(self):\n        self.end_time = datetime.utcnow()\n\n    def tag(self, key, value):\n        if key in self.tags:\n            logger.debug('Overwriting previously set tag for span %s: %s' % self.span_id, key)\n        self.tags[key] = value\n\n    # In seconds\n    def duration(self):\n        if self.end_time is not None:\n            return (self.end_time - self.start_time).total_seconds()\n        else:\n            # Current, running duration\n            return (datetime.utcnow() - self.start_time).total_seconds()\n\n    def duration_in_ms(self):\n        return self.duration() / 1000\n\n    # Add any interesting annotations to the span. Assumes that we are in the\n    # process of stopping this span.\n    def annotate(self):\n        slow_threshold = 0.500\n        if self.duration() > slow_threshold:\n            self.capture_backtrace()\n\n    def capture_backtrace(self):\n        stack = scout_apm.core.backtrace.capture()\n        self.tag('stack', stack)\n", "path": "src/scout_apm/core/tracked_request.py"}], "after_files": [{"content": "from scout_apm.core.tracked_request import TrackedRequest\n\nfrom sqlalchemy import event\n\ndef instrument_sqlalchemy(engine):\n    def before_cursor_execute(conn, cursor, statement, parameters, context, executemany):\n        tr = TrackedRequest.instance()\n        span = tr.start_span(operation='SQL/Query')\n        span.tag('db.statement', statement)\n\n    def after_cursor_execute(conn, cursor, statement, parameters, context, executemany):\n        tr = TrackedRequest.instance()\n        span = tr.current_span()\n        if span is not None:\n            tr.callset.update(statement, 1, span.duration())\n            if tr.callset.should_capture_backtrace(statement) is True:\n                span.capture_backtrace()\n        tr.stop_span()\n\n    if getattr(engine, \"_scout_instrumented\", False) != True:\n        event.listen(engine, 'before_cursor_execute', before_cursor_execute)\n        event.listen(engine, 'after_cursor_execute', after_cursor_execute)\n        setattr(engine, \"_scout_instrumented\", True)\n", "path": "src/scout_apm/sqlalchemy/__init__.py"}, {"content": "from glob import glob\nfrom os.path import basename, splitext\n\nfrom setuptools import find_packages, setup\n\nsetup(name='scout_apm',\n      version='1.1.9',\n      description='Scout Application Performance Monitoring Agent',\n      long_description='Scout Application Performance Monitoring Agent',\n      url='https://github.com/scoutapp/scout_apm_python',\n      author='Scout',\n      author_email='support@scoutapp.com',\n      license='MIT',\n      zip_safe=False,\n      python_requires='>=3.4, <4',\n      packages=find_packages('src'),\n      package_dir={'': 'src'},\n      py_modules=[splitext(basename(path))[0] for path in glob('src/*.py')],\n      entry_points={\n          'console_scripts': [\n              'core-agent-manager = scout_apm.core.cli.core_agent_manager:main'\n          ]\n      },\n      install_requires=['psutil', 'PyYAML', 'requests'],\n      keywords='apm performance monitoring development',\n      classifiers=[\n        'Development Status :: 3 - Alpha',\n        'Intended Audience :: Developers',\n        'Topic :: System :: Monitoring',\n        'License :: Other/Proprietary License',\n        'Operating System :: MacOS',\n        'Operating System :: POSIX',\n        'Operating System :: POSIX :: Linux',\n        'Programming Language :: Python :: 3',\n        'Programming Language :: Python :: 3.4',\n        'Programming Language :: Python :: 3.5',\n        'Programming Language :: Python :: 3.6',\n        'Programming Language :: Python :: 3.7',\n      ])\n", "path": "setup.py"}, {"content": "from __future__ import absolute_import\n\nimport logging\nfrom datetime import datetime\nfrom uuid import uuid4\n\nfrom scout_apm.core.samplers import Samplers\nfrom scout_apm.core.request_manager import RequestManager\nfrom scout_apm.core.thread_local import ThreadLocalSingleton\nfrom scout_apm.core.n_plus_one_call_set import NPlusOneCallSet\nimport scout_apm.core.backtrace\n\n# Logging\nlogger = logging.getLogger(__name__)\n\n\nclass TrackedRequest(ThreadLocalSingleton):\n    \"\"\"\n    This is a container which keeps track of all module instances for a single\n    request. For convenience they are made available as attributes based on\n    their keyname\n    \"\"\"\n    def __init__(self, *args, **kwargs):\n        self.req_id = 'req-' + str(uuid4())\n        self.start_time = kwargs.get('start_time', datetime.utcnow())\n        self.end_time = kwargs.get('end_time', None)\n        self.active_spans = kwargs.get('active_spans', [])\n        self.complete_spans = kwargs.get('complete_spans', [])\n        self.tags = kwargs.get('tags', {})\n        self.real_request = kwargs.get('real_request', False)\n        self.callset = NPlusOneCallSet()\n        logger.debug('Starting request: %s', self.req_id)\n\n    def mark_real_request(self):\n        self.real_request = True\n\n    def is_real_request(self):\n        return self.real_request\n\n    def tag(self, key, value):\n        if key in self.tags:\n            logger.debug('Overwriting previously set tag for request %s: %s' % (self.req_id, key))\n        self.tags[key] = value\n\n    def start_span(self, operation=None):\n        maybe_parent = self.current_span()\n\n        if maybe_parent is not None:\n            parent_id = maybe_parent.span_id\n        else:\n            parent_id = None\n\n        new_span = Span(\n            request_id=self.req_id,\n            operation=operation,\n            parent=parent_id)\n        self.active_spans.append(new_span)\n        return new_span\n\n    def stop_span(self):\n        stopping_span = None\n        try:\n            stopping_span = self.active_spans.pop()\n        except IndexError as e:\n            logger.debug('Exception when stopping span: %s' % repr(e))\n\n        if stopping_span is not None:\n            stopping_span.stop()\n            stopping_span.annotate()\n            self.complete_spans.append(stopping_span)\n\n        if len(self.active_spans) == 0:\n            self.finish()\n\n    def current_span(self):\n        if len(self.active_spans) > 0:\n            return self.active_spans[-1]\n        else:\n            return None\n\n    # Request is done, release any info we have about it.\n    def finish(self):\n        logger.debug('Stopping request: %s', self.req_id)\n        if self.end_time is None:\n            self.end_time = datetime.utcnow()\n        RequestManager.instance().add_request(self)\n        if self.is_real_request():\n            Samplers.ensure_running()\n\n        # This can fail if the Tracked Request was created directly, not through instance()\n        try:\n            self.release()\n        except:\n            pass\n\n\nclass Span:\n    def __init__(self, *args, **kwargs):\n        self.span_id = kwargs.get('span_id', 'span-' + str(uuid4()))\n        self.start_time = kwargs.get('start_time', datetime.utcnow())\n        self.end_time = kwargs.get('end_time', None)\n        self.request_id = kwargs.get('request_id', None)\n        self.operation = kwargs.get('operation', None)\n        self.parent = kwargs.get('parent', None)\n        self.tags = kwargs.get('tags', {})\n\n    def stop(self):\n        self.end_time = datetime.utcnow()\n\n    def tag(self, key, value):\n        if key in self.tags:\n            logger.debug('Overwriting previously set tag for span %s: %s' % (self.span_id, key))\n        self.tags[key] = value\n\n    # In seconds\n    def duration(self):\n        if self.end_time is not None:\n            return (self.end_time - self.start_time).total_seconds()\n        else:\n            # Current, running duration\n            return (datetime.utcnow() - self.start_time).total_seconds()\n\n    def duration_in_ms(self):\n        return self.duration() / 1000\n\n    # Add any interesting annotations to the span. Assumes that we are in the\n    # process of stopping this span.\n    def annotate(self):\n        slow_threshold = 0.500\n        if self.duration() > slow_threshold:\n            self.capture_backtrace()\n\n    def capture_backtrace(self):\n        stack = scout_apm.core.backtrace.capture()\n        self.tag('stack', stack)\n", "path": "src/scout_apm/core/tracked_request.py"}]}