cavisson-pythonagent 0.0.1__py3-none-any.whl
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.
- cavisson_pythonagent-0.0.1.dist-info/METADATA +32 -0
- cavisson_pythonagent-0.0.1.dist-info/RECORD +180 -0
- cavisson_pythonagent-0.0.1.dist-info/WHEEL +5 -0
- cavisson_pythonagent-0.0.1.dist-info/licenses/LICENSE +19 -0
- cavisson_pythonagent-0.0.1.dist-info/top_level.txt +1 -0
- pythonagent/__init__.py +22 -0
- pythonagent/agent/__init__.py +219 -0
- pythonagent/agent/internal/__init__.py +1 -0
- pythonagent/agent/internal/agent.py +1651 -0
- pythonagent/agent/internal/framesinfo.py +152 -0
- pythonagent/agent/internal/heap_dump.py +39 -0
- pythonagent/agent/internal/intercept_module.py +70 -0
- pythonagent/agent/internal/logs.py +122 -0
- pythonagent/agent/internal/metadata/__init__.py +0 -0
- pythonagent/agent/internal/metadata/agent_meta_data.py +276 -0
- pythonagent/agent/internal/proc_compat.py +75 -0
- pythonagent/agent/internal/profile.py +47 -0
- pythonagent/agent/internal/provider.py +83 -0
- pythonagent/agent/internal/thread_dump.py +85 -0
- pythonagent/agent/internal/udp.py +245 -0
- pythonagent/agent/internal/udp_message.py +800 -0
- pythonagent/agent/probes/Instrumentation/__init__.py +340 -0
- pythonagent/agent/probes/Instrumentation/find.py +243 -0
- pythonagent/agent/probes/Instrumentation/module_version_resolver.py +155 -0
- pythonagent/agent/probes/Instrumentation/new_parser.py +64 -0
- pythonagent/agent/probes/Instrumentation/parser.py +129 -0
- pythonagent/agent/probes/__init__.py +219 -0
- pythonagent/agent/probes/base.py +303 -0
- pythonagent/agent/probes/cache/__init__.py +51 -0
- pythonagent/agent/probes/cache/redis.py +119 -0
- pythonagent/agent/probes/cache/redis_asyncio.py +83 -0
- pythonagent/agent/probes/coroutines/__init__.py +1 -0
- pythonagent/agent/probes/coroutines/asyncio.py +63 -0
- pythonagent/agent/probes/elasticdb/__init__.py +7 -0
- pythonagent/agent/probes/elasticdb/aelastic.py +54 -0
- pythonagent/agent/probes/frameworks/__init__.py +27 -0
- pythonagent/agent/probes/frameworks/agentprofiler.py +105 -0
- pythonagent/agent/probes/frameworks/aiohttp_web.py +155 -0
- pythonagent/agent/probes/frameworks/aisess.py +151 -0
- pythonagent/agent/probes/frameworks/asgi.py +340 -0
- pythonagent/agent/probes/frameworks/bottle.py +27 -0
- pythonagent/agent/probes/frameworks/cherry.py +25 -0
- pythonagent/agent/probes/frameworks/django.py +128 -0
- pythonagent/agent/probes/frameworks/falcon.py +21 -0
- pythonagent/agent/probes/frameworks/fastapi.py +35 -0
- pythonagent/agent/probes/frameworks/flask.py +30 -0
- pythonagent/agent/probes/frameworks/pyramid.py +56 -0
- pythonagent/agent/probes/frameworks/test.py +108 -0
- pythonagent/agent/probes/frameworks/tornado_async_web.py +117 -0
- pythonagent/agent/probes/frameworks/tornado_web.py +133 -0
- pythonagent/agent/probes/frameworks/wsgi.py +353 -0
- pythonagent/agent/probes/grpc/__init__.py +76 -0
- pythonagent/agent/probes/grpc/client_interceptor.py +132 -0
- pythonagent/agent/probes/grpc/server_interceptor.py +129 -0
- pythonagent/agent/probes/havoc/__init__.py +0 -0
- pythonagent/agent/probes/havoc/custom_memory_stress.py +186 -0
- pythonagent/agent/probes/havoc/custom_thread_stress.py +187 -0
- pythonagent/agent/probes/havoc/havoc_constants.py +218 -0
- pythonagent/agent/probes/havoc/havoc_manager.py +981 -0
- pythonagent/agent/probes/http/__init__.py +49 -0
- pythonagent/agent/probes/http/aiohttp_client.py +59 -0
- pythonagent/agent/probes/http/boto.py +12 -0
- pythonagent/agent/probes/http/httplib.py +110 -0
- pythonagent/agent/probes/http/httpx_client.py +116 -0
- pythonagent/agent/probes/http/requests.py +15 -0
- pythonagent/agent/probes/http/tornado_httpclient.py +85 -0
- pythonagent/agent/probes/http/urllib3.py +16 -0
- pythonagent/agent/probes/langchain/__init__.py +21 -0
- pythonagent/agent/probes/langchain/base_tool.py +95 -0
- pythonagent/agent/probes/langchain/langchain_community.py +136 -0
- pythonagent/agent/probes/langchain/langchain_core.py +32 -0
- pythonagent/agent/probes/langchain/langchain_openai.py +110 -0
- pythonagent/agent/probes/logging/__init__.py +106 -0
- pythonagent/agent/probes/message_brokers/__init__.py +4 -0
- pythonagent/agent/probes/message_brokers/pika.py +126 -0
- pythonagent/agent/probes/mongodb/__init__.py +6 -0
- pythonagent/agent/probes/mongodb/pymongo.py +286 -0
- pythonagent/agent/probes/openai/__init__.py +3 -0
- pythonagent/agent/probes/openai/openai.py +797 -0
- pythonagent/agent/probes/span.py +101 -0
- pythonagent/agent/probes/sql/__init__.py +13 -0
- pythonagent/agent/probes/sql/botocores3.py +51 -0
- pythonagent/agent/probes/sql/dbapi.py +285 -0
- pythonagent/agent/probes/sql/dynamodb.py +90 -0
- pythonagent/agent/probes/sql/mysql_connector.py +24 -0
- pythonagent/agent/probes/sql/mysql_connector_cext.py +24 -0
- pythonagent/agent/probes/sql/mysqldb.py +43 -0
- pythonagent/agent/probes/sql/psycopg2.py +174 -0
- pythonagent/agent/probes/sql/pymysql.py +25 -0
- pythonagent/bootstrap/__init__.py +0 -0
- pythonagent/bootstrap/cav_gunicorn.py +26 -0
- pythonagent/bootstrap/cavagent_lambda_wrapper.py +291 -0
- pythonagent/bootstrap/run.py +47 -0
- pythonagent/bootstrap/sitecustomize.py +287 -0
- pythonagent/cavisson/netdiagnostics/CavAgent/instrumentationprofile.json +26 -0
- pythonagent/cavisson/netdiagnostics/CavAgent/interceptor_points.txt +29 -0
- pythonagent/cavisson/netdiagnostics/python/CavAgent/instrumentationprofile.json +42 -0
- pythonagent/cavisson/netdiagnostics/python/CavAgent/interceptor_points.txt +29 -0
- pythonagent/cavisson/netdiagnostics/python/config/ndsettings.conf +6 -0
- pythonagent/config.py +279 -0
- pythonagent/find.py +72 -0
- pythonagent/find_mod_cls_name.py +54 -0
- pythonagent/lang.py +131 -0
- pythonagent/lib.py +91 -0
- pythonagent/main/__init__.py +0 -0
- pythonagent/main/pytrace/__init__.py +79 -0
- pythonagent/main/pytrace/commands/__init__.py +0 -0
- pythonagent/main/pytrace/commands/auto_discovery.py +25 -0
- pythonagent/main/pytrace/commands/run.py +401 -0
- pythonagent/main/pytrace/pytrace.py +133 -0
- pythonagent/main/wsgi.py +6 -0
- pythonagent/main.py +27 -0
- pythonagent/run.py +46 -0
- pythonagent/sqins.py +8 -0
- pythonagent/test.py +73 -0
- pythonagent/utils.py +168 -0
- pythonagent/vendor/__init__.py +0 -0
- pythonagent/vendor/pympler/__init__.py +1 -0
- pythonagent/vendor/pympler/asizeof.py +2810 -0
- pythonagent/vendor/pympler/charts.py +62 -0
- pythonagent/vendor/pympler/classtracker.py +590 -0
- pythonagent/vendor/pympler/classtracker_stats.py +780 -0
- pythonagent/vendor/pympler/garbagegraph.py +80 -0
- pythonagent/vendor/pympler/mprofile.py +97 -0
- pythonagent/vendor/pympler/muppy.py +275 -0
- pythonagent/vendor/pympler/panels.py +115 -0
- pythonagent/vendor/pympler/process.py +238 -0
- pythonagent/vendor/pympler/py.typed +0 -0
- pythonagent/vendor/pympler/refbrowser.py +451 -0
- pythonagent/vendor/pympler/refgraph.py +350 -0
- pythonagent/vendor/pympler/summary.py +321 -0
- pythonagent/vendor/pympler/tracker.py +267 -0
- pythonagent/vendor/pympler/util/__init__.py +0 -0
- pythonagent/vendor/pympler/util/bottle.py +3809 -0
- pythonagent/vendor/pympler/util/compat.py +23 -0
- pythonagent/vendor/pympler/util/stringutils.py +77 -0
- pythonagent/vendor/pympler/web.py +346 -0
- pythonagent/vendor/werkzeug/__init__.py +20 -0
- pythonagent/vendor/werkzeug/_compat.py +228 -0
- pythonagent/vendor/werkzeug/_internal.py +473 -0
- pythonagent/vendor/werkzeug/_reloader.py +341 -0
- pythonagent/vendor/werkzeug/datastructures.py +3120 -0
- pythonagent/vendor/werkzeug/debug/__init__.py +498 -0
- pythonagent/vendor/werkzeug/debug/console.py +218 -0
- pythonagent/vendor/werkzeug/debug/repr.py +297 -0
- pythonagent/vendor/werkzeug/debug/tbtools.py +628 -0
- pythonagent/vendor/werkzeug/exceptions.py +829 -0
- pythonagent/vendor/werkzeug/filesystem.py +64 -0
- pythonagent/vendor/werkzeug/formparser.py +584 -0
- pythonagent/vendor/werkzeug/http.py +1307 -0
- pythonagent/vendor/werkzeug/local.py +420 -0
- pythonagent/vendor/werkzeug/middleware/__init__.py +25 -0
- pythonagent/vendor/werkzeug/middleware/dispatcher.py +66 -0
- pythonagent/vendor/werkzeug/middleware/http_proxy.py +219 -0
- pythonagent/vendor/werkzeug/middleware/lint.py +408 -0
- pythonagent/vendor/werkzeug/middleware/profiler.py +132 -0
- pythonagent/vendor/werkzeug/middleware/proxy_fix.py +169 -0
- pythonagent/vendor/werkzeug/middleware/shared_data.py +293 -0
- pythonagent/vendor/werkzeug/posixemulation.py +117 -0
- pythonagent/vendor/werkzeug/routing.py +2210 -0
- pythonagent/vendor/werkzeug/security.py +249 -0
- pythonagent/vendor/werkzeug/serving.py +1117 -0
- pythonagent/vendor/werkzeug/test.py +1123 -0
- pythonagent/vendor/werkzeug/testapp.py +241 -0
- pythonagent/vendor/werkzeug/urls.py +1138 -0
- pythonagent/vendor/werkzeug/useragents.py +202 -0
- pythonagent/vendor/werkzeug/utils.py +778 -0
- pythonagent/vendor/werkzeug/wrappers/__init__.py +36 -0
- pythonagent/vendor/werkzeug/wrappers/accept.py +50 -0
- pythonagent/vendor/werkzeug/wrappers/auth.py +33 -0
- pythonagent/vendor/werkzeug/wrappers/base_request.py +673 -0
- pythonagent/vendor/werkzeug/wrappers/base_response.py +700 -0
- pythonagent/vendor/werkzeug/wrappers/common_descriptors.py +341 -0
- pythonagent/vendor/werkzeug/wrappers/cors.py +100 -0
- pythonagent/vendor/werkzeug/wrappers/etag.py +304 -0
- pythonagent/vendor/werkzeug/wrappers/json.py +145 -0
- pythonagent/vendor/werkzeug/wrappers/request.py +49 -0
- pythonagent/vendor/werkzeug/wrappers/response.py +84 -0
- pythonagent/vendor/werkzeug/wrappers/user_agent.py +14 -0
- pythonagent/vendor/werkzeug/wsgi.py +1000 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
class BaseSpan(object):
|
|
4
|
+
def __init__(self, name, start_us, duration, status, meta, test_run, fpi, entry_fpi, nd_session_id, nv_session_id, page_id, full_fp):
|
|
5
|
+
|
|
6
|
+
self.trace_id = None
|
|
7
|
+
self.span_id = None
|
|
8
|
+
self.parent_id = None
|
|
9
|
+
self.name = name
|
|
10
|
+
self.start_us = start_us
|
|
11
|
+
self.duration = duration
|
|
12
|
+
self.status = status
|
|
13
|
+
self.meta = meta
|
|
14
|
+
"""
|
|
15
|
+
self.meta = {
|
|
16
|
+
"span_kind": None,
|
|
17
|
+
"input": None,
|
|
18
|
+
"output": None,
|
|
19
|
+
"metadata": None
|
|
20
|
+
}
|
|
21
|
+
"""
|
|
22
|
+
self.metrics = {}
|
|
23
|
+
self.test_run = test_run
|
|
24
|
+
self.fpi = fpi
|
|
25
|
+
self.entry_fpi =entry_fpi
|
|
26
|
+
self.nd_session_id = nd_session_id
|
|
27
|
+
self.nv_session_id = nv_session_id
|
|
28
|
+
self.page_id = page_id
|
|
29
|
+
self.full_fp = full_fp
|
|
30
|
+
|
|
31
|
+
def create_span_json(self):
|
|
32
|
+
span = {
|
|
33
|
+
"trace_id": self.trace_id,
|
|
34
|
+
"span_id": self.span_id,
|
|
35
|
+
"parent_id": self.parent_id,
|
|
36
|
+
"name": self.name,
|
|
37
|
+
"start_us": self.start_us,
|
|
38
|
+
"duration": self.duration,
|
|
39
|
+
"status": self.status,
|
|
40
|
+
"meta": self.meta,
|
|
41
|
+
"metrics": self.metrics,
|
|
42
|
+
"test_run":self.test_run,
|
|
43
|
+
"fpi":self.fpi,
|
|
44
|
+
"entry_fpi":self.entry_fpi,
|
|
45
|
+
"nd_session_id":self.nd_session_id,
|
|
46
|
+
"nv_session_id":self.nv_session_id,
|
|
47
|
+
"page_id":self.page_id,
|
|
48
|
+
"fp": self.full_fp
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return json.dumps(span)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class ToolSpan(BaseSpan):
|
|
56
|
+
pass
|
|
57
|
+
|
|
58
|
+
class EmbeddingSpan(BaseSpan):
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
class RetrievalSpan(BaseSpan):
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class LLMSpan(BaseSpan):
|
|
66
|
+
|
|
67
|
+
def __init__(self, fqm, start_time, duration, status, meta, metrics, test_run, fpi, entry_fpi, nd_session_id, nv_session_id, page_id, full_fp):
|
|
68
|
+
super().__init__(fqm, start_time, duration, status, meta, test_run, fpi, entry_fpi, nd_session_id, nv_session_id, page_id, full_fp)
|
|
69
|
+
self.metrics = metrics
|
|
70
|
+
"""
|
|
71
|
+
self.metrics = {
|
|
72
|
+
"prompt_tokens": None,
|
|
73
|
+
"completion_tokens": None,
|
|
74
|
+
"total_tokens": None,
|
|
75
|
+
"prompt_tokens_details": {
|
|
76
|
+
"prompt_audio_tokens": None,
|
|
77
|
+
"prompt_cached_tokens": None
|
|
78
|
+
},
|
|
79
|
+
"completion_tokens_details": {
|
|
80
|
+
"completion_accepted_prediction_tokens": None,
|
|
81
|
+
"completion_rejected_prediction_tokens": None,
|
|
82
|
+
"completion_audio_tokens": None,
|
|
83
|
+
"completion_reasoning_tokens": None
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
"""
|
|
91
|
+
class WorkFlowSpan(BaseSpan):
|
|
92
|
+
pass
|
|
93
|
+
|
|
94
|
+
class AgentSpan(BaseSpan):
|
|
95
|
+
pass
|
|
96
|
+
|
|
97
|
+
class TaskSpan(BaseSpan):
|
|
98
|
+
pass
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
"""Interceptors for SQL databases.
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import unicode_literals
|
|
9
|
+
|
|
10
|
+
from . import mysql_connector, mysql_connector_cext, mysqldb, pymysql, psycopg2, dynamodb, botocores3
|
|
11
|
+
|
|
12
|
+
__all__ = ['pymysql', 'mysql_connector', 'mysql_connector_cext', 'mysqldb', 'psycopg2', 'dynamodb', 'botocores3']
|
|
13
|
+
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
|
|
2
|
+
"""Interceptor for httplib/http.client.
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import unicode_literals
|
|
7
|
+
from ..base import ExitCallInterceptor
|
|
8
|
+
import time
|
|
9
|
+
#from functools import wraps
|
|
10
|
+
# from agent.internal.proxy import *
|
|
11
|
+
from pythonagent.utils import get_current_timestamp_in_ms
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BotocoreS3Interceptor(ExitCallInterceptor):
|
|
15
|
+
|
|
16
|
+
def _cav_s3_make_request(self, make_request, Endpoint, operation_model, request_dict):#, _agent):
|
|
17
|
+
try:
|
|
18
|
+
if operation_model.name != "GetObject": # PutItem and Scan in DynamoDB use the same function
|
|
19
|
+
return make_request(Endpoint, operation_model, request_dict)
|
|
20
|
+
|
|
21
|
+
method_name = "botocore.endpoint.Endpoint.make_request"
|
|
22
|
+
ctx = self.agent.get_transaction_context()
|
|
23
|
+
if ctx:
|
|
24
|
+
ctx.entry_point_fqm = method_name
|
|
25
|
+
query_string = operation_model.name
|
|
26
|
+
start_time = get_current_timestamp_in_ms()
|
|
27
|
+
url = request_dict["url"]
|
|
28
|
+
ip_handle = self.db_call_begin(0, None, query_string, url, start_time)
|
|
29
|
+
|
|
30
|
+
except Exception as e:
|
|
31
|
+
self.agent.logger.exception('Exception in S3 db_call_begin {}'.format(e))
|
|
32
|
+
|
|
33
|
+
endpiont_method = make_request(Endpoint, operation_model, request_dict)
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
end_time = get_current_timestamp_in_ms()
|
|
37
|
+
duration = end_time - start_time
|
|
38
|
+
ctx = self.agent.get_transaction_context()
|
|
39
|
+
if ctx:
|
|
40
|
+
ctx.host_str = "s3"
|
|
41
|
+
ctx.status_code = 200
|
|
42
|
+
self.db_call_end(0, ip_handle, duration, start_time)
|
|
43
|
+
except Exception as e:
|
|
44
|
+
self.agent.logger.exception("Exception in S3 db_call_end {}".format(e))
|
|
45
|
+
|
|
46
|
+
return endpiont_method
|
|
47
|
+
|
|
48
|
+
def intercept_s3(agent, mod):
|
|
49
|
+
agent.logger.warning("Instrument module: botocore.endpoint{}".format(", mod: {}".format(mod) if mod else ""))
|
|
50
|
+
interceptor = BotocoreS3Interceptor(agent, mod.Endpoint)
|
|
51
|
+
interceptor.attach('make_request', patched_method_name='_cav_s3_make_request')
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
|
|
2
|
+
"""Interceptors for dealing with DB-API 2.0 compatible libraries.
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import unicode_literals
|
|
7
|
+
import abc
|
|
8
|
+
import re
|
|
9
|
+
#import agent
|
|
10
|
+
#from agent.internal.proxy import *
|
|
11
|
+
from pythonagent.lang import str
|
|
12
|
+
#from pythonagentynamics.agent.core.registries import MissingConfigException
|
|
13
|
+
#from pythonagentynamics.agent.models.exitcalls import EXIT_DB, EXIT_SUBTYPE_DB
|
|
14
|
+
#from .. import HOST_PROPERTY_MAX_LEN, DB_NAME_PROPERTY_MAX_LEN, VENDOR_PROPERTY_MAX_LEN
|
|
15
|
+
from ..base import ExitCallInterceptor
|
|
16
|
+
from pythonagent.utils import generate_flow_path_id, get_utf8_bytes, get_current_timestamp_in_us, get_validated_duration
|
|
17
|
+
|
|
18
|
+
EXIT_DB = 1
|
|
19
|
+
EXIT_SUBTYPE_DB = 'DB'
|
|
20
|
+
|
|
21
|
+
HOST_PROPERTY_MAX_LEN = 50
|
|
22
|
+
DB_NAME_PROPERTY_MAX_LEN = 50
|
|
23
|
+
VENDOR_PROPERTY_MAX_LEN = 50
|
|
24
|
+
|
|
25
|
+
class MissingConfigException(Exception):
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
#def get_db_backend(agent, host, port, dbname, vendor):
|
|
30
|
+
# if agent.backend_registry is None:
|
|
31
|
+
# raise MissingConfigException
|
|
32
|
+
|
|
33
|
+
# naming_format_string = '{HOST}:{PORT} - {DATABASE} - {VENDOR} - {VERSION}'
|
|
34
|
+
# host = host[:HOST_PROPERTY_MAX_LEN]
|
|
35
|
+
# dbname = dbname[:DB_NAME_PROPERTY_MAX_LEN]
|
|
36
|
+
# vendor = vendor[:VENDOR_PROPERTY_MAX_LEN]
|
|
37
|
+
|
|
38
|
+
# backend_properties = {
|
|
39
|
+
# 'VENDOR': vendor,
|
|
40
|
+
# 'HOST': host,
|
|
41
|
+
# 'PORT': str(port),
|
|
42
|
+
# 'DATABASE': dbname,
|
|
43
|
+
# 'VERSION': 'unknown',
|
|
44
|
+
# }
|
|
45
|
+
|
|
46
|
+
#return agent.backend_registry.get_backend(EXIT_DB, EXIT_SUBTYPE_DB, backend_properties, naming_format_string)
|
|
47
|
+
# return None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class DbAPICursorInterceptor(ExitCallInterceptor):
|
|
51
|
+
|
|
52
|
+
def __init__(self, agent, cls):
|
|
53
|
+
super(DbAPICursorInterceptor, self).__init__(agent, cls)
|
|
54
|
+
self.connection_properties = None
|
|
55
|
+
|
|
56
|
+
#print("going to get proxy instance (DbAPICursor Interceptor)")
|
|
57
|
+
#proxy = Proxy.getInstance()
|
|
58
|
+
#print("proxy handle = ",proxy )
|
|
59
|
+
|
|
60
|
+
def db_call_end(self, bt, exit_call, duration, start_time):
|
|
61
|
+
#self.agent.logger.info('Modulename: DbAPICursorInterceptor class inside db_call_end function')
|
|
62
|
+
# execute_result is intentionally not used here. Its purpose is to
|
|
63
|
+
# allow subclasses to override this method and use the value.
|
|
64
|
+
super(DbAPICursorInterceptor, self).db_call_end(bt, exit_call, duration, start_time)
|
|
65
|
+
|
|
66
|
+
def _execute(self, execute, cursor, operation, *args, **kwargs):
|
|
67
|
+
if self.agent.get_transaction_context() is None:
|
|
68
|
+
return execute(cursor, operation, *args, **kwargs)
|
|
69
|
+
exit_call = None
|
|
70
|
+
with self.log_exceptions():
|
|
71
|
+
self.agent.get_transaction_context().entry_point_fqm = str(execute.__module__ + "." + execute.__qualname__)
|
|
72
|
+
host, port, db_name, user, db_type = self.connection_properties
|
|
73
|
+
# format :- "PROTOCOL|HOST|PORT|URL|DBPRODNAME|DBNAME|DBPRODVER|DRIVERNAME|DRIVERVER|USERNAME|SERVICENAME"
|
|
74
|
+
self.agent.get_transaction_context().host_str = f"NA|{host}|{port}|NA|{db_type}|{db_name}|NA|NA|NA|{user}|NA"
|
|
75
|
+
db_start_time = 0
|
|
76
|
+
|
|
77
|
+
query_params = args
|
|
78
|
+
token_string = ""
|
|
79
|
+
if query_params:
|
|
80
|
+
if len(query_params) != 0:
|
|
81
|
+
for parameters in query_params:
|
|
82
|
+
counter = 0
|
|
83
|
+
if parameters:
|
|
84
|
+
for tokens in parameters:
|
|
85
|
+
token_string += "{}:{}\n".format(counter, tokens)
|
|
86
|
+
counter += 1
|
|
87
|
+
else:
|
|
88
|
+
token_string = None
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
#print("operation in db query in dbapi.py\n\n", operation)
|
|
92
|
+
backend = True
|
|
93
|
+
|
|
94
|
+
# host = None
|
|
95
|
+
#self.agent.logger.info("inside _execute funciton")
|
|
96
|
+
#self.agent.logger.info('Modulename: DbAPICursorInterceptor class inside _execute function')
|
|
97
|
+
self.agent.logger.info("Modulename: DbAPICursorInterceptor class || execute value is : {0}".format(execute))
|
|
98
|
+
self.agent.logger.info("Modulename: DbAPICursorInterceptor class || operation value is :{0}".format(str(operation)))
|
|
99
|
+
#self.agent.logger.info("execute: {}",execute,"cursor: {}",cursor,"operation:{} ",operation)
|
|
100
|
+
#print("cursor host: ", cursor.host)
|
|
101
|
+
|
|
102
|
+
#bt = self.agent.bt
|
|
103
|
+
bt = self.bt
|
|
104
|
+
if bt:
|
|
105
|
+
#print("bt value is ------------------",bt)
|
|
106
|
+
#connection = self.get_connection(cursor)
|
|
107
|
+
module = self.cls.__module__.lower()
|
|
108
|
+
|
|
109
|
+
if "psycopg2" in module:
|
|
110
|
+
mName = "psycopg2.connect"
|
|
111
|
+
self.agent.get_transaction_context().entry_point_fqm = mName
|
|
112
|
+
|
|
113
|
+
if backend and not hasattr(cursor, '_pythonagent_exit_call'):
|
|
114
|
+
db_start_time = get_current_timestamp_in_us()
|
|
115
|
+
self.agent.logger.debug("db_call_begin for _execute bt {} host {} query {} query_params {} db_start_time {}".format(bt, host, operation, token_string, db_start_time))
|
|
116
|
+
host_str = self.agent.get_transaction_context().host_str
|
|
117
|
+
exit_call = self.db_call_begin(bt, host, operation, token_string, db_start_time, host_str=host_str)
|
|
118
|
+
cursor._pythonagent_exit_call = exit_call
|
|
119
|
+
self.agent.get_transaction_context().db_callout_start_time = db_start_time
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
result = execute(cursor, operation, pythonagent_exit_call=exit_call, *args, **kwargs)
|
|
124
|
+
except Exception as e:
|
|
125
|
+
self.agent.logger.exception("Error in application: {}".format(e))
|
|
126
|
+
try:
|
|
127
|
+
db_end_time = get_current_timestamp_in_us()
|
|
128
|
+
db_start_time = self.agent.get_transaction_context().db_callout_start_time
|
|
129
|
+
duration = get_validated_duration(db_start_time, db_end_time, "_execute")
|
|
130
|
+
self.agent.get_transaction_context().status_code = 500
|
|
131
|
+
self.agent.get_transaction_context().db_callout_start_time = 0
|
|
132
|
+
self.agent.logger.debug("db_call_end for _execute with exception bt {} ip_handle {} duration {} db_start_time {}".format(bt, exit_call, duration, db_start_time))
|
|
133
|
+
self.db_call_end(bt, exit_call, duration, db_start_time)
|
|
134
|
+
except Exception as e:
|
|
135
|
+
self.agent.logger.exception("Exception in Original Method DB Call End for dbapi execute {}".format(e))
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
delattr(cursor, '_pythonagent_exit_call')
|
|
139
|
+
except AttributeError:
|
|
140
|
+
pass
|
|
141
|
+
|
|
142
|
+
raise
|
|
143
|
+
|
|
144
|
+
try:
|
|
145
|
+
|
|
146
|
+
db_end_time = get_current_timestamp_in_us()
|
|
147
|
+
db_start_time = self.agent.get_transaction_context().db_callout_start_time
|
|
148
|
+
duration = get_validated_duration(db_start_time, db_end_time, "_execute")
|
|
149
|
+
|
|
150
|
+
# Normally it's fine to just try to end the exit call even if we
|
|
151
|
+
# aren't sure it actually started. However for cases where we have
|
|
152
|
+
# several `execute` calls nested inside an `executemany` call, we do
|
|
153
|
+
# not want to end the exit call until the outer call is over.
|
|
154
|
+
|
|
155
|
+
if not exit_call:
|
|
156
|
+
self.agent.get_transaction_context().status_code = 200
|
|
157
|
+
self.agent.get_transaction_context().db_callout_start_time = 0
|
|
158
|
+
self.agent.logger.debug("db_call_end for _execute bt {} ip_handle {} duration {} db_start_time {}".format(bt, exit_call, duration, db_start_time))
|
|
159
|
+
self.db_call_end(bt, exit_call, duration, db_start_time)
|
|
160
|
+
try:
|
|
161
|
+
delattr(cursor, '_pythonagent_exit_call')
|
|
162
|
+
except AttributeError:
|
|
163
|
+
pass
|
|
164
|
+
|
|
165
|
+
except Exception as e:
|
|
166
|
+
self.agent.logger.exception("Exception in dbapi execute end{}".format(e))
|
|
167
|
+
|
|
168
|
+
return result
|
|
169
|
+
|
|
170
|
+
@abc.abstractmethod
|
|
171
|
+
def get_connection(self, cursor):
|
|
172
|
+
"""Return the `Connection` object used to create this `Cursor`.
|
|
173
|
+
|
|
174
|
+
"""
|
|
175
|
+
pass
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class DbAPIConnectionInterceptor(ExitCallInterceptor):
|
|
179
|
+
|
|
180
|
+
def __init__(self, agent, cls, cursor_interceptor):
|
|
181
|
+
super(DbAPIConnectionInterceptor, self).__init__(agent, cls)
|
|
182
|
+
self.cursor_interceptor = cursor_interceptor
|
|
183
|
+
self.backend_properties = None
|
|
184
|
+
|
|
185
|
+
def attach(self, connect_func):
|
|
186
|
+
super(DbAPIConnectionInterceptor, self).attach(connect_func, patched_method_name='_connect')
|
|
187
|
+
super(DbAPIConnectionInterceptor, self).attach('cursor')
|
|
188
|
+
|
|
189
|
+
def db_call_end(self, bt, exit_call, duration, db_start_time):
|
|
190
|
+
# maybe_connection is intentionally not used here. Its purpose is to
|
|
191
|
+
# allow subclasses to override this method and use the value.
|
|
192
|
+
super(DbAPIConnectionInterceptor, self).db_call_end(bt, exit_call, duration, db_start_time)
|
|
193
|
+
|
|
194
|
+
def _connect(self, connect, connection, *args, **kwargs):
|
|
195
|
+
exit_call = None
|
|
196
|
+
|
|
197
|
+
with self.log_exceptions():
|
|
198
|
+
|
|
199
|
+
backend_properties = self.get_backend_properties(connection, *args, **kwargs)
|
|
200
|
+
self.backend_properties = backend_properties
|
|
201
|
+
if self.agent.get_transaction_context() is None:
|
|
202
|
+
maybe_connection = connect(connection, pythonagent_exit_call=None, *args, **kwargs)
|
|
203
|
+
return maybe_connection
|
|
204
|
+
|
|
205
|
+
mName = str(connect.__module__ + "." + connect.__qualname__)
|
|
206
|
+
self.agent.get_transaction_context().entry_point_fqm = mName
|
|
207
|
+
bt = self.bt
|
|
208
|
+
db_start_time = 0
|
|
209
|
+
|
|
210
|
+
backend = True
|
|
211
|
+
|
|
212
|
+
try:
|
|
213
|
+
connection._pythonagent_backend = backend
|
|
214
|
+
except MissingConfigException:
|
|
215
|
+
# If the agent has just started and doesn't have config yet,
|
|
216
|
+
# we cannot create and store a backend on the connection object.
|
|
217
|
+
# We store the backend properties instead so that the cursor
|
|
218
|
+
# interceptor can try again later.
|
|
219
|
+
connection._pythonagent_backend_properties = backend_properties
|
|
220
|
+
if bt:
|
|
221
|
+
db_start_time = get_current_timestamp_in_us()
|
|
222
|
+
self.agent.logger.debug("db_call_begin for _connect bt {} host {} query {} query_params {} db_start_time {}".format(bt, backend_properties[0], '', None, db_start_time))
|
|
223
|
+
#exit_call = self.db_call_begin(bt, backend_properties[0], '', None, db_start_time)
|
|
224
|
+
self.agent.get_transaction_context().db_callout_start_time = db_start_time
|
|
225
|
+
|
|
226
|
+
# The reason this is called `maybe_connection` is that different
|
|
227
|
+
# interceptors will return different values here. `connect` could
|
|
228
|
+
# be an __init__ method on a class, returning None, it could be a
|
|
229
|
+
# function which returns an initialized connection object, or even a
|
|
230
|
+
# method returning an async future object. The only reason we capture
|
|
231
|
+
# this value and pass it to `end_exit_call` is to allow subclasses to
|
|
232
|
+
# override the behaviour of `end_exit_call` (for example in the async
|
|
233
|
+
# case, to only end the exit call when the future is completed).
|
|
234
|
+
|
|
235
|
+
try:
|
|
236
|
+
maybe_connection = connect(connection, pythonagent_exit_call=exit_call, *args, **kwargs)
|
|
237
|
+
except Exception as e:
|
|
238
|
+
self.agent.logger.exception("Error in application: {}".format(e))
|
|
239
|
+
try:
|
|
240
|
+
db_end_time = get_current_timestamp_in_us()
|
|
241
|
+
db_start_time = self.agent.get_transaction_context().db_callout_start_time
|
|
242
|
+
duration = get_validated_duration(db_start_time, db_end_time, "_connect")
|
|
243
|
+
self.agent.get_transaction_context().status_code = 500
|
|
244
|
+
self.agent.get_transaction_context().db_callout_start_time = 0
|
|
245
|
+
self.agent.logger.debug("db_call_end for _connect with exception bt {} ip_handle {} duration {} db_start_time {}".format(bt, exit_call, duration, db_start_time))
|
|
246
|
+
#self.db_call_end(bt, exit_call, duration, db_start_time)
|
|
247
|
+
except Exception as e:
|
|
248
|
+
self.agent.logger.exception("Exception in Original Method DB Call End for dbapi connect {}".format(e))
|
|
249
|
+
|
|
250
|
+
raise
|
|
251
|
+
|
|
252
|
+
try:
|
|
253
|
+
db_end_time = get_current_timestamp_in_us()
|
|
254
|
+
db_start_time = self.agent.get_transaction_context().db_callout_start_time
|
|
255
|
+
duration = get_validated_duration(db_start_time, db_end_time, "_connect")
|
|
256
|
+
self.agent.get_transaction_context().status_code = 200
|
|
257
|
+
self.agent.get_transaction_context().db_callout_start_time = 0
|
|
258
|
+
self.agent.logger.debug("db_call_end for _connect bt {} ip_handle {} duration {} db_start_time {}".format(bt, exit_call, duration, db_start_time))
|
|
259
|
+
#self.db_call_end(bt, exit_call, duration, db_start_time)
|
|
260
|
+
|
|
261
|
+
except Exception as e:
|
|
262
|
+
self.agent.logger.exception("Exception in dbapi connect end{}".format(e))
|
|
263
|
+
|
|
264
|
+
return maybe_connection
|
|
265
|
+
|
|
266
|
+
def _cursor(self, cursor, connection, *args, **kwargs):
|
|
267
|
+
cursor_instance = cursor(connection, pythonagent_exit_call=None, *args, **kwargs)
|
|
268
|
+
with (self.log_exceptions()):
|
|
269
|
+
cursor_obj = self.cursor_interceptor(self.agent, type(cursor_instance))
|
|
270
|
+
cursor_obj.attach('execute',patched_method_name='_execute')
|
|
271
|
+
cursor_obj.connection_properties = self.backend_properties
|
|
272
|
+
return cursor_instance
|
|
273
|
+
|
|
274
|
+
@abc.abstractmethod
|
|
275
|
+
def get_backend_properties(self, connection, *args, **kwargs):
|
|
276
|
+
"""Return a tuple of (host, port, database, vendor) for this connection.
|
|
277
|
+
|
|
278
|
+
The parameters passed to this function are the same as those passed to
|
|
279
|
+
the intercepted `connect` function.
|
|
280
|
+
|
|
281
|
+
WARNING: `connection` may not have been initialized when this
|
|
282
|
+
function is called; be careful.
|
|
283
|
+
|
|
284
|
+
"""
|
|
285
|
+
pass
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
|
|
2
|
+
"""Interceptor for httplib/http.client.
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import unicode_literals
|
|
7
|
+
from ..base import ExitCallInterceptor
|
|
8
|
+
import time
|
|
9
|
+
#from functools import wraps
|
|
10
|
+
# from agent.internal.proxy import *
|
|
11
|
+
from pythonagent.utils import get_current_timestamp_in_ms
|
|
12
|
+
|
|
13
|
+
# import agent
|
|
14
|
+
class BotocoreClientInterceptor(ExitCallInterceptor):
|
|
15
|
+
#print("INSIDE dynamodb.py BotocoreClientInterceptor class")
|
|
16
|
+
|
|
17
|
+
def bind__create_api_method(py_operation_name, operation_name, service_model,
|
|
18
|
+
*args, **kwargs):
|
|
19
|
+
return py_operation_name
|
|
20
|
+
|
|
21
|
+
def _cav_boto_api_method(self, _create_api_method, ClientCreator,py_operation_name, operation_name, service_mode, *args, **kwargs):
|
|
22
|
+
|
|
23
|
+
def _cav_wrapped_api_method(func, py_operation_name, _agent):
|
|
24
|
+
# operation_name = py_operation_name
|
|
25
|
+
agent = _agent
|
|
26
|
+
def wrapper(*args, **kwargs):
|
|
27
|
+
start_time = None
|
|
28
|
+
query_string = None
|
|
29
|
+
method_name = None
|
|
30
|
+
ip_handle = None
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
if "TableName" in kwargs:
|
|
34
|
+
table_name = kwargs["TableName"]
|
|
35
|
+
else:
|
|
36
|
+
table_name = "default"
|
|
37
|
+
|
|
38
|
+
operation_name = py_operation_name
|
|
39
|
+
if operation_name is None:
|
|
40
|
+
operation_name = "default"
|
|
41
|
+
|
|
42
|
+
method_name = "botocore.client.ClientCreator._create_api_method"
|
|
43
|
+
|
|
44
|
+
query_string = str(table_name)+"."+str(operation_name)
|
|
45
|
+
start_time = get_current_timestamp_in_ms()
|
|
46
|
+
ctx = self.agent.get_transaction_context()
|
|
47
|
+
if ctx:
|
|
48
|
+
ctx.entry_point_fqm = method_name
|
|
49
|
+
bt = 0
|
|
50
|
+
db_host = None
|
|
51
|
+
ip_handle = self.db_call_begin(bt, db_host, query_string, "dynamodb", start_time)
|
|
52
|
+
|
|
53
|
+
except Exception as e:
|
|
54
|
+
self.agent.logger.exception("Some error occurred inside wrapper in method entry call {}".format(e))
|
|
55
|
+
|
|
56
|
+
results = func(*args, **kwargs)
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
end_time = get_current_timestamp_in_ms()
|
|
60
|
+
duration = end_time - start_time
|
|
61
|
+
ctx = self.agent.get_transaction_context()
|
|
62
|
+
if ctx:
|
|
63
|
+
ctx.host_str = "dynamodb"
|
|
64
|
+
ctx.status_code = 200
|
|
65
|
+
self.db_call_end(0, ip_handle, duration, start_time)
|
|
66
|
+
|
|
67
|
+
except Exception as e:
|
|
68
|
+
self.agent.logger.exception("Some error occurred inside wrapper in method exit call {}".format(e))
|
|
69
|
+
|
|
70
|
+
return results
|
|
71
|
+
|
|
72
|
+
return wrapper
|
|
73
|
+
|
|
74
|
+
service_name = None
|
|
75
|
+
try:
|
|
76
|
+
service_name = service_mode.service_name.lower()
|
|
77
|
+
except Exception as e:
|
|
78
|
+
self.agent.logger.exception("Some error occurred inside _cav_boto_api_method {}".format(e))
|
|
79
|
+
|
|
80
|
+
api_method = _create_api_method(ClientCreator, py_operation_name, operation_name, service_mode, *args, **kwargs)
|
|
81
|
+
|
|
82
|
+
if service_name == "dynamodb":
|
|
83
|
+
return _cav_wrapped_api_method(api_method, py_operation_name, self.agent)
|
|
84
|
+
else:
|
|
85
|
+
return api_method
|
|
86
|
+
|
|
87
|
+
def intercept_dynamodb(agent, mod):
|
|
88
|
+
agent.logger.warning("Instrument module: botocore.client{}".format(", mod: {}".format(mod) if mod else ""))
|
|
89
|
+
interceptor = BotocoreClientInterceptor(agent, mod.ClientCreator)
|
|
90
|
+
interceptor.attach('_create_api_method', patched_method_name="_cav_boto_api_method")
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
"""Intercept the mysql-connector-python package.
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import unicode_literals
|
|
8
|
+
|
|
9
|
+
from .dbapi import DbAPIConnectionInterceptor, DbAPICursorInterceptor
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class MySQLConnectionInterceptor(DbAPIConnectionInterceptor):
|
|
13
|
+
def get_backend_properties(self, conn, *args, **kwargs):
|
|
14
|
+
return conn._host, conn._port, conn._database, conn._user, 'MYSQL'
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class MySQLCursorInterceptor(DbAPICursorInterceptor):
|
|
18
|
+
def get_connection(self, cursor):
|
|
19
|
+
return cursor._connection
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def intercept_mysql_connector_connection(agent, mod):
|
|
23
|
+
agent.logger.warning("Instrument module: mysql.connector.connection{}".format(", mod: {}".format(mod) if mod else ""))
|
|
24
|
+
MySQLConnectionInterceptor(agent, mod.MySQLConnection, MySQLCursorInterceptor).attach('_open_connection')
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
"""Intercept the mysql-connector-python package.
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import unicode_literals
|
|
8
|
+
|
|
9
|
+
from .dbapi import DbAPIConnectionInterceptor, DbAPICursorInterceptor
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CMySQLConnectionInterceptor(DbAPIConnectionInterceptor):
|
|
13
|
+
def get_backend_properties(self, conn, *args, **kwargs):
|
|
14
|
+
return conn._host, conn._port, conn._database, conn._user, 'MYSQL'
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CMySQLCursorInterceptor(DbAPICursorInterceptor):
|
|
18
|
+
def get_connection(self, cursor):
|
|
19
|
+
return cursor._cnx
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def intercept_mysql_connector_cext_connection(agent, mod):
|
|
23
|
+
agent.logger.warning("Instrument module: mysql.connector.connection_cext{}".format(", mod: {}".format(mod) if mod else ""))
|
|
24
|
+
CMySQLConnectionInterceptor(agent, mod.CMySQLConnection, CMySQLCursorInterceptor).attach('_open_connection')
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
"""Intercept the MySQLdb package.
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import unicode_literals
|
|
8
|
+
import weakref
|
|
9
|
+
|
|
10
|
+
from .dbapi import DbAPIConnectionInterceptor, DbAPICursorInterceptor
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class MySQLdbConnectionInterceptor(DbAPIConnectionInterceptor):
|
|
14
|
+
def get_backend_properties(self, conn, *args, **kwargs):
|
|
15
|
+
self.agent.logger.info('Modulename: MySQLdbCursorInterceptor class inside get_backend_properties function')
|
|
16
|
+
host = kwargs.get('host', 'localhost')
|
|
17
|
+
#self.agent.get_transaction_context().dbhost = host
|
|
18
|
+
port = kwargs.get('port', '3306')
|
|
19
|
+
db = kwargs.get('database', kwargs.get('db', ''))
|
|
20
|
+
user = kwargs.get('user', "mysqldb_user")
|
|
21
|
+
db_type = "MYSQL"
|
|
22
|
+
#format :- "PROTOCOL|HOST|PORT|URL|DBPRODNAME|DBNAME|DBPRODVER|DRIVERNAME|DRIVERVER|USERNAME|SERVICENAME"
|
|
23
|
+
# host_name_str = f"NA|{host}|{port}|NA|MYSQL|{db}|NA|NA|NA|{kwargs['user']}|NA"
|
|
24
|
+
# print("host_name_str", host_name_str)
|
|
25
|
+
# self.agent.get_transaction_context().host_str = host_name_str
|
|
26
|
+
# print("self.agent.get_transaction_context().host_str", self.agent.get_transaction_context().host_str)
|
|
27
|
+
return host, port, db, user, db_type
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class MySQLdbCursorInterceptor(DbAPICursorInterceptor):
|
|
31
|
+
def get_connection(self, cursor):
|
|
32
|
+
self.agent.logger.info('Modulename: MySQLdbCursorInterceptor class inside get_connection function ')
|
|
33
|
+
conn = cursor.connection
|
|
34
|
+
self.agent.logger.info("Modulename: MySQLdbCursorInterceptor class inside get_connection function connection is {0} ".format(conn))
|
|
35
|
+
|
|
36
|
+
if isinstance(conn, weakref.ReferenceType):
|
|
37
|
+
conn = conn()
|
|
38
|
+
return conn
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def intercept_MySQLdb_connection(agent, mod):
|
|
42
|
+
agent.logger.warning("Instrument module: MySQLdb.connections{}".format(", mod: {}".format(mod) if mod else ""))
|
|
43
|
+
MySQLdbConnectionInterceptor(agent, mod.Connection, MySQLdbCursorInterceptor).attach('__init__')
|