whatap-python 2.1.0__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.
- whatap/LICENSE +0 -0
- whatap/README.rst +49 -0
- whatap/__init__.py +923 -0
- whatap/__main__.py +4 -0
- whatap/agent/darwin/amd64/whatap_python +0 -0
- whatap/agent/darwin/arm64/whatap_python +0 -0
- whatap/agent/linux/amd64/whatap_python +0 -0
- whatap/agent/linux/arm64/whatap_python +0 -0
- whatap/agent/windows/whatap_python.exe +0 -0
- whatap/bootstrap/__init__.py +0 -0
- whatap/bootstrap/sitecustomize.py +19 -0
- whatap/build.py +4 -0
- whatap/conf/__init__.py +0 -0
- whatap/conf/configuration.py +280 -0
- whatap/conf/configure.py +105 -0
- whatap/conf/license.py +49 -0
- whatap/control/__init__.py +0 -0
- whatap/counter/__init__.py +14 -0
- whatap/counter/counter_manager.py +45 -0
- whatap/counter/tasks/__init__.py +3 -0
- whatap/counter/tasks/base_task.py +26 -0
- whatap/counter/tasks/llm_evaluator_task.py +501 -0
- whatap/counter/tasks/llm_log_sink_task.py +309 -0
- whatap/counter/tasks/llm_stat_task.py +78 -0
- whatap/counter/tasks/openfiledescriptor.py +67 -0
- whatap/io/__init__.py +1 -0
- whatap/io/data_inputx.py +161 -0
- whatap/io/data_outputx.py +262 -0
- whatap/llm/__init__.py +17 -0
- whatap/llm/definitions.py +43 -0
- whatap/llm/evaluators/__init__.py +136 -0
- whatap/llm/evaluators/base.py +114 -0
- whatap/llm/evaluators/builtins/__init__.py +91 -0
- whatap/llm/evaluators/builtins/answer_relevance.py +46 -0
- whatap/llm/evaluators/builtins/combined_judge.py +271 -0
- whatap/llm/evaluators/builtins/factuality.py +71 -0
- whatap/llm/evaluators/builtins/hallucination.py +97 -0
- whatap/llm/evaluators/builtins/llm_judge.py +516 -0
- whatap/llm/evaluators/builtins/pii_leak.py +214 -0
- whatap/llm/evaluators/builtins/prompt_injection.py +71 -0
- whatap/llm/evaluators/builtins/toxicity.py +53 -0
- whatap/llm/evaluators/builtins/url_scan.py +194 -0
- whatap/llm/evaluators/registry.py +192 -0
- whatap/llm/evaluators/sampler.py +83 -0
- whatap/llm/evaluators/scope.py +334 -0
- whatap/llm/features.py +66 -0
- whatap/llm/log_sink_packs/__init__.py +9 -0
- whatap/llm/log_sink_packs/llm_input_message.py +16 -0
- whatap/llm/log_sink_packs/llm_log_sink_pack.py +72 -0
- whatap/llm/log_sink_packs/llm_output_message.py +19 -0
- whatap/llm/log_sink_packs/llm_step_eval_status.py +94 -0
- whatap/llm/log_sink_packs/llm_step_status.py +118 -0
- whatap/llm/log_sink_packs/llm_system_message.py +16 -0
- whatap/llm/log_sink_packs/llm_tool_calls.py +44 -0
- whatap/llm/log_sink_packs/llm_tool_results.py +16 -0
- whatap/llm/log_sink_packs/llm_tx_status.py +108 -0
- whatap/llm/pricing.py +236 -0
- whatap/llm/prompt_meta.py +288 -0
- whatap/llm/providers/__init__.py +0 -0
- whatap/llm/providers/anthropic/__init__.py +37 -0
- whatap/llm/providers/anthropic/messages/__init__.py +0 -0
- whatap/llm/providers/anthropic/messages/messages.py +70 -0
- whatap/llm/providers/anthropic/messages/messages_context.py +76 -0
- whatap/llm/providers/anthropic/messages/messages_extractor.py +126 -0
- whatap/llm/providers/interceptor.py +182 -0
- whatap/llm/providers/openai/__init__.py +133 -0
- whatap/llm/providers/openai/chat/__init__.py +0 -0
- whatap/llm/providers/openai/chat/chat.py +82 -0
- whatap/llm/providers/openai/chat/chat_context.py +78 -0
- whatap/llm/providers/openai/chat/chat_extractor.py +127 -0
- whatap/llm/providers/openai/completions/__init__.py +0 -0
- whatap/llm/providers/openai/completions/completions.py +70 -0
- whatap/llm/providers/openai/completions/completions_context.py +31 -0
- whatap/llm/providers/openai/completions/completions_extractor.py +61 -0
- whatap/llm/providers/openai/content_parser.py +41 -0
- whatap/llm/providers/openai/embeddings/__init__.py +0 -0
- whatap/llm/providers/openai/embeddings/embeddings.py +59 -0
- whatap/llm/providers/openai/embeddings/embeddings_context.py +25 -0
- whatap/llm/providers/openai/embeddings/embeddings_extractor.py +26 -0
- whatap/llm/providers/openai/responses/__init__.py +0 -0
- whatap/llm/providers/openai/responses/responses.py +70 -0
- whatap/llm/providers/openai/responses/responses_context.py +88 -0
- whatap/llm/providers/openai/responses/responses_extractor.py +126 -0
- whatap/llm/providers/stream_accumulator.py +73 -0
- whatap/llm/stats/__init__.py +35 -0
- whatap/llm/stats/active_stat.py +86 -0
- whatap/llm/stats/answer_relevance_eval_stat.py +10 -0
- whatap/llm/stats/api_status_stat.py +35 -0
- whatap/llm/stats/base_stat.py +107 -0
- whatap/llm/stats/combined_judge_eval_stat.py +11 -0
- whatap/llm/stats/error_stat.py +59 -0
- whatap/llm/stats/eval_stat.py +225 -0
- whatap/llm/stats/factuality_eval_stat.py +10 -0
- whatap/llm/stats/feature_stat.py +104 -0
- whatap/llm/stats/finish_stat.py +105 -0
- whatap/llm/stats/hallucination_eval_stat.py +10 -0
- whatap/llm/stats/meter.py +18 -0
- whatap/llm/stats/perf_stat.py +117 -0
- whatap/llm/stats/pii_leak_eval_stat.py +12 -0
- whatap/llm/stats/prompt_injection_eval_stat.py +10 -0
- whatap/llm/stats/token_usage_stat.py +133 -0
- whatap/llm/stats/toxicity_eval_stat.py +10 -0
- whatap/llm/stats/url_scan_eval_stat.py +12 -0
- whatap/net/__init__.py +0 -0
- whatap/net/async_sender.py +107 -0
- whatap/net/packet_enum.py +44 -0
- whatap/net/packet_type_enum.py +31 -0
- whatap/net/param_def.py +69 -0
- whatap/net/stackhelper.py +87 -0
- whatap/net/udp_session.py +394 -0
- whatap/net/udp_thread.py +54 -0
- whatap/pack/__init__.py +0 -0
- whatap/pack/logSinkPack.py +77 -0
- whatap/pack/pack.py +34 -0
- whatap/pack/pack_enum.py +41 -0
- whatap/pack/tagCountPack.py +61 -0
- whatap/scripts/__init__.py +208 -0
- whatap/trace/__init__.py +12 -0
- whatap/trace/mod/__init__.py +0 -0
- whatap/trace/mod/amqp/__init__.py +0 -0
- whatap/trace/mod/amqp/kombu.py +122 -0
- whatap/trace/mod/amqp/pika.py +62 -0
- whatap/trace/mod/application/__init__.py +0 -0
- whatap/trace/mod/application/bottle.py +34 -0
- whatap/trace/mod/application/celery.py +81 -0
- whatap/trace/mod/application/cherrypy.py +30 -0
- whatap/trace/mod/application/django.py +287 -0
- whatap/trace/mod/application/django_asgi.py +266 -0
- whatap/trace/mod/application/django_py3.py +251 -0
- whatap/trace/mod/application/fastapi/__init__.py +31 -0
- whatap/trace/mod/application/fastapi/endpoint.py +73 -0
- whatap/trace/mod/application/fastapi/exception_log.py +63 -0
- whatap/trace/mod/application/fastapi/instrumentation.py +204 -0
- whatap/trace/mod/application/fastapi/scope.py +115 -0
- whatap/trace/mod/application/fastapi/transaction.py +67 -0
- whatap/trace/mod/application/flask.py +52 -0
- whatap/trace/mod/application/frappe.py +224 -0
- whatap/trace/mod/application/graphql.py +170 -0
- whatap/trace/mod/application/nameko.py +39 -0
- whatap/trace/mod/application/odoo.py +63 -0
- whatap/trace/mod/application/starlette.py +126 -0
- whatap/trace/mod/application/tornado.py +163 -0
- whatap/trace/mod/application/wsgi.py +195 -0
- whatap/trace/mod/database/__init__.py +0 -0
- whatap/trace/mod/database/cxoracle.py +49 -0
- whatap/trace/mod/database/mongo.py +169 -0
- whatap/trace/mod/database/mysql.py +80 -0
- whatap/trace/mod/database/neo4j.py +90 -0
- whatap/trace/mod/database/psycopg2.py +45 -0
- whatap/trace/mod/database/psycopg3.py +359 -0
- whatap/trace/mod/database/redis.py +122 -0
- whatap/trace/mod/database/sqlalchemy.py +213 -0
- whatap/trace/mod/database/sqlite3.py +130 -0
- whatap/trace/mod/database/util.py +630 -0
- whatap/trace/mod/email/__init__.py +0 -0
- whatap/trace/mod/email/smtp.py +78 -0
- whatap/trace/mod/httpc/__init__.py +0 -0
- whatap/trace/mod/httpc/django.py +31 -0
- whatap/trace/mod/httpc/httplib.py +70 -0
- whatap/trace/mod/httpc/httpx.py +62 -0
- whatap/trace/mod/httpc/requests.py +20 -0
- whatap/trace/mod/httpc/urllib3.py +27 -0
- whatap/trace/mod/httpc/util.py +388 -0
- whatap/trace/mod/logging.py +161 -0
- whatap/trace/mod/plugin.py +84 -0
- whatap/trace/mod/standalone/__init__.py +0 -0
- whatap/trace/mod/standalone/multiple.py +293 -0
- whatap/trace/mod/standalone/single.py +135 -0
- whatap/trace/simple_trace_context.py +18 -0
- whatap/trace/trace_context.py +212 -0
- whatap/trace/trace_context_manager.py +244 -0
- whatap/trace/trace_error.py +84 -0
- whatap/trace/trace_handler.py +89 -0
- whatap/trace/trace_import.py +91 -0
- whatap/trace/trace_module_definition.py +156 -0
- whatap/util/__init__.py +0 -0
- whatap/util/bit_util.py +49 -0
- whatap/util/cardinality/__init__.py +0 -0
- whatap/util/cardinality/hyperloglog.py +84 -0
- whatap/util/cardinality/murmurhash.py +20 -0
- whatap/util/cardinality/registerset.py +60 -0
- whatap/util/compare_util.py +19 -0
- whatap/util/date_util.py +55 -0
- whatap/util/debug_util.py +73 -0
- whatap/util/escape_literal_sql.py +233 -0
- whatap/util/frame_util.py +20 -0
- whatap/util/hash_util.py +103 -0
- whatap/util/hexa32.py +66 -0
- whatap/util/int_set.py +199 -0
- whatap/util/ip_util.py +63 -0
- whatap/util/keygen.py +11 -0
- whatap/util/linked_list.py +113 -0
- whatap/util/linked_map.py +359 -0
- whatap/util/metering_util.py +103 -0
- whatap/util/request_double_queue.py +68 -0
- whatap/util/request_queue.py +60 -0
- whatap/util/string_util.py +20 -0
- whatap/util/throttle_util.py +99 -0
- whatap/util/userid_util.py +134 -0
- whatap/value/__init__.py +1 -0
- whatap/value/blob_value.py +38 -0
- whatap/value/boolean_value.py +33 -0
- whatap/value/decimal_value.py +36 -0
- whatap/value/double_summary.py +86 -0
- whatap/value/double_value.py +33 -0
- whatap/value/float_array.py +42 -0
- whatap/value/float_value.py +34 -0
- whatap/value/int_array.py +42 -0
- whatap/value/ip4_value.py +50 -0
- whatap/value/list_value.py +105 -0
- whatap/value/long_array.py +44 -0
- whatap/value/long_summary.py +83 -0
- whatap/value/map_value.py +154 -0
- whatap/value/null_value.py +21 -0
- whatap/value/number_value.py +33 -0
- whatap/value/summary_value.py +39 -0
- whatap/value/text_array.py +58 -0
- whatap/value/text_hash_value.py +37 -0
- whatap/value/text_value.py +43 -0
- whatap/value/value.py +26 -0
- whatap/value/value_enum.py +80 -0
- whatap/whatap.conf +14 -0
- whatap_python-2.1.0.dist-info/METADATA +87 -0
- whatap_python-2.1.0.dist-info/RECORD +227 -0
- whatap_python-2.1.0.dist-info/WHEEL +5 -0
- whatap_python-2.1.0.dist-info/entry_points.txt +6 -0
- whatap_python-2.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
|
|
3
|
+
from whatap.trace.trace_handler import trace_handler, async_trace_handler
|
|
4
|
+
from whatap.trace.mod.database.util import (
|
|
5
|
+
interceptor_db_con, interceptor_db_execute, interceptor_db_close,
|
|
6
|
+
async_interceptor_db_con, async_interceptor_db_execute, async_interceptor_db_close,
|
|
7
|
+
interceptor_pool_get, interceptor_pool_release,
|
|
8
|
+
async_interceptor_pool_get, async_interceptor_pool_release
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
db_info = {}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BaseCursor:
|
|
15
|
+
def __init__(self, cursor, db_info):
|
|
16
|
+
self._cursor = cursor
|
|
17
|
+
self._db_info = db_info
|
|
18
|
+
self._is_wrapped = True
|
|
19
|
+
|
|
20
|
+
def __getattr__(self, name):
|
|
21
|
+
return getattr(self._cursor, name)
|
|
22
|
+
|
|
23
|
+
def __setattr__(self, name, value):
|
|
24
|
+
if name.startswith('_'):
|
|
25
|
+
object.__setattr__(self, name, value)
|
|
26
|
+
else:
|
|
27
|
+
setattr(self._cursor, name, value)
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def connection(self):
|
|
31
|
+
return self._cursor.connection
|
|
32
|
+
|
|
33
|
+
def _execute_wrapper(self, original_execute_method):
|
|
34
|
+
owner = getattr(original_execute_method, "__self__", None)
|
|
35
|
+
|
|
36
|
+
def safe_execute(*args, **kwargs):
|
|
37
|
+
if args and owner is not None and args[0] is owner:
|
|
38
|
+
args = args[1:]
|
|
39
|
+
return original_execute_method(*args, **kwargs)
|
|
40
|
+
|
|
41
|
+
return safe_execute
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class SyncCursor(BaseCursor):
|
|
45
|
+
def __enter__(self):
|
|
46
|
+
self._cursor.__enter__()
|
|
47
|
+
return self
|
|
48
|
+
|
|
49
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
50
|
+
return self._cursor.__exit__(exc_type, exc_val, exc_tb)
|
|
51
|
+
|
|
52
|
+
def execute(self, *args, **kwargs):
|
|
53
|
+
if hasattr(self._cursor, '_is_wrapped'):
|
|
54
|
+
return self._cursor.execute(*args, **kwargs)
|
|
55
|
+
real_execute = self._cursor.execute
|
|
56
|
+
safe_fn = self._execute_wrapper(real_execute)
|
|
57
|
+
return interceptor_db_execute(safe_fn, self._db_info, self._cursor, *args, **kwargs)
|
|
58
|
+
|
|
59
|
+
def executemany(self, *args, **kwargs):
|
|
60
|
+
if hasattr(self._cursor, '_is_wrapped'):
|
|
61
|
+
return self._cursor.executemany(*args, **kwargs)
|
|
62
|
+
real_executemany = getattr(self._cursor, "executemany", None)
|
|
63
|
+
if real_executemany is None:
|
|
64
|
+
return self._cursor.executemany(*args, **kwargs)
|
|
65
|
+
safe_fn = self._execute_wrapper(real_executemany)
|
|
66
|
+
return interceptor_db_execute(safe_fn, self._db_info, self._cursor, *args, **kwargs)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class AsyncCursor(BaseCursor):
|
|
70
|
+
async def __aenter__(self):
|
|
71
|
+
await self._cursor.__aenter__()
|
|
72
|
+
return self
|
|
73
|
+
|
|
74
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
75
|
+
return await self._cursor.__aexit__(exc_type, exc_val, exc_tb)
|
|
76
|
+
|
|
77
|
+
def _async_execute_wrapper(self, original_execute_method):
|
|
78
|
+
owner = getattr(original_execute_method, "__self__", None)
|
|
79
|
+
|
|
80
|
+
async def async_safe_execute(*args, **kwargs):
|
|
81
|
+
if args and owner is not None and args[0] is owner:
|
|
82
|
+
args = args[1:]
|
|
83
|
+
return await original_execute_method(*args, **kwargs)
|
|
84
|
+
|
|
85
|
+
return async_safe_execute
|
|
86
|
+
|
|
87
|
+
async def execute(self, *args, **kwargs):
|
|
88
|
+
if hasattr(self._cursor, '_is_wrapped'):
|
|
89
|
+
return await self._cursor.execute(*args, **kwargs)
|
|
90
|
+
real_execute = self._cursor.execute
|
|
91
|
+
safe_fn = self._async_execute_wrapper(real_execute)
|
|
92
|
+
return await async_interceptor_db_execute(safe_fn, self._db_info, self._cursor, *args, **kwargs)
|
|
93
|
+
|
|
94
|
+
async def executemany(self, *args, **kwargs):
|
|
95
|
+
if hasattr(self._cursor, '_is_wrapped'):
|
|
96
|
+
return await self._cursor.executemany(*args, **kwargs)
|
|
97
|
+
real_executemany = getattr(self._cursor, "executemany", None)
|
|
98
|
+
if real_executemany is None:
|
|
99
|
+
return await self._cursor.executemany(*args, **kwargs)
|
|
100
|
+
safe_fn = self._async_execute_wrapper(real_executemany)
|
|
101
|
+
return await async_interceptor_db_execute(safe_fn, self._db_info, self._cursor, *args, **kwargs)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class BaseConnection:
|
|
105
|
+
def __init__(self, connection, db_info):
|
|
106
|
+
self._connection = connection
|
|
107
|
+
self._db_info = db_info
|
|
108
|
+
self._is_wrapped = True
|
|
109
|
+
|
|
110
|
+
def __getattr__(self, name):
|
|
111
|
+
return getattr(self._connection, name)
|
|
112
|
+
|
|
113
|
+
def __setattr__(self, name, value):
|
|
114
|
+
if name.startswith('_'):
|
|
115
|
+
object.__setattr__(self, name, value)
|
|
116
|
+
else:
|
|
117
|
+
setattr(self._connection, name, value)
|
|
118
|
+
|
|
119
|
+
def _execute_wrapper(self, original_execute_method):
|
|
120
|
+
owner = getattr(original_execute_method, "__self__", None)
|
|
121
|
+
|
|
122
|
+
def safe_execute(*args, **kwargs):
|
|
123
|
+
if args and owner is not None and args[0] is owner:
|
|
124
|
+
args = args[1:]
|
|
125
|
+
return original_execute_method(*args, **kwargs)
|
|
126
|
+
|
|
127
|
+
return safe_execute
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class SyncConnection(BaseConnection):
|
|
131
|
+
def __enter__(self):
|
|
132
|
+
self._connection.__enter__()
|
|
133
|
+
return self
|
|
134
|
+
|
|
135
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
136
|
+
return self._connection.__exit__(exc_type, exc_val, exc_tb)
|
|
137
|
+
|
|
138
|
+
def close(self, *args, **kwargs):
|
|
139
|
+
if self._db_info.get("pool"):
|
|
140
|
+
interceptor_pool_release()
|
|
141
|
+
return self._connection.close(*args, **kwargs)
|
|
142
|
+
|
|
143
|
+
real_close = self._connection.close
|
|
144
|
+
return interceptor_db_close(real_close, *args, **kwargs)
|
|
145
|
+
|
|
146
|
+
def cursor(self, *args, **kwargs):
|
|
147
|
+
real_cursor = self._connection.cursor(*args, **kwargs)
|
|
148
|
+
if hasattr(real_cursor, '_is_wrapped'):
|
|
149
|
+
return real_cursor
|
|
150
|
+
return SyncCursor(real_cursor, self._db_info)
|
|
151
|
+
|
|
152
|
+
def execute(self, *args, **kwargs):
|
|
153
|
+
if hasattr(self._connection, '_is_wrapped'):
|
|
154
|
+
return self._connection.execute(*args, **kwargs)
|
|
155
|
+
real_execute = getattr(self._connection, "execute", None)
|
|
156
|
+
if real_execute is None:
|
|
157
|
+
return self._connection.execute(*args, **kwargs)
|
|
158
|
+
safe_fn = self._execute_wrapper(real_execute)
|
|
159
|
+
return interceptor_db_execute(safe_fn, self._db_info, self._connection, *args, **kwargs)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class AsyncConnection(BaseConnection):
|
|
163
|
+
|
|
164
|
+
def __init__(self, connection, db_info, proxy=None):
|
|
165
|
+
super().__init__(connection, db_info) # 부모 생성자 호출
|
|
166
|
+
self._pool_proxy = proxy # proxy 참조 저장
|
|
167
|
+
|
|
168
|
+
async def __aenter__(self):
|
|
169
|
+
await self._connection.__aenter__()
|
|
170
|
+
return self
|
|
171
|
+
|
|
172
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
173
|
+
if self._db_info.get("pool") and self._pool_proxy:
|
|
174
|
+
|
|
175
|
+
# Pool connection이고 proxy가 있으면 proxy의 __aexit__ 호출
|
|
176
|
+
await async_interceptor_pool_release()
|
|
177
|
+
return await self._pool_proxy.__aexit__(exc_type, exc_val, exc_tb)
|
|
178
|
+
|
|
179
|
+
return await self._connection.__aexit__(exc_type, exc_val, exc_tb)
|
|
180
|
+
|
|
181
|
+
def cursor(self, *args, **kwargs):
|
|
182
|
+
real_cursor = self._connection.cursor(*args, **kwargs)
|
|
183
|
+
if hasattr(real_cursor, '_is_wrapped'):
|
|
184
|
+
return real_cursor
|
|
185
|
+
return AsyncCursor(real_cursor, self._db_info)
|
|
186
|
+
|
|
187
|
+
def _async_execute_wrapper(self, original_execute_method):
|
|
188
|
+
owner = getattr(original_execute_method, "__self__", None)
|
|
189
|
+
|
|
190
|
+
async def async_safe_execute(*args, **kwargs):
|
|
191
|
+
if args and owner is not None and args[0] is owner:
|
|
192
|
+
args = args[1:]
|
|
193
|
+
return await original_execute_method(*args, **kwargs)
|
|
194
|
+
|
|
195
|
+
return async_safe_execute
|
|
196
|
+
|
|
197
|
+
async def execute(self, *args, **kwargs):
|
|
198
|
+
if hasattr(self._connection, '_is_wrapped'):
|
|
199
|
+
return await self._connection.execute(*args, **kwargs)
|
|
200
|
+
real_execute = getattr(self._connection, "execute", None)
|
|
201
|
+
if real_execute is None:
|
|
202
|
+
return await self._connection.execute(*args, **kwargs)
|
|
203
|
+
safe_fn = self._async_execute_wrapper(real_execute)
|
|
204
|
+
return await async_interceptor_db_execute(safe_fn, self._db_info, self._connection, *args, **kwargs)
|
|
205
|
+
|
|
206
|
+
async def close(self, *args, **kwargs):
|
|
207
|
+
if self._db_info.get("pool"):
|
|
208
|
+
await async_interceptor_pool_release()
|
|
209
|
+
return await self._connection.close(*args, **kwargs)
|
|
210
|
+
|
|
211
|
+
real_close = self._connection.close
|
|
212
|
+
return await async_interceptor_db_close(real_close, *args, **kwargs)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def _is_called_by_pool():
|
|
216
|
+
try:
|
|
217
|
+
# 실제로 psycopg_pool은 보통 3-4 레벨 내에서 호출되므로 깊이 5로 결정.
|
|
218
|
+
filenames = [f.filename for f in inspect.stack(context=0)[2:7]]
|
|
219
|
+
return any('psycopg_pool' in f for f in filenames if f)
|
|
220
|
+
except Exception:
|
|
221
|
+
return False
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _sync_wrapper(fn):
|
|
225
|
+
@trace_handler(fn)
|
|
226
|
+
def wrapper(*args, **kwargs):
|
|
227
|
+
if _is_called_by_pool():
|
|
228
|
+
return fn(*args, **kwargs)
|
|
229
|
+
|
|
230
|
+
db_info = {"type": "postgresql"}
|
|
231
|
+
|
|
232
|
+
if args:
|
|
233
|
+
conn_str = args[0]
|
|
234
|
+
if isinstance(args[0], str) and '=' in args[0]:
|
|
235
|
+
parsed_kwargs = dict(
|
|
236
|
+
x.split('=') for x in conn_str.split()
|
|
237
|
+
)
|
|
238
|
+
kwargs.update(parsed_kwargs)
|
|
239
|
+
db_info.update(kwargs)
|
|
240
|
+
else:
|
|
241
|
+
db_info.update({"db_con_stc": "completed"})
|
|
242
|
+
db_info.update({"db_str": args[0]})
|
|
243
|
+
|
|
244
|
+
connection = interceptor_db_con(fn, db_info, *args, **kwargs)
|
|
245
|
+
if hasattr(connection, '_is_wrapped'):
|
|
246
|
+
return connection
|
|
247
|
+
return SyncConnection(connection, dict(db_info))
|
|
248
|
+
|
|
249
|
+
return wrapper
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def _async_wrapper(fn):
|
|
253
|
+
@async_trace_handler(fn)
|
|
254
|
+
async def wrapper(*args, **kwargs):
|
|
255
|
+
if _is_called_by_pool():
|
|
256
|
+
return await fn(*args, **kwargs)
|
|
257
|
+
|
|
258
|
+
db_info = {"type": "postgresql"}
|
|
259
|
+
|
|
260
|
+
if args:
|
|
261
|
+
conn_str = args[0]
|
|
262
|
+
if isinstance(args[0], str) and '=' in args[0]:
|
|
263
|
+
parsed_kwargs = dict(
|
|
264
|
+
x.split('=') for x in conn_str.split()
|
|
265
|
+
)
|
|
266
|
+
kwargs.update(parsed_kwargs)
|
|
267
|
+
db_info.update(kwargs)
|
|
268
|
+
else:
|
|
269
|
+
db_info.update({"db_con_stc": "completed"})
|
|
270
|
+
db_info.update({"db_str": args[0]})
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
connection = await async_interceptor_db_con(fn, db_info, *args, **kwargs)
|
|
274
|
+
if hasattr(connection, '_is_wrapped'):
|
|
275
|
+
return connection
|
|
276
|
+
return AsyncConnection(connection, dict(db_info))
|
|
277
|
+
|
|
278
|
+
return wrapper
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def _get_conn_info(connection):
|
|
282
|
+
conn_info = {}
|
|
283
|
+
try:
|
|
284
|
+
if hasattr(connection, 'info'):
|
|
285
|
+
conn_info['host'] = connection.info.host
|
|
286
|
+
conn_info['port'] = connection.info.port
|
|
287
|
+
conn_info['dbname'] = connection.info.dbname
|
|
288
|
+
conn_info['user'] = connection.info.user
|
|
289
|
+
elif hasattr(connection, 'dsn'):
|
|
290
|
+
import re
|
|
291
|
+
dsn_params = dict(x.split('=') for x in re.sub(r'\s*=\s*', '=', connection.dsn).split())
|
|
292
|
+
conn_info.update(dsn_params)
|
|
293
|
+
except Exception as e:
|
|
294
|
+
print(f"Failed to extract connection info: {e}")
|
|
295
|
+
return conn_info
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def _pool_getconn_wrapper(original_getconn):
|
|
299
|
+
def wrapper(self, *args, **kwargs):
|
|
300
|
+
connection = original_getconn(self, *args, **kwargs)
|
|
301
|
+
conn_info = _get_conn_info(connection)
|
|
302
|
+
db_info = {"type": "postgresql", "pool": True, **conn_info}
|
|
303
|
+
|
|
304
|
+
interceptor_pool_get(db_info)
|
|
305
|
+
|
|
306
|
+
return SyncConnection(connection, db_info)
|
|
307
|
+
|
|
308
|
+
return wrapper
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
class AsyncConnectionProxy:
|
|
312
|
+
"""AsyncConnectionPool.connection()이 반환하는 proxy 객체를 래핑"""
|
|
313
|
+
|
|
314
|
+
def __init__(self, proxy):
|
|
315
|
+
self._proxy = proxy
|
|
316
|
+
self._wrapped_connection = None
|
|
317
|
+
|
|
318
|
+
async def __aenter__(self):
|
|
319
|
+
connection = await self._proxy.__aenter__()
|
|
320
|
+
conn_info = _get_conn_info(connection)
|
|
321
|
+
db_info = {"type": "postgresql", "pool": True, **conn_info}
|
|
322
|
+
await async_interceptor_pool_get(db_info)
|
|
323
|
+
|
|
324
|
+
self._wrapped_connection = AsyncConnection(connection, db_info, proxy=self._proxy)
|
|
325
|
+
return self._wrapped_connection
|
|
326
|
+
|
|
327
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
328
|
+
if self._wrapped_connection:
|
|
329
|
+
await async_interceptor_pool_release()
|
|
330
|
+
return await self._proxy.__aexit__(exc_type, exc_val, exc_tb)
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def _async_pool_connection_wrapper(original_connection):
|
|
334
|
+
"""AsyncConnectionPool.connection() 메서드를 래핑"""
|
|
335
|
+
|
|
336
|
+
def wrapper(self, *args, **kwargs):
|
|
337
|
+
proxy = original_connection(self, *args, **kwargs)
|
|
338
|
+
return AsyncConnectionProxy(proxy)
|
|
339
|
+
|
|
340
|
+
return wrapper
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def instrument_psycopg(module):
|
|
344
|
+
original_connect = module.connect
|
|
345
|
+
module.connect = _sync_wrapper(original_connect)
|
|
346
|
+
if hasattr(module, 'AsyncConnection') and hasattr(module.AsyncConnection, 'connect'):
|
|
347
|
+
original_async_connect = module.AsyncConnection.connect
|
|
348
|
+
module.AsyncConnection.connect = _async_wrapper(original_async_connect)
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def instrument_psycopg_pool(pool_module):
|
|
352
|
+
if hasattr(pool_module, 'ConnectionPool'):
|
|
353
|
+
if hasattr(pool_module.ConnectionPool, 'getconn'):
|
|
354
|
+
pool_module.ConnectionPool.getconn = _pool_getconn_wrapper(pool_module.ConnectionPool.getconn)
|
|
355
|
+
|
|
356
|
+
if hasattr(pool_module, 'AsyncConnectionPool'):
|
|
357
|
+
if hasattr(pool_module.AsyncConnectionPool, 'connection'):
|
|
358
|
+
original_connection = pool_module.AsyncConnectionPool.connection
|
|
359
|
+
pool_module.AsyncConnectionPool.connection = _async_pool_connection_wrapper(original_connection)
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
from whatap.trace import get_dict
|
|
2
|
+
from whatap.trace.trace_handler import trace_handler
|
|
3
|
+
from whatap.trace.trace_error import interceptor_step_error
|
|
4
|
+
from whatap.trace.trace_context_manager import TraceContextManager
|
|
5
|
+
import whatap.net.async_sender as async_sender
|
|
6
|
+
from whatap.net.packet_type_enum import PacketTypeEnum
|
|
7
|
+
from whatap.util.date_util import DateUtil
|
|
8
|
+
import numbers
|
|
9
|
+
|
|
10
|
+
_current_command = None
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def intercept_send_command(fn, instance, *args, **kwargs):
|
|
14
|
+
global _current_command
|
|
15
|
+
command = str(args[0]).upper() if args else None
|
|
16
|
+
_current_command = command
|
|
17
|
+
|
|
18
|
+
if command not in {'SET', 'GET', 'DEL', 'HSET', 'HGET'}:
|
|
19
|
+
return fn(instance, *args, **kwargs)
|
|
20
|
+
|
|
21
|
+
ctx = TraceContextManager.getLocalContext()
|
|
22
|
+
if not ctx:
|
|
23
|
+
return fn(instance, *args, **kwargs)
|
|
24
|
+
|
|
25
|
+
start_time = DateUtil.nowSystem()
|
|
26
|
+
ctx.start_time = start_time
|
|
27
|
+
|
|
28
|
+
port_or_path = getattr(instance, 'port', getattr(instance, 'path', None))
|
|
29
|
+
text = 'redis://'
|
|
30
|
+
text += getattr(instance, 'host', 'localhost')
|
|
31
|
+
text += ':{}'.format(port_or_path)
|
|
32
|
+
text += '/'
|
|
33
|
+
text += str(getattr(instance, 'db', 0))
|
|
34
|
+
ctx.active_dbc = text
|
|
35
|
+
ctx.lctx['dbc'] = text
|
|
36
|
+
|
|
37
|
+
ctx.active_dbc = 0
|
|
38
|
+
ctx.db_opening = True
|
|
39
|
+
datas = [text]
|
|
40
|
+
ctx.elapsed = DateUtil.nowSystem() - start_time
|
|
41
|
+
async_sender.send_packet(PacketTypeEnum.TX_DB_CONN, ctx, datas)
|
|
42
|
+
query = f"{command} " + " ".join([str(arg)[:20] for arg in args[1:]])
|
|
43
|
+
|
|
44
|
+
start_time = DateUtil.nowSystem()
|
|
45
|
+
ctx.start_time = start_time
|
|
46
|
+
ctx.active_sqlhash = query
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
callback = fn(instance, *args, **kwargs)
|
|
50
|
+
return callback
|
|
51
|
+
except Exception as e:
|
|
52
|
+
interceptor_step_error(e)
|
|
53
|
+
finally:
|
|
54
|
+
ctx.db_opening = False
|
|
55
|
+
datas = [ctx.lctx.get('dbc', ''), query, 0]
|
|
56
|
+
ctx.elapsed = DateUtil.nowSystem() - start_time
|
|
57
|
+
async_sender.send_packet(PacketTypeEnum.TX_SQL, ctx, datas)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def interceptor_read_response(fn, *args, **kwargs):
|
|
61
|
+
global _current_command
|
|
62
|
+
|
|
63
|
+
if _current_command not in {'SET', 'GET', 'DEL', 'HSET', 'HGET'}:
|
|
64
|
+
_current_command = None
|
|
65
|
+
return fn(*args, **kwargs)
|
|
66
|
+
|
|
67
|
+
ctx = TraceContextManager.getLocalContext()
|
|
68
|
+
if not ctx:
|
|
69
|
+
_current_command = None
|
|
70
|
+
return fn(*args, **kwargs)
|
|
71
|
+
|
|
72
|
+
start_time = DateUtil.nowSystem()
|
|
73
|
+
ctx.start_time = start_time
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
callback = fn(*args, **kwargs)
|
|
77
|
+
|
|
78
|
+
if callback:
|
|
79
|
+
count = -1
|
|
80
|
+
if isinstance(callback, int):
|
|
81
|
+
count = callback
|
|
82
|
+
elif isinstance(callback, list):
|
|
83
|
+
count = len(callback)
|
|
84
|
+
|
|
85
|
+
if count > -1:
|
|
86
|
+
msg = '{0}: {1}'.format('Fetch bytes', count)
|
|
87
|
+
datas = [msg, ' ', ' ']
|
|
88
|
+
ctx.elapsed = 0
|
|
89
|
+
async_sender.send_packet(PacketTypeEnum.TX_MSG, ctx, datas)
|
|
90
|
+
|
|
91
|
+
ctx.active_sqlhash = 0
|
|
92
|
+
return callback
|
|
93
|
+
finally:
|
|
94
|
+
_current_command = None
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def instrument_redis_connection(module):
|
|
98
|
+
def wrapper(fn):
|
|
99
|
+
@trace_handler(fn)
|
|
100
|
+
def trace(*args, **kwargs):
|
|
101
|
+
callback = intercept_send_command(fn, args[0], *args[1:], **kwargs)
|
|
102
|
+
return callback
|
|
103
|
+
|
|
104
|
+
return trace
|
|
105
|
+
|
|
106
|
+
if hasattr(module, 'Connection') and hasattr(module.Connection, 'send_command'):
|
|
107
|
+
if not getattr(module.Connection.send_command, '_wrapped', False):
|
|
108
|
+
module.Connection.send_command = wrapper(module.Connection.send_command)
|
|
109
|
+
module.Connection.send_command._wrapped = True
|
|
110
|
+
|
|
111
|
+
def wrapper(fn):
|
|
112
|
+
@trace_handler(fn)
|
|
113
|
+
def trace(*args, **kwargs):
|
|
114
|
+
callback = interceptor_read_response(fn, *args, **kwargs)
|
|
115
|
+
return callback
|
|
116
|
+
|
|
117
|
+
return trace
|
|
118
|
+
|
|
119
|
+
if hasattr(module, 'Connection') and hasattr(module.Connection, 'read_response'):
|
|
120
|
+
if not getattr(module.Connection.read_response, '_wrapped', False):
|
|
121
|
+
module.Connection.read_response = wrapper(module.Connection.read_response)
|
|
122
|
+
module.Connection.read_response._wrapped = True
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
from whatap.net.packet_type_enum import PacketTypeEnum
|
|
2
|
+
import whatap.net.async_sender as async_sender
|
|
3
|
+
from whatap.trace.trace_handler import trace_handler
|
|
4
|
+
from whatap.trace.trace_error import interceptor_step_error, sendDebugProfile
|
|
5
|
+
from whatap.util.date_util import DateUtil
|
|
6
|
+
from whatap.trace.trace_context_manager import TraceContextManager
|
|
7
|
+
import sys
|
|
8
|
+
from functools import wraps
|
|
9
|
+
|
|
10
|
+
def instrument_sqlalchemy(module):
|
|
11
|
+
def wrapper(fn):
|
|
12
|
+
@trace_handler(fn)
|
|
13
|
+
def trace(*args, **kwargs):
|
|
14
|
+
ctx = TraceContextManager.getLocalContext()
|
|
15
|
+
|
|
16
|
+
start_time = DateUtil.nowSystem()
|
|
17
|
+
ctx.start_time = start_time
|
|
18
|
+
|
|
19
|
+
text = args[0].bind.url.__to_string__().replace('***', '')
|
|
20
|
+
ctx.lctx['dbc'] = text
|
|
21
|
+
|
|
22
|
+
datas = [' ', ' ', 'DB SESSION INFO: ' + text]
|
|
23
|
+
ctx.elapsed = DateUtil.nowSystem() - start_time
|
|
24
|
+
async_sender.send_packet(PacketTypeEnum.TX_MSG, ctx, datas)
|
|
25
|
+
|
|
26
|
+
callback = fn(*args, **kwargs)
|
|
27
|
+
return callback
|
|
28
|
+
|
|
29
|
+
return trace
|
|
30
|
+
if sys.modules.get("flask_sqlalchemy") is None:
|
|
31
|
+
module.Session.get_bind = wrapper(module.Session.get_bind)
|
|
32
|
+
|
|
33
|
+
def addQuote(arg_dict):
|
|
34
|
+
quoted_dict = dict()
|
|
35
|
+
|
|
36
|
+
for k, v in arg_dict.items():
|
|
37
|
+
if isinstance(v, str):
|
|
38
|
+
quoted_dict[k] = "'" + v.replace("'", "\\'") + "'"
|
|
39
|
+
else:
|
|
40
|
+
quoted_dict[k] = v
|
|
41
|
+
|
|
42
|
+
return quoted_dict
|
|
43
|
+
|
|
44
|
+
def instrument_sqlalchemy_engine(module):
|
|
45
|
+
def wrapper(fn):
|
|
46
|
+
@trace_handler(fn)
|
|
47
|
+
def trace(*args, **kwargs):
|
|
48
|
+
ctx = TraceContextManager.getLocalContext()
|
|
49
|
+
cursor = args[1]
|
|
50
|
+
query = None
|
|
51
|
+
if len(args) > 3 and args[3]:
|
|
52
|
+
try:
|
|
53
|
+
##oracle을 사용하는 경우
|
|
54
|
+
if (type(args[3]) == dict) and (":" in args[2]) and ("oracle" in str(args[0])):
|
|
55
|
+
oracle_sql_query = args[2]
|
|
56
|
+
for k, v in args[3].items():
|
|
57
|
+
replaced_key = f":{k}"
|
|
58
|
+
replaced_value = f"'{v}'"
|
|
59
|
+
oracle_sql_query = oracle_sql_query.replace(replaced_key,
|
|
60
|
+
replaced_value) if replaced_key in oracle_sql_query else None
|
|
61
|
+
query = oracle_sql_query
|
|
62
|
+
|
|
63
|
+
##mysql를 사용하는 경우
|
|
64
|
+
elif (type(args[3]) == tuple) and ("%s" in args[2]) and ("mysql" in str(args[0])):
|
|
65
|
+
my_sql_query = args[2]
|
|
66
|
+
for v in args[3]:
|
|
67
|
+
replaced_value = f"'{v}'"
|
|
68
|
+
my_sql_query = my_sql_query.replace("%s", replaced_value,
|
|
69
|
+
1) if "%s" in my_sql_query else None
|
|
70
|
+
query = my_sql_query
|
|
71
|
+
else:
|
|
72
|
+
query = args[2] % addQuote(args[3])
|
|
73
|
+
except Exception as e:
|
|
74
|
+
pass
|
|
75
|
+
# print('instrument_sqlalchemy_engine 2:', query)
|
|
76
|
+
try:
|
|
77
|
+
if not query:
|
|
78
|
+
query = args[2].decode()
|
|
79
|
+
except Exception as e:
|
|
80
|
+
query = str(args[2])
|
|
81
|
+
# print('instrument_sqlalchemy_engine 3:', query)
|
|
82
|
+
sqlalchemy_track_skip = False
|
|
83
|
+
except_track_module = ['pymysql', 'mysqldb', 'psycopg2','psycopg','sqlite3']
|
|
84
|
+
|
|
85
|
+
# 이미 DB드라이브 추적 모듈이 존재하면 sqlAlhechmy 의 추적 중지
|
|
86
|
+
if any(keyword in str(args[0]) for keyword in except_track_module):
|
|
87
|
+
sqlalchemy_track_skip = True
|
|
88
|
+
|
|
89
|
+
if (not query) or (sqlalchemy_track_skip):
|
|
90
|
+
return fn(*args, **kwargs)
|
|
91
|
+
|
|
92
|
+
start_time = DateUtil.nowSystem()
|
|
93
|
+
ctx.start_time = start_time
|
|
94
|
+
ctx.active_sqlhash = query
|
|
95
|
+
# print('instrument_sqlalchemy_engine 4')
|
|
96
|
+
try:
|
|
97
|
+
callback = fn(*args, **kwargs)
|
|
98
|
+
# print('instrument_sqlalchemy_engine 5')
|
|
99
|
+
return callback
|
|
100
|
+
except Exception as e:
|
|
101
|
+
interceptor_step_error(e)
|
|
102
|
+
finally:
|
|
103
|
+
# print('instrument_sqlalchemy_engine 6')
|
|
104
|
+
ctx = TraceContextManager.getLocalContext()
|
|
105
|
+
if ctx:
|
|
106
|
+
datas = [ctx.lctx.get('dbc', ''), query, 0]
|
|
107
|
+
ctx.elapsed = DateUtil.nowSystem() - start_time
|
|
108
|
+
# print('instrument_sqlalchemy_engine 6.1', datas)
|
|
109
|
+
async_sender.send_packet(PacketTypeEnum.TX_SQL, ctx,
|
|
110
|
+
datas)
|
|
111
|
+
# print('instrument_sqlalchemy_engine 7')
|
|
112
|
+
if hasattr(cursor, 'rowcount'):
|
|
113
|
+
count = cursor.rowcount
|
|
114
|
+
# print('instrument_sqlalchemy_engine 8')
|
|
115
|
+
if count > -1:
|
|
116
|
+
desc = '{0}: {1}'.format('Fetch count', count)
|
|
117
|
+
datas = [' ', ' ', desc]
|
|
118
|
+
ctx.elapsed = 0
|
|
119
|
+
async_sender.send_packet(PacketTypeEnum.TX_MSG, ctx, datas)
|
|
120
|
+
ctx.active_sqlhash = 0
|
|
121
|
+
|
|
122
|
+
# print('instrument_sqlalchemy_engine 9')
|
|
123
|
+
|
|
124
|
+
return trace
|
|
125
|
+
|
|
126
|
+
# print('database_toolkit.instrument_sqlalchemy_engine step -1')
|
|
127
|
+
if hasattr(module, 'DefaultDialect') and hasattr(module.DefaultDialect, 'do_execute'):
|
|
128
|
+
# print('database_toolkit.instrument_sqlalchemy_engine step -2')
|
|
129
|
+
module.DefaultDialect.do_execute = wrapper(module.DefaultDialect.do_execute)
|
|
130
|
+
module.DefaultDialect.do_executemany = wrapper(module.DefaultDialect.do_executemany)
|
|
131
|
+
module.DefaultDialect.do_execute_no_params = wrapper(module.DefaultDialect.do_execute_no_params)
|
|
132
|
+
# print('database_toolkit.instrument_sqlalchemy_engine step -3')
|
|
133
|
+
|
|
134
|
+
class _urlbase(object):
|
|
135
|
+
def __init__(self, url):
|
|
136
|
+
self.url = url
|
|
137
|
+
|
|
138
|
+
class connect(_urlbase):
|
|
139
|
+
def __call__(self,*args, **kwargs):
|
|
140
|
+
TraceContextManager.addDBPoolIdle(self.url)
|
|
141
|
+
# import os
|
|
142
|
+
# print("connect for ",self.url, os.getpid())
|
|
143
|
+
|
|
144
|
+
class checkin(_urlbase):
|
|
145
|
+
def __call__(self,*args, **kwargs):
|
|
146
|
+
TraceContextManager.addDBPoolIdle(self.url, isCheckIn=True)
|
|
147
|
+
#print("checkin for ",self.url)
|
|
148
|
+
|
|
149
|
+
class checkout(_urlbase):
|
|
150
|
+
def __call__(self,*args, **kwargs):
|
|
151
|
+
TraceContextManager.addDBPoolActive(self.url)
|
|
152
|
+
#print("checkout for ",self.url)
|
|
153
|
+
|
|
154
|
+
class reset(_urlbase):
|
|
155
|
+
def __call__(self,*args, **kwargs):
|
|
156
|
+
#print("reset for ",self.url)
|
|
157
|
+
pass
|
|
158
|
+
|
|
159
|
+
class invalidate(_urlbase):
|
|
160
|
+
def __call__(self,*args, **kwargs):
|
|
161
|
+
#print("invalidate for ",self.url)
|
|
162
|
+
TraceContextManager.removeDBPoolIdle(self.url)
|
|
163
|
+
|
|
164
|
+
class close(_urlbase):
|
|
165
|
+
def __call__(self,*args, **kwargs):
|
|
166
|
+
TraceContextManager.removeDBPoolIdle(self.url)
|
|
167
|
+
|
|
168
|
+
class detach(_urlbase):
|
|
169
|
+
def __call__(self,*args, **kwargs):
|
|
170
|
+
TraceContextManager.removeDBPoolIdle(self.url)
|
|
171
|
+
|
|
172
|
+
class close_detached(_urlbase):
|
|
173
|
+
def __call__(self,*args, **kwargs):
|
|
174
|
+
#print("close_detached for ",self.url)
|
|
175
|
+
pass
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def instrument_sqlalchemy_engine_basic(module):
|
|
179
|
+
def wrapper(fn):
|
|
180
|
+
@wraps(fn)
|
|
181
|
+
def trace(*args, **kwargs):
|
|
182
|
+
engine = fn(*args, **kwargs)
|
|
183
|
+
if len(args) > 0:
|
|
184
|
+
url = str(args[0])
|
|
185
|
+
try:
|
|
186
|
+
import sqlalchemy.engine.event as event
|
|
187
|
+
|
|
188
|
+
event.listen(engine, "connect", connect(url))
|
|
189
|
+
event.listen(engine, "checkin", checkin(url))
|
|
190
|
+
event.listen(engine, "checkout", checkout(url))
|
|
191
|
+
event.listen(engine, "close", close(url))
|
|
192
|
+
except Exception as e:
|
|
193
|
+
pass
|
|
194
|
+
try:
|
|
195
|
+
import sqlalchemy.event.api as event
|
|
196
|
+
|
|
197
|
+
event.listen(engine, "connect", connect(url))
|
|
198
|
+
event.listen(engine, "checkin", checkin(url))
|
|
199
|
+
event.listen(engine, "checkout", checkout(url))
|
|
200
|
+
|
|
201
|
+
#event.listen(engine, "reset", reset(url))
|
|
202
|
+
#event.listen(engine, "invalidate", invalidate(url))
|
|
203
|
+
event.listen(engine, "close", close(url))
|
|
204
|
+
#event.listen(engine, "detach", detach(url))
|
|
205
|
+
#event.listen(engine, "close_detached", close_detached(url))
|
|
206
|
+
|
|
207
|
+
except Exception as e:
|
|
208
|
+
pass
|
|
209
|
+
return engine
|
|
210
|
+
|
|
211
|
+
return trace
|
|
212
|
+
if hasattr(module, "create_engine"):
|
|
213
|
+
module.create_engine = wrapper(module.create_engine)
|