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,155 @@
1
+ # Purpose: given an absolute file path (as found in sys.modules - application files and
2
+ # site-packages dependencies alike), resolve the installed distribution that file belongs to: its
3
+ # name, its version, and whether it IS the monitored application itself rather than a dependency.
4
+ #
5
+ # Used by find.py to report a jar-name-equivalent field per discovered module/class, mirroring the
6
+ # sibling NodeJS agent's moduleVersionResolver.js (itself mirroring the Java agent's per-class
7
+ # origin-jar reporting). NodeJS resolves ownership by walking up from a file to the nearest
8
+ # package.json - Python has no such per-directory manifest, so this instead builds a one-time
9
+ # reverse index from every installed distribution's own file list (RECORD), then falls back to a
10
+ # stdlib/site-packages boundary check to decide whether an unresolved file is the application's own
11
+ # code. Both the index and the boundary set are memoized, so a lookup after the first is O(1).
12
+
13
+ import os
14
+ import sys
15
+ import logging
16
+ import sysconfig
17
+
18
+ try:
19
+ from importlib.metadata import distributions # Python 3.8+
20
+ except ImportError:
21
+ try:
22
+ from importlib_metadata import distributions # backport for older Python 3
23
+ except ImportError:
24
+ distributions = None
25
+
26
+ logger = logging.getLogger('pythonagent.agent')
27
+
28
+ _file_to_package = None
29
+ _boundary_dirs = None
30
+
31
+
32
+ def _normalize(path):
33
+ return os.path.normcase(os.path.abspath(path))
34
+
35
+
36
+ def _build_file_to_package_index():
37
+ index = {}
38
+ if distributions is None:
39
+ return index
40
+ for dist in distributions():
41
+ try:
42
+ name = dist.metadata['Name'] if dist.metadata else None
43
+ version = dist.version
44
+ files = dist.files or []
45
+ except Exception:
46
+ continue
47
+ if not name or not version:
48
+ continue
49
+ for f in files:
50
+ try:
51
+ index[_normalize(str(dist.locate_file(f)))] = (name, version)
52
+ except Exception:
53
+ continue
54
+ return index
55
+
56
+
57
+ def _get_file_to_package_index():
58
+ global _file_to_package
59
+ if _file_to_package is None:
60
+ try:
61
+ _file_to_package = _build_file_to_package_index()
62
+ except Exception as e:
63
+ logger.warning('module_version_resolver | Error building package file index : %s', e)
64
+ _file_to_package = {}
65
+ return _file_to_package
66
+
67
+
68
+ def _build_boundary_dirs():
69
+ dirs = set()
70
+ try:
71
+ paths = sysconfig.get_paths()
72
+ for key in ('stdlib', 'platstdlib', 'purelib', 'platlib'):
73
+ p = paths.get(key)
74
+ if p:
75
+ dirs.add(_normalize(p))
76
+ except Exception:
77
+ pass
78
+ try:
79
+ import site
80
+ if hasattr(site, 'getsitepackages'):
81
+ for p in site.getsitepackages():
82
+ dirs.add(_normalize(p))
83
+ if hasattr(site, 'getusersitepackages'):
84
+ dirs.add(_normalize(site.getusersitepackages()))
85
+ except Exception:
86
+ pass
87
+ return dirs
88
+
89
+
90
+ def _get_boundary_dirs():
91
+ global _boundary_dirs
92
+ if _boundary_dirs is None:
93
+ try:
94
+ _boundary_dirs = _build_boundary_dirs()
95
+ except Exception as e:
96
+ logger.warning('module_version_resolver | Error building stdlib/site-packages boundary : %s', e)
97
+ _boundary_dirs = set()
98
+ return _boundary_dirs
99
+
100
+
101
+ def _is_under_boundary(abs_path):
102
+ for boundary_dir in _get_boundary_dirs():
103
+ if abs_path == boundary_dir or abs_path.startswith(boundary_dir + os.sep):
104
+ return True
105
+ return False
106
+
107
+
108
+ def resolve(file_path):
109
+ """Resolve the installed distribution owning file_path.
110
+
111
+ @return dict with 'name', 'version', 'isApp' - name/version are None when the file is the
112
+ application's own code (isApp True) or when nothing could be resolved at all (isApp False,
113
+ e.g. a stdlib module or a distribution with no readable RECORD); returns None only when
114
+ file_path itself is unusable.
115
+ """
116
+ if not file_path:
117
+ return None
118
+ try:
119
+ abs_path = _normalize(file_path)
120
+ except Exception:
121
+ return None
122
+
123
+ match = _get_file_to_package_index().get(abs_path)
124
+ if match:
125
+ return {'name': match[0], 'version': match[1], 'isApp': False}
126
+
127
+ if _is_under_boundary(abs_path):
128
+ # Inside stdlib/site-packages but not owned by any distribution we could index (e.g. a
129
+ # namespace package, or an editable/legacy install with no RECORD) - not app code, but no
130
+ # name/version to report either.
131
+ return {'name': None, 'version': None, 'isApp': False}
132
+
133
+ # Outside stdlib and site-packages entirely: this is the monitored application's own code.
134
+ return {'name': None, 'version': None, 'isApp': True}
135
+
136
+
137
+ def format_jar_field(pkg_info):
138
+ """Format a resolve() result into the auto-discovery jar-equivalent field, mirroring
139
+ autoDiscovery.js's pkgField: "<name>@<version>", suffixed "(app)" when the file belongs to the
140
+ monitored application itself, or '' when nothing could be resolved."""
141
+ if not pkg_info:
142
+ return ''
143
+ name = pkg_info.get('name') or ''
144
+ version = pkg_info.get('version') or ''
145
+ field = (name + '@' + version) if (name and version) else ''
146
+ if pkg_info.get('isApp'):
147
+ field += '(app)'
148
+ return field
149
+
150
+
151
+ def clear_cache():
152
+ """Exposed for tests/diagnostics only - not used by production callers."""
153
+ global _file_to_package, _boundary_dirs
154
+ _file_to_package = None
155
+ _boundary_dirs = None
@@ -0,0 +1,64 @@
1
+ import json
2
+
3
+
4
+ def create_module_list(filePath):
5
+ try:
6
+ f = open(filePath, "r")
7
+ except:
8
+ return []
9
+ x = f.read()
10
+ if x[1] == "[" and x[-1] != "]":
11
+ x += "]"
12
+ obj2 = json.loads(x)
13
+ list_of_modules = []
14
+ for item in obj2:
15
+ module_name_value = item.get("modulename", None)
16
+ module_name_split = module_name_value.split("|")
17
+ module_name = module_name_split[0]
18
+
19
+ if module_name not in list_of_modules:
20
+ list_of_modules.append(module_name)
21
+ return list_of_modules
22
+
23
+
24
+ def create_method_list(filePath):
25
+ print("filePath", filePath)
26
+ try:
27
+ f = open(filePath, "r")
28
+ except:
29
+ return []
30
+
31
+ x = f.read()
32
+
33
+ if x[1] == "[" and x[-1] != "]":
34
+ x += "]"
35
+
36
+ obj2 = json.loads(x)
37
+ LOM = []
38
+ for item in obj2:
39
+ module_name_value = item.get("modulename", None)
40
+ module_name_split = module_name_value.split("|")
41
+ module_name = module_name_split[0]
42
+
43
+ if item.get("classes", None) != "":
44
+ classes_split = item.get("classes").split("|")
45
+ class_name = classes_split[0]
46
+ class_level_methods_str = classes_split[1]
47
+ class_level_methods = class_level_methods_str.split(",")
48
+ for class_level_method in class_level_methods:
49
+ LOM.append(module_name + "." + class_name + "." + class_level_method)
50
+ else:
51
+ module_level_methods_str = module_name_split[1]
52
+ module_level_methods = module_level_methods_str.split(",")
53
+ for module_level_method in module_level_methods:
54
+ LOM.append(module_name + "." + module_level_method)
55
+
56
+ list_of_methods = [str(r) for r in LOM]
57
+
58
+ return list_of_methods
59
+
60
+
61
+ if __name__ == "__main__":
62
+ abc = create_method_list("k.json")
63
+ print(abc)
64
+
@@ -0,0 +1,129 @@
1
+ import json
2
+ import logging
3
+ #import jsonpickle
4
+ #from json import JSONEncoder
5
+
6
+ _logger = logging.getLogger('pythonagent.agent')
7
+
8
+ try:
9
+ from types import SimpleNamespace as Namespace
10
+ except ImportError:
11
+ # Python 2.x fallback
12
+ from argparse import Namespace
13
+
14
+
15
+
16
+
17
+ #print("Encode Object into JSON formatted Data using jsonpickle")
18
+ def flatten_hook(obj):
19
+ for key, value in obj.items():
20
+ if isinstance(value, str):
21
+ try:
22
+ obj[key] = json.loads(value, object_hook=flatten_hook)
23
+ except ValueError:
24
+ pass
25
+ return obj
26
+
27
+
28
+ def create_method_json(filePath):
29
+ try:
30
+ f = open(filePath, "r")
31
+ except:
32
+ return {}
33
+ x = f.read()
34
+ if x[1] == "[" and x[-1] != "]":
35
+ x += "]"
36
+ obj2 = json.loads(x)
37
+ #obj2 = json.loads(f.read(),object_hook=flatten_hook)
38
+
39
+ return obj2
40
+
41
+ def create_method_array(filePath):
42
+ #print('reading the profile at path: ',filePath)
43
+ try:
44
+ f = open(filePath, "r")
45
+ except:
46
+ return []
47
+
48
+ x = f.read()
49
+ if x[1] == "[" and x[-1] != "]":
50
+ x += "]"
51
+ obj2 = json.loads(x)
52
+ #print('Exception occure to open profiler file')
53
+ #obj2 = json.loads(f.read(),object_hook=flatten_hook)
54
+
55
+ #list of methods
56
+ LOM = []
57
+
58
+ for module in obj2["modules"]:
59
+
60
+ #module = module.split("/")[-1].replace(".py","")
61
+ # print(module+"--------------------------------------------")
62
+ for MLM in module["moduleLevelMethod"]:
63
+ #print(module["moduleName"])
64
+ LOM.append(module["moduleName"]+"."+MLM["name"])
65
+ for each_class in module["classes"]:
66
+ for CLM in each_class["classLevelMethods"]:
67
+ LOM.append(module["moduleName"]+"."+each_class["className"]+"."+CLM["name"])
68
+
69
+ # print(LOM)
70
+
71
+ arr = [str(r) for r in LOM]
72
+
73
+ #print(arr)
74
+ return arr
75
+
76
+ #abc = create_method_json("/home/cavisson/methodTest/instrumentationprofile.json")["modules"]
77
+
78
+ #print(abc["moduleName"])
79
+
80
+ def create_method_list(filePath):
81
+ print("filePath", filePath)
82
+ try:
83
+ f = open(filePath, "r")
84
+ except:
85
+ return []
86
+
87
+ LOM = set()
88
+
89
+ string_of_profiles = f.read()
90
+ list_of_profiles = string_of_profiles.split("\n\n\n")
91
+
92
+ for profile in list_of_profiles:
93
+ try:
94
+ obj2 = json.loads(profile)
95
+ except:
96
+ continue
97
+
98
+ for item in obj2:
99
+ try:
100
+ module_name_value = item.get("modulename", None)
101
+ module_name_split = module_name_value.split("|")
102
+ module_name = module_name_split[0]
103
+
104
+ if item.get("classes", None) != "":
105
+ classes_split = item.get("classes").split("|")
106
+ class_name = classes_split[0]
107
+ class_level_methods_str = classes_split[1]
108
+ class_level_methods = class_level_methods_str.split(",")
109
+ for class_level_method in class_level_methods:
110
+ LOM.add(module_name + "." + class_name + "." + class_level_method)
111
+ else:
112
+ module_level_methods_str = module_name_split[1]
113
+ module_level_methods = module_level_methods_str.split(",")
114
+ for module_level_method in module_level_methods:
115
+ LOM.add(module_name + "." + module_level_method)
116
+ except Exception:
117
+ # A single malformed profile entry (e.g. missing "modulename",
118
+ # or "classes" empty with no "|" in "modulename") must not abort
119
+ # parsing of the rest of the profile -- that previously dropped
120
+ # every remaining module (including app modules) from a large
121
+ # "complete" profile and silently fell back to the stale local
122
+ # instrumentationprofile.json.
123
+ _logger.warning("Skipping malformed instrumentation profile entry: %r", item)
124
+ continue
125
+
126
+ list_of_methods = [str(r) for r in LOM]
127
+
128
+ return list_of_methods
129
+
@@ -0,0 +1,219 @@
1
+ from . import frameworks, logging, http, sql,Instrumentation
2
+ import sys
3
+
4
+ try:
5
+ from importlib.machinery import ModuleSpec
6
+ except ImportError:
7
+ pass
8
+
9
+ try:
10
+ from importlib import reload
11
+ except ImportError:
12
+ from imp import reload
13
+
14
+
15
+ URL_PROPERTY_MAX_LEN = 100
16
+ HOST_PROPERTY_MAX_LEN = 50
17
+ DB_NAME_PROPERTY_MAX_LEN = 50
18
+ VENDOR_PROPERTY_MAX_LEN = 50
19
+
20
+
21
+ #from pythonagent.agent.internal.intercept_module import BT
22
+ #BT_INTERCEPTORS = BT
23
+
24
+
25
+
26
+
27
+ # BT_INTERCEPTORS = (
28
+ # # Entry points
29
+ # ('flask', frameworks.intercept_flask),
30
+ # ('django.core.handlers.wsgi', frameworks.intercept_django_wsgi_handler),
31
+ # ('django.core.handlers.base', frameworks.intercept_django_base_handler),
32
+ #
33
+ # # HTTP exit calls
34
+ # ('httplib', http.intercept_httplib),
35
+ # ('http.client', http.intercept_httplib),
36
+ # ('urllib3', http.intercept_urllib3),
37
+ # ('requests', http.intercept_requests),
38
+ #
39
+ # # Logging
40
+ # ('logging', logging.intercept_logging),
41
+ #
42
+ # # SQL exit calls
43
+ # ('psycopg2', sql.psycopg2.intercept_psycopg2_connection),
44
+ # ('pymysql.connections', sql.pymysql.intercept_pymysql_connections),
45
+ # ('mysql.connector.connection', sql.mysql_connector.intercept_mysql_connector_connection),
46
+ # ('MySQLdb.connections', sql.mysqldb.intercept_MySQLdb_connection),
47
+ # )
48
+
49
+
50
+ def add_hook(agent):
51
+ """Add the module interceptor hook for pythonagent, if it's not already registered.
52
+
53
+ Reuses the existing ModuleInterceptor for this agent when one is already present in
54
+ sys.meta_path. This prevents accumulating N interceptors after N re-bootstraps, which
55
+ would cause O(N) overhead on every module import and N-times callback execution.
56
+ """
57
+ for finder in sys.meta_path:
58
+ if isinstance(finder, ModuleInterceptor) and finder.agent is agent:
59
+ return finder # reuse — prevents sys.meta_path accumulation
60
+ interceptor = ModuleInterceptor(agent)
61
+ sys.meta_path.insert(0, interceptor)
62
+ return interceptor
63
+
64
+
65
+ class ModuleInterceptor(object):
66
+ """Intercepts finding and loading modules in order to monkey patch them on load.
67
+
68
+ """
69
+
70
+ def __init__(self, agent):
71
+ super(ModuleInterceptor, self).__init__()
72
+ self.agent = agent
73
+ self.module_hooks = {}
74
+ self.intercepted_modules = set()
75
+
76
+ def find_spec(self, full_name, path, target=None):
77
+ #print("FIND SPEC {} ".format(full_name))
78
+ if full_name in self.module_hooks:
79
+ top = full_name.split('.')[0]
80
+ stdlib_names = getattr(sys, 'stdlib_module_names', None) or Instrumentation._FALLBACK_STDLIB_NAMES
81
+ if top in stdlib_names:
82
+ self.module_hooks.pop(full_name, None)
83
+ return None
84
+ return ModuleSpec(full_name, self)
85
+ return None
86
+
87
+ def find_module(self, full_name, path=None):
88
+ #print("FIND MODULE", full_name)
89
+ #self.agent.logger.info("Finding module {0}".format(full_name))
90
+ self.agent.logger.info('Modulename: ModuleInterceptor class || full_name {0}'.format(full_name))
91
+ if full_name in self.module_hooks:
92
+ top = full_name.split('.')[0]
93
+ stdlib_names = getattr(sys, 'stdlib_module_names', None) or Instrumentation._FALLBACK_STDLIB_NAMES
94
+ if top in stdlib_names:
95
+ self.module_hooks.pop(full_name, None)
96
+ return None
97
+ return self
98
+ return None
99
+
100
+ def load_module(self, name):
101
+ #print("LOAD MODULE {}".format(name))
102
+ # Remove the module from the list of hooks so that we never see it again.
103
+ #self.agent.logger.info('Modulename: ModuleInterceptor class || function name {0}'.format(name))
104
+ #self.agent.logger.info("Loader loading load module {0}".format(name))
105
+ # for module in custom_methods_to_instrument_json["modules"]:
106
+ # if name == module["moduleName"]:
107
+ # hooks = Instrumentation.intercept_instrumented_method
108
+
109
+ # hooks = self.module_hooks.pop(name, [])
110
+ # print("hooks for module: ",name," ->",hooks)
111
+
112
+ #if name in all_module_names:
113
+ # hooks = Instrumentation.intercept_instrumented_method
114
+ # all_module_names.remove(name)
115
+ #else:
116
+ # hooks = self.module_hooks.pop(name, [])
117
+
118
+
119
+
120
+
121
+ hooks = self.module_hooks.pop(name, [])
122
+
123
+
124
+
125
+
126
+
127
+ #self.agent.logger.info("hooks for module: {0} and hook {1}".format(name,hooks))
128
+ #self.agent.logger.info('Modulename: ModuleInterceptor class || hooks for module {0}'.format(hooks))
129
+ """
130
+ if name in sys.modules:
131
+ # Already been loaded. Return it as is.
132
+ return sys.modules[name]
133
+ """
134
+ #self.agent.logger.debug('Intercepting import %s', name)
135
+ #self.agent.logger.info(("Intercepting import {0}".format(name)))
136
+ #self.agent.logger.info('Modulename: ModuleInterceptor class || intercepting import {0}'.format(name))
137
+ try:
138
+ __import__(name) # __import__('a.b.c') returns <module a>, not <module a.b.c>
139
+ except ImportError:
140
+ raise # propagate missing-module errors as-is
141
+ except Exception as e:
142
+ # A non-ImportError from module initialisation (e.g. AttributeError from
143
+ # a version mismatch in dns/query.py when httpcore._backends is absent).
144
+ # Callers such as mysql.connector.pooling use "except ImportError" guards —
145
+ # wrapping here lets those guards work correctly instead of crashing the app.
146
+ raise ImportError(
147
+ "pythonagent: {!r} raised {} during load: {}".format(
148
+ name, type(e).__name__, e)
149
+ ) from e
150
+ module = sys.modules.get(name) # ...so get <module a.b.c> from sys.modules
151
+ if module is None:
152
+ return None
153
+
154
+ self._intercept_module(module, hooks)
155
+
156
+ return module
157
+
158
+ def call_on_import(self, module_name, cb):
159
+ # Never intercept stdlib module imports — adding them to module_hooks causes
160
+ # load_module to call __import__ re-entrantly, which corrupts Python 3.12
161
+ # per-module import locks (_bootstrap._weakref = None → AttributeError).
162
+ top = module_name.split('.')[0]
163
+ stdlib_names = getattr(sys, 'stdlib_module_names', None) or Instrumentation._FALLBACK_STDLIB_NAMES
164
+ if top in stdlib_names and top not in {"http", "urllib"}:
165
+ return
166
+
167
+ #print("agent/probes/init.call_on_import() ...")
168
+ #self.agent.logger.info('Modulename: ModuleInterceptor class || module_name is {0} and callback is {1}'.format(module_name,cb))
169
+ #self.agent.logger.info("modulename: %s", module_name, " callback: %s", cb)
170
+ #self.agent.logger.info('Modulename: ModuleInterceptor class inside call_on_import function callback is {0}'.format(cb))
171
+
172
+ # print(custom_methods_to_instrument_json["modules"])
173
+ # print("hooks for module: ",name," ->",hooks)
174
+
175
+ #if module_name in all_module_names:
176
+ # hooks = Instrumentation.intercept_instrumented_method
177
+ # self._intercept_module(sys.modules[module_name], [hooks])
178
+
179
+ if module_name in sys.modules:
180
+ #print("FOUND IN SYS MODULES")
181
+ #print("module" ,module_name, " found in sys.modules. Calling intercept module")
182
+ self._intercept_module(sys.modules[module_name], [cb])
183
+ self.module_hooks.setdefault(module_name, [])
184
+ if cb not in self.module_hooks[module_name]:
185
+ self.module_hooks[module_name].append(cb)
186
+ else:
187
+ #print("NOT FOUND IN SYS MODULES")
188
+ #print("module" ,module_name, " not found in sys.modules. Will be called from load modules")
189
+ self.module_hooks.setdefault(module_name, [])
190
+ if cb not in self.module_hooks[module_name]:
191
+ self.module_hooks[module_name].append(cb)
192
+
193
+
194
+ #print('self.module_hooks value',self.module_hooks)
195
+ #if module_name in all_module_names:
196
+ # hooks = Instrumentation.intercept_instrumented_method
197
+ # __import__(module_name)
198
+ # self._intercept_module(sys.modules[module_name], [hooks])
199
+
200
+ def _intercept_module(self, module, hooks):
201
+ #print("intercept module : {} hooks {}".format(module, hooks))
202
+ try:
203
+ for hook in hooks:
204
+ #self.agent.logger.debug("Running {0} hook {1}".format(module.__name__, hook))
205
+ hook(self.agent, module)
206
+ self.intercepted_modules.add(module)
207
+ #print("self.intercepted_modules", self.intercepted_modules)
208
+ #print("HOOK CALLED")
209
+ except:
210
+ #print("exception in _intercept_module")
211
+ self.agent.logger.exception("Exception in {0} hook.".format(module.__name__))
212
+
213
+ # Re-import to ensure the module hasn't been partially patched.
214
+ self.agent.logger.debug("Re-importing {0} after error in module hook".format( module.__name__))
215
+ reload(module)
216
+
217
+
218
+
219
+