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.
Files changed (180) hide show
  1. cavisson_pythonagent-0.0.1.dist-info/METADATA +32 -0
  2. cavisson_pythonagent-0.0.1.dist-info/RECORD +180 -0
  3. cavisson_pythonagent-0.0.1.dist-info/WHEEL +5 -0
  4. cavisson_pythonagent-0.0.1.dist-info/licenses/LICENSE +19 -0
  5. cavisson_pythonagent-0.0.1.dist-info/top_level.txt +1 -0
  6. pythonagent/__init__.py +22 -0
  7. pythonagent/agent/__init__.py +219 -0
  8. pythonagent/agent/internal/__init__.py +1 -0
  9. pythonagent/agent/internal/agent.py +1651 -0
  10. pythonagent/agent/internal/framesinfo.py +152 -0
  11. pythonagent/agent/internal/heap_dump.py +39 -0
  12. pythonagent/agent/internal/intercept_module.py +70 -0
  13. pythonagent/agent/internal/logs.py +122 -0
  14. pythonagent/agent/internal/metadata/__init__.py +0 -0
  15. pythonagent/agent/internal/metadata/agent_meta_data.py +276 -0
  16. pythonagent/agent/internal/proc_compat.py +75 -0
  17. pythonagent/agent/internal/profile.py +47 -0
  18. pythonagent/agent/internal/provider.py +83 -0
  19. pythonagent/agent/internal/thread_dump.py +85 -0
  20. pythonagent/agent/internal/udp.py +245 -0
  21. pythonagent/agent/internal/udp_message.py +800 -0
  22. pythonagent/agent/probes/Instrumentation/__init__.py +340 -0
  23. pythonagent/agent/probes/Instrumentation/find.py +243 -0
  24. pythonagent/agent/probes/Instrumentation/module_version_resolver.py +155 -0
  25. pythonagent/agent/probes/Instrumentation/new_parser.py +64 -0
  26. pythonagent/agent/probes/Instrumentation/parser.py +129 -0
  27. pythonagent/agent/probes/__init__.py +219 -0
  28. pythonagent/agent/probes/base.py +303 -0
  29. pythonagent/agent/probes/cache/__init__.py +51 -0
  30. pythonagent/agent/probes/cache/redis.py +119 -0
  31. pythonagent/agent/probes/cache/redis_asyncio.py +83 -0
  32. pythonagent/agent/probes/coroutines/__init__.py +1 -0
  33. pythonagent/agent/probes/coroutines/asyncio.py +63 -0
  34. pythonagent/agent/probes/elasticdb/__init__.py +7 -0
  35. pythonagent/agent/probes/elasticdb/aelastic.py +54 -0
  36. pythonagent/agent/probes/frameworks/__init__.py +27 -0
  37. pythonagent/agent/probes/frameworks/agentprofiler.py +105 -0
  38. pythonagent/agent/probes/frameworks/aiohttp_web.py +155 -0
  39. pythonagent/agent/probes/frameworks/aisess.py +151 -0
  40. pythonagent/agent/probes/frameworks/asgi.py +340 -0
  41. pythonagent/agent/probes/frameworks/bottle.py +27 -0
  42. pythonagent/agent/probes/frameworks/cherry.py +25 -0
  43. pythonagent/agent/probes/frameworks/django.py +128 -0
  44. pythonagent/agent/probes/frameworks/falcon.py +21 -0
  45. pythonagent/agent/probes/frameworks/fastapi.py +35 -0
  46. pythonagent/agent/probes/frameworks/flask.py +30 -0
  47. pythonagent/agent/probes/frameworks/pyramid.py +56 -0
  48. pythonagent/agent/probes/frameworks/test.py +108 -0
  49. pythonagent/agent/probes/frameworks/tornado_async_web.py +117 -0
  50. pythonagent/agent/probes/frameworks/tornado_web.py +133 -0
  51. pythonagent/agent/probes/frameworks/wsgi.py +353 -0
  52. pythonagent/agent/probes/grpc/__init__.py +76 -0
  53. pythonagent/agent/probes/grpc/client_interceptor.py +132 -0
  54. pythonagent/agent/probes/grpc/server_interceptor.py +129 -0
  55. pythonagent/agent/probes/havoc/__init__.py +0 -0
  56. pythonagent/agent/probes/havoc/custom_memory_stress.py +186 -0
  57. pythonagent/agent/probes/havoc/custom_thread_stress.py +187 -0
  58. pythonagent/agent/probes/havoc/havoc_constants.py +218 -0
  59. pythonagent/agent/probes/havoc/havoc_manager.py +981 -0
  60. pythonagent/agent/probes/http/__init__.py +49 -0
  61. pythonagent/agent/probes/http/aiohttp_client.py +59 -0
  62. pythonagent/agent/probes/http/boto.py +12 -0
  63. pythonagent/agent/probes/http/httplib.py +110 -0
  64. pythonagent/agent/probes/http/httpx_client.py +116 -0
  65. pythonagent/agent/probes/http/requests.py +15 -0
  66. pythonagent/agent/probes/http/tornado_httpclient.py +85 -0
  67. pythonagent/agent/probes/http/urllib3.py +16 -0
  68. pythonagent/agent/probes/langchain/__init__.py +21 -0
  69. pythonagent/agent/probes/langchain/base_tool.py +95 -0
  70. pythonagent/agent/probes/langchain/langchain_community.py +136 -0
  71. pythonagent/agent/probes/langchain/langchain_core.py +32 -0
  72. pythonagent/agent/probes/langchain/langchain_openai.py +110 -0
  73. pythonagent/agent/probes/logging/__init__.py +106 -0
  74. pythonagent/agent/probes/message_brokers/__init__.py +4 -0
  75. pythonagent/agent/probes/message_brokers/pika.py +126 -0
  76. pythonagent/agent/probes/mongodb/__init__.py +6 -0
  77. pythonagent/agent/probes/mongodb/pymongo.py +286 -0
  78. pythonagent/agent/probes/openai/__init__.py +3 -0
  79. pythonagent/agent/probes/openai/openai.py +797 -0
  80. pythonagent/agent/probes/span.py +101 -0
  81. pythonagent/agent/probes/sql/__init__.py +13 -0
  82. pythonagent/agent/probes/sql/botocores3.py +51 -0
  83. pythonagent/agent/probes/sql/dbapi.py +285 -0
  84. pythonagent/agent/probes/sql/dynamodb.py +90 -0
  85. pythonagent/agent/probes/sql/mysql_connector.py +24 -0
  86. pythonagent/agent/probes/sql/mysql_connector_cext.py +24 -0
  87. pythonagent/agent/probes/sql/mysqldb.py +43 -0
  88. pythonagent/agent/probes/sql/psycopg2.py +174 -0
  89. pythonagent/agent/probes/sql/pymysql.py +25 -0
  90. pythonagent/bootstrap/__init__.py +0 -0
  91. pythonagent/bootstrap/cav_gunicorn.py +26 -0
  92. pythonagent/bootstrap/cavagent_lambda_wrapper.py +291 -0
  93. pythonagent/bootstrap/run.py +47 -0
  94. pythonagent/bootstrap/sitecustomize.py +287 -0
  95. pythonagent/cavisson/netdiagnostics/CavAgent/instrumentationprofile.json +26 -0
  96. pythonagent/cavisson/netdiagnostics/CavAgent/interceptor_points.txt +29 -0
  97. pythonagent/cavisson/netdiagnostics/python/CavAgent/instrumentationprofile.json +42 -0
  98. pythonagent/cavisson/netdiagnostics/python/CavAgent/interceptor_points.txt +29 -0
  99. pythonagent/cavisson/netdiagnostics/python/config/ndsettings.conf +6 -0
  100. pythonagent/config.py +279 -0
  101. pythonagent/find.py +72 -0
  102. pythonagent/find_mod_cls_name.py +54 -0
  103. pythonagent/lang.py +131 -0
  104. pythonagent/lib.py +91 -0
  105. pythonagent/main/__init__.py +0 -0
  106. pythonagent/main/pytrace/__init__.py +79 -0
  107. pythonagent/main/pytrace/commands/__init__.py +0 -0
  108. pythonagent/main/pytrace/commands/auto_discovery.py +25 -0
  109. pythonagent/main/pytrace/commands/run.py +401 -0
  110. pythonagent/main/pytrace/pytrace.py +133 -0
  111. pythonagent/main/wsgi.py +6 -0
  112. pythonagent/main.py +27 -0
  113. pythonagent/run.py +46 -0
  114. pythonagent/sqins.py +8 -0
  115. pythonagent/test.py +73 -0
  116. pythonagent/utils.py +168 -0
  117. pythonagent/vendor/__init__.py +0 -0
  118. pythonagent/vendor/pympler/__init__.py +1 -0
  119. pythonagent/vendor/pympler/asizeof.py +2810 -0
  120. pythonagent/vendor/pympler/charts.py +62 -0
  121. pythonagent/vendor/pympler/classtracker.py +590 -0
  122. pythonagent/vendor/pympler/classtracker_stats.py +780 -0
  123. pythonagent/vendor/pympler/garbagegraph.py +80 -0
  124. pythonagent/vendor/pympler/mprofile.py +97 -0
  125. pythonagent/vendor/pympler/muppy.py +275 -0
  126. pythonagent/vendor/pympler/panels.py +115 -0
  127. pythonagent/vendor/pympler/process.py +238 -0
  128. pythonagent/vendor/pympler/py.typed +0 -0
  129. pythonagent/vendor/pympler/refbrowser.py +451 -0
  130. pythonagent/vendor/pympler/refgraph.py +350 -0
  131. pythonagent/vendor/pympler/summary.py +321 -0
  132. pythonagent/vendor/pympler/tracker.py +267 -0
  133. pythonagent/vendor/pympler/util/__init__.py +0 -0
  134. pythonagent/vendor/pympler/util/bottle.py +3809 -0
  135. pythonagent/vendor/pympler/util/compat.py +23 -0
  136. pythonagent/vendor/pympler/util/stringutils.py +77 -0
  137. pythonagent/vendor/pympler/web.py +346 -0
  138. pythonagent/vendor/werkzeug/__init__.py +20 -0
  139. pythonagent/vendor/werkzeug/_compat.py +228 -0
  140. pythonagent/vendor/werkzeug/_internal.py +473 -0
  141. pythonagent/vendor/werkzeug/_reloader.py +341 -0
  142. pythonagent/vendor/werkzeug/datastructures.py +3120 -0
  143. pythonagent/vendor/werkzeug/debug/__init__.py +498 -0
  144. pythonagent/vendor/werkzeug/debug/console.py +218 -0
  145. pythonagent/vendor/werkzeug/debug/repr.py +297 -0
  146. pythonagent/vendor/werkzeug/debug/tbtools.py +628 -0
  147. pythonagent/vendor/werkzeug/exceptions.py +829 -0
  148. pythonagent/vendor/werkzeug/filesystem.py +64 -0
  149. pythonagent/vendor/werkzeug/formparser.py +584 -0
  150. pythonagent/vendor/werkzeug/http.py +1307 -0
  151. pythonagent/vendor/werkzeug/local.py +420 -0
  152. pythonagent/vendor/werkzeug/middleware/__init__.py +25 -0
  153. pythonagent/vendor/werkzeug/middleware/dispatcher.py +66 -0
  154. pythonagent/vendor/werkzeug/middleware/http_proxy.py +219 -0
  155. pythonagent/vendor/werkzeug/middleware/lint.py +408 -0
  156. pythonagent/vendor/werkzeug/middleware/profiler.py +132 -0
  157. pythonagent/vendor/werkzeug/middleware/proxy_fix.py +169 -0
  158. pythonagent/vendor/werkzeug/middleware/shared_data.py +293 -0
  159. pythonagent/vendor/werkzeug/posixemulation.py +117 -0
  160. pythonagent/vendor/werkzeug/routing.py +2210 -0
  161. pythonagent/vendor/werkzeug/security.py +249 -0
  162. pythonagent/vendor/werkzeug/serving.py +1117 -0
  163. pythonagent/vendor/werkzeug/test.py +1123 -0
  164. pythonagent/vendor/werkzeug/testapp.py +241 -0
  165. pythonagent/vendor/werkzeug/urls.py +1138 -0
  166. pythonagent/vendor/werkzeug/useragents.py +202 -0
  167. pythonagent/vendor/werkzeug/utils.py +778 -0
  168. pythonagent/vendor/werkzeug/wrappers/__init__.py +36 -0
  169. pythonagent/vendor/werkzeug/wrappers/accept.py +50 -0
  170. pythonagent/vendor/werkzeug/wrappers/auth.py +33 -0
  171. pythonagent/vendor/werkzeug/wrappers/base_request.py +673 -0
  172. pythonagent/vendor/werkzeug/wrappers/base_response.py +700 -0
  173. pythonagent/vendor/werkzeug/wrappers/common_descriptors.py +341 -0
  174. pythonagent/vendor/werkzeug/wrappers/cors.py +100 -0
  175. pythonagent/vendor/werkzeug/wrappers/etag.py +304 -0
  176. pythonagent/vendor/werkzeug/wrappers/json.py +145 -0
  177. pythonagent/vendor/werkzeug/wrappers/request.py +49 -0
  178. pythonagent/vendor/werkzeug/wrappers/response.py +84 -0
  179. pythonagent/vendor/werkzeug/wrappers/user_agent.py +14 -0
  180. pythonagent/vendor/werkzeug/wsgi.py +1000 -0
@@ -0,0 +1,1651 @@
1
+ import logging
2
+ from pythonagent.lib import get_ident
3
+ import ctypes
4
+ from ctypes import create_string_buffer
5
+ import os
6
+ import sys
7
+ import time
8
+ import platform
9
+ from pythonagent.agent.probes.havoc.havoc_manager import NDNetHavocMonitor, NDHavocException
10
+
11
+ from pythonagent.agent.internal import udp
12
+ from pythonagent.agent.internal.provider import ContextProvider, CurrentBTProvider, StatusCodeProvider
13
+ from pythonagent.agent.probes.frameworks import wsgi # aiflagset
14
+ from pythonagent.agent.probes.Instrumentation.find import find
15
+ from pythonagent.agent.internal.metadata.agent_meta_data import build_metadata_block
16
+ from pythonagent.utils import generate_flow_path_id, get_utf8_bytes, get_current_timestamp_in_us, process_raw_havoc_message
17
+ import threading,gc
18
+ from pythonagent.agent.internal.proc_compat import get_rss_bytes
19
+ from threading import Timer
20
+ from pythonagent.agent.internal.thread_dump import dumpstacks
21
+ from pythonagent.agent.internal.heap_dump import create_heap_dump_muppy
22
+ from pythonagent.utils import get_current_timestamp_in_us
23
+
24
+
25
+ class RepeatedTimer(object):
26
+ def __init__(self, interval, function, *args, **kwargs):
27
+ self._timer = None
28
+ self.interval = interval
29
+ self.function = function
30
+ self.args = args
31
+ self.kwargs = kwargs
32
+ self.is_running = False
33
+ self.start()
34
+
35
+ def _run(self):
36
+ self.is_running = False
37
+ self.start()
38
+ self.function(*self.args, **self.kwargs)
39
+ def start(self):
40
+ if not self.is_running:
41
+ self._timer = Timer(self.interval, self._run)
42
+ self._timer.start()
43
+ self.is_running = True
44
+
45
+ def stop(self):
46
+ self._timer.cancel()
47
+ self.is_running = False
48
+
49
+ class TransactionContext(object):
50
+ def __init__(self):
51
+ self.nd_init_done = None
52
+ self.request_id = None
53
+ self.api_request_id = None
54
+ self.aws_request_id = None
55
+ self.function_name = None
56
+ self.bt_id = None
57
+ self.tier_callout_type = None
58
+ self.tier_callout_start_time = 0
59
+ self.db_callout_start_time = 0
60
+ self.backend_header = None
61
+ self.http_request_type = None
62
+ self.tier_name = None
63
+ self.server_name = None
64
+ self.instance_name = None
65
+ self.url_path = None
66
+ self.flow_path_id = None
67
+ self.havoc_applied = False
68
+ self.fp_topo = None
69
+ self.host_str = None
70
+ self.callout_id = 0
71
+ self.btname = None
72
+
73
+
74
+
75
+ class Agent(object):
76
+ """The entry point for the Python agent.
77
+
78
+ """
79
+ _instance = None
80
+ @staticmethod
81
+ def get_instance():
82
+ if Agent._instance is None:
83
+ Agent()
84
+ return Agent._instance
85
+
86
+ def __init__(self):
87
+ if Agent._instance is not None:
88
+ raise Exception("Agent class is a singleton! Use get_instance()")
89
+
90
+ Agent._instance = self
91
+
92
+ super(Agent, self).__init__()
93
+ self.logger = logging.getLogger('pythonagent.agent')
94
+ self.aiobj = None
95
+ # if os.environ['CAV_RUNNING_MODE']=='0':
96
+ # os.environ['CAV_RUNNING_MODE']='1'
97
+ # return
98
+ self.app_id = None
99
+ self.tier_id = None
100
+ self.node_id = None
101
+ self.account_guid = None
102
+ self.controller_guid = None
103
+ self._tx_factory = None
104
+
105
+ # Services
106
+ # self.proxy_control_svc = None
107
+ # self.config_svc = None
108
+ # self.tx_svc = None
109
+ # self.snapshot_svc = None
110
+
111
+ self.active_bts = set()
112
+ self.current_bts = {}
113
+ self.transaction_context = {}
114
+ self.eum_config = None
115
+
116
+ self.nd_init_done = None
117
+ self.last_forced_snapshot = 0
118
+ self.lib = None
119
+ self.fp_topo = None
120
+
121
+ if "CAV_APP_AGENT_ENV" in os.environ:
122
+ if os.environ['CAV_APP_AGENT_ENV'] == "AWS_LAMBDA":
123
+ self.cav_env = "AWS_LAMBDA"
124
+ else:
125
+ self.cav_env = "NATIVE"
126
+ else:
127
+ self.cav_env = "NATIVE"
128
+
129
+ if "CAV_APP_AGENT_TIER" in os.environ:
130
+ self.tier_name = os.environ.get("CAV_APP_AGENT_TIER")
131
+ else:
132
+ self.tier_name = "default"
133
+
134
+ if "CAV_APP_AGENT_SERVER" in os.environ:
135
+ self.server_name = os.environ.get("CAV_APP_AGENT_SERVER")
136
+ else:
137
+ self.server_name = "default"
138
+
139
+ if "CAV_APP_AGENT_INSTANCE" in os.environ:
140
+ self.instance_name = os.environ.get("CAV_APP_AGENT_INSTANCE")
141
+ self.function_name = os.environ.get("CAV_APP_AGENT_INSTANCE")
142
+ else:
143
+ self.instance_name = "default"
144
+ self.function_name = "default"
145
+
146
+ self.nd_cookie_key = None
147
+ self.nv_cookie_key = None
148
+ self.cookie_method_position = None
149
+ self.cookie_domain = None
150
+ self.header_in_response = None
151
+ self.disable_nd_nv = False
152
+ self.exception_stack_depth = 50
153
+ self.test_running = True
154
+ self.nf_enabled = False
155
+
156
+ self.start()
157
+
158
+ if self.cav_env == "NATIVE":
159
+ self.ai_wrapper_begin()
160
+ self.ad_wrapper()
161
+ self.register_nd_cookie_callback()
162
+ self.gc_nd_status_callback()
163
+ self.thread_dump_callback()
164
+ self.nd_pythread_status_callback()
165
+ self.register_havoc_callback()
166
+ self.get_nf_status()
167
+ # self.register_test_status_callback()
168
+ # self.thd_wrapper()
169
+ # self.ai_wrapper_end()
170
+ # self.ai_wrapper_begin()
171
+
172
+ self.current_status_code = {}
173
+
174
+ self.havoc_monitor = NDNetHavocMonitor.get_instance()
175
+
176
+ self.application_loggers = set()
177
+
178
+ if self.cav_env == "NATIVE":
179
+ try:
180
+ self.gc_monitor_rt = RepeatedTimer(60, self.heap_gc_stats)
181
+ self.thread_monitor_rt = RepeatedTimer(60, self.thread_stats)
182
+ self.refresh_config_rt = RepeatedTimer(25, self.havoc_monitor.refresh_configs, self)
183
+ except Exception as e:
184
+ self.logger.info("Exception while starting GC thread : {}".format(e))
185
+
186
+ self.context_provider = ContextProvider()
187
+ self.currentbt_provider = CurrentBTProvider()
188
+ self.statuscode_provider = StatusCodeProvider()
189
+
190
+ def start(self):
191
+ # Use NDHOME env variable to locate libndsdk_py.so, fallback to default if missing
192
+ ndhome = os.environ.get('NDHOME')
193
+ path = os.path.join(ndhome,'python' ,'libs', 'libndsdk_py.so')
194
+
195
+ if not os.path.exists(path):
196
+ path = '/usr/local/lib/libndsdk_py.so'
197
+
198
+
199
+
200
+ if self.cav_env == "NATIVE":
201
+ self.lib = self.load_common_lib(path)
202
+ self.register_nv_cookie_callback()
203
+ self.register_exception_stack_depth_callback()
204
+ self.register_instr_prof_callback()
205
+ self.register_heap_dump_callback()
206
+
207
+ #self.logger.info("going to start sdk_init()")
208
+ self.sdk_init()
209
+ #self.logger.info("sdk_init() done")
210
+ # self.nd_init_done = True
211
+ os.environ['nd_init_done'] = '1'
212
+
213
+
214
+ def stop(self):
215
+ """Stop the agent from doing anything else.
216
+
217
+ Ideally this will stop any interceptors from doing anything, it will
218
+ disconnect all ties to the proxy etc etc.
219
+
220
+ """
221
+ self.nd_init_done = False
222
+ os.environ['nd_init_done'] = '0'
223
+
224
+ # @staticmethod
225
+ def getInstance(self):
226
+ """Static Access Method"""
227
+ if self.start.__shared_instance is None:
228
+ # Proxy()
229
+ self.start()
230
+ # return Proxy.__shared_instance
231
+ return self.start.__shared_instance
232
+
233
+ # @profile
234
+ def load_common_lib(self, lib_path):
235
+
236
+ self.lib = ctypes.cdll.LoadLibrary(lib_path)
237
+ # self.lib.nd_init2.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
238
+
239
+ ################
240
+ # DECLARATIONS
241
+ ################
242
+
243
+ self.lib.nd_method_entry.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_longlong]
244
+ self.lib.nd_method_exit.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_longlong, ctypes.c_longlong, ctypes.c_longlong, ctypes.POINTER(ctypes.POINTER(ctypes.c_char_p))]
245
+
246
+
247
+ self.lib.nd_bt_begin.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_longlong]
248
+ self.lib.nd_bt_begin.restype = ctypes.c_void_p
249
+
250
+ self.lib.nd_bt_end.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_longlong, ctypes.c_longlong, ctypes.POINTER(ctypes.POINTER(ctypes.c_char_p))]
251
+ self.lib.nd_bt_end.restype = ctypes.c_int
252
+
253
+ self.lib.nd_bt_store.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
254
+
255
+ self.lib.nd_ip_db_callout_begin.argtypes = [ctypes.c_char_p, ctypes.c_void_p, ctypes.c_char_p,ctypes.c_char_p, ctypes.c_longlong]
256
+ self.lib.nd_ip_db_callout_begin.restype = ctypes.c_int
257
+
258
+ self.lib.nd_ip_db_callout_end.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_void_p, ctypes.c_int, ctypes.c_longlong, ctypes.c_longlong, ctypes.POINTER(ctypes.POINTER(ctypes.c_char_p))]
259
+ self.lib.nd_ip_db_callout_end.restype = ctypes.c_int
260
+
261
+ self.lib.nd_ip_http_callout_begin.argtypes = [ctypes.c_char_p,ctypes.c_void_p, ctypes.c_char_p]
262
+ self.lib.nd_ip_http_callout_begin.restype = ctypes.c_int
263
+
264
+ self.lib.nd_ip_http_callout_end.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_void_p, ctypes.c_int, ctypes.c_longlong, ctypes.c_longlong, ctypes.POINTER(ctypes.POINTER(ctypes.c_char_p)), ctypes.c_longlong]
265
+ self.lib.nd_ip_http_callout_end.restype = ctypes.c_int
266
+
267
+ self.lib.sdk_getTopoFpStr.argtypes = [ctypes.c_void_p]
268
+ self.lib.sdk_getTopoFpStr.restype = ctypes.POINTER(ctypes.c_char_p)
269
+
270
+ self.lib.sdk_getNFStatus.argtypes = None
271
+ self.lib.sdk_getNFStatus.restype = ctypes.c_int
272
+
273
+ self.lib.sdk_get_propagation_header.argtypes = [ctypes.c_void_p]
274
+ self.lib.sdk_get_propagation_header.restype = ctypes.POINTER(ctypes.c_char_p)
275
+
276
+ self.lib.sdk_getNdBuild.argtypes = None
277
+ self.lib.sdk_getNdBuild.restype = ctypes.c_char_p
278
+
279
+ #self.lib.sdk_free_memory.argtypes = [ctypes.c_char_p]
280
+
281
+ self.lib.handleUploadDownload.argtypes = [ctypes.c_char_p]
282
+ self.lib.handleUploadDownload.restype = ctypes.c_void_p
283
+
284
+ self.lib.sdk_getNDSessionCookie.argtypes = [ctypes.c_void_p]
285
+ self.lib.sdk_getNDSessionCookie.restype = ctypes.POINTER(ctypes.c_char_p)
286
+
287
+ self.lib.get_custom_nd_header.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_longlong]
288
+ self.lib.get_custom_nd_header.restype = ctypes.c_char_p
289
+
290
+ self.lib.sendGCReport.argtypes = [ctypes.c_int,ctypes.c_char_p]
291
+
292
+ self.lib.sdk_get_otl_traceparent.argtypes = [ctypes.c_void_p]
293
+ self.lib.sdk_get_otl_traceparent.restype = ctypes.POINTER(ctypes.c_char_p)
294
+
295
+ self.lib.sdk_get_otl_tracestate.argtypes = [ctypes.c_void_p]
296
+ self.lib.sdk_get_otl_tracestate.restype = ctypes.POINTER(ctypes.c_char_p)
297
+
298
+ self.lib.getstacktracearray.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p,
299
+ ctypes.c_char_p,
300
+ ctypes.c_char_p, ctypes.c_char_p, ctypes.c_int, ctypes.c_char_p]
301
+
302
+ self.lib.sdk_httpReqRespWrapper.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_int]
303
+
304
+ self.lib.havoc_response_from_agent.argtypes = [ctypes.c_char_p]
305
+
306
+ self.lib.sdk_dumpLogMessage.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
307
+ self.lib.sdk_dumpLogMessage.restype = ctypes.c_void_p
308
+
309
+
310
+
311
+
312
+ self.lib.sdk_getTierName.argtypes = []
313
+ self.lib.sdk_getTierName.restype = ctypes.c_char_p
314
+
315
+ self.lib.sdk_getAppServerName.argtypes = []
316
+ self.lib.sdk_getAppServerName.restype = ctypes.c_char_p
317
+
318
+ self.lib.sdk_getAppName.argtypes = []
319
+ self.lib.sdk_getAppName.restype = ctypes.c_char_p
320
+
321
+ self.lib.sdk_getCurrentTR.argtypes = []
322
+ self.lib.sdk_getCurrentTR.restype = ctypes.c_int
323
+
324
+
325
+
326
+
327
+ self.lib.sdk_getBTName.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p]
328
+ self.lib.sdk_getBTName.restype = ctypes.POINTER(ctypes.c_char_p)
329
+
330
+ self.lib.sdk_getBciInstrSessionPctVal.argtypes=[]
331
+ self.lib.sdk_getBciInstrSessionPctVal.restype=ctypes.c_int
332
+
333
+
334
+
335
+ self.lib.sdk_UpdateBTCounters.argtypes=[ctypes.c_char_p, ctypes.c_int, ctypes.c_double, ctypes.c_long, ctypes.c_double, ctypes.c_double, ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.POINTER(ctypes.c_long)]
336
+ self.lib.sdk_UpdateBTCounters.restype=ctypes.c_void_p
337
+
338
+ self.lib.sdk_UpdateIPCounters.argtypes = [ctypes.c_char_p, ctypes.c_double, ctypes.c_long, ctypes.c_double, ctypes.c_double, ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.POINTER(ctypes.c_long), ctypes.c_char_p, ctypes.c_char_p]
339
+ self.lib.sdk_UpdateIPCounters.restype = ctypes.c_void_p
340
+
341
+
342
+ self.lib.sdk_settingBackendNameOtel.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
343
+ self.lib.sdk_settingBackendNameOtel.restype = ctypes.POINTER(ctypes.c_char_p)
344
+
345
+
346
+ self.lib.sdk_getTierCallOutOtel.argtypes = [ctypes.c_char_p, ctypes.c_longlong]
347
+ self.lib.sdk_getTierCallOutOtel.restype = ctypes.POINTER(ctypes.c_char_p)
348
+
349
+ self.lib.sdk_setTierCallOutOtel.argtypes = [ctypes.c_char_p]
350
+ self.lib.sdk_setTierCallOutOtel.restype = ctypes.c_void_p
351
+
352
+ self.lib.sdk_UpdateIPCountersUsingSpan.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_double, ctypes.c_int]
353
+ self.lib.sdk_UpdateIPCountersUsingSpan.restype = ctypes.c_void_p
354
+
355
+
356
+ self.lib.sdk_getDelayAtCurrentInstant.argtypes = [ctypes.c_long, ctypes.c_long, ctypes.c_long, ctypes.c_long, ctypes.c_long]
357
+ self.lib.sdk_getDelayAtCurrentInstant.restype = None
358
+
359
+
360
+
361
+
362
+
363
+ # self.lib.register_AI_end_callback.argtypes = [ctypes.c_char_p]
364
+
365
+ #self.lib.getDelayAtCurrentInstant.argtypes = [ctypes.c_long, ctypes.c_long, ctypes.c_long, ctypes.c_long, ctypes.c_long]
366
+
367
+ ################
368
+ # CALLBACKS
369
+ ################
370
+
371
+ CB_FTYPE_DOUBLE_DOUBLE = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_int, ctypes.c_longlong,
372
+ ctypes.c_longlong, ctypes.c_char_p)
373
+ self.c_startaisession = CB_FTYPE_DOUBLE_DOUBLE(self.startaisession)
374
+
375
+ ai_end_ftype = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_char_p)
376
+ self.c_endaisession = ai_end_ftype(self.endaisessioncc)
377
+
378
+ ftype_autodiscovery = ctypes.CFUNCTYPE(ctypes.c_void_p, # Return type
379
+ ctypes.POINTER(ctypes.c_char_p), # methodFiltersPatternList
380
+ ctypes.POINTER(ctypes.c_char_p), # classFiltersPatternList
381
+ ctypes.c_int, # methodListLength
382
+ ctypes.c_int) # classListLength
383
+
384
+
385
+ self.autodiscovery_c = ftype_autodiscovery(self.autodiscovery_py)
386
+
387
+ ftype_exception_stack_depth = ctypes.CFUNCTYPE(ctypes.c_void_p, # Return type
388
+ ctypes.c_int) # Stack Depth
389
+
390
+ self.exception_stack_depth_c=ftype_exception_stack_depth(self.exception_stack_depth_py)
391
+
392
+ thd_ftype = ctypes.CFUNCTYPE(ctypes.c_char_p)
393
+ self.c_thd = thd_ftype(self.thd)
394
+
395
+ ftype_nd_cookie = ctypes.CFUNCTYPE(ctypes.c_void_p, # Pointer to Python Function
396
+ ctypes.c_char_p, # char *name
397
+ ctypes.c_char_p, # char *domain
398
+ ctypes.c_int, # int rheader
399
+ ctypes.c_int, # int mpos
400
+ ctypes.c_longlong) # long long int duration
401
+
402
+ self.nd_cookie_callback_c = ftype_nd_cookie(self.nd_cookie_callback_py)
403
+
404
+ ftype_nd_gc_status = ctypes.CFUNCTYPE(ctypes.c_void_p, # Pointer to Python Function
405
+ ctypes.c_int) # int status
406
+
407
+ self.nd_gcstatus_callback_c = ftype_nd_gc_status(self.nd_gcstatus_callback_py)
408
+
409
+ ftype_nd_python_thread_status = ctypes.CFUNCTYPE(ctypes.c_void_p, # Pointer to Python Function
410
+ ctypes.c_int) # int status
411
+ self.nd_pythread_status_callback_c = ftype_nd_python_thread_status(self.nd_pythread_status_callback_py)
412
+
413
+ thread_dump_ftype = ctypes.CFUNCTYPE(ctypes.c_char_p)
414
+ self.nd_thread_dump_callback_c = thread_dump_ftype(self.nd_thread_dump_callback_py)
415
+
416
+ ftype_nv_cookie = ctypes.CFUNCTYPE(ctypes.c_void_p, # Pointer to Python Function
417
+ ctypes.c_char_p) # char *name
418
+
419
+ self.nv_cookie_callback_c = ftype_nv_cookie(self.nv_cookie_callback_py)
420
+
421
+
422
+ ftype_havoc_message = ctypes.CFUNCTYPE(ctypes.c_void_p, # Return type
423
+ ctypes.c_char_p) # Havoc Message
424
+
425
+ ftype_heap_dump = ctypes.CFUNCTYPE(ctypes.c_char_p)
426
+ self.heap_dump_c = ftype_heap_dump(self.heap_dump_py)
427
+
428
+ self.receive_havoc_message_c = ftype_havoc_message(self.receive_havoc_message_py)
429
+
430
+
431
+ self.logger.info("load common lib -> lib.obj :{0}".format(self.lib))
432
+
433
+ ftype_test_status_callback = ctypes.CFUNCTYPE(ctypes.c_void_p, # Return type
434
+ ctypes.c_int) # Test Status
435
+
436
+ self.test_status_callback_c = ftype_test_status_callback(self.test_status_callback_py)
437
+
438
+ ftype_instr_prof_callback = ctypes.CFUNCTYPE(ctypes.c_void_p, # Return type
439
+ ctypes.c_char_p) # Test Status
440
+
441
+ self.instr_prof_callback_c = ftype_instr_prof_callback(self.instr_prof_callback_py)
442
+
443
+
444
+ return self.lib
445
+
446
+ ###############################
447
+ # GET VALUES FROM COMMONLIB
448
+ ###############################
449
+
450
+ def sdk_getNDSessionCookie(self, bt):
451
+ if not self.get_current_bt():
452
+ return None
453
+ nd_cookie_value = self.lib.sdk_getNDSessionCookie(bt)
454
+ nd_cookie_value_py = ctypes.cast(nd_cookie_value, ctypes.c_char_p).value
455
+ self.lib.sdk_free_memory(nd_cookie_value)
456
+ return nd_cookie_value_py
457
+
458
+ def get_nd_header(self, bt, backend_name, unique_id):
459
+ if not self.get_current_bt():
460
+ return None
461
+ backend_name_c = create_string_buffer(get_utf8_bytes(backend_name))
462
+ header = self.lib.get_custom_nd_header(ctypes.c_void_p(bt), backend_name_c, ctypes.c_longlong(unique_id))
463
+ del backend_name_c
464
+ return header
465
+
466
+ def get_trace_headers(self, bt):
467
+ if not self.get_current_bt():
468
+ return None, None
469
+
470
+ traceparent = self.lib.sdk_get_otl_traceparent(bt)
471
+ traceparent_py = ctypes.cast(traceparent, ctypes.c_char_p).value
472
+ self.lib.sdk_free_memory(traceparent)
473
+
474
+ tracestate = self.lib.sdk_get_otl_tracestate(bt)
475
+ tracestate_py = ctypes.cast(tracestate, ctypes.c_char_p).value
476
+ self.lib.sdk_free_memory(tracestate)
477
+
478
+ return traceparent_py, tracestate_py
479
+
480
+ def sdk_getTopoFpStr(self, bt):
481
+ if not self.get_current_bt():
482
+ return None
483
+ topo = None
484
+ topo_py = None
485
+ if bt:
486
+ topo = self.lib.sdk_getTopoFpStr(bt)
487
+ topo_py = ctypes.cast(topo, ctypes.c_char_p).value
488
+ self.lib.sdk_free_memory(topo)
489
+ if topo_py:
490
+ topo_py = topo_py.decode()
491
+ return topo_py
492
+
493
+ def sdk_get_propagation_header(self,bt):
494
+ if not self.get_current_bt():
495
+ return None
496
+ prop_headers = self.lib.sdk_get_propagation_header(bt)
497
+ prop_headers_py = ctypes.cast(prop_headers, ctypes.c_char_p).value
498
+ self.lib.sdk_free_memory(prop_headers)
499
+ return prop_headers_py
500
+
501
+ def get_nd_build(self):
502
+ return self.lib.sdk_getNdBuild().decode()
503
+
504
+ def get_nf_status(self):
505
+ nf_enabled = self.lib.sdk_getNFStatus()
506
+ if nf_enabled == 1:
507
+ self.nf_enabled = True
508
+ elif nf_enabled == 0:
509
+ self.nf_enabled = False
510
+
511
+ def get_app_name(self):
512
+ app_name = self.lib.sdk_getAppName()
513
+ app_name_py = ctypes.cast(app_name, ctypes.c_char_p).value
514
+ del app_name
515
+ return app_name_py
516
+
517
+ def get_tier_name(self):
518
+ tier = self.lib.sdk_getTierName()
519
+ tier_py = ctypes.cast(tier, ctypes.c_char_p).value
520
+ del tier
521
+ return tier_py
522
+
523
+
524
+ def get_app_server_name(self):
525
+ app_server = self.lib.sdk_getAppServerName()
526
+
527
+ app_server_py = ctypes.cast(app_server, ctypes.c_char_p).value
528
+ del app_server
529
+
530
+ return app_server_py
531
+
532
+ def get_current_tr(self):
533
+ TR = self.lib.sdk_getCurrentTR()
534
+ return TR
535
+
536
+ def getBciInstrSessionPctVal(self):
537
+ BciInstrSessionPctVal= self.lib.sdk_getBciInstrSessionPctVal()
538
+ return BciInstrSessionPctVal
539
+
540
+ def get_bt_name(self, url, parameters, btHeaderValue, httpMethod):
541
+ try:
542
+ bt_name = self.lib.sdk_getBTName(url, parameters, btHeaderValue, httpMethod)
543
+
544
+ bt_name_py = ctypes.cast(bt_name, ctypes.c_char_p).value
545
+ if bt_name:
546
+ self.lib.sdk_free_memory(bt_name)
547
+
548
+ return bt_name_py
549
+ except Exception as e:
550
+ self.logger.exception("Exception in get_bt_name: {}".format(e))
551
+ return None
552
+
553
+
554
+ def get_tier_callout(self, backend_name, thread_id):
555
+ backend_name_b = backend_name.encode('utf-8') if isinstance(backend_name, str) else backend_name
556
+ result = self.lib.sdk_getTierCallOutOtel(backend_name_b, thread_id)
557
+ # Decode the native bridge result into a Python header value.
558
+ tiercallout_py = ctypes.cast(result, ctypes.c_char_p).value
559
+
560
+ if result:
561
+ self.lib.sdk_free_memory(result)
562
+
563
+ return tiercallout_py
564
+
565
+
566
+ def setting_backend_name_otel(self, backendName, type_):
567
+ try:
568
+ # Convert Python str to byte
569
+ backendName_b = backendName.encode('utf-8') if backendName else None
570
+ type_b = type_.encode('utf-8') if type_ else None
571
+ # Call C function
572
+ result = self.lib.sdk_settingBackendNameOtel(backendName_b, type_b)
573
+ result_py = ctypes.cast(result,ctypes.c_char_p).value
574
+ # Free memory from C side
575
+ if result:
576
+ self.lib.sdk_free_memory(result)
577
+
578
+ return result_py
579
+ except Exception as e:
580
+ self.logger.exception("Exception in setting_backend_name_otel: {}".format(e))
581
+ return None
582
+
583
+
584
+ def UpdateBTCounters(self, bt_name, status_code, sum_value, count, min_val, max_val, boundaries, boundaries_len, bucketsCounts):
585
+ # Convert bt_name to bytes (C expects char*)
586
+ bt_name_bytes = bt_name.encode('utf-8')
587
+
588
+ # Convert boundaries to ctypes array
589
+ boundaries_array = (ctypes.c_double * boundaries_len)(*boundaries)
590
+
591
+ # Convert bucketsCounts to ctypes array
592
+ buckets_array = (ctypes.c_long * (boundaries_len+1))(*bucketsCounts)
593
+
594
+ # Call the C function
595
+ BT_Counters = self.lib.sdk_UpdateBTCounters(
596
+ bt_name_bytes,
597
+ status_code,
598
+ ctypes.c_double(sum_value),
599
+ ctypes.c_long(count),
600
+ ctypes.c_double(min_val),
601
+ ctypes.c_double(max_val),
602
+ boundaries_array,
603
+ ctypes.c_int(boundaries_len),
604
+ buckets_array
605
+ )
606
+
607
+ return BT_Counters
608
+
609
+ def UpdateIPCounters(self, backend_name, sum_value, count, min_val, max_val, boundaries, boundaries_len, bucketsCounts, type_str, dbtype_str):
610
+ backend_name_bytes = backend_name.encode('utf-8')
611
+ type_bytes = type_str.encode('utf-8')
612
+ dbtype_bytes = dbtype_str.encode('utf-8')
613
+ # Convert boundaries to ctypes array
614
+ boundaries_array = (ctypes.c_double * boundaries_len)(*boundaries)
615
+
616
+ # Convert bucketsCounts to ctypes array (length = boundaries_len + 1)
617
+ buckets_array = (ctypes.c_long * (boundaries_len + 1))(*bucketsCounts)
618
+
619
+ # Call the C function
620
+ IP_Counters = self.lib.sdk_UpdateIPCounters(
621
+ backend_name_bytes,
622
+ ctypes.c_double(sum_value),
623
+ ctypes.c_long(count),
624
+ ctypes.c_double(min_val),
625
+ ctypes.c_double(max_val),
626
+ boundaries_array,
627
+ ctypes.c_int(boundaries_len),
628
+ buckets_array,
629
+ type_bytes,
630
+ dbtype_bytes
631
+ )
632
+
633
+
634
+ return IP_Counters
635
+
636
+ def set_tier_callout(self, value):
637
+ if isinstance(value, str):
638
+ value = value.encode()
639
+
640
+ # The setter restores inbound tier-callout state in the native bridge.
641
+ return self.lib.sdk_setTierCallOutOtel(value)
642
+
643
+ def UpdateIPCountersUsingSpan(self, backend_name, type_str, dbtype_str, duration, status_code):
644
+ backend_name_bytes = backend_name.encode('utf-8')
645
+ type_bytes = type_str.encode('utf-8')
646
+ dbtype_bytes = dbtype_str.encode('utf-8')
647
+ IP_Counters = self.lib.sdk_UpdateIPCountersUsingSpan(
648
+ backend_name_bytes,
649
+ type_bytes,
650
+ dbtype_bytes,
651
+ ctypes.c_double(duration),
652
+ ctypes.c_int(status_code)
653
+
654
+ )
655
+
656
+ return IP_Counters
657
+
658
+
659
+ #########################
660
+ # DUMP TO COMMONLIB
661
+ #########################
662
+
663
+ def dump_log_message(self, bt, logs):
664
+ if not self.get_current_bt():
665
+ return None
666
+
667
+ logs_c = create_string_buffer(get_utf8_bytes(logs))
668
+
669
+ resp = self.lib.sdk_dumpLogMessage(bt, logs_c)
670
+
671
+ del logs_c
672
+
673
+
674
+ ##########################
675
+ # REGISTER CALLBACKS
676
+ ##########################
677
+
678
+ def register_nd_cookie_callback(self):
679
+ self.lib.register_nd_cookie_callback(self.nd_cookie_callback_c)
680
+ #print("**** callback registered for ND cookie ****")
681
+
682
+ def gc_nd_status_callback(self):
683
+ self.lib.register_GC_status_for_agent(self.nd_gcstatus_callback_c)
684
+
685
+ def register_exception_stack_depth_callback(self):
686
+ self.lib.register_exception_depth_callback(self.exception_stack_depth_c)
687
+
688
+ def nd_pythread_status_callback(self):
689
+ self.lib.register_TH_status_for_agent(self.nd_pythread_status_callback_c)
690
+
691
+ def thread_dump_callback(self):
692
+ self.lib.register_thread_dump_callback(self.nd_thread_dump_callback_c)
693
+
694
+ def register_nv_cookie_callback(self):
695
+ self.lib.register_nv_cookie_callback(self.nv_cookie_callback_c)
696
+ #print("**** callback registered for NV cookie ****")
697
+
698
+ def ad_wrapper(self):
699
+ self.lib.register_AD_callback(self.autodiscovery_c)
700
+
701
+ def thd_wrapper(self):
702
+ self.lib.register_thread_dump_callback(self.c_thd)
703
+
704
+ def ai_wrapper_begin(self):
705
+ #print("************************ callback registered ********************************************")
706
+ self.lib.register_AI_start_callback(self.c_startaisession)
707
+
708
+ def ai_wrapper_end(self):
709
+ self.lib.register_AI_end_callback(self.c_endaisession)
710
+
711
+ def register_test_status_callback(self):
712
+ self.lib.register_test_status_for_agent(self.test_status_callback_c)
713
+
714
+ def register_instr_prof_callback(self):
715
+ self.lib.register_instr_prof_callback(self.instr_prof_callback_c)
716
+
717
+ def register_heap_dump_callback(self):
718
+ self.lib.register_heap_dump_callback(self.heap_dump_c)
719
+
720
+ def register_havoc_callback(self):
721
+ self.lib.register_havoc_msg_for_agent_callback_sdk(self.receive_havoc_message_c)
722
+
723
+ ##########################
724
+ # CALLBACK DEFINITIONS
725
+ ##########################
726
+
727
+ def common_sleep(self, havocStarttime, shootUpDuration, stableDuration, tumbleDuration, delayInSec):
728
+ self.lib.sdk_getDelayAtCurrentInstant(ctypes.c_long(int(havocStarttime)),
729
+ ctypes.c_long(int(shootUpDuration * 1000)),
730
+ ctypes.c_long(int(stableDuration * 1000)),
731
+ ctypes.c_long(int(tumbleDuration * 1000)),
732
+ ctypes.c_long(int(delayInSec)))
733
+
734
+ def thd(self):
735
+ print("INSIDE THD")
736
+ # dumpstacks()
737
+
738
+ def exception_stack_depth_py(self, stack_depth):
739
+ self.logger.debug("Stack depth callback called {}".format(stack_depth))
740
+ self.exception_stack_depth=stack_depth
741
+
742
+ def test_status_callback_py(self, test_status):
743
+ if test_status == 1:
744
+ self.test_running = True
745
+ elif test_status == 0:
746
+ self.test_running = False
747
+ self.logger.info("Test Running: {}".format(self.test_running))
748
+
749
+ def nd_cookie_callback_py(self, name, domain, rheader, mpos, duration):
750
+ self.logger.info(f"nd_cookie name {name} \ndomain {domain}\nrheader {rheader}\nmpos {mpos}\nduration {duration}")
751
+ if name:
752
+ self.nd_cookie_key = name.decode()
753
+ if not mpos:
754
+ self.nd_cookie_key = None
755
+ self.disable_nd_nv = True
756
+
757
+ self.header_in_response = rheader
758
+ self.cookie_method_position = mpos
759
+ if domain:
760
+ self.cookie_domain = domain.decode()
761
+
762
+
763
+
764
+ def nd_gcstatus_callback_py(self,status):
765
+ self.gc_run_status = status
766
+ if self.gc_run_status == 1:
767
+ if not self.gc_monitor_rt.is_running:
768
+ self.gc_monitor_rt.start()
769
+ elif self.gc_run_status == 0:
770
+ if self.gc_monitor_rt.is_running:
771
+ self.gc_monitor_rt.stop()
772
+
773
+ def nv_cookie_callback_py(self, name):
774
+ #print(f"nv_cookie name {name}")
775
+ if name:
776
+ self.nv_cookie_key = name.decode()
777
+
778
+ def nd_pythread_status_callback_py(self, status):
779
+ self.pythread_run_status = status
780
+ if self.pythread_run_status == 1:
781
+ if not self.thread_monitor_rt.is_running:
782
+ self.thread_monitor_rt.start()
783
+ elif self.pythread_run_status == 0:
784
+ if self.thread_monitor_rt.is_running:
785
+ self.thread_monitor_rt.stop()
786
+
787
+ def nd_thread_dump_callback_py(self):
788
+ build_details = self.get_nd_build()
789
+ dump_stack_str = dumpstacks(build_details)
790
+ try:
791
+ dump_str = bytes(dump_stack_str, 'utf-8')
792
+ except:
793
+ dump_str = bytes(dump_stack_str.encode("utf-8"))
794
+
795
+ return dump_str
796
+
797
+ def endaisessioncc(self, char):
798
+ print("INSIDE END AI SESSION")
799
+
800
+ def startaisession(self, istart, startTime, duration, sname):
801
+ # if not self.get_current_bt():
802
+ # return
803
+ self.logger.info("ai start")
804
+ #print(" IN startaisession", sname.decode('ascii'))
805
+ if sname:
806
+ wsgi.aiflagset(istart, startTime, duration, sname)
807
+ #pathd = "/opt/cavisson/netdiagnostics/logs/"
808
+ ndhome = os.environ.get('NDHOME')
809
+ pathd = ndhome + '/python/logs/'
810
+ filenameai1 = str(self.sname.decode('ascii')) + ".txt"
811
+ aifile_to_open_to_d = os.path.join(pathd, filenameai1)
812
+ self.lib.handleUploadDownload(bytes(aifile_to_open_to_d, 'utf-8'))
813
+ self.logger.info("ai end")
814
+
815
+
816
+ def autodiscovery_py(self, method_filters_pattern_list, class_filters_pattern_list,
817
+ method_list_length, class_list_length):
818
+ # if not self.get_current_bt():
819
+ # return
820
+
821
+ self.logger.info("ad start")
822
+ if method_list_length > 0:
823
+ method_filter_list = []
824
+ for i in range(method_list_length):
825
+ method_filter_list.append(method_filters_pattern_list[i].decode())
826
+ else:
827
+ method_filter_list = None
828
+
829
+ if class_list_length > 0:
830
+ class_filter_list = []
831
+ for i in range(class_list_length):
832
+ class_filter_list.append(class_filters_pattern_list[i].decode())
833
+ else:
834
+ class_filter_list = None
835
+
836
+ start_time = time.time()
837
+
838
+ try: # Defensive check for failure of finder.run_script(sys.argv[0])
839
+ output_from_ad, num_of_modules, num_of_methods = find(method_filter_list, class_filter_list)
840
+ except Exception as e:
841
+ self.logger.error("Unable to auto-discover methods, please try again")
842
+ self.logger.debug(e)
843
+ output_from_ad = "default||default"
844
+ num_of_modules = 1
845
+ num_of_methods = 1
846
+
847
+ end_time = time.time()
848
+ total_time = end_time - start_time
849
+ ad_summary = "totalTimeTaken={} ms;totalModules={};totalMethods={};\n".format(total_time, num_of_modules, num_of_methods)
850
+
851
+ output_from_ad_c = create_string_buffer(get_utf8_bytes(output_from_ad))
852
+ self.lib.wraphandleMessageForDiscovery(output_from_ad_c)
853
+
854
+ # Metadata must be sent before the "totalTimeTaken=...;" summary line below - that line is
855
+ # treated by the collector as the terminal response for this discovery request, so anything
856
+ # sent after it would never be attached to the .adr output. Defensive try/except so a
857
+ # metadata-collection failure never breaks the rest of auto-discovery.
858
+ try:
859
+ metadata_block_c = create_string_buffer(get_utf8_bytes(build_metadata_block(self)))
860
+ self.lib.wraphandleMessageForDiscovery(metadata_block_c)
861
+ del metadata_block_c
862
+ except Exception as e:
863
+ self.logger.exception("Error building/sending auto-discovery metadata block")
864
+
865
+ self.logger.info("ad sending summary")
866
+ ad_summary_c = create_string_buffer(get_utf8_bytes(ad_summary))
867
+ self.lib.wraphandleMessageForDiscovery(ad_summary_c)
868
+ del output_from_ad_c, ad_summary_c
869
+
870
+
871
+ def instr_prof_callback_py(self, instr_prof):
872
+ self.logger.info("Received Instrumentation Profile Callback")
873
+ self.logger.debug("Instr Prof {}".format(instr_prof))
874
+
875
+ try:
876
+ if instr_prof:
877
+ instr_prof_str = instr_prof.decode()
878
+
879
+ instr_prof_str_split = instr_prof_str.split("\n\n\n")
880
+
881
+ instr_prof_list = []
882
+
883
+ for profile in instr_prof_str_split:
884
+ profile = profile.strip()
885
+ if profile[0] == "[" and profile[-1] != "]":
886
+ profile += "}]"
887
+ instr_prof_list.append(profile)
888
+
889
+ new_instr_prof_str = "\n\n\n".join(instr_prof_list)
890
+
891
+
892
+ from pythonagent import config
893
+ pythonagent_path = os.path.dirname(config.__file__)
894
+ instr_prof_path = os.path.join(pythonagent_path, 'agent/internal/instrprof.json')
895
+ try:
896
+ with open(instr_prof_path, "w+") as outfile:
897
+ outfile.write(new_instr_prof_str)
898
+
899
+ except:
900
+ self.logger.exception("Unable to write instrprof.json")
901
+
902
+ import pythonagent.agent as agent
903
+ agent.bootstrap(self)
904
+
905
+
906
+ except Exception as e:
907
+ self.logger.exception("Error in Instrumentation Profile Callback")
908
+
909
+
910
+ def receive_havoc_message_py(self, havoc_message):
911
+ self.logger.warning("Havoc callback called{}".format(havoc_message))
912
+ body, header_dict = process_raw_havoc_message(havoc_message.decode(), self.cav_env)
913
+ self.logger.debug("Header:".format(header_dict))
914
+ self.logger.debug("Body:".format(body))
915
+ self.havoc_monitor.parse_nethavoc_config(body, header_dict)
916
+
917
+ def send_havoc_response(self, header_str):
918
+ if self.cav_env == "NATIVE":
919
+ self.logger.warning("Havoc Response from Agent{}".format(header_str))
920
+ header_c = create_string_buffer(get_utf8_bytes(header_str))
921
+ self.lib.havoc_response_from_agent(header_c)
922
+ del header_c
923
+ elif self.cav_env == "AWS_LAMBDA":
924
+ udp.havoc_message(self, header_str)
925
+
926
+
927
+ #############################
928
+ # REPEATER TIMER FUNCTIONS
929
+ #############################
930
+
931
+ def send_gc_report(self, record_string):
932
+
933
+ record_string_c = create_string_buffer(get_utf8_bytes(record_string))
934
+
935
+ self.lib.sendGCReport(ctypes.c_int(77),record_string_c)
936
+ del record_string_c
937
+
938
+ def heap_gc_stats(self):
939
+ try:
940
+ RSS = get_rss_bytes()
941
+ x = gc.get_count()
942
+ y = gc.get_stats()
943
+ record_str = ""
944
+ record_str += str(int(RSS / 1000)) + ' '
945
+ for i in range(0, 3):
946
+ record_str += str(x[i]) + ' '
947
+ record_str += str(y[i]['collected']) + ' '
948
+ record_str += str(y[i]['uncollectable']) + ' '
949
+ if i < 2:
950
+ record_str += str(y[i]['collections']) + ' '
951
+ else:
952
+ record_str += str(y[i]['collections'])
953
+ self.send_gc_report(record_str)
954
+ except Exception as e:
955
+ self.logger.info("Exception on heap_gc_stats : {}".format(e))
956
+
957
+
958
+ def send_thread_report(self, record_string):
959
+ record_string_c = create_string_buffer(get_utf8_bytes(record_string))
960
+
961
+ self.lib.sendGCReport(ctypes.c_int(83), record_string_c)
962
+ del record_string_c
963
+
964
+ def thread_stats(self):
965
+ thread_details_ = threading.enumerate()
966
+ total_threads = str(len(thread_details_))
967
+ thread_status_dict = {'deamon': 0, 'notdeamon': 0,}
968
+ for thread in thread_details_:
969
+
970
+ if thread.daemon == True:
971
+ thread_status_dict['deamon'] += 1
972
+
973
+ if thread.daemon == False:
974
+ thread_status_dict['notdeamon'] += 1
975
+
976
+ thread_stats_string = (total_threads + " " +
977
+ str(thread_status_dict['deamon']) + " " +
978
+ str(thread_status_dict['notdeamon']))
979
+
980
+ self.send_thread_report(thread_stats_string)
981
+
982
+ ######################
983
+ # CORE SDK FUNCTIONS
984
+ ######################
985
+
986
+ # @profile
987
+ def sdk_init_native(self):
988
+ self.logger.info("sdk_init -> lib.obj :{0}".format(self.lib))
989
+ agent_type = bytes("python", 'utf-8')
990
+ log_file_name = bytes("cavlib", 'utf-8')
991
+ version_string = "python" + platform.python_version()
992
+
993
+ """
994
+ appname = None
995
+ for item in sys.argv:
996
+ if item.endswith(".py"):
997
+ appname = item.split("/")[-1]
998
+ appname = appname[:-3] # Remove .py extension
999
+ break
1000
+
1001
+ if not appname:
1002
+ appname = "wsgi"
1003
+ """
1004
+
1005
+ appname = "Python"
1006
+
1007
+
1008
+
1009
+ version_string_c = create_string_buffer(get_utf8_bytes(version_string))
1010
+ appname_string_c = create_string_buffer(get_utf8_bytes(appname))
1011
+ self.lib.nd_init2(agent_type, log_file_name, version_string_c, appname_string_c)
1012
+
1013
+ del version_string_c
1014
+ del appname_string_c
1015
+
1016
+ def sdk_init(self):
1017
+ if self.cav_env == "NATIVE":
1018
+ self.sdk_init_native()
1019
+ elif self.cav_env == "AWS_LAMBDA":
1020
+ udp.sdk_init(self)
1021
+
1022
+ def sdk_free_native(self):
1023
+ self.logger.info("sdk_free -> lib.obj :{0}".format(self.lib))
1024
+ self.lib.nd_free()
1025
+
1026
+ def sdk_free(self):
1027
+ if self.cav_env == "NATIVE":
1028
+ self.sdk_free_native()
1029
+ elif self.cav_env == "AWS_LAMBDA":
1030
+ udp.sdk_free()
1031
+
1032
+ def method_entry_native(self, bt, method, start_time):
1033
+ if not self.get_current_bt():
1034
+ return
1035
+ self.logger.info("method entry: {}".format(method))
1036
+ method_c = create_string_buffer(get_utf8_bytes(method))
1037
+ self.lib.nd_method_entry(bt, method_c, ctypes.c_longlong(start_time))
1038
+ del method_c
1039
+
1040
+
1041
+ def method_entry(self, bt, method, start_time=0):
1042
+ if self.cav_env == "NATIVE":
1043
+ self.method_entry_native(bt, method, start_time)
1044
+ elif self.cav_env == "AWS_LAMBDA":
1045
+ udp.method_entry(self, bt, method, "NA", "NA")
1046
+
1047
+ #@profile
1048
+ def method_exit_native(self, bt, method, duration, cpu_time, method_start_time):
1049
+ if not self.get_current_bt():
1050
+ return
1051
+ self.logger.info("method exit: {}".format(method))
1052
+ method_bytes = get_utf8_bytes(str(method))
1053
+ str_span_c = ctypes.POINTER(ctypes.c_char_p)()
1054
+ method_c = create_string_buffer(get_utf8_bytes(method))
1055
+
1056
+ self.lib.nd_method_exit(bt, method_c, ctypes.c_longlong(cpu_time), ctypes.c_longlong(duration), ctypes.c_longlong(method_start_time), ctypes.byref(str_span_c))
1057
+
1058
+ span_obj = ctypes.c_char_p.from_buffer(str_span_c)
1059
+ self.dump_span(span_obj)
1060
+ self.lib.sdk_free_memory(str_span_c)
1061
+ del span_obj, method_c
1062
+
1063
+ def method_exit(self, bt, method, duration, cpu_time=0, method_start_time=0):
1064
+ if self.cav_env == "NATIVE":
1065
+ self.method_exit_native(bt, method, duration, cpu_time, method_start_time)
1066
+ elif self.cav_env == "AWS_LAMBDA":
1067
+ udp.method_exit(self, bt, method, "NA", 0, duration)
1068
+
1069
+ # @profile
1070
+ def start_business_transaction_native(self, bt_name, correlation_header, nd_cookie, nv_cookie, bt_header_value, fp_instance):
1071
+ start_time = get_current_timestamp_in_us()
1072
+ self.unset_current_bt()
1073
+ if os.environ['nd_init_done'] == '0':
1074
+ self.start()
1075
+ #print("start_business_transaction ->")
1076
+ #self.logger.debug(" start_business_transaction -> lib.obj {0}:".format(self.lib))
1077
+
1078
+ self.logger.info(" start_business_transaction -> bt_name {0}:".format(bt_name))
1079
+ bt_name_c = create_string_buffer(get_utf8_bytes(bt_name))
1080
+ correlation_header_c = create_string_buffer(get_utf8_bytes(correlation_header))
1081
+
1082
+
1083
+ if not fp_instance:
1084
+ self.get_transaction_context().flow_path_id = generate_flow_path_id()
1085
+ else:
1086
+ self.get_transaction_context().flow_path_id = fp_instance
1087
+
1088
+
1089
+ nd_cookie_c = create_string_buffer(get_utf8_bytes(nd_cookie))
1090
+ nv_cookie_c = create_string_buffer(get_utf8_bytes(nv_cookie))
1091
+ bt_header_value_c = create_string_buffer(get_utf8_bytes(bt_header_value))
1092
+
1093
+ flow_path_id = self.get_transaction_context().flow_path_id
1094
+ flow_path_id_c = create_string_buffer(get_utf8_bytes(flow_path_id))
1095
+ start_time_c = ctypes.c_longlong(start_time)
1096
+
1097
+ bt = self.lib.nd_bt_begin(bt_name_c, correlation_header_c, nd_cookie_c, nv_cookie_c, bt_header_value_c, flow_path_id_c, start_time_c)
1098
+
1099
+ del start_time_c, bt_header_value_c, nd_cookie, nv_cookie, bt_name_c, correlation_header_c
1100
+
1101
+
1102
+ if not bt:
1103
+ self.logger.warning("BT is None. Either Test Run is stopped or Connection is broken")
1104
+ #self.logger.info("bt datatype : {0}".format(type(bt)))
1105
+ #print("btname value: {0}".format(btname))
1106
+ # print('-----------------\nCurrent heap memory stack for BT: ',bt_name,' is : ',hpy().heap())
1107
+ self.active_bts.add(bt)
1108
+ self.set_current_bt(bt)
1109
+ #print("BT value of this txn: ", bt)
1110
+ return bt
1111
+
1112
+
1113
+ def inbound_havoc_delay_otel(self, req_url, bt_name=None):
1114
+ # Apply configured inbound service delay during OTel instrumentation flow.
1115
+ # req_url is the request URL/path used for havoc matching; bt_name is optional
1116
+ # for backward-compatible OTel callers while ndotel is migrated.
1117
+ try:
1118
+ self.havoc_monitor.apply_inbound_service_delay(req_url, bt_name)
1119
+ except Exception as e:
1120
+ # Keep OTel span processing aligned with the existing BT path:
1121
+ # havoc config/load issues should not break the request.
1122
+ print(e)
1123
+ pass
1124
+
1125
+ def inbound_havoc_failure_otel(self, req_url, bt_name=None):
1126
+ self.havoc_monitor.apply_inbound_service_failure(req_url, bt_name)
1127
+
1128
+ def outbound_havoc_delay_otel(
1129
+ self,
1130
+ req_hostname,
1131
+ backend_name=None,
1132
+ req_url=None,
1133
+ bt_name=None,
1134
+ ):
1135
+ # Apply configured outbound service delay during OTel instrumentation flow.
1136
+ # req_hostname is used for host matching; backend_name, req_url and bt_name
1137
+ # are optional for backward-compatible OTel callers while ndotel is migrated.
1138
+ try:
1139
+ self.havoc_monitor.apply_outbound_service_delay(
1140
+ req_hostname,
1141
+ backend_name,
1142
+ req_url,
1143
+ bt_name,
1144
+ )
1145
+ except Exception as e:
1146
+ print(e)
1147
+ pass
1148
+
1149
+ def outbound_havoc_failure_otel(
1150
+ self,
1151
+ req_hostname,
1152
+ backend_name=None,
1153
+ req_url=None,
1154
+ bt_name=None,
1155
+ ):
1156
+ self.havoc_monitor.apply_outbound_service_failure(
1157
+ req_hostname,
1158
+ backend_name,
1159
+ req_url,
1160
+ bt_name,
1161
+ )
1162
+ def start_business_transaction(self, urlinfo, correlation_header, nd_cookie=None, nv_cookie=None, bt_header_value=None, fp_instance=None):
1163
+ bt = None
1164
+ btname = urlinfo
1165
+ context = self.get_transaction_context()
1166
+ if context is None:
1167
+ context = TransactionContext()
1168
+ self.set_transaction_context(context)
1169
+
1170
+ if self.cav_env == "NATIVE":
1171
+ bt = self.start_business_transaction_native(urlinfo, correlation_header, nd_cookie, nv_cookie, bt_header_value, fp_instance)
1172
+ fp_topo_val = self.sdk_getTopoFpStr(bt)
1173
+
1174
+ self.get_transaction_context().fp_topo = fp_topo_val
1175
+ self.get_transaction_context().url_path = str(urlinfo).split("|", 1)[0]
1176
+ elif self.cav_env == "AWS_LAMBDA":
1177
+ bt = udp.start_business_transaction(self, urlinfo, correlation_header)
1178
+
1179
+ try:
1180
+ if self.cav_env == "NATIVE":
1181
+ url, http_method = str(urlinfo).rsplit("|", 1) if "|" in str(urlinfo) else (urlinfo, "")
1182
+ btname_value = self.get_bt_name(
1183
+ get_utf8_bytes(url),
1184
+ get_utf8_bytes(""),
1185
+ get_utf8_bytes(bt_header_value or ""),
1186
+ get_utf8_bytes(http_method)
1187
+ )
1188
+ if btname_value:
1189
+ btname = btname_value.decode() if isinstance(btname_value, bytes) else btname_value
1190
+ except Exception as e:
1191
+ self.logger.exception("Unable to get BT name from SDK: {}".format(e))
1192
+
1193
+ if self.get_transaction_context():
1194
+ self.get_transaction_context().btname = btname
1195
+
1196
+ try:
1197
+ self.havoc_monitor.apply_inbound_service_delay(urlinfo, btname)
1198
+ except Exception as e:
1199
+ # Will fail first time
1200
+ self.logger.exception("apply_inbound_service_delay exception: {}".format(e))
1201
+ pass
1202
+
1203
+ return bt
1204
+
1205
+ # @profile
1206
+ def end_business_transaction_native(self, bt, cpu_time):
1207
+ end_time = get_current_timestamp_in_us()
1208
+ #print("end_business_transaction--> BT: ", bt)
1209
+ if not self.get_current_bt():
1210
+ return None
1211
+
1212
+ self.logger.info('At end_business_transaction bt value is {0}'.format(bt))
1213
+ statuscode = self.get_current_status_code()
1214
+ if statuscode:
1215
+ c_statuscode = ctypes.c_int(statuscode)
1216
+ else:
1217
+ c_statuscode = ctypes.c_int(200)
1218
+ str_span_c = ctypes.POINTER(ctypes.c_char_p)()
1219
+ end_time_c = ctypes.c_longlong(end_time)
1220
+ rc = self.lib.nd_bt_end(bt, c_statuscode, ctypes.c_int(0), end_time_c, ctypes.c_longlong(cpu_time), ctypes.byref(str_span_c))
1221
+
1222
+ span_obj = ctypes.c_char_p.from_buffer(str_span_c)
1223
+ self.dump_span(span_obj)
1224
+ self.lib.sdk_free_memory(str_span_c)
1225
+ # self.lib.sdk_free_memory(bt)
1226
+
1227
+ del span_obj
1228
+ self.logger.info("nd_bt_end return value: {0}".format(int(rc)))
1229
+ #self.unset_current_bt()
1230
+ self.unset_current_status_code()
1231
+ self.active_bts.discard(bt)
1232
+ return int(rc)
1233
+
1234
+ def end_business_transaction(self, bt, cpu_time):
1235
+ if self.cav_env == "NATIVE":
1236
+ rc = self.end_business_transaction_native(bt, cpu_time)
1237
+ elif self.cav_env == "AWS_LAMBDA":
1238
+ rc = udp.end_business_transaction(self, bt)
1239
+ if self.get_transaction_context():
1240
+ self.get_transaction_context().havoc_applied = False
1241
+ context_object = self.get_transaction_context()
1242
+ del context_object
1243
+ if sys.version_info >= (3, 7, 0):
1244
+ self.context_provider.reset()
1245
+ else:
1246
+ self.transaction_context.pop(get_ident(), None)
1247
+
1248
+ return rc
1249
+
1250
+ def dump_span(self, span_obj):
1251
+ if not span_obj:
1252
+ return
1253
+ span_value = span_obj.value.decode()
1254
+ for x in self.application_loggers:
1255
+ #print("\n inside for", x.name, "\n")
1256
+ if x.name != "werkzeug" and not x.name.startswith("pythonagent"):
1257
+ #print("\n inside if", x.name, "\n")
1258
+ x.info(span_value)
1259
+
1260
+ """
1261
+ #@profile
1262
+ def store_business_transaction_native(self, bt, unique_bt_id):
1263
+ self.logger.info('lib variable in store business txn: {0}'.format(self.lib))
1264
+ # unique_bt_id_bytes = bytes(unique_bt_id, 'utf-8')
1265
+ try:
1266
+ unique_bt_id_bytes = bytes(unique_bt_id, 'utf-8')
1267
+ except:
1268
+ unique_bt_id_bytes = bytes(unique_bt_id.encode("utf-8"))
1269
+
1270
+ bt_id_c = ctypes.c_char_p(unique_bt_id_bytes)
1271
+ self.lib.nd_bt_store(bt, bt_id_c)
1272
+
1273
+
1274
+ def store_business_transaction(self, bt, unique_bt_id):
1275
+ if self.cav_env == "NATIVE":
1276
+ self.store_business_transaction_native(bt, unique_bt_id)
1277
+ elif self.cav_env == "AWS_LAMBDA":
1278
+ udp.store_business_transaction(bt, unique_bt_id)
1279
+ """
1280
+
1281
+ def db_call_begin_native(self, method_name, bt, db_host, db_query, query_parameters, db_start_time):
1282
+ if not self.get_current_bt():
1283
+ return None
1284
+ self.logger.info("db call begin: db_host {} db_query {}".format(db_host, db_query))
1285
+
1286
+ db_host_bytes = get_utf8_bytes(str(db_host))
1287
+ db_query_c = create_string_buffer(get_utf8_bytes(db_query))
1288
+
1289
+ if not query_parameters:
1290
+ query_parameters = ""
1291
+
1292
+ db_query_parameters_c = create_string_buffer(get_utf8_bytes(query_parameters))
1293
+ method_name_c = create_string_buffer(get_utf8_bytes(method_name))
1294
+
1295
+ ip_handle = self.lib.nd_ip_db_callout_begin(method_name_c, bt, db_query_c,
1296
+ db_query_parameters_c, ctypes.c_longlong(db_start_time))
1297
+
1298
+ del method_name_c, db_query_parameters_c, db_query_c
1299
+ return ip_handle
1300
+
1301
+ def db_call_begin(self, method_name, bt, db_host, hostinfo, query_parameters=None, db_start_time=None):
1302
+ #db_host = "NA|" + str(db_host) + "|NA|NA|NA|NA|NA|NA|NA|NA|NA|NA"
1303
+ ip_handle = 0
1304
+ if self.cav_env == "NATIVE":
1305
+ ip_handle = self.db_call_begin_native(method_name, bt, db_host, hostinfo, query_parameters, db_start_time)
1306
+ elif self.cav_env == "AWS_LAMBDA":
1307
+ entry_point_fqm = self.get_transaction_context().entry_point_fqm
1308
+ if not query_parameters:
1309
+ query_parameters = "NA"
1310
+ udp.method_entry(self, bt, entry_point_fqm, hostinfo, query_parameters)
1311
+
1312
+ backend_name = None
1313
+ try:
1314
+ if self.cav_env == "NATIVE":
1315
+ context = self.get_transaction_context()
1316
+ host_str = context.host_str if context and context.host_str else db_host
1317
+ backend_name_value = self.setting_backend_name_otel(host_str, "DB")
1318
+ if backend_name_value:
1319
+ backend_name = backend_name_value.decode() if isinstance(backend_name_value, bytes) else backend_name_value
1320
+ except Exception as e:
1321
+ self.logger.exception("Unable to get DB backend name from SDK: {}".format(e))
1322
+
1323
+ context = self.get_transaction_context()
1324
+ btname = context.btname if context else None
1325
+ req_url = context.url_path if context else None
1326
+ self.havoc_monitor.apply_outbound_service_delay(hostinfo, backend_name, req_url, btname)
1327
+
1328
+ return ip_handle
1329
+
1330
+ #@profile #@staticmethod
1331
+ def db_call_end_native(self, bt, ip_handle, duration, db_start_time, entry_point_fqm, host_str, _status_code):
1332
+ if not self.get_current_bt():
1333
+ return None
1334
+ str_span_c = ctypes.POINTER(ctypes.c_char_p)()
1335
+
1336
+ if not entry_point_fqm:
1337
+ method_name = get_utf8_bytes("NA")
1338
+ else:
1339
+ method_name = get_utf8_bytes(entry_point_fqm)
1340
+
1341
+ if not host_str:
1342
+ host_name = get_utf8_bytes("NA|NA|NA|NA|NA|NA|NA|NA|NA|NA|NA")
1343
+ else:
1344
+ host_name = get_utf8_bytes(host_str)
1345
+
1346
+ self.logger.info("db call end: db_host {} status {}".format(host_name, _status_code))
1347
+
1348
+ method_name_c = create_string_buffer(method_name)
1349
+ host_name_c = create_string_buffer(host_name)
1350
+
1351
+ rc = self.lib.nd_ip_db_callout_end(method_name_c, host_name_c, bt, ctypes.c_int(_status_code),ctypes.c_longlong(duration), ctypes.c_longlong(db_start_time), ctypes.byref(str_span_c))
1352
+ span_obj = ctypes.c_char_p.from_buffer(str_span_c)
1353
+ self.dump_span(span_obj)
1354
+ self.lib.sdk_free_memory(str_span_c)
1355
+ # self.lib.sdk_free_memory(ip_handle)
1356
+
1357
+ del span_obj
1358
+ del method_name_c, host_name_c
1359
+ return int(rc)
1360
+
1361
+ def db_call_end(self, bt, ip_handle, duration, db_start_time, entry_point_fqm, host_str, status_code):
1362
+ if self.cav_env == "NATIVE":
1363
+ self.db_call_end_native(bt, ip_handle, duration, db_start_time, entry_point_fqm, host_str, status_code)
1364
+ elif self.cav_env == "AWS_LAMBDA":
1365
+ entry_point_fqm = self.get_transaction_context().entry_point_fqm
1366
+ backend_header = self.get_transaction_context().host_str
1367
+ status_code = self.get_transaction_context().status_code
1368
+ udp.method_exit(self, bt, entry_point_fqm, backend_header, status_code, duration)
1369
+
1370
+ #@profile #@staticmethod
1371
+ def http_call_begin_native(self, bt, http_host, url, method_name, http_start_time):
1372
+ if not self.get_current_bt():
1373
+ return None
1374
+ self.logger.info("http call begin: http_host {} url {}".format(http_host, url))
1375
+ host_bytes = get_utf8_bytes(str(http_host))
1376
+ url_c = create_string_buffer(get_utf8_bytes(url))
1377
+ method_name_c = create_string_buffer(get_utf8_bytes(method_name))
1378
+
1379
+ handle = self.lib.nd_ip_http_callout_begin(method_name_c, bt, url_c, ctypes.c_longlong(http_start_time))
1380
+
1381
+ del url_c, method_name_c
1382
+ return handle
1383
+
1384
+ def http_call_begin(self, bt, http_host, url, method_name, http_start_time=0):
1385
+ if self.cav_env == "NATIVE":
1386
+ handle = self.http_call_begin_native(bt, http_host, url, method_name, http_start_time)
1387
+ elif self.cav_env == "AWS_LAMBDA":
1388
+ handle = udp.method_entry(self, bt, method_name, http_host, url)
1389
+
1390
+ backend_name = None
1391
+ try:
1392
+ if self.cav_env == "NATIVE":
1393
+ backend_name_value = self.setting_backend_name_otel(http_host, "HTTP")
1394
+ if backend_name_value:
1395
+ backend_name = backend_name_value.decode() if isinstance(backend_name_value, bytes) else backend_name_value
1396
+ except Exception as e:
1397
+ self.logger.exception("Unable to get HTTP backend name from SDK: {}".format(e))
1398
+
1399
+ context = self.get_transaction_context()
1400
+ btname = context.btname if context else None
1401
+ req_url = context.url_path if context else None
1402
+ self.havoc_monitor.apply_outbound_service_delay(http_host, backend_name, req_url, btname)
1403
+ return handle
1404
+
1405
+ #@profile #@staticmethod
1406
+ def http_call_end_native(self, bt, ip_handle, method_name, backend_name, status_code, wall_time, http_start_time, callout_id):
1407
+ if not self.get_current_bt():
1408
+ return None
1409
+ self.logger.info("http call end: backend_name {} status_code {}".format(backend_name, status_code))
1410
+ str_span_c = ctypes.POINTER(ctypes.c_char_p)()
1411
+ method_name_c = create_string_buffer(get_utf8_bytes(method_name))
1412
+ backend_name_c = create_string_buffer(get_utf8_bytes(backend_name))
1413
+ status_code_c = ctypes.c_int(status_code)
1414
+ rc = self.lib.nd_ip_http_callout_end(method_name_c, backend_name_c, bt, status_code_c, ctypes.c_longlong(wall_time), ctypes.c_longlong(http_start_time), ctypes.byref(str_span_c), ctypes.c_longlong(callout_id))
1415
+ span_obj = ctypes.c_char_p.from_buffer(str_span_c)
1416
+ self.dump_span(span_obj)
1417
+ self.lib.sdk_free_memory(str_span_c)
1418
+ # self.lib.sdk_free_memory(ip_handle)
1419
+
1420
+ del span_obj
1421
+ del method_name_c, backend_name_c
1422
+ return int(rc)
1423
+
1424
+ def http_call_end(self, bt, ip_handle, method_name=None, backend_name=None, status_code=200, duration=0, http_start_time=0, callout_id=0):
1425
+ if self.cav_env == "NATIVE":
1426
+ self.http_call_end_native(bt, ip_handle, method_name, backend_name, status_code, duration, http_start_time, callout_id)
1427
+ elif self.cav_env == "AWS_LAMBDA":
1428
+ udp.method_exit(self, bt, method_name, backend_name, status_code, duration)
1429
+
1430
+ def http_req_resp_wrapper_native(self, bt, rbuffer, rtype, statuscode):
1431
+ if not self.get_current_bt():
1432
+ return
1433
+
1434
+ r_buffer_c = create_string_buffer(get_utf8_bytes(rbuffer))
1435
+ r_type_c = create_string_buffer(get_utf8_bytes(rtype))
1436
+
1437
+ self.lib.sdk_httpReqRespWrapper(bt, r_buffer_c, r_type_c, statuscode)
1438
+
1439
+ del r_buffer_c, r_type_c
1440
+
1441
+ def http_req_resp_wrapper(self, bt, rbuffer, rtype, statuscode):
1442
+ if self.cav_env == "NATIVE":
1443
+ self.http_req_resp_wrapper_native(bt, rbuffer, rtype, statuscode)
1444
+ elif self.cav_env == "AWS_LAMBDA":
1445
+ udp.http_req_resp_wrapper(self, bt, rbuffer, rtype, statuscode)
1446
+
1447
+
1448
+ def exception_dump_native(self, bt, mpp, starttime, excptnclsname, excptnmsg, throwingclsname,
1449
+ throwingmtdname, excptncause, excptnlineno, stacktrace, file_name):
1450
+ if not self.get_current_bt():
1451
+ return
1452
+
1453
+ stack_trace_c = create_string_buffer(get_utf8_bytes(stacktrace))
1454
+ file_name_c = create_string_buffer(get_utf8_bytes(file_name))
1455
+ exception_class_c = create_string_buffer(get_utf8_bytes(excptnclsname))
1456
+ throwing_class_c = create_string_buffer(get_utf8_bytes(throwingclsname))
1457
+ exception_message_c = create_string_buffer(get_utf8_bytes(excptnmsg))
1458
+ throwing_method_c = create_string_buffer(get_utf8_bytes(throwingmtdname))
1459
+ exception_cause_c = create_string_buffer(get_utf8_bytes(excptncause))
1460
+
1461
+ self.lib.getstacktracearray(bt,
1462
+ stack_trace_c,
1463
+ file_name_c,
1464
+ exception_class_c,
1465
+ throwing_class_c,
1466
+ exception_message_c,
1467
+ throwing_method_c,
1468
+ excptnlineno,
1469
+ exception_cause_c
1470
+ )
1471
+
1472
+ del stack_trace_c, file_name_c, exception_class_c, throwing_class_c
1473
+ del exception_message_c, throwing_method_c, exception_cause_c
1474
+
1475
+ def exceptiondump(self, bt, mpp, starttime, excptnclsname, excptnmsg, throwingclsname,
1476
+ throwingmtdname, excptncause, excptnlineno, stacktrace, file_name):
1477
+ if self.cav_env == "NATIVE":
1478
+ self.exception_dump_native(bt, mpp, starttime, excptnclsname, excptnmsg, throwingclsname,
1479
+ throwingmtdname, excptncause, excptnlineno, stacktrace, file_name)
1480
+ elif self.cav_env == "AWS_LAMBDA":
1481
+ udp.exception_dump(self, bt, mpp, starttime, excptnclsname, excptnmsg, throwingclsname,
1482
+ throwingmtdname, excptncause, excptnlineno, stacktrace)
1483
+
1484
+ def heap_dump_py(self):
1485
+ heap_string = create_heap_dump_muppy(self)
1486
+ heap = bytes(heap_string.encode('utf-8'))
1487
+ return heap
1488
+
1489
+ ######################
1490
+ # UNUSED FUNCTIONS
1491
+ ######################
1492
+
1493
+ def wait_for_start(self, timeout_ms=None):
1494
+ """Wait for the agent to start and get configured.
1495
+
1496
+ Other Parameters
1497
+ ----------------
1498
+ timeout_ms : int, optional
1499
+ The maximum time to wait for the agent to start and be configured
1500
+ before returning.
1501
+
1502
+ Returns
1503
+ -------
1504
+ bool
1505
+ Returns ``True`` if the agent is enabled after waiting, else
1506
+ ``False``.
1507
+
1508
+ """
1509
+ if timeout_ms is not None:
1510
+ with self.timer() as timer:
1511
+ if self.proxy_control_svc is not None:
1512
+ self.proxy_control_svc.wait_for_start(timeout_ms=timeout_ms)
1513
+
1514
+ if self.config_svc is not None:
1515
+ timeout_ms = max(0, timeout_ms - timer.duration_ms)
1516
+ self.config_svc.wait_for_config(timeout_ms=timeout_ms)
1517
+
1518
+ if self.tx_svc is not None:
1519
+ timeout_ms = max(0, timeout_ms - timer.duration_ms)
1520
+ self.tx_svc.wait_for_start(timeout_ms=timeout_ms)
1521
+ else:
1522
+ self.proxy_control_svc.wait_for_start()
1523
+ self.config_svc.wait_for_config()
1524
+ self.tx_svc.wait_for_start()
1525
+
1526
+ return self.enabled
1527
+
1528
+
1529
+ def wait_for_end(self, timeout_ms=None):
1530
+ """Wait for the agent to finish reporting any pending BTs.
1531
+
1532
+ """
1533
+ self.tx_svc.wait_for_end(timeout_ms=timeout_ms)
1534
+
1535
+ #@property
1536
+ def enabled(self):
1537
+ """Return true if the agent has started and is enabled.
1538
+
1539
+ """
1540
+ return (
1541
+ self.nd_init_done and
1542
+ self.config_svc and self.config_svc.enabled and
1543
+ self.tx_svc)
1544
+
1545
+ ##################################
1546
+ # TRANSACTION RELATED FUNCTIONS
1547
+ ##################################
1548
+
1549
+ def get_current_bt(self):
1550
+ """Get the currently active BT for the calling context.
1551
+
1552
+ The calling context is the active greenlet or thread, depending on
1553
+ whether greenlets are in use or not. If the agent is disabled, or if
1554
+ there is no active transaction for the calling context, None is
1555
+ returned.
1556
+
1557
+ Returns
1558
+ -------
1559
+ bt : appdynamics.agent.core.bt.Transaction or None
1560
+ the active business transaction (if any)
1561
+
1562
+ """
1563
+ # if not self.enabled:
1564
+ # return None
1565
+
1566
+ if sys.version_info >= (3, 7, 0):
1567
+ return self.currentbt_provider.active()
1568
+ else:
1569
+ return self.current_bts.get(get_ident(), None)
1570
+
1571
+ def set_current_bt(self, bt):
1572
+ if bt:
1573
+ if sys.version_info >= (3, 7, 0):
1574
+ self.currentbt_provider.activate(bt)
1575
+ else:
1576
+ self.current_bts[get_ident()] = bt
1577
+
1578
+ def unset_current_bt(self):
1579
+ if sys.version_info >= (3, 7, 0):
1580
+ self.currentbt_provider.reset()
1581
+ else:
1582
+ self.current_bts.pop(get_ident(), None)
1583
+
1584
+ def get_current_status_code(self):
1585
+ if sys.version_info >= (3, 7, 0):
1586
+ return self.statuscode_provider.active()
1587
+ else:
1588
+ return self.current_status_code.get(get_ident(), None)
1589
+
1590
+ def set_current_status_code(self, status_code):
1591
+ if status_code:
1592
+ if sys.version_info >= (3, 7, 0):
1593
+ self.statuscode_provider.activate(status_code)
1594
+ else:
1595
+ self.current_status_code[get_ident()] = status_code
1596
+
1597
+ def unset_current_status_code(self):
1598
+ if sys.version_info >= (3, 7, 0):
1599
+ self.statuscode_provider.reset()
1600
+ else:
1601
+ self.current_status_code.pop(get_ident(), None)
1602
+
1603
+ def set_transaction_context(self, context):
1604
+ if context:
1605
+ context.tier_name = self.tier_name
1606
+ context.server_name = self.server_name
1607
+ context.instance_name = self.instance_name
1608
+ context.function_name = self.function_name
1609
+ context.flow_path_id = generate_flow_path_id()
1610
+ context.fp_topo = self.fp_topo
1611
+
1612
+ if sys.version_info >= (3, 7, 0):
1613
+ self.context_provider.activate(context)
1614
+ else:
1615
+ self.transaction_context[get_ident()] = context
1616
+
1617
+ def get_transaction_context(self):
1618
+ if sys.version_info >= (3, 7, 0):
1619
+ context = self.context_provider.active()
1620
+ else:
1621
+ context = self.transaction_context.get(get_ident(), None)
1622
+ return context
1623
+
1624
+ def reset_transaction_context(self):
1625
+ if sys.version_info >= (3, 7, 0):
1626
+ self.currentbt_provider.reset()
1627
+ self.statuscode_provider.reset()
1628
+ self.context_provider.reset()
1629
+ else:
1630
+ self.transaction_context.pop(get_ident(), None)
1631
+ self.current_status_code.pop(get_ident(), None)
1632
+ self.current_bts.pop(get_ident(), None)
1633
+
1634
+
1635
+ ##################
1636
+ # UNUSED CLASSES
1637
+ ##################
1638
+
1639
+
1640
+ class AgentNotStartedException(Exception):
1641
+ pass
1642
+
1643
+
1644
+ class AgentNotReadyException(Exception):
1645
+ pass
1646
+
1647
+
1648
+ class IgnoreTransaction(Exception):
1649
+ pass
1650
+
1651
+