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,303 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
"""Definition of base entry and exit point interceptors.
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
import types
|
|
10
|
+
import inspect
|
|
11
|
+
from functools import wraps
|
|
12
|
+
from contextlib import contextmanager
|
|
13
|
+
import time
|
|
14
|
+
from pythonagent.utils import get_current_timestamp_in_us
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class BaseInterceptor(object):
|
|
18
|
+
def __init__(self, agent, cls):
|
|
19
|
+
self.agent = agent
|
|
20
|
+
self.cls = cls
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def bt(self):
|
|
24
|
+
# add a docstring here about what current bt means now.
|
|
25
|
+
return self.agent.get_current_bt()
|
|
26
|
+
|
|
27
|
+
def __setitem__(self, key, value):
|
|
28
|
+
bt = self.bt
|
|
29
|
+
if bt:
|
|
30
|
+
bt._properties[key] = value
|
|
31
|
+
|
|
32
|
+
def __getitem__(self, key):
|
|
33
|
+
bt = self.bt
|
|
34
|
+
if bt:
|
|
35
|
+
return bt._properties.get(key)
|
|
36
|
+
|
|
37
|
+
def __delitem__(self, key):
|
|
38
|
+
bt = self.bt
|
|
39
|
+
if bt:
|
|
40
|
+
bt._properties.pop(key, None)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@staticmethod
|
|
44
|
+
def _fix_dunder_method_name(method, class_name):
|
|
45
|
+
# If `method` starts with '__', then it will have been renamed by the lexer to '_SomeClass__some_method'
|
|
46
|
+
# (unless the method name ends with '__').
|
|
47
|
+
if method.startswith('__') and not method.endswith('__'):
|
|
48
|
+
method = '_' + class_name.lstrip('_') + method
|
|
49
|
+
return method
|
|
50
|
+
|
|
51
|
+
def _attach(self, method, wrapper_func, patched_method_name):
|
|
52
|
+
patched_method_name = patched_method_name or '_' + method
|
|
53
|
+
|
|
54
|
+
# Deal with reserved identifiers.
|
|
55
|
+
# https://docs.python.org/2/reference/lexical_analysis.html#reserved-classes-of-identifiers
|
|
56
|
+
# method = self._fix_dunder_method_name(method, self.cls.__name__)
|
|
57
|
+
# patched_method_name = self._fix_dunder_method_name(patched_method_name, self.__class__.__name__)
|
|
58
|
+
|
|
59
|
+
# Skip classmethods and staticmethods: replacing the descriptor with a
|
|
60
|
+
# plain function via setattr breaks subclass cls-binding for classmethods
|
|
61
|
+
# (the captured bound-to-base version is called instead of bound-to-subclass)
|
|
62
|
+
# and breaks staticmethods (they receive 'self' unexpectedly).
|
|
63
|
+
# Modules have no __mro__; skip the walk for module-level functions
|
|
64
|
+
# (module attrs can never be classmethod/staticmethod descriptors).
|
|
65
|
+
mro = getattr(self.cls, '__mro__', None)
|
|
66
|
+
method = self._fix_dunder_method_name(method, self.cls.__name__)
|
|
67
|
+
if mro is not None:
|
|
68
|
+
for klass in mro:
|
|
69
|
+
raw = vars(klass).get(method)
|
|
70
|
+
if raw is not None:
|
|
71
|
+
if isinstance(raw, (classmethod, staticmethod)):
|
|
72
|
+
return
|
|
73
|
+
break # found as a plain function/descriptor, safe to wrap
|
|
74
|
+
|
|
75
|
+
patched_method_name = self._fix_dunder_method_name(patched_method_name, self.__class__.__name__)
|
|
76
|
+
|
|
77
|
+
# Wrap the original method if required.
|
|
78
|
+
original_method = getattr(self.cls, method)
|
|
79
|
+
|
|
80
|
+
if not isinstance(original_method, types.FunctionType) and not isinstance(original_method, types.MethodType):
|
|
81
|
+
return
|
|
82
|
+
|
|
83
|
+
# Do not intercept the same method more than once.
|
|
84
|
+
if hasattr(original_method, '_pythonagent_intercepted'):
|
|
85
|
+
return
|
|
86
|
+
|
|
87
|
+
if wrapper_func:
|
|
88
|
+
@wraps(original_method)
|
|
89
|
+
def wrapped_method(*args, **kwargs):
|
|
90
|
+
return wrapper_func(original_method, *args, **kwargs)
|
|
91
|
+
real_method = wrapped_method
|
|
92
|
+
else:
|
|
93
|
+
real_method = original_method
|
|
94
|
+
|
|
95
|
+
# Replace `self.cls.method` with a call to the patched method.
|
|
96
|
+
patched_method = getattr(self, patched_method_name)
|
|
97
|
+
|
|
98
|
+
if inspect.iscoroutinefunction(patched_method):
|
|
99
|
+
@wraps(original_method)
|
|
100
|
+
async def call_patched_method(*args, **kwargs):
|
|
101
|
+
return await patched_method(real_method, *args, **kwargs)
|
|
102
|
+
else:
|
|
103
|
+
@wraps(original_method)
|
|
104
|
+
def call_patched_method(*args, **kwargs):
|
|
105
|
+
return patched_method(real_method, *args, **kwargs)
|
|
106
|
+
|
|
107
|
+
call_patched_method._pythonagent_intercepted = True
|
|
108
|
+
|
|
109
|
+
setattr(self.cls, method, call_patched_method)
|
|
110
|
+
|
|
111
|
+
def attach(self, method_or_methods, wrapper_func=None, patched_method_name=None):
|
|
112
|
+
if not isinstance(method_or_methods, list):
|
|
113
|
+
method_or_methods = [method_or_methods]
|
|
114
|
+
for method in method_or_methods:
|
|
115
|
+
self._attach(method, wrapper_func, patched_method_name)
|
|
116
|
+
|
|
117
|
+
def log_exception(self, level=1):
|
|
118
|
+
self.agent.logger.exception('Exception in {klass}.{function}.'.format(klass=self.__class__.__name__, function=level))
|
|
119
|
+
|
|
120
|
+
@contextmanager
|
|
121
|
+
def log_exceptions(self):
|
|
122
|
+
try:
|
|
123
|
+
yield
|
|
124
|
+
except Exception as e:
|
|
125
|
+
from pythonagent.agent.probes.havoc.havoc_manager import NDHavocException
|
|
126
|
+
if isinstance(e, NDHavocException):
|
|
127
|
+
raise e
|
|
128
|
+
self.log_exception(level=3)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
NO_WRAPPER = object()
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class ExitCallInterceptor(BaseInterceptor):
|
|
135
|
+
def attach(self, method_or_methods, wrapper_func=NO_WRAPPER, patched_method_name=None):
|
|
136
|
+
if wrapper_func is NO_WRAPPER:
|
|
137
|
+
wrapper_func = self.run
|
|
138
|
+
super(ExitCallInterceptor, self).attach(method_or_methods, wrapper_func=wrapper_func,
|
|
139
|
+
patched_method_name=patched_method_name)
|
|
140
|
+
|
|
141
|
+
def make_correlation_header(self, exit_call):
|
|
142
|
+
header = None
|
|
143
|
+
if exit_call and header is not None:
|
|
144
|
+
exit_call.optional_properties['CorrelationHeader'] = header[1]
|
|
145
|
+
return header
|
|
146
|
+
|
|
147
|
+
def http_call_begin(self, bt, http_host, url, method_name, start_time, backend_name=None, callout_id=0):
|
|
148
|
+
"""Start an exit call."""
|
|
149
|
+
|
|
150
|
+
exit_call = None
|
|
151
|
+
backend_name = backend_name or http_host
|
|
152
|
+
with self.log_exceptions():
|
|
153
|
+
self.agent.logger.debug("http call begin bt {} http_host {} url {} method_name {} current_time {}".format(bt, http_host, url, method_name, start_time))
|
|
154
|
+
exit_call= self.agent.http_call_begin(bt, http_host, url, method_name, start_time) # Native
|
|
155
|
+
try:
|
|
156
|
+
from pythonagent.agent.probes.havoc.havoc_manager import NDHavocException
|
|
157
|
+
backend_name_value = self.agent.setting_backend_name_otel(backend_name, "HTTP")
|
|
158
|
+
if backend_name_value:
|
|
159
|
+
backend_name_value = backend_name_value.decode() if isinstance(backend_name_value, bytes) else backend_name_value
|
|
160
|
+
ctx = self.agent.get_transaction_context()
|
|
161
|
+
btname = ctx.btname if ctx else None
|
|
162
|
+
req_url = ctx.url_path if ctx else None
|
|
163
|
+
self.agent.havoc_monitor.apply_outbound_service_failure(backend_name, backend_name_value, req_url, btname)
|
|
164
|
+
|
|
165
|
+
except Exception as e:
|
|
166
|
+
if isinstance(e, NDHavocException):
|
|
167
|
+
self.agent.logger.info("Havoc Exception {}".format(e))
|
|
168
|
+
status = 503
|
|
169
|
+
self.agent.set_current_status_code(503)
|
|
170
|
+
self.agent.get_nd_header(bt, backend_name, callout_id)
|
|
171
|
+
self.agent.http_call_end(bt, exit_call, method_name, backend_name, status, 0, start_time, callout_id)
|
|
172
|
+
raise e
|
|
173
|
+
else:
|
|
174
|
+
self.agent.logger.info("Non-Havoc Exception {}".format(e))
|
|
175
|
+
return exit_call
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def run(self, func, *args, **kwargs):
|
|
179
|
+
"""Run the function. If it raises an exception, end the exit call started from func
|
|
180
|
+
and raise the exception.
|
|
181
|
+
|
|
182
|
+
The exit call that needs to be managed should be passed as key word argument pythonagent_exit_call.
|
|
183
|
+
|
|
184
|
+
"""
|
|
185
|
+
exit_call = kwargs.pop('pythonagent_exit_call', None)
|
|
186
|
+
with self.end_exit_call_and_reraise_on_exception(exit_call):
|
|
187
|
+
return func(*args, **kwargs)
|
|
188
|
+
|
|
189
|
+
def http_call_end(self, bt, exit_call, method_name, status=200, duration=0, start_time=0, backend_name=None, callout_id=0):
|
|
190
|
+
"""End the exit call.
|
|
191
|
+
"""
|
|
192
|
+
ctx = self.agent.get_transaction_context()
|
|
193
|
+
if not method_name:
|
|
194
|
+
method_name = ctx.entry_point_fqm if ctx else None
|
|
195
|
+
|
|
196
|
+
if not backend_name:
|
|
197
|
+
backend_name = ctx.backend_header if ctx else None
|
|
198
|
+
|
|
199
|
+
if start_time == 0:
|
|
200
|
+
start_time = ctx.tier_callout_start_time if ctx else 0
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
with self.log_exceptions():
|
|
204
|
+
if not exit_call:
|
|
205
|
+
self.agent.logger.debug("http call end bt {} exit_call {} method_name {} backend_name {} status {} duration {} start_time {}".format(bt, exit_call, method_name, backend_name, status, duration, start_time))
|
|
206
|
+
self.agent.http_call_end(bt, exit_call, method_name, backend_name, status, duration, start_time, callout_id)
|
|
207
|
+
|
|
208
|
+
def db_call_begin(self, bt, db_host, db_query, query_parameters=None, db_start_time=0, method_name=None, host_str=None):
|
|
209
|
+
"""Start an exit call.
|
|
210
|
+
"""
|
|
211
|
+
ip_handle = None
|
|
212
|
+
ctx = self.agent.get_transaction_context()
|
|
213
|
+
if not host_str:
|
|
214
|
+
host_str = ctx.host_str if ctx else None
|
|
215
|
+
if not host_str:
|
|
216
|
+
host_str = db_host
|
|
217
|
+
|
|
218
|
+
with self.log_exceptions():
|
|
219
|
+
if not method_name:
|
|
220
|
+
method_name = ctx.entry_point_fqm if ctx else None
|
|
221
|
+
ip_handle = self.agent.db_call_begin(method_name, bt, db_host, db_query, query_parameters, db_start_time)
|
|
222
|
+
try:
|
|
223
|
+
|
|
224
|
+
from pythonagent.agent.probes.havoc.havoc_manager import NDHavocException
|
|
225
|
+
backend_name = None
|
|
226
|
+
backend_name_value = self.agent.setting_backend_name_otel(host_str, "DB")
|
|
227
|
+
if backend_name_value:
|
|
228
|
+
backend_name = backend_name_value.decode() if isinstance(backend_name_value, bytes) else backend_name_value
|
|
229
|
+
btname = ctx.btname if ctx else None
|
|
230
|
+
req_url = ctx.url_path if ctx else None
|
|
231
|
+
self.agent.havoc_monitor.apply_outbound_service_failure(host_str, backend_name, req_url, btname)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
return ip_handle
|
|
235
|
+
|
|
236
|
+
except Exception as e:
|
|
237
|
+
from pythonagent.agent.probes.havoc.havoc_manager import NDHavocException
|
|
238
|
+
if isinstance(e, NDHavocException):
|
|
239
|
+
self.agent.logger.info("Havoc Exception {}".format(e))
|
|
240
|
+
status_code = 503
|
|
241
|
+
self.agent.set_current_status_code(status_code)
|
|
242
|
+
if ctx:
|
|
243
|
+
ctx.status_code = status_code
|
|
244
|
+
self.agent.db_call_end(bt, ip_handle, 0, db_start_time, method_name, host_str, status_code)
|
|
245
|
+
raise e
|
|
246
|
+
else:
|
|
247
|
+
self.agent.logger.info("Non-Havoc Exception {}".format(e))
|
|
248
|
+
return ip_handle
|
|
249
|
+
|
|
250
|
+
def db_call_end(self, bt, ip_handle, duration=None, db_start_time=None, entry_point_fqm=None, host_str=None, status_code=None):
|
|
251
|
+
"""End the exit call.
|
|
252
|
+
"""
|
|
253
|
+
ctx = self.agent.get_transaction_context()
|
|
254
|
+
if not entry_point_fqm:
|
|
255
|
+
entry_point_fqm = ctx.entry_point_fqm if ctx else None
|
|
256
|
+
|
|
257
|
+
if not host_str:
|
|
258
|
+
host_str = ctx.host_str if ctx else None
|
|
259
|
+
|
|
260
|
+
if not status_code:
|
|
261
|
+
status_code = ctx.status_code if ctx else None
|
|
262
|
+
|
|
263
|
+
with self.log_exceptions():
|
|
264
|
+
if bt:
|
|
265
|
+
self.agent.db_call_end(bt, ip_handle, duration, db_start_time, entry_point_fqm, host_str, status_code)
|
|
266
|
+
|
|
267
|
+
@contextmanager
|
|
268
|
+
def end_exit_call_and_reraise_on_exception(self, exit_call, ignored_exceptions=()):
|
|
269
|
+
try:
|
|
270
|
+
yield
|
|
271
|
+
except ignored_exceptions:
|
|
272
|
+
raise
|
|
273
|
+
except:
|
|
274
|
+
self.agent.logger.exception("Exception raised in end exit call !!! {0}".format(sys.exc_info()))
|
|
275
|
+
raise
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
class EntryPointInterceptor(BaseInterceptor):
|
|
279
|
+
HTTP_ERROR_DISPLAY_NAME = 'HTTP {code}'
|
|
280
|
+
|
|
281
|
+
def start_business_transaction(self, bt_name, correlation_header, nd_cookie=None, nv_cookie=None, bt_header_value=None, fp_instance=None):
|
|
282
|
+
with self.log_exceptions():
|
|
283
|
+
return self.agent.start_business_transaction(bt_name, correlation_header, nd_cookie, nv_cookie,bt_header_value, fp_instance)
|
|
284
|
+
|
|
285
|
+
def end_business_transaction(self, bt, cpu_time):
|
|
286
|
+
with self.log_exceptions():
|
|
287
|
+
self.agent.end_business_transaction(bt, cpu_time)
|
|
288
|
+
|
|
289
|
+
def handle_http_status_code(self, bt, status_code, msg):
|
|
290
|
+
"""Add the status code to the BT and deal with error codes.
|
|
291
|
+
|
|
292
|
+
If the status code is in the error config and enabled, or the status
|
|
293
|
+
code is >= 400, create an ErrorInfo object and add it to the BT.
|
|
294
|
+
|
|
295
|
+
"""
|
|
296
|
+
self.agent.set_current_status_code(status_code)
|
|
297
|
+
if status_code >= 400:
|
|
298
|
+
self.agent.logger.info('Message is '.format(msg))
|
|
299
|
+
else:
|
|
300
|
+
return
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Base interceptor for distributed caches (typically, key-value stores).
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import unicode_literals
|
|
6
|
+
|
|
7
|
+
#from appdynamics.agent.models.exitcalls import EXIT_CACHE, EXIT_SUBTYPE_CACHE
|
|
8
|
+
from ..base import ExitCallInterceptor
|
|
9
|
+
|
|
10
|
+
EXIT_CACHE= 1
|
|
11
|
+
EXIT_SUBTYPE_CACHE ='CACHE'
|
|
12
|
+
class CacheInterceptor(ExitCallInterceptor):
|
|
13
|
+
"""Base class for cache interceptors.
|
|
14
|
+
|
|
15
|
+
Extra Parameters
|
|
16
|
+
-----------------
|
|
17
|
+
vendor : string
|
|
18
|
+
The vendor name of this cache backend e.g. MEMCACHED.
|
|
19
|
+
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
backend_name_format_string = '{SERVER POOL} - {VENDOR}'
|
|
23
|
+
|
|
24
|
+
def __init__(self, agent, cls, vendor):
|
|
25
|
+
self.vendor = vendor
|
|
26
|
+
super(CacheInterceptor, self).__init__(agent, cls)
|
|
27
|
+
|
|
28
|
+
def get_backend(self, server_pool):
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
Parameters
|
|
32
|
+
----------
|
|
33
|
+
server_pool : list of str
|
|
34
|
+
|
|
35
|
+
"""
|
|
36
|
+
self.agent.logger.info('Modulenam CacheInterceptor class inside get_backend')
|
|
37
|
+
backend_properties = {
|
|
38
|
+
'VENDOR': self.vendor,
|
|
39
|
+
'SERVER POOL': '\n'.join(server_pool),
|
|
40
|
+
}
|
|
41
|
+
self.agent.logger.info("Modulenam CacheInterceptor class inside get_backend backend_properties is {0}".format(backend_properties))
|
|
42
|
+
return self.agent.backend_registry.get_backend(EXIT_CACHE, EXIT_SUBTYPE_CACHE, backend_properties,self.backend_name_format_string)
|
|
43
|
+
# return None
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
from .redis import intercept_redis
|
|
47
|
+
from .redis_asyncio import intercept_redis_asyncio
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
__all__ = ['intercept_redis', 'intercept_redis_asyncio']
|
|
51
|
+
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""Interceptor for Redis.
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import unicode_literals
|
|
6
|
+
|
|
7
|
+
from pythonagent.agent.probes.cache import CacheInterceptor
|
|
8
|
+
from pythonagent.utils import generate_flow_path_id, get_utf8_bytes, get_current_timestamp_in_us, get_validated_duration
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class RedisConnectionInterceptor(CacheInterceptor):
|
|
12
|
+
|
|
13
|
+
def __init__(self, agent, cls):
|
|
14
|
+
super(RedisConnectionInterceptor, self).__init__(agent, cls, 'REDIS')
|
|
15
|
+
|
|
16
|
+
def _send_packed_command(self, send_packed_command, connection, command, check_health=True):
|
|
17
|
+
exit_call = None
|
|
18
|
+
bt = None
|
|
19
|
+
db_start_time = 0
|
|
20
|
+
try:
|
|
21
|
+
# Extract command string early so we can guard on PING before touching context
|
|
22
|
+
command_str = ""
|
|
23
|
+
command_len = len(command)
|
|
24
|
+
if command_len != 0:
|
|
25
|
+
if command_len == 1:
|
|
26
|
+
parts = command[0].decode('utf-8', errors='replace').split('\n')
|
|
27
|
+
command_str = parts[2][:-1] if len(parts) > 2 else ""
|
|
28
|
+
else:
|
|
29
|
+
for i in range(command_len):
|
|
30
|
+
try:
|
|
31
|
+
parts = command[i].decode('utf-8', errors='replace').split('\n')
|
|
32
|
+
if len(parts) > 2:
|
|
33
|
+
sep = ',' if i < command_len - 1 else ''
|
|
34
|
+
command_str += parts[2][:-1] + sep
|
|
35
|
+
except AttributeError:
|
|
36
|
+
continue
|
|
37
|
+
|
|
38
|
+
# Skip internal health-check PINGs to prevent infinite recursion:
|
|
39
|
+
# Redis's check_health() sends a PING through the patched send_packed_command,
|
|
40
|
+
# which would re-enter this interceptor and loop indefinitely.
|
|
41
|
+
if command_str == "PING":
|
|
42
|
+
return send_packed_command(connection, command,
|
|
43
|
+
check_health=check_health,
|
|
44
|
+
pythonagent_exit_call=None)
|
|
45
|
+
|
|
46
|
+
# format :- "PROTOCOL|HOST|PORT|URL|DBPRODNAME|DBNAME|DBPRODVER|DRIVERNAME|DRIVERVER|USERNAME|SERVICENAME"
|
|
47
|
+
host_name_str = f"NA|{connection.host}|{connection.port}|NA|REDIS|{connection.db}|NA|NA|NA|{connection.username}|NA"
|
|
48
|
+
ctx = self.agent.get_transaction_context()
|
|
49
|
+
if ctx is not None:
|
|
50
|
+
ctx.host_str = host_name_str
|
|
51
|
+
ctx.entry_point_fqm = connection.__module__ + "." + send_packed_command.__qualname__
|
|
52
|
+
|
|
53
|
+
bt = self.bt or self.agent.get_current_bt()
|
|
54
|
+
self.agent.logger.info("Modulename: RedisConnectionInterceptor class || bt value is {0}".format(bt))
|
|
55
|
+
|
|
56
|
+
if bt:
|
|
57
|
+
try:
|
|
58
|
+
server_pool = ['%s:%s' % (connection.host, connection.port)]
|
|
59
|
+
except AttributeError:
|
|
60
|
+
# For UnixDomainSocketConnection objects.
|
|
61
|
+
server_pool = [connection.path]
|
|
62
|
+
#backend = self.get_backend(server_pool)
|
|
63
|
+
backend = True
|
|
64
|
+
if backend:
|
|
65
|
+
db_start_time = get_current_timestamp_in_us()
|
|
66
|
+
if ctx is not None:
|
|
67
|
+
ctx.db_callout_start_time = db_start_time
|
|
68
|
+
self.agent.logger.debug("db_call_begin for redis bt {} host {} query {} query_params {} db_start_time {}".format(bt, connection.host, command_str, None, db_start_time))
|
|
69
|
+
exit_call = self.db_call_begin(bt, connection.host, command_str, None, db_start_time, host_str=host_name_str)
|
|
70
|
+
|
|
71
|
+
except Exception as e:
|
|
72
|
+
from pythonagent.agent.probes.havoc.havoc_manager import NDHavocException
|
|
73
|
+
if isinstance(e, NDHavocException):
|
|
74
|
+
raise e
|
|
75
|
+
self.agent.logger.exception("Exception in DB begin for redis {}".format(e))
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
# Forward check_health so the original receives check_health=False when the
|
|
79
|
+
# health-check retry path calls us, preventing another check_health() cycle.
|
|
80
|
+
result = send_packed_command(connection, command,
|
|
81
|
+
check_health=check_health,
|
|
82
|
+
pythonagent_exit_call=exit_call)
|
|
83
|
+
except Exception as e:
|
|
84
|
+
self.agent.logger.exception("Error in application: {}".format(e))
|
|
85
|
+
try:
|
|
86
|
+
db_end_time = get_current_timestamp_in_us()
|
|
87
|
+
ctx = self.agent.get_transaction_context()
|
|
88
|
+
db_start_time = ctx.db_callout_start_time if ctx else 0
|
|
89
|
+
duration = get_validated_duration(db_start_time, db_end_time, "Redis")
|
|
90
|
+
if ctx:
|
|
91
|
+
ctx.status_code = 500
|
|
92
|
+
ctx.db_callout_start_time = 0
|
|
93
|
+
self.agent.logger.debug("db_call_end for redis with exception bt {} ip_handle {} duration {} db_start_time {}".format(bt, exit_call, duration, db_start_time))
|
|
94
|
+
self.db_call_end(bt, exit_call, duration, db_start_time)
|
|
95
|
+
except Exception as e:
|
|
96
|
+
self.agent.logger.exception("Exception in Original Method DB Call End for redis {}".format(e))
|
|
97
|
+
raise
|
|
98
|
+
|
|
99
|
+
try:
|
|
100
|
+
db_end_time = get_current_timestamp_in_us()
|
|
101
|
+
ctx = self.agent.get_transaction_context()
|
|
102
|
+
db_start_time = ctx.db_callout_start_time if ctx else 0
|
|
103
|
+
duration = get_validated_duration(db_start_time, db_end_time, "Redis")
|
|
104
|
+
if ctx:
|
|
105
|
+
ctx.status_code = 200
|
|
106
|
+
ctx.db_callout_start_time = 0
|
|
107
|
+
self.agent.logger.debug("db_call_end for redis bt {} ip_handle {} duration {} db_start_time {}".format(bt, exit_call, duration, db_start_time))
|
|
108
|
+
self.db_call_end(bt, exit_call, duration, db_start_time)
|
|
109
|
+
|
|
110
|
+
except Exception as e:
|
|
111
|
+
self.agent.logger.debug("Exception in DB End for redis {}".format(e))
|
|
112
|
+
|
|
113
|
+
return result
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def intercept_redis(agent, mod):
|
|
117
|
+
agent.logger.warning("Instrument module: redis.connection{}".format(", mod: {}".format(mod) if mod else ""))
|
|
118
|
+
RedisConnectionInterceptor(agent, mod.Connection).attach('send_packed_command')
|
|
119
|
+
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""Interceptor for Async Redis.
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import unicode_literals
|
|
6
|
+
|
|
7
|
+
from pythonagent.agent.probes.cache import CacheInterceptor
|
|
8
|
+
from pythonagent.utils import generate_flow_path_id, get_utf8_bytes, get_current_timestamp_in_us, get_validated_duration
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class RedisAsyncIOConnectionInterceptor(CacheInterceptor):
|
|
12
|
+
|
|
13
|
+
def __init__(self, agent, cls):
|
|
14
|
+
super(RedisAsyncIOConnectionInterceptor, self).__init__(agent, cls, 'RedisAsyncIO')
|
|
15
|
+
|
|
16
|
+
async def _send_packed_command(self, send_packed_command, *args, **kwargs):
|
|
17
|
+
|
|
18
|
+
bt = None
|
|
19
|
+
exit_call = None
|
|
20
|
+
db_start_time = 0
|
|
21
|
+
entry_point_fqm = ""
|
|
22
|
+
host_str = ""
|
|
23
|
+
status_code = 0
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
connection = args[0]
|
|
27
|
+
command = args[1]
|
|
28
|
+
|
|
29
|
+
command_str = ""
|
|
30
|
+
command_len = len(command)
|
|
31
|
+
if command_len != 0:
|
|
32
|
+
if command_len == 1:
|
|
33
|
+
command_str = command[0].decode().split('\n')[2][:-1]
|
|
34
|
+
else:
|
|
35
|
+
for i in range(command_len):
|
|
36
|
+
if i < command_len - 1:
|
|
37
|
+
command_str += command[i].decode().split('\n')[2][:-1] + ','
|
|
38
|
+
else:
|
|
39
|
+
command_str += command[i].decode().split('\n')[2][:-1]
|
|
40
|
+
|
|
41
|
+
if command_str == "CLIENT":
|
|
42
|
+
return await send_packed_command(*args, **kwargs)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
# format :- "PROTOCOL|HOST|PORT|URL|DBPRODNAME|DBNAME|DBPRODVER|DRIVERNAME|DRIVERVER|USERNAME|SERVICENAME"
|
|
46
|
+
host_str = f"NA|{connection.host}|{connection.port}|NA|REDIS|{connection.db}|NA|NA|NA|{connection.username}|NA"
|
|
47
|
+
entry_point_fqm = connection.__module__ + "." + send_packed_command.__qualname__
|
|
48
|
+
|
|
49
|
+
bt = self.bt
|
|
50
|
+
query_parameters = None
|
|
51
|
+
db_start_time = get_current_timestamp_in_us()
|
|
52
|
+
exit_call = self.db_call_begin(bt, connection.host, command_str, query_parameters, db_start_time, entry_point_fqm, host_str)
|
|
53
|
+
except Exception as e:
|
|
54
|
+
from pythonagent.agent.probes.havoc.havoc_manager import NDHavocException
|
|
55
|
+
if isinstance(e, NDHavocException):
|
|
56
|
+
raise e
|
|
57
|
+
self.agent.logger.exception("Error in DB Begin part of redis_asyncio: {}".format(e))
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
result = await send_packed_command(*args, **kwargs)
|
|
61
|
+
except Exception as e:
|
|
62
|
+
db_end_time = get_current_timestamp_in_us()
|
|
63
|
+
duration = get_validated_duration(db_start_time, db_end_time, "redis_asyncio")
|
|
64
|
+
status_code = 500
|
|
65
|
+
self.db_call_end(bt, exit_call, duration, db_start_time, entry_point_fqm, host_str, status_code)
|
|
66
|
+
raise
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
db_end_time = get_current_timestamp_in_us()
|
|
70
|
+
duration = get_validated_duration(db_start_time, db_end_time, "Redis")
|
|
71
|
+
status_code = 200
|
|
72
|
+
self.agent.logger.debug("db_call_end for redis bt {} ip_handle {} duration {} db_start_time {}".format(bt, exit_call, duration, db_start_time))
|
|
73
|
+
self.db_call_end(bt, exit_call, duration, db_start_time, entry_point_fqm, host_str, status_code)
|
|
74
|
+
|
|
75
|
+
except Exception as e:
|
|
76
|
+
self.agent.logger.exception("Error in DB End part of redis_asyncio: {}".format(e))
|
|
77
|
+
|
|
78
|
+
return result
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def intercept_redis_asyncio(agent, mod):
|
|
82
|
+
agent.logger.warning("Instrument module: redis.asyncio.connection{}".format(", mod: {}".format(mod) if mod else ""))
|
|
83
|
+
RedisAsyncIOConnectionInterceptor(agent, mod.Connection).attach('send_packed_command')
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .asyncio import intercept_asyncio
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Interceptor for Asyncio
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import unicode_literals
|
|
6
|
+
from ..base import ExitCallInterceptor
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AsyncioInterceptor(ExitCallInterceptor):
|
|
10
|
+
|
|
11
|
+
def _dd_create_task(self, create_task, *args, **kwargs):
|
|
12
|
+
|
|
13
|
+
coro = self.get_argument_value(args, kwargs, 1, "coro")
|
|
14
|
+
|
|
15
|
+
context = self.agent.get_transaction_context()
|
|
16
|
+
|
|
17
|
+
async def traced_coro(*args_c, **kwargs_c):
|
|
18
|
+
|
|
19
|
+
if context and context != self.agent.get_transaction_context():
|
|
20
|
+
self.agent.set_transaction_context(context)
|
|
21
|
+
|
|
22
|
+
return await coro
|
|
23
|
+
|
|
24
|
+
args, kwargs = self.set_argument_value(args, kwargs, 1, "coro", traced_coro())
|
|
25
|
+
|
|
26
|
+
call = create_task(*args, **kwargs)
|
|
27
|
+
|
|
28
|
+
return call
|
|
29
|
+
|
|
30
|
+
def _set_event_loop(self, set_event_loop, *args, **kwargs):
|
|
31
|
+
ss = set_event_loop(*args, **kwargs)
|
|
32
|
+
return ss
|
|
33
|
+
|
|
34
|
+
def _get_event_loop(self, get_event_loop, *args, **kwargs):
|
|
35
|
+
get = get_event_loop()
|
|
36
|
+
|
|
37
|
+
def get_argument_value(self, args, kwargs, pos, kw, optional=False):
|
|
38
|
+
try:
|
|
39
|
+
return kwargs[kw]
|
|
40
|
+
except KeyError:
|
|
41
|
+
try:
|
|
42
|
+
return args[pos]
|
|
43
|
+
except IndexError:
|
|
44
|
+
if optional:
|
|
45
|
+
return None
|
|
46
|
+
raise Exception("%s (at position %d)" % (kw, pos))
|
|
47
|
+
|
|
48
|
+
def set_argument_value(self, args, kwargs, pos, kw, value, override_unset=False):
|
|
49
|
+
if len(args) > pos:
|
|
50
|
+
args = args[:pos] + (value,) + args[pos + 1:]
|
|
51
|
+
elif kw in kwargs or override_unset:
|
|
52
|
+
kwargs[kw] = value
|
|
53
|
+
else:
|
|
54
|
+
raise Exception("%s (at position %d) is invalid" % (kw, pos))
|
|
55
|
+
|
|
56
|
+
return args, kwargs
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def intercept_asyncio(agent, mod):
|
|
60
|
+
agent.logger.warning("Instrument module: asyncio{}".format(", mod: {}".format(mod) if mod else ""))
|
|
61
|
+
AsyncioInterceptor(agent, mod.base_events.BaseEventLoop).attach('create_task',
|
|
62
|
+
patched_method_name="_dd_create_task")
|
|
63
|
+
#AsyncioInterceptor(agent, mod.events.BaseDefaultEventLoopPolicy).attach("set_event_loop")
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from __future__ import unicode_literals
|
|
2
|
+
from ..base import ExitCallInterceptor
|
|
3
|
+
from pythonagent.lang import str
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def intercept_elastic(agent, mod):
|
|
7
|
+
class ExitCallListener(mod.monitoring.CommandListener):
|
|
8
|
+
backend_name_format_string = '{HOST}:{PORT} - {DATABASE}'
|
|
9
|
+
|
|
10
|
+
def __init__(self):
|
|
11
|
+
self.interceptor = ExitCallInterceptor(agent, None)
|
|
12
|
+
self.exit_call_map = {}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_backend(self, connection_id):
|
|
16
|
+
#agent.logger.debug('Modulenameintercept_pymongo class inside get_backend function')
|
|
17
|
+
print("connection iddddddddddddddddddddddddddddddddd::::::::::::::::::", connection_id)
|
|
18
|
+
host, port = connection_id
|
|
19
|
+
backend_properties = {
|
|
20
|
+
'HOST': host,
|
|
21
|
+
'PORT': str(port)
|
|
22
|
+
}
|
|
23
|
+
return backend_properties
|
|
24
|
+
|
|
25
|
+
def started(self, event):
|
|
26
|
+
agent.logger.info('Modulenameintercept_elastic class inside started function is ')
|
|
27
|
+
with self.interceptor.log_exceptions():
|
|
28
|
+
agent.logger.info('Modulenameintercept_elastic class inside started function is ')
|
|
29
|
+
with self.interceptor.log_exceptions():
|
|
30
|
+
agent.logger.info("inside _execute funciton")
|
|
31
|
+
agent.logger.info("event:{0} ".format(event))
|
|
32
|
+
bt = self.interceptor.bt
|
|
33
|
+
|
|
34
|
+
agent.logger.info("bt statment....{0}".format(bt))
|
|
35
|
+
if not bt:
|
|
36
|
+
bt = agent.get_current_bt()
|
|
37
|
+
agent.logger.info("new bt value{0}".format(bt))
|
|
38
|
+
if bt:
|
|
39
|
+
backend = self.get_backend(event.connection_id, event.database_name)
|
|
40
|
+
agent.logger.info("backend..........{0}".format(backend))
|
|
41
|
+
agent.logger.info("Modulenameintercept_pymongo class || backend is{0}".format(backend))
|
|
42
|
+
if backend:
|
|
43
|
+
agent.logger.info("host.....".format(backend["HOST"]))
|
|
44
|
+
|
|
45
|
+
if backend and not hasattr(event, '_pythonagent_exit_call'):
|
|
46
|
+
exit_call = self.interceptor.db_call_begin(bt, backend["HOST"], str(event.command))
|
|
47
|
+
self.exit_call_map[event.operation_id] = exit_call
|
|
48
|
+
|
|
49
|
+
def succeeded(self, event):
|
|
50
|
+
self.interceptor.db_call_end(self.interceptor.bt,self.exit_call_map.pop(event.operation_id,None))
|
|
51
|
+
def failed(self, event):
|
|
52
|
+
self.interceptor.db_call_end(self.interceptor.bt,self.exit_call_map.pop(event.operation_id,None))
|
|
53
|
+
|
|
54
|
+
mod.monitoring.register(ExitCallListener())
|