cavisson-pythonagent 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cavisson_pythonagent-0.0.1.dist-info/METADATA +32 -0
- cavisson_pythonagent-0.0.1.dist-info/RECORD +180 -0
- cavisson_pythonagent-0.0.1.dist-info/WHEEL +5 -0
- cavisson_pythonagent-0.0.1.dist-info/licenses/LICENSE +19 -0
- cavisson_pythonagent-0.0.1.dist-info/top_level.txt +1 -0
- pythonagent/__init__.py +22 -0
- pythonagent/agent/__init__.py +219 -0
- pythonagent/agent/internal/__init__.py +1 -0
- pythonagent/agent/internal/agent.py +1651 -0
- pythonagent/agent/internal/framesinfo.py +152 -0
- pythonagent/agent/internal/heap_dump.py +39 -0
- pythonagent/agent/internal/intercept_module.py +70 -0
- pythonagent/agent/internal/logs.py +122 -0
- pythonagent/agent/internal/metadata/__init__.py +0 -0
- pythonagent/agent/internal/metadata/agent_meta_data.py +276 -0
- pythonagent/agent/internal/proc_compat.py +75 -0
- pythonagent/agent/internal/profile.py +47 -0
- pythonagent/agent/internal/provider.py +83 -0
- pythonagent/agent/internal/thread_dump.py +85 -0
- pythonagent/agent/internal/udp.py +245 -0
- pythonagent/agent/internal/udp_message.py +800 -0
- pythonagent/agent/probes/Instrumentation/__init__.py +340 -0
- pythonagent/agent/probes/Instrumentation/find.py +243 -0
- pythonagent/agent/probes/Instrumentation/module_version_resolver.py +155 -0
- pythonagent/agent/probes/Instrumentation/new_parser.py +64 -0
- pythonagent/agent/probes/Instrumentation/parser.py +129 -0
- pythonagent/agent/probes/__init__.py +219 -0
- pythonagent/agent/probes/base.py +303 -0
- pythonagent/agent/probes/cache/__init__.py +51 -0
- pythonagent/agent/probes/cache/redis.py +119 -0
- pythonagent/agent/probes/cache/redis_asyncio.py +83 -0
- pythonagent/agent/probes/coroutines/__init__.py +1 -0
- pythonagent/agent/probes/coroutines/asyncio.py +63 -0
- pythonagent/agent/probes/elasticdb/__init__.py +7 -0
- pythonagent/agent/probes/elasticdb/aelastic.py +54 -0
- pythonagent/agent/probes/frameworks/__init__.py +27 -0
- pythonagent/agent/probes/frameworks/agentprofiler.py +105 -0
- pythonagent/agent/probes/frameworks/aiohttp_web.py +155 -0
- pythonagent/agent/probes/frameworks/aisess.py +151 -0
- pythonagent/agent/probes/frameworks/asgi.py +340 -0
- pythonagent/agent/probes/frameworks/bottle.py +27 -0
- pythonagent/agent/probes/frameworks/cherry.py +25 -0
- pythonagent/agent/probes/frameworks/django.py +128 -0
- pythonagent/agent/probes/frameworks/falcon.py +21 -0
- pythonagent/agent/probes/frameworks/fastapi.py +35 -0
- pythonagent/agent/probes/frameworks/flask.py +30 -0
- pythonagent/agent/probes/frameworks/pyramid.py +56 -0
- pythonagent/agent/probes/frameworks/test.py +108 -0
- pythonagent/agent/probes/frameworks/tornado_async_web.py +117 -0
- pythonagent/agent/probes/frameworks/tornado_web.py +133 -0
- pythonagent/agent/probes/frameworks/wsgi.py +353 -0
- pythonagent/agent/probes/grpc/__init__.py +76 -0
- pythonagent/agent/probes/grpc/client_interceptor.py +132 -0
- pythonagent/agent/probes/grpc/server_interceptor.py +129 -0
- pythonagent/agent/probes/havoc/__init__.py +0 -0
- pythonagent/agent/probes/havoc/custom_memory_stress.py +186 -0
- pythonagent/agent/probes/havoc/custom_thread_stress.py +187 -0
- pythonagent/agent/probes/havoc/havoc_constants.py +218 -0
- pythonagent/agent/probes/havoc/havoc_manager.py +981 -0
- pythonagent/agent/probes/http/__init__.py +49 -0
- pythonagent/agent/probes/http/aiohttp_client.py +59 -0
- pythonagent/agent/probes/http/boto.py +12 -0
- pythonagent/agent/probes/http/httplib.py +110 -0
- pythonagent/agent/probes/http/httpx_client.py +116 -0
- pythonagent/agent/probes/http/requests.py +15 -0
- pythonagent/agent/probes/http/tornado_httpclient.py +85 -0
- pythonagent/agent/probes/http/urllib3.py +16 -0
- pythonagent/agent/probes/langchain/__init__.py +21 -0
- pythonagent/agent/probes/langchain/base_tool.py +95 -0
- pythonagent/agent/probes/langchain/langchain_community.py +136 -0
- pythonagent/agent/probes/langchain/langchain_core.py +32 -0
- pythonagent/agent/probes/langchain/langchain_openai.py +110 -0
- pythonagent/agent/probes/logging/__init__.py +106 -0
- pythonagent/agent/probes/message_brokers/__init__.py +4 -0
- pythonagent/agent/probes/message_brokers/pika.py +126 -0
- pythonagent/agent/probes/mongodb/__init__.py +6 -0
- pythonagent/agent/probes/mongodb/pymongo.py +286 -0
- pythonagent/agent/probes/openai/__init__.py +3 -0
- pythonagent/agent/probes/openai/openai.py +797 -0
- pythonagent/agent/probes/span.py +101 -0
- pythonagent/agent/probes/sql/__init__.py +13 -0
- pythonagent/agent/probes/sql/botocores3.py +51 -0
- pythonagent/agent/probes/sql/dbapi.py +285 -0
- pythonagent/agent/probes/sql/dynamodb.py +90 -0
- pythonagent/agent/probes/sql/mysql_connector.py +24 -0
- pythonagent/agent/probes/sql/mysql_connector_cext.py +24 -0
- pythonagent/agent/probes/sql/mysqldb.py +43 -0
- pythonagent/agent/probes/sql/psycopg2.py +174 -0
- pythonagent/agent/probes/sql/pymysql.py +25 -0
- pythonagent/bootstrap/__init__.py +0 -0
- pythonagent/bootstrap/cav_gunicorn.py +26 -0
- pythonagent/bootstrap/cavagent_lambda_wrapper.py +291 -0
- pythonagent/bootstrap/run.py +47 -0
- pythonagent/bootstrap/sitecustomize.py +287 -0
- pythonagent/cavisson/netdiagnostics/CavAgent/instrumentationprofile.json +26 -0
- pythonagent/cavisson/netdiagnostics/CavAgent/interceptor_points.txt +29 -0
- pythonagent/cavisson/netdiagnostics/python/CavAgent/instrumentationprofile.json +42 -0
- pythonagent/cavisson/netdiagnostics/python/CavAgent/interceptor_points.txt +29 -0
- pythonagent/cavisson/netdiagnostics/python/config/ndsettings.conf +6 -0
- pythonagent/config.py +279 -0
- pythonagent/find.py +72 -0
- pythonagent/find_mod_cls_name.py +54 -0
- pythonagent/lang.py +131 -0
- pythonagent/lib.py +91 -0
- pythonagent/main/__init__.py +0 -0
- pythonagent/main/pytrace/__init__.py +79 -0
- pythonagent/main/pytrace/commands/__init__.py +0 -0
- pythonagent/main/pytrace/commands/auto_discovery.py +25 -0
- pythonagent/main/pytrace/commands/run.py +401 -0
- pythonagent/main/pytrace/pytrace.py +133 -0
- pythonagent/main/wsgi.py +6 -0
- pythonagent/main.py +27 -0
- pythonagent/run.py +46 -0
- pythonagent/sqins.py +8 -0
- pythonagent/test.py +73 -0
- pythonagent/utils.py +168 -0
- pythonagent/vendor/__init__.py +0 -0
- pythonagent/vendor/pympler/__init__.py +1 -0
- pythonagent/vendor/pympler/asizeof.py +2810 -0
- pythonagent/vendor/pympler/charts.py +62 -0
- pythonagent/vendor/pympler/classtracker.py +590 -0
- pythonagent/vendor/pympler/classtracker_stats.py +780 -0
- pythonagent/vendor/pympler/garbagegraph.py +80 -0
- pythonagent/vendor/pympler/mprofile.py +97 -0
- pythonagent/vendor/pympler/muppy.py +275 -0
- pythonagent/vendor/pympler/panels.py +115 -0
- pythonagent/vendor/pympler/process.py +238 -0
- pythonagent/vendor/pympler/py.typed +0 -0
- pythonagent/vendor/pympler/refbrowser.py +451 -0
- pythonagent/vendor/pympler/refgraph.py +350 -0
- pythonagent/vendor/pympler/summary.py +321 -0
- pythonagent/vendor/pympler/tracker.py +267 -0
- pythonagent/vendor/pympler/util/__init__.py +0 -0
- pythonagent/vendor/pympler/util/bottle.py +3809 -0
- pythonagent/vendor/pympler/util/compat.py +23 -0
- pythonagent/vendor/pympler/util/stringutils.py +77 -0
- pythonagent/vendor/pympler/web.py +346 -0
- pythonagent/vendor/werkzeug/__init__.py +20 -0
- pythonagent/vendor/werkzeug/_compat.py +228 -0
- pythonagent/vendor/werkzeug/_internal.py +473 -0
- pythonagent/vendor/werkzeug/_reloader.py +341 -0
- pythonagent/vendor/werkzeug/datastructures.py +3120 -0
- pythonagent/vendor/werkzeug/debug/__init__.py +498 -0
- pythonagent/vendor/werkzeug/debug/console.py +218 -0
- pythonagent/vendor/werkzeug/debug/repr.py +297 -0
- pythonagent/vendor/werkzeug/debug/tbtools.py +628 -0
- pythonagent/vendor/werkzeug/exceptions.py +829 -0
- pythonagent/vendor/werkzeug/filesystem.py +64 -0
- pythonagent/vendor/werkzeug/formparser.py +584 -0
- pythonagent/vendor/werkzeug/http.py +1307 -0
- pythonagent/vendor/werkzeug/local.py +420 -0
- pythonagent/vendor/werkzeug/middleware/__init__.py +25 -0
- pythonagent/vendor/werkzeug/middleware/dispatcher.py +66 -0
- pythonagent/vendor/werkzeug/middleware/http_proxy.py +219 -0
- pythonagent/vendor/werkzeug/middleware/lint.py +408 -0
- pythonagent/vendor/werkzeug/middleware/profiler.py +132 -0
- pythonagent/vendor/werkzeug/middleware/proxy_fix.py +169 -0
- pythonagent/vendor/werkzeug/middleware/shared_data.py +293 -0
- pythonagent/vendor/werkzeug/posixemulation.py +117 -0
- pythonagent/vendor/werkzeug/routing.py +2210 -0
- pythonagent/vendor/werkzeug/security.py +249 -0
- pythonagent/vendor/werkzeug/serving.py +1117 -0
- pythonagent/vendor/werkzeug/test.py +1123 -0
- pythonagent/vendor/werkzeug/testapp.py +241 -0
- pythonagent/vendor/werkzeug/urls.py +1138 -0
- pythonagent/vendor/werkzeug/useragents.py +202 -0
- pythonagent/vendor/werkzeug/utils.py +778 -0
- pythonagent/vendor/werkzeug/wrappers/__init__.py +36 -0
- pythonagent/vendor/werkzeug/wrappers/accept.py +50 -0
- pythonagent/vendor/werkzeug/wrappers/auth.py +33 -0
- pythonagent/vendor/werkzeug/wrappers/base_request.py +673 -0
- pythonagent/vendor/werkzeug/wrappers/base_response.py +700 -0
- pythonagent/vendor/werkzeug/wrappers/common_descriptors.py +341 -0
- pythonagent/vendor/werkzeug/wrappers/cors.py +100 -0
- pythonagent/vendor/werkzeug/wrappers/etag.py +304 -0
- pythonagent/vendor/werkzeug/wrappers/json.py +145 -0
- pythonagent/vendor/werkzeug/wrappers/request.py +49 -0
- pythonagent/vendor/werkzeug/wrappers/response.py +84 -0
- pythonagent/vendor/werkzeug/wrappers/user_agent.py +14 -0
- pythonagent/vendor/werkzeug/wsgi.py +1000 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
"""Intercept the psycopg2 package.
|
|
4
|
+
|
|
5
|
+
The interceptors in here are more complex than for other packages because the
|
|
6
|
+
classes are defined in C extension code. We have to wrap the connection and
|
|
7
|
+
cursor classes with our own, which allows us to attach to the relevant methods.
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
# pylint: disable=no-self-argument
|
|
12
|
+
|
|
13
|
+
from __future__ import unicode_literals
|
|
14
|
+
import re
|
|
15
|
+
|
|
16
|
+
from pythonagent.lang import parse_qs, str, urlparse
|
|
17
|
+
from ..base import BaseInterceptor
|
|
18
|
+
from .dbapi import DbAPIConnectionInterceptor, DbAPICursorInterceptor
|
|
19
|
+
|
|
20
|
+
# For format of PostgreSQL connection strings, see:
|
|
21
|
+
# http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
|
|
22
|
+
|
|
23
|
+
KV_RE = re.compile(r'\s*(?P<key>[a-zA-Z_]+)\s*=\s*(?P<remainder>.+)')
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def parse_postgresql_url_dsn(dsn):
|
|
27
|
+
url = urlparse(dsn, allow_fragments=False)
|
|
28
|
+
|
|
29
|
+
if '?' in url.path:
|
|
30
|
+
parts = url.path.split('?', 1)
|
|
31
|
+
path, params = parts[0], parse_qs(parts[1])
|
|
32
|
+
else:
|
|
33
|
+
path = url.path
|
|
34
|
+
params = parse_qs(url.query) if url.query else {}
|
|
35
|
+
|
|
36
|
+
if 'host' in params:
|
|
37
|
+
host = params['host'][0]
|
|
38
|
+
else:
|
|
39
|
+
host = url.hostname or 'localhost'
|
|
40
|
+
|
|
41
|
+
if 'port' in params:
|
|
42
|
+
port = params['port'][0]
|
|
43
|
+
elif url.port:
|
|
44
|
+
port = str(url.port)
|
|
45
|
+
else:
|
|
46
|
+
port = '5432'
|
|
47
|
+
|
|
48
|
+
path = path.strip('/')
|
|
49
|
+
|
|
50
|
+
if 'dbname' in params:
|
|
51
|
+
dbname = params['dbname'][0]
|
|
52
|
+
elif path:
|
|
53
|
+
dbname = path
|
|
54
|
+
elif 'user' in params:
|
|
55
|
+
dbname = params['user'][0]
|
|
56
|
+
else:
|
|
57
|
+
dbname = url.username or 'postgres'
|
|
58
|
+
|
|
59
|
+
return host, port, dbname
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def parse_quoted_value(remainder):
|
|
63
|
+
length = len(remainder)
|
|
64
|
+
idx = 1
|
|
65
|
+
|
|
66
|
+
start_idx = idx
|
|
67
|
+
val = []
|
|
68
|
+
|
|
69
|
+
while idx < length and remainder[idx] != "'":
|
|
70
|
+
if remainder[idx:idx + 2] in ("\\\\", "\\'"):
|
|
71
|
+
# Valid escape sequence: collect the current run with the
|
|
72
|
+
# escaped character, move past the escape sequence, and start a
|
|
73
|
+
# new run.
|
|
74
|
+
val.append(remainder[start_idx:idx] + remainder[idx + 1])
|
|
75
|
+
idx += 2
|
|
76
|
+
start_idx = idx
|
|
77
|
+
else:
|
|
78
|
+
idx += 1
|
|
79
|
+
|
|
80
|
+
val.append(remainder[start_idx:idx])
|
|
81
|
+
return ''.join(val), remainder[idx + 1:]
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def parse_postgresql_kv_dsn(dsn):
|
|
85
|
+
if "'" not in dsn: # Fast path when there are no quoted strings.
|
|
86
|
+
dsn = re.sub(r'(\s*=\s+|\s+=\s*)', '=', dsn).split()
|
|
87
|
+
parts = dict(pair.split('=', 1) for pair in dsn)
|
|
88
|
+
else:
|
|
89
|
+
parts = {}
|
|
90
|
+
m = KV_RE.match(dsn)
|
|
91
|
+
|
|
92
|
+
while m:
|
|
93
|
+
key, remainder = m.group('key'), m.group('remainder')
|
|
94
|
+
|
|
95
|
+
if remainder[0] == "'":
|
|
96
|
+
value, remainder = parse_quoted_value(remainder)
|
|
97
|
+
else:
|
|
98
|
+
split = remainder.split(None, 1)
|
|
99
|
+
if len(split) == 1:
|
|
100
|
+
value, remainder = split[0], ''
|
|
101
|
+
elif split:
|
|
102
|
+
value, remainder = split
|
|
103
|
+
else:
|
|
104
|
+
break
|
|
105
|
+
|
|
106
|
+
parts[key] = value
|
|
107
|
+
m = KV_RE.match(remainder)
|
|
108
|
+
|
|
109
|
+
return parse_postgresql_keyword_args(parts)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def parse_postgresql_keyword_args(parts):
|
|
113
|
+
host = parts.get('host', 'localhost')
|
|
114
|
+
port = parts.get('port', '5432')
|
|
115
|
+
dbname = parts.get('dbname', parts.get('user', 'postgres'))
|
|
116
|
+
user = parts.get('user', 'postgres')
|
|
117
|
+
return host, port, dbname, user
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def parse_postgresql_dsn(dsn=None, *args, **kwargs):
|
|
121
|
+
if dsn:
|
|
122
|
+
if dsn.startswith('postgresql://'):
|
|
123
|
+
return parse_postgresql_url_dsn(dsn)
|
|
124
|
+
else:
|
|
125
|
+
return parse_postgresql_kv_dsn(dsn)
|
|
126
|
+
else:
|
|
127
|
+
return parse_postgresql_keyword_args(kwargs)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class Psycopg2ConnectionInterceptor(DbAPIConnectionInterceptor):
|
|
131
|
+
def get_backend_properties(self, conn, *args, **kwargs):
|
|
132
|
+
return parse_postgresql_dsn(*args, **kwargs) + ('POSTGRES',)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class Psycopg2CursorInterceptor(DbAPICursorInterceptor):
|
|
136
|
+
def get_connection(self, cursor):
|
|
137
|
+
return cursor.connection
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class Psycopg2Interceptor(BaseInterceptor):
|
|
141
|
+
cursor_classes = {}
|
|
142
|
+
|
|
143
|
+
def _connect(self, connect, *args, **kwargs):
|
|
144
|
+
connection_factory = kwargs.pop('connection_factory', None) or self.cls.extensions.connection
|
|
145
|
+
|
|
146
|
+
class Connection(connection_factory):
|
|
147
|
+
def __init__(conn, *args, **kwargs):
|
|
148
|
+
super(Connection, conn).__init__(*args, **kwargs)
|
|
149
|
+
|
|
150
|
+
def cursor(conn, *args, **kwargs):
|
|
151
|
+
cursor_factory = kwargs.pop('cursor_factory', None) or conn.cursor_factory or self.cls.extensions.cursor
|
|
152
|
+
try:
|
|
153
|
+
# we store these wrapper classes to avoid 're-instrumenting' each time
|
|
154
|
+
cursor_class = self.cursor_classes[cursor_factory]
|
|
155
|
+
except KeyError:
|
|
156
|
+
class Cursor(cursor_factory):
|
|
157
|
+
def execute(curs, *args, **kwargs):
|
|
158
|
+
return super(Cursor, curs).execute(*args, **kwargs)
|
|
159
|
+
|
|
160
|
+
def executemany(curs, *args, **kwargs):
|
|
161
|
+
return super(Cursor, curs).executemany(*args, **kwargs)
|
|
162
|
+
self.cursor_classes[cursor_factory] = Cursor
|
|
163
|
+
cursor_class = Cursor
|
|
164
|
+
return super(Connection, conn).cursor(cursor_factory=cursor_class, *args, **kwargs)
|
|
165
|
+
|
|
166
|
+
Psycopg2ConnectionInterceptor(
|
|
167
|
+
self.agent, Connection, Psycopg2CursorInterceptor).attach('__init__')
|
|
168
|
+
|
|
169
|
+
return connect(connection_factory=Connection, *args, **kwargs)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def intercept_psycopg2_connection(agent, mod):
|
|
173
|
+
agent.logger.warning("Instrument module: psycopg2{}".format(", mod: {}".format(mod) if mod else ""))
|
|
174
|
+
Psycopg2Interceptor(agent, mod).attach('connect')
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
|
|
2
|
+
"""Intercept the pymysql package.
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import unicode_literals
|
|
7
|
+
|
|
8
|
+
from .dbapi import DbAPIConnectionInterceptor, DbAPICursorInterceptor
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PymysqlConnectionInterceptor(DbAPIConnectionInterceptor):
|
|
12
|
+
def get_backend_properties(self, conn, *args, **kwargs):
|
|
13
|
+
conn.db_type = "MYSQL"
|
|
14
|
+
# self.agent.get_transaction_context().dbhost = conn.host
|
|
15
|
+
return conn.host, conn.port, conn.db, conn.user, conn.db_type
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class PymysqlCursorInterceptor(DbAPICursorInterceptor):
|
|
19
|
+
def get_connection(self, cursor):
|
|
20
|
+
return cursor.connection
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def intercept_pymysql_connections(agent, mod):
|
|
24
|
+
agent.logger.warning("Instrument module: pymysql.connections{}".format(", mod: {}".format(mod) if mod else ""))
|
|
25
|
+
PymysqlConnectionInterceptor(agent, mod.Connection, PymysqlCursorInterceptor).attach('connect')
|
|
File without changes
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Cavisson Python Agent — gunicorn integration config
|
|
2
|
+
#
|
|
3
|
+
# This file is a ready-to-use gunicorn config that bootstraps the Cavisson agent
|
|
4
|
+
# in each worker process without requiring changes to your own gunicorn.conf.
|
|
5
|
+
#
|
|
6
|
+
# Usage (add to gunicorn command):
|
|
7
|
+
# gunicorn -c $NDHOME/python/config/cav_gunicorn.py myapp:application
|
|
8
|
+
#
|
|
9
|
+
# If you already have a gunicorn config file, place cav_gunicorn.py FIRST:
|
|
10
|
+
# gunicorn -c $NDHOME/python/config/cav_gunicorn.py -c your_gunicorn.conf myapp:application
|
|
11
|
+
#
|
|
12
|
+
# Note: When multiple -c files define the same function (e.g. post_fork), the
|
|
13
|
+
# LAST config wins. Place your own config after cav_gunicorn.py so your post_fork
|
|
14
|
+
# takes precedence; ensure your post_fork also calls agent.bootstrap() if needed.
|
|
15
|
+
#
|
|
16
|
+
# This file is a fallback for environments where sitecustomize.py is not on
|
|
17
|
+
# PYTHONPATH. When sitecustomize.py is active, auto-patching via Worker.init_process
|
|
18
|
+
# handles gunicorn worker bootstrap automatically without this file.
|
|
19
|
+
|
|
20
|
+
def post_fork(server, worker):
|
|
21
|
+
try:
|
|
22
|
+
import pythonagent.agent as _agent
|
|
23
|
+
_agent.configure()
|
|
24
|
+
_agent.bootstrap()
|
|
25
|
+
except Exception:
|
|
26
|
+
pass
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
from __future__ import unicode_literals
|
|
2
|
+
import imp
|
|
3
|
+
import os
|
|
4
|
+
import warnings
|
|
5
|
+
import logging
|
|
6
|
+
import sys
|
|
7
|
+
from subprocess import call
|
|
8
|
+
import subprocess
|
|
9
|
+
import uuid
|
|
10
|
+
import datetime
|
|
11
|
+
import time
|
|
12
|
+
|
|
13
|
+
is_lambda = True
|
|
14
|
+
|
|
15
|
+
if is_lambda:
|
|
16
|
+
os.environ.setdefault("NDHOME", "/opt/python/pythonagent/cavisson/netdiagnostics")
|
|
17
|
+
sys.path.insert(1, '/opt')
|
|
18
|
+
|
|
19
|
+
os.environ.setdefault("CAVISSON_APP_NAME", os.getenv("AWS_LAMBDA_FUNCTION_NAME", ""))
|
|
20
|
+
os.environ.setdefault("CAVISSON_NO_CONFIG_FILE", "true")
|
|
21
|
+
os.environ.setdefault("CAVISSON_DISTRIBUTED_TRACING_ENABLED", "true")
|
|
22
|
+
os.environ.setdefault("CAVISSON_SERVERLESS_MODE_ENABLED", "true")
|
|
23
|
+
os.environ.setdefault("CAVISSON_TRUSTED_ACCOUNT_KEY", os.getenv("CAVISSON_ACCOUNT_ID", ""))
|
|
24
|
+
|
|
25
|
+
_agent = None
|
|
26
|
+
logger = None
|
|
27
|
+
|
|
28
|
+
try:
|
|
29
|
+
import pythonagent.agent as agent
|
|
30
|
+
agent.configure()
|
|
31
|
+
#_agent = agent.bootstrap()
|
|
32
|
+
_agent = agent.get_agent_instance()
|
|
33
|
+
#_agent.init_sent = True
|
|
34
|
+
|
|
35
|
+
except:
|
|
36
|
+
print("import error in Agent")
|
|
37
|
+
logger = logging.getLogger('pythonagent.agent')
|
|
38
|
+
logger.exception('Exception in agent startup.')
|
|
39
|
+
finally:
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
if _agent is None:
|
|
43
|
+
raise ValueError("Failed to initialize agent")
|
|
44
|
+
|
|
45
|
+
from pythonagent.agent.internal.agent import TransactionContext
|
|
46
|
+
|
|
47
|
+
# from pythonagent.agent.probes.havoc.havoc_manager import NDNetHavocMonitor, NDHavocException
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def get_handler():
|
|
51
|
+
print("inside get_handler function first", sys.executable)
|
|
52
|
+
modandpackage = os.path.abspath('.')
|
|
53
|
+
mod = sys.modules[__name__]
|
|
54
|
+
print("inside get_handler function mod", mod)
|
|
55
|
+
try:
|
|
56
|
+
sys.path.remove(os.path.dirname(__file__))
|
|
57
|
+
except ValueError: # directory not in sys.path
|
|
58
|
+
pass
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
if (
|
|
62
|
+
"CAVISSON_LAMBDA_HANDLER" not in os.environ
|
|
63
|
+
or not os.environ["CAVISSON_LAMBDA_HANDLER"]
|
|
64
|
+
):
|
|
65
|
+
raise ValueError(
|
|
66
|
+
"No value specified in CAVISSON_LAMBDA_HANDLER environment variable"
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
try:
|
|
70
|
+
module_path, handler_name = os.environ["CAVISSON_LAMBDA_HANDLER"].rsplit(
|
|
71
|
+
".", 1
|
|
72
|
+
)
|
|
73
|
+
print("inside get_handler function module_path, handler name: ", module_path, handler_name)
|
|
74
|
+
|
|
75
|
+
except ValueError:
|
|
76
|
+
raise ValueError(
|
|
77
|
+
"Improperly formated handler value: %s"
|
|
78
|
+
% os.environ["CAVISSON_LAMBDA_HANDLER"]
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
file_handle, pathname, desc = None, None, None
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
for segment in module_path.split("."):
|
|
85
|
+
if pathname is not None:
|
|
86
|
+
pathname = [pathname]
|
|
87
|
+
|
|
88
|
+
file_handle, pathname, desc = imp.find_module(segment, pathname)
|
|
89
|
+
|
|
90
|
+
if file_handle is None:
|
|
91
|
+
module_type = desc[2]
|
|
92
|
+
if module_type == imp.C_BUILTIN:
|
|
93
|
+
raise ImportError(
|
|
94
|
+
"Cannot use built-in module %s as a handler module" % module_path
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
print("inside get_handler function module_path, file_handle, pathname, desc", module_path, file_handle, pathname, desc)
|
|
98
|
+
|
|
99
|
+
module = imp.load_module(module_path, file_handle, pathname, desc)
|
|
100
|
+
print("inside get_handler function module in cavagent_lambda_wrapper ", module)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
except Exception as e:
|
|
104
|
+
print("Module not found")
|
|
105
|
+
raise ImportError("Failed to import module '%s': %s" % (module_path, e))
|
|
106
|
+
finally:
|
|
107
|
+
if file_handle is not None:
|
|
108
|
+
file_handle.close()
|
|
109
|
+
|
|
110
|
+
try:
|
|
111
|
+
handler = getattr(module, handler_name)
|
|
112
|
+
print("inside get_handler function handler", handler)
|
|
113
|
+
except AttributeError:
|
|
114
|
+
print("NO HANDLER FOUND")
|
|
115
|
+
raise AttributeError(
|
|
116
|
+
"No handler '%s' in module '%s'" % (handler_name, module_path)
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
return handler, handler_name, modandpackage
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def local_customer_application(event, context):
|
|
123
|
+
from .run import db_callout, flask_wsgi, http_callout, first
|
|
124
|
+
print("inside local_customer_application function Lambda Handler Function")
|
|
125
|
+
|
|
126
|
+
first()
|
|
127
|
+
# second()
|
|
128
|
+
# http_callout()
|
|
129
|
+
# db_callout()
|
|
130
|
+
# flask_wsgi()
|
|
131
|
+
|
|
132
|
+
return "Nothing"
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def local_lambda_handler():
|
|
136
|
+
#for i in range(100):
|
|
137
|
+
# print(1)
|
|
138
|
+
class TestObj:
|
|
139
|
+
def __init__(self):
|
|
140
|
+
self.__module__ = "test"
|
|
141
|
+
|
|
142
|
+
t = TestObj()
|
|
143
|
+
return t , "test", "test"
|
|
144
|
+
|
|
145
|
+
# Greedily load the handler during cold start, so we don't pay for it on first invoke
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def wrapped_handler(event, context, is_lambda):
|
|
149
|
+
if is_lambda:
|
|
150
|
+
a, b, c = get_handler()
|
|
151
|
+
else:
|
|
152
|
+
a, b, c = local_lambda_handler()
|
|
153
|
+
return a, b, c
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def handler(event, context):
|
|
157
|
+
context_obj = TransactionContext()
|
|
158
|
+
start_time = datetime.datetime.now()
|
|
159
|
+
|
|
160
|
+
if context.aws_request_id is not None:
|
|
161
|
+
context_obj.aws_request_id = context.aws_request_id
|
|
162
|
+
else:
|
|
163
|
+
context_obj.aws_request_id = "default_aws_request_id"
|
|
164
|
+
|
|
165
|
+
if context.function_name is not None:
|
|
166
|
+
context_obj.function_name = context.function_name
|
|
167
|
+
else:
|
|
168
|
+
context_obj.function_name = "default"
|
|
169
|
+
print("function name inside context object in cavwrapper handler", context_obj.function_name)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
try:
|
|
173
|
+
# context_obj.function_name = event['requestContext']['path']
|
|
174
|
+
context_obj.url_path = event['requestContext']['path']
|
|
175
|
+
|
|
176
|
+
except:
|
|
177
|
+
if "path" in event:
|
|
178
|
+
context_obj.url_path = event["path"]
|
|
179
|
+
else:
|
|
180
|
+
context_obj.url_path = context.function_name
|
|
181
|
+
|
|
182
|
+
if context.log_stream_name is not None:
|
|
183
|
+
context_obj.api_request_id = context.log_stream_name
|
|
184
|
+
else:
|
|
185
|
+
new_id = uuid.uuid4()
|
|
186
|
+
id_int = new_id.int
|
|
187
|
+
context_obj.api_request_id = id_int
|
|
188
|
+
|
|
189
|
+
_agent.set_transaction_context(context_obj)
|
|
190
|
+
|
|
191
|
+
from pythonagent.agent.probes.havoc.havoc_manager import NDNetHavocMonitor, NDHavocException
|
|
192
|
+
havoc_monitor = NDNetHavocMonitor.get_instance()
|
|
193
|
+
|
|
194
|
+
bt = None
|
|
195
|
+
|
|
196
|
+
try:
|
|
197
|
+
bt = _agent.start_business_transaction(context_obj.url_path, "")
|
|
198
|
+
except Exception as e:
|
|
199
|
+
print("Error occurred in Start Business transaction Call {}".format(e))
|
|
200
|
+
|
|
201
|
+
# import time
|
|
202
|
+
# print("Start fp done, sleep 30")
|
|
203
|
+
# time.sleep(30)
|
|
204
|
+
|
|
205
|
+
try:
|
|
206
|
+
handle, handler_name, modandpackage = wrapped_handler(event, context, is_lambda)
|
|
207
|
+
except Exception as e:
|
|
208
|
+
print("Error occurred in Calling Wrapped Handler {}".format(e))
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
print("inside handler function handle, handler_name, modandpackage IN CAVAGENT_LAMBDA_WRAPPER", handle, handler_name, modandpackage)
|
|
212
|
+
#fqmmethodentry = str(modandpackage) + "." + str(handler_name)
|
|
213
|
+
fqmmethodentry = str(handle.__module__) + "." + str(handler_name)
|
|
214
|
+
|
|
215
|
+
_agent.method_entry(bt, fqmmethodentry)
|
|
216
|
+
|
|
217
|
+
if is_lambda:
|
|
218
|
+
try:
|
|
219
|
+
response = handle(event, context) # Client Lambda Function
|
|
220
|
+
print("inside handler function RESPONSE IN LAMBDA IN CAVAGENT_LAMBDA_WRAPPER", response)
|
|
221
|
+
except Exception as e:
|
|
222
|
+
print("Error while invoking handler {}".format(e))
|
|
223
|
+
_agent.method_exit(bt, fqmmethodentry, 503)
|
|
224
|
+
_agent.set_current_status_code(503)
|
|
225
|
+
rc = _agent.end_business_transaction(bt)
|
|
226
|
+
havoc_monitor.refresh_configs(_agent)
|
|
227
|
+
raise e
|
|
228
|
+
else:
|
|
229
|
+
response = local_customer_application(event, context)
|
|
230
|
+
print("inside handler function RESPONSE IN LAMBDA IN CAVAGENT_LAMBDA_WRAPPER", response)
|
|
231
|
+
|
|
232
|
+
status_code = 200
|
|
233
|
+
try:
|
|
234
|
+
if "statusCode" in response:
|
|
235
|
+
status_code = response["statusCode"]
|
|
236
|
+
|
|
237
|
+
print("Inside handler function: response inside get_handler function firststatus code ", status_code)
|
|
238
|
+
|
|
239
|
+
except Exception as e:
|
|
240
|
+
print("Error occurred in get status code {}".format(e))
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
###############################
|
|
245
|
+
# HAVOC
|
|
246
|
+
###############################
|
|
247
|
+
|
|
248
|
+
# Apply Inbound Delay --> agent/start_business_transaction
|
|
249
|
+
|
|
250
|
+
# Apply Inbound Failure
|
|
251
|
+
|
|
252
|
+
try:
|
|
253
|
+
print("Url request: ", context_obj.url_path)
|
|
254
|
+
btname = _agent.get_transaction_context().btname if _agent.get_transaction_context() else None
|
|
255
|
+
havoc_monitor.apply_inbound_service_failure(context_obj.url_path, btname)
|
|
256
|
+
|
|
257
|
+
except Exception as e:
|
|
258
|
+
if isinstance(e, NDHavocException):
|
|
259
|
+
print("Havoc Exception {}".format(e))
|
|
260
|
+
_agent.method_exit(bt, fqmmethodentry, 503)
|
|
261
|
+
_agent.set_current_status_code(503)
|
|
262
|
+
rc = _agent.end_business_transaction(bt)
|
|
263
|
+
havoc_monitor.refresh_configs(_agent)
|
|
264
|
+
raise e
|
|
265
|
+
else:
|
|
266
|
+
print("Non-Havoc Exception {}".format(e))
|
|
267
|
+
|
|
268
|
+
# Apply Outbound Delay --> agent/method_entry_http_callout
|
|
269
|
+
|
|
270
|
+
# Apply Outbound Failure --> agent/probes/base.py/http_call_end
|
|
271
|
+
# --> agent/probes/sql/dynamodb.py/_cav_boto_api_method
|
|
272
|
+
|
|
273
|
+
# Apply Method Delay --> Instrumentation/__init__
|
|
274
|
+
|
|
275
|
+
# Apply Method Failure --> Instrumentation/__init__
|
|
276
|
+
|
|
277
|
+
####################################################################################
|
|
278
|
+
|
|
279
|
+
# havoc_monitor.apply_outbound_service_failure("sample_hostname")
|
|
280
|
+
|
|
281
|
+
havoc_monitor.refresh_configs(_agent)
|
|
282
|
+
|
|
283
|
+
try:
|
|
284
|
+
_agent.method_exit(bt, fqmmethodentry, status_code)
|
|
285
|
+
_agent.set_current_status_code(status_code)
|
|
286
|
+
rc = _agent.end_business_transaction(bt)
|
|
287
|
+
|
|
288
|
+
except Exception as e:
|
|
289
|
+
print("Error occurred in End Business transaction Call {}".format(e))
|
|
290
|
+
|
|
291
|
+
return response
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import boto3
|
|
3
|
+
from flask import Flask
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def http_callout():
|
|
7
|
+
print("Client Lambda - HTTP Callout Begin")
|
|
8
|
+
x = requests.get('https://www.facebook.com/')
|
|
9
|
+
# x = requests.put('https://httpbin.org/put', data={'key': 'value'})
|
|
10
|
+
# x = requests.post('https://www.w3schools.com/python/demopage.php', data={'key': 'value'})
|
|
11
|
+
# x = requests.delete('https://httpbin.org/delete', data={'key': 'value'})
|
|
12
|
+
print("Client Lambda - HTTP Callout End")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def first():
|
|
16
|
+
print("Client Lambda - First Function")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def second():
|
|
20
|
+
print("Client Lambda - Second Function")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def db_callout():
|
|
24
|
+
print("Client Lambda - DB Callout Begin")
|
|
25
|
+
client = boto3.client('dynamodb')
|
|
26
|
+
print("client METHODS FOR THIS SESSION::", dir(client))
|
|
27
|
+
data = client.scan(TableName='Person')
|
|
28
|
+
item = {
|
|
29
|
+
"id": {"N": "556"},
|
|
30
|
+
"address": {"S": "United States"},
|
|
31
|
+
"firstName": {"S": "John"},
|
|
32
|
+
"lastName": {"S": "Doe"},
|
|
33
|
+
"age": {"N": "30"}
|
|
34
|
+
}
|
|
35
|
+
response = client.put_item(TableName='Person', Item=item)
|
|
36
|
+
print("Client Lambda - DB Call out Begin")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def flask_wsgi():
|
|
40
|
+
app = Flask(__name__)
|
|
41
|
+
|
|
42
|
+
@app.route("/")
|
|
43
|
+
def hello_world():
|
|
44
|
+
return "<p>Hello, World!</p>"
|
|
45
|
+
|
|
46
|
+
app.run(port=6063)
|
|
47
|
+
|