whatap-python 1.8.10__tar.gz → 1.8.11__tar.gz

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.

Potentially problematic release.


This version of whatap-python might be problematic. Click here for more details.

Files changed (146) hide show
  1. {whatap_python-1.8.10 → whatap_python-1.8.11}/PKG-INFO +1 -1
  2. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/agent/linux/amd64/whatap_python +0 -0
  3. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/agent/linux/arm64/whatap_python +0 -0
  4. whatap_python-1.8.11/whatap/build.py +4 -0
  5. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/database/psycopg3.py +128 -58
  6. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/database/sqlalchemy.py +4 -4
  7. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/database/util.py +64 -7
  8. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/trace_module_definition.py +2 -1
  9. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap_python.egg-info/PKG-INFO +1 -1
  10. whatap_python-1.8.10/whatap/build.py +0 -4
  11. {whatap_python-1.8.10 → whatap_python-1.8.11}/README.md +0 -0
  12. {whatap_python-1.8.10 → whatap_python-1.8.11}/setup.cfg +0 -0
  13. {whatap_python-1.8.10 → whatap_python-1.8.11}/setup.py +0 -0
  14. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/LICENSE +0 -0
  15. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/README.rst +0 -0
  16. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/__init__.py +0 -0
  17. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/__main__.py +0 -0
  18. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/agent/darwin/amd64/whatap_python +0 -0
  19. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/agent/darwin/arm64/whatap_python +0 -0
  20. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/bootstrap/__init__.py +0 -0
  21. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/bootstrap/sitecustomize.py +0 -0
  22. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/conf/__init__.py +0 -0
  23. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/conf/configuration.py +0 -0
  24. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/conf/configure.py +0 -0
  25. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/conf/license.py +0 -0
  26. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/control/__init__.py +0 -0
  27. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/counter/__init__.py +0 -0
  28. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/counter/counter_manager.py +0 -0
  29. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/counter/tasks/__init__.py +0 -0
  30. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/counter/tasks/openfiledescriptor.py +0 -0
  31. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/io/__init__.py +0 -0
  32. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/io/data_inputx.py +0 -0
  33. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/io/data_outputx.py +0 -0
  34. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/net/__init__.py +0 -0
  35. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/net/async_sender.py +0 -0
  36. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/net/packet_enum.py +0 -0
  37. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/net/packet_type_enum.py +0 -0
  38. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/net/param_def.py +0 -0
  39. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/net/stackhelper.py +0 -0
  40. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/net/udp_session.py +0 -0
  41. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/net/udp_thread.py +0 -0
  42. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/pack/__init__.py +0 -0
  43. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/pack/logSinkPack.py +0 -0
  44. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/pack/pack.py +0 -0
  45. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/pack/pack_enum.py +0 -0
  46. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/pack/tagCountPack.py +0 -0
  47. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/scripts/__init__.py +0 -0
  48. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/__init__.py +0 -0
  49. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/__init__.py +0 -0
  50. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/amqp/__init__.py +0 -0
  51. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/amqp/kombu.py +0 -0
  52. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/amqp/pika.py +0 -0
  53. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/application/__init__.py +0 -0
  54. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/application/bottle.py +0 -0
  55. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/application/celery.py +0 -0
  56. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/application/cherrypy.py +0 -0
  57. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/application/django.py +0 -0
  58. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/application/django_asgi.py +0 -0
  59. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/application/django_py3.py +0 -0
  60. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/application/fastapi.py +0 -0
  61. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/application/flask.py +0 -0
  62. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/application/frappe.py +0 -0
  63. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/application/graphql.py +0 -0
  64. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/application/nameko.py +0 -0
  65. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/application/odoo.py +0 -0
  66. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/application/starlette.py +0 -0
  67. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/application/tornado.py +0 -0
  68. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/application/wsgi.py +0 -0
  69. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/database/__init__.py +0 -0
  70. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/database/cxoracle.py +0 -0
  71. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/database/mongo.py +0 -0
  72. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/database/mysql.py +0 -0
  73. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/database/neo4j.py +0 -0
  74. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/database/psycopg2.py +0 -0
  75. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/database/redis.py +0 -0
  76. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/database/sqlite3.py +0 -0
  77. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/email/__init__.py +0 -0
  78. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/email/smtp.py +0 -0
  79. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/httpc/__init__.py +0 -0
  80. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/httpc/django.py +0 -0
  81. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/httpc/httplib.py +0 -0
  82. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/httpc/httpx.py +0 -0
  83. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/httpc/requests.py +0 -0
  84. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/httpc/urllib3.py +0 -0
  85. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/llm/__init__.py +0 -0
  86. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/llm/openai.py +0 -0
  87. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/logging.py +0 -0
  88. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/plugin.py +0 -0
  89. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/standalone/__init__.py +0 -0
  90. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/standalone/multiple.py +0 -0
  91. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/mod/standalone/single.py +0 -0
  92. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/simple_trace_context.py +0 -0
  93. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/trace_context.py +0 -0
  94. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/trace_context_manager.py +0 -0
  95. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/trace/trace_import.py +0 -0
  96. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/__init__.py +0 -0
  97. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/bit_util.py +0 -0
  98. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/cardinality/__init__.py +0 -0
  99. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/cardinality/hyperloglog.py +0 -0
  100. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/cardinality/murmurhash.py +0 -0
  101. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/cardinality/registerset.py +0 -0
  102. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/compare_util.py +0 -0
  103. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/date_util.py +0 -0
  104. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/debug_util.py +0 -0
  105. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/escape_literal_sql.py +0 -0
  106. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/hash_util.py +0 -0
  107. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/hexa32.py +0 -0
  108. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/int_set.py +0 -0
  109. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/ip_util.py +0 -0
  110. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/keygen.py +0 -0
  111. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/linked_list.py +0 -0
  112. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/linked_map.py +0 -0
  113. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/metering_util.py +0 -0
  114. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/request_double_queue.py +0 -0
  115. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/request_queue.py +0 -0
  116. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/string_util.py +0 -0
  117. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/throttle_util.py +0 -0
  118. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/util/userid_util.py +0 -0
  119. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/value/__init__.py +0 -0
  120. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/value/blob_value.py +0 -0
  121. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/value/boolean_value.py +0 -0
  122. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/value/decimal_value.py +0 -0
  123. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/value/double_summary.py +0 -0
  124. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/value/double_value.py +0 -0
  125. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/value/float_array.py +0 -0
  126. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/value/float_value.py +0 -0
  127. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/value/int_array.py +0 -0
  128. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/value/ip4_value.py +0 -0
  129. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/value/list_value.py +0 -0
  130. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/value/long_array.py +0 -0
  131. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/value/long_summary.py +0 -0
  132. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/value/map_value.py +0 -0
  133. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/value/null_value.py +0 -0
  134. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/value/number_value.py +0 -0
  135. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/value/summary_value.py +0 -0
  136. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/value/text_array.py +0 -0
  137. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/value/text_hash_value.py +0 -0
  138. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/value/text_value.py +0 -0
  139. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/value/value.py +0 -0
  140. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/value/value_enum.py +0 -0
  141. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap/whatap.conf +0 -0
  142. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap_python.egg-info/SOURCES.txt +0 -0
  143. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap_python.egg-info/dependency_links.txt +0 -0
  144. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap_python.egg-info/entry_points.txt +0 -0
  145. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap_python.egg-info/not-zip-safe +0 -0
  146. {whatap_python-1.8.10 → whatap_python-1.8.11}/whatap_python.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: whatap-python
3
- Version: 1.8.10
3
+ Version: 1.8.11
4
4
  Summary: Monitoring and Profiling Service
5
5
  Home-page: https://www.whatap.io
6
6
  Author: whatap
@@ -0,0 +1,4 @@
1
+ app = 'Python'
2
+ name = 'whatap-python'
3
+ version = '1.8.11'
4
+ release_date = '20250901'
@@ -1,7 +1,11 @@
1
+ import inspect
2
+
1
3
  from whatap.trace.mod.application.wsgi import trace_handler
2
4
  from whatap.trace.mod.database.util import (
3
5
  interceptor_db_con, interceptor_db_execute, interceptor_db_close,
4
- async_interceptor_db_con, async_interceptor_db_execute, async_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
5
9
  )
6
10
 
7
11
  db_info = {}
@@ -11,6 +15,7 @@ class BaseCursor:
11
15
  def __init__(self, cursor, db_info):
12
16
  self._cursor = cursor
13
17
  self._db_info = db_info
18
+ self._is_wrapped = True
14
19
 
15
20
  def __getattr__(self, name):
16
21
  return getattr(self._cursor, name)
@@ -45,28 +50,23 @@ class SyncCursor(BaseCursor):
45
50
  return self._cursor.__exit__(exc_type, exc_val, exc_tb)
46
51
 
47
52
  def execute(self, *args, **kwargs):
53
+ if hasattr(self._cursor, '_is_wrapped'):
54
+ return self._cursor.execute(*args, **kwargs)
48
55
  real_execute = self._cursor.execute
49
56
  safe_fn = self._execute_wrapper(real_execute)
50
-
51
- callback = interceptor_db_execute(safe_fn,self._db_info,self._cursor,*args,**kwargs)
52
-
53
- return callback
57
+ return interceptor_db_execute(safe_fn, self._db_info, self._cursor, *args, **kwargs)
54
58
 
55
59
  def executemany(self, *args, **kwargs):
60
+ if hasattr(self._cursor, '_is_wrapped'):
61
+ return self._cursor.executemany(*args, **kwargs)
56
62
  real_executemany = getattr(self._cursor, "executemany", None)
57
-
58
63
  if real_executemany is None:
59
64
  return self._cursor.executemany(*args, **kwargs)
60
-
61
65
  safe_fn = self._execute_wrapper(real_executemany)
62
-
63
- callback = interceptor_db_execute(safe_fn,self._db_info,self._cursor,*args,**kwargs)
64
-
65
- return callback
66
+ return interceptor_db_execute(safe_fn, self._db_info, self._cursor, *args, **kwargs)
66
67
 
67
68
 
68
69
  class AsyncCursor(BaseCursor):
69
-
70
70
  async def __aenter__(self):
71
71
  await self._cursor.__aenter__()
72
72
  return self
@@ -85,30 +85,27 @@ class AsyncCursor(BaseCursor):
85
85
  return async_safe_execute
86
86
 
87
87
  async def execute(self, *args, **kwargs):
88
+ if hasattr(self._cursor, '_is_wrapped'):
89
+ return await self._cursor.execute(*args, **kwargs)
88
90
  real_execute = self._cursor.execute
89
91
  safe_fn = self._async_execute_wrapper(real_execute)
90
-
91
-
92
- callback = await async_interceptor_db_execute(safe_fn,self._db_info,self._cursor,*args,**kwargs)
93
-
94
- return callback
92
+ return await async_interceptor_db_execute(safe_fn, self._db_info, self._cursor, *args, **kwargs)
95
93
 
96
94
  async def executemany(self, *args, **kwargs):
95
+ if hasattr(self._cursor, '_is_wrapped'):
96
+ return await self._cursor.executemany(*args, **kwargs)
97
97
  real_executemany = getattr(self._cursor, "executemany", None)
98
-
99
98
  if real_executemany is None:
100
99
  return await self._cursor.executemany(*args, **kwargs)
101
-
102
100
  safe_fn = self._async_execute_wrapper(real_executemany)
103
-
104
- callback = await async_interceptor_db_execute(safe_fn,self._db_info,self._cursor,*args,**kwargs)
105
- return callback
101
+ return await async_interceptor_db_execute(safe_fn, self._db_info, self._cursor, *args, **kwargs)
106
102
 
107
103
 
108
104
  class BaseConnection:
109
105
  def __init__(self, connection, db_info):
110
106
  self._connection = connection
111
107
  self._db_info = db_info
108
+ self._is_wrapped = True
112
109
 
113
110
  def __getattr__(self, name):
114
111
  return getattr(self._connection, name)
@@ -129,15 +126,8 @@ class BaseConnection:
129
126
 
130
127
  return safe_execute
131
128
 
132
- def close(self, *args, **kwargs):
133
- real_close = self._connection.close
134
-
135
- callback = interceptor_db_close(real_close, *args, **kwargs)
136
- return callback
137
-
138
129
 
139
130
  class SyncConnection(BaseConnection):
140
-
141
131
  def __enter__(self):
142
132
  self._connection.__enter__()
143
133
  return self
@@ -145,25 +135,31 @@ class SyncConnection(BaseConnection):
145
135
  def __exit__(self, exc_type, exc_val, exc_tb):
146
136
  return self._connection.__exit__(exc_type, exc_val, exc_tb)
147
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
+
148
146
  def cursor(self, *args, **kwargs):
149
147
  real_cursor = self._connection.cursor(*args, **kwargs)
148
+ if hasattr(real_cursor, '_is_wrapped'):
149
+ return real_cursor
150
150
  return SyncCursor(real_cursor, self._db_info)
151
151
 
152
152
  def execute(self, *args, **kwargs):
153
+ if hasattr(self._connection, '_is_wrapped'):
154
+ return self._connection.execute(*args, **kwargs)
153
155
  real_execute = getattr(self._connection, "execute", None)
154
-
155
156
  if real_execute is None:
156
157
  return self._connection.execute(*args, **kwargs)
157
-
158
158
  safe_fn = self._execute_wrapper(real_execute)
159
-
160
- callback = interceptor_db_execute(safe_fn,self._db_info,self._cursor,*args,**kwargs)
161
-
162
- return callback
159
+ return interceptor_db_execute(safe_fn, self._db_info, self._connection, *args, **kwargs)
163
160
 
164
161
 
165
162
  class AsyncConnection(BaseConnection):
166
-
167
163
  async def __aenter__(self):
168
164
  await self._connection.__aenter__()
169
165
  return self
@@ -173,6 +169,8 @@ class AsyncConnection(BaseConnection):
173
169
 
174
170
  def cursor(self, *args, **kwargs):
175
171
  real_cursor = self._connection.cursor(*args, **kwargs)
172
+ if hasattr(real_cursor, '_is_wrapped'):
173
+ return real_cursor
176
174
  return AsyncCursor(real_cursor, self._db_info)
177
175
 
178
176
  def _async_execute_wrapper(self, original_execute_method):
@@ -186,66 +184,138 @@ class AsyncConnection(BaseConnection):
186
184
  return async_safe_execute
187
185
 
188
186
  async def execute(self, *args, **kwargs):
187
+ if hasattr(self._connection, '_is_wrapped'):
188
+ return await self._connection.execute(*args, **kwargs)
189
189
  real_execute = getattr(self._connection, "execute", None)
190
-
191
190
  if real_execute is None:
192
191
  return await self._connection.execute(*args, **kwargs)
193
-
194
192
  safe_fn = self._async_execute_wrapper(real_execute)
195
-
196
- callback = await async_interceptor_db_execute(safe_fn,self._db_info,self._connection,*args,**kwargs)
197
-
198
- return callback
193
+ return await async_interceptor_db_execute(safe_fn, self._db_info, self._connection, *args, **kwargs)
199
194
 
200
195
  async def close(self, *args, **kwargs):
196
+ if self._db_info.get("pool"):
197
+ await async_interceptor_pool_release()
198
+ return await self._connection.close(*args, **kwargs)
199
+
201
200
  real_close = self._connection.close
201
+ return await async_interceptor_db_close(real_close, *args, **kwargs)
202
202
 
203
- callback = await async_interceptor_db_close(real_close, *args, **kwargs)
204
203
 
205
- return callback
204
+ def _is_called_by_pool():
205
+ try:
206
+ # 실제로 psycopg_pool은 보통 3-4 레벨 내에서 호출되므로 깊이 5로 결정.
207
+ filenames = [f.filename for f in inspect.stack(context=0)[2:7]]
208
+ return any('psycopg_pool' in f for f in filenames if f)
209
+ except Exception:
210
+ return False
206
211
 
207
212
 
208
213
  def _sync_wrapper(fn):
209
-
210
214
  @trace_handler(fn)
211
215
  def wrapper(*args, **kwargs):
212
- global db_info
216
+ if _is_called_by_pool():
217
+ return fn(*args, **kwargs)
213
218
 
214
219
  db_info = {"type": "postgresql"}
220
+
221
+ if args and isinstance(args[0], str) and '=' in args[0]:
222
+ conn_str = args[0]
223
+ parsed_kwargs = dict(
224
+ x.split('=') for x in conn_str.split()
225
+ )
226
+ kwargs.update(parsed_kwargs)
227
+
215
228
  db_info.update(kwargs)
216
229
 
217
230
  connection = interceptor_db_con(fn, db_info, *args, **kwargs)
218
-
231
+ if hasattr(connection, '_is_wrapped'):
232
+ return connection
219
233
  return SyncConnection(connection, dict(db_info))
220
234
 
221
235
  return wrapper
222
236
 
223
237
 
224
238
  def _async_wrapper(fn):
225
-
226
239
  @trace_handler(fn)
227
240
  async def wrapper(*args, **kwargs):
228
- global db_info
241
+ if _is_called_by_pool():
242
+ return await fn(*args, **kwargs)
229
243
 
230
244
  db_info = {"type": "postgresql"}
231
- db_info.update(kwargs)
232
245
 
233
- connection = await async_interceptor_db_con(fn,db_info,*args,**kwargs)
246
+ if args and isinstance(args[0], str) and '=' in args[0]:
247
+ conn_str = args[0]
248
+ parsed_kwargs = dict(
249
+ x.split('=') for x in conn_str.split()
250
+ )
251
+ kwargs.update(parsed_kwargs)
252
+
253
+ db_info.update(kwargs)
234
254
 
255
+ connection = await async_interceptor_db_con(fn, db_info, *args, **kwargs)
256
+ if hasattr(connection, '_is_wrapped'):
257
+ return connection
235
258
  return AsyncConnection(connection, dict(db_info))
236
259
 
237
260
  return wrapper
238
261
 
239
262
 
240
- def instrument_psycopg3(module):
241
- original_connect = module.connect
263
+ def _get_conn_info(connection):
264
+ conn_info = {}
265
+ try:
266
+ if hasattr(connection, 'info'):
267
+ conn_info['host'] = connection.info.host
268
+ conn_info['port'] = connection.info.port
269
+ conn_info['dbname'] = connection.info.dbname
270
+ conn_info['user'] = connection.info.user
271
+ elif hasattr(connection, 'dsn'):
272
+ import re
273
+ dsn_params = dict(x.split('=') for x in re.sub(r'\s*=\s*', '=', connection.dsn).split())
274
+ conn_info.update(dsn_params)
275
+ except Exception as e:
276
+ print(f"Failed to extract connection info: {e}")
277
+ return conn_info
278
+
279
+
280
+ def _pool_getconn_wrapper(original_getconn):
281
+ @trace_handler(original_getconn)
282
+ def wrapper(self, *args, **kwargs):
283
+ connection = original_getconn(self, *args, **kwargs)
284
+ conn_info = _get_conn_info(connection)
285
+ db_info = {"type": "postgresql", "pool": True, **conn_info}
286
+
287
+ interceptor_pool_get(db_info)
288
+
289
+ return SyncConnection(connection, db_info)
290
+
291
+ return wrapper
292
+
242
293
 
294
+ def _async_pool_getconn_wrapper(original_getconn):
295
+ @trace_handler(original_getconn)
296
+ async def wrapper(self, *args, **kwargs):
297
+ connection = await original_getconn(self, *args, **kwargs)
298
+ conn_info = _get_conn_info(connection)
299
+ db_info = {"type": "postgresql", "pool": True, **conn_info}
300
+
301
+ await async_interceptor_pool_get(db_info)
302
+
303
+ return AsyncConnection(connection, db_info)
304
+
305
+ return wrapper
306
+
307
+
308
+ def instrument_psycopg(module):
309
+ original_connect = module.connect
243
310
  module.connect = _sync_wrapper(original_connect)
311
+ if hasattr(module, 'AsyncConnection') and hasattr(module.AsyncConnection, 'connect'):
312
+ original_async_connect = module.AsyncConnection.connect
313
+ module.AsyncConnection.connect = _async_wrapper(original_async_connect)
244
314
 
245
- if hasattr(module, 'AsyncConnection'):
246
- async_conn = module.AsyncConnection
247
315
 
248
- if hasattr(async_conn, 'connect'):
249
- original_async_connect = async_conn.connect
250
- async_conn.connect = _async_wrapper(original_async_connect)
316
+ def instrument_psycopg_pool(pool_module):
317
+ if hasattr(pool_module, 'ConnectionPool'):
318
+ pool_module.ConnectionPool.getconn = _pool_getconn_wrapper(pool_module.ConnectionPool.getconn)
319
+ if hasattr(pool_module, 'AsyncConnectionPool'):
320
+ pool_module.AsyncConnectionPool.getconn = _async_pool_getconn_wrapper(pool_module.AsyncConnectionPool.getconn)
251
321
 
@@ -49,7 +49,7 @@ def instrument_sqlalchemy_engine(module):
49
49
  query = None
50
50
  if len(args) > 3 and args[3]:
51
51
  try:
52
- ##oracledb 에서 orm 툴로 sqlalchemy 사용하는 경우
52
+ ##oracle을 사용하는 경우
53
53
  if (type(args[3]) == dict) and (":" in args[2]) and ("oracle" in str(args[0])):
54
54
  oracle_sql_query = args[2]
55
55
  for k, v in args[3].items():
@@ -59,8 +59,8 @@ def instrument_sqlalchemy_engine(module):
59
59
  replaced_value) if replaced_key in oracle_sql_query else None
60
60
  query = oracle_sql_query
61
61
 
62
- ##aiomysql 에서 orm 툴로 sqlalchemy 사용하는 경우
63
- elif (type(args[3]) == tuple) and ("%s" in args[2]) and ("aiomysql" in str(args[0])):
62
+ ##mysql를 사용하는 경우
63
+ elif (type(args[3]) == tuple) and ("%s" in args[2]) and ("mysql" in str(args[0])):
64
64
  my_sql_query = args[2]
65
65
  for v in args[3]:
66
66
  replaced_value = f"'{v}'"
@@ -79,7 +79,7 @@ def instrument_sqlalchemy_engine(module):
79
79
  query = str(args[2])
80
80
  # print('instrument_sqlalchemy_engine 3:', query)
81
81
  sqlalchemy_track_skip = False
82
- except_track_module = ['pymysql', 'mysqldb', 'psycopg2']
82
+ except_track_module = ['pymysql', 'mysqldb', 'psycopg2','psycopg','sqlite3']
83
83
 
84
84
  # 이미 DB드라이브 추적 모듈이 존재하면 sqlAlhechmy 의 추적 중지
85
85
  if any(keyword in str(args[0]) for keyword in except_track_module):
@@ -63,7 +63,6 @@ def addQuoteMany(arg_list, query_template=None):
63
63
  Returns:
64
64
  str: 포매팅된 문자열
65
65
  """
66
- print(arg_list)
67
66
  if not arg_list:
68
67
  return ""
69
68
 
@@ -110,7 +109,6 @@ def addQuoteMany(arg_list, query_template=None):
110
109
 
111
110
  result = ";\n".join(queries)
112
111
 
113
- print(result)
114
112
  return result
115
113
 
116
114
  except Exception as e:
@@ -228,7 +226,6 @@ def interceptor_db_execute(fn, db_info, *args, **kwargs):
228
226
  self = args[0]
229
227
  db_type = db_info.get('type')
230
228
  query = None
231
-
232
229
  if db_type == "neo4j":
233
230
  try:
234
231
  query = neo4jQuery(args[1], kwargs)
@@ -332,8 +329,6 @@ def interceptor_db_close(fn, *args, **kwargs):
332
329
  async_sender.send_packet(PacketTypeEnum.TX_MSG, ctx, datas)
333
330
 
334
331
 
335
- # ===== 비동기 버전 (새로 추가) =====
336
-
337
332
  async def async_interceptor_db_con(fn, db_info, *args, **kwargs):
338
333
  ctx = TraceContextManager.getLocalContext()
339
334
  if not ctx:
@@ -381,7 +376,6 @@ async def async_interceptor_db_execute(fn, db_info, *args, **kwargs):
381
376
  self = args[0]
382
377
  db_type = db_info.get('type')
383
378
  query = None
384
-
385
379
  if db_type == "neo4j":
386
380
  try:
387
381
  query = neo4jQuery(args[1], kwargs)
@@ -491,4 +485,67 @@ async def async_interceptor_db_close(fn, *args, **kwargs):
491
485
  text = 'DB: Close Connection.'
492
486
  datas = [' ', ' ', text]
493
487
  ctx.elapsed = DateUtil.nowSystem() - start_time
494
- async_sender.send_packet(PacketTypeEnum.TX_MSG, ctx, datas)
488
+ async_sender.send_packet(PacketTypeEnum.TX_MSG, ctx, datas)
489
+
490
+
491
+ def interceptor_pool_get(db_info):
492
+ ctx = TraceContextManager.getLocalContext()
493
+ if not ctx:
494
+ return
495
+
496
+ start_time = DateUtil.nowSystem()
497
+
498
+ db_type = db_info.get('type', 'db')
499
+ text = f"{db_type}://{db_info.get('user', '')}@{db_info.get('host', '')}/{db_info.get('dbname', '')}"
500
+
501
+ ctx.active_dbc = text
502
+ ctx.lctx['dbc'] = text
503
+ ctx.active_dbc = 0
504
+
505
+ datas = [text]
506
+ ctx.elapsed = DateUtil.nowSystem() - start_time
507
+
508
+ async_sender.send_packet(PacketTypeEnum.TX_DB_CONN, ctx, datas)
509
+
510
+
511
+ def interceptor_pool_release():
512
+ ctx = TraceContextManager.getLocalContext()
513
+ if not ctx or not conf.profile_dbc_close:
514
+ return
515
+
516
+ start_time = DateUtil.nowSystem()
517
+ text = 'DB: Close Connection.'
518
+ datas = [' ', ' ', text]
519
+ ctx.elapsed = DateUtil.nowSystem() - start_time
520
+ async_sender.send_packet(PacketTypeEnum.TX_MSG, ctx, datas)
521
+
522
+
523
+ async def async_interceptor_pool_get(db_info):
524
+ ctx = TraceContextManager.getLocalContext()
525
+ if not ctx:
526
+ return
527
+
528
+ start_time = DateUtil.nowSystem()
529
+
530
+ db_type = db_info.get('type', 'db')
531
+ text = f"{db_type}://{db_info.get('user', '')}@{db_info.get('host', '')}/{db_info.get('dbname', '')}"
532
+
533
+ ctx.active_dbc = text
534
+ ctx.lctx['dbc'] = text
535
+ ctx.active_dbc = 0
536
+
537
+ datas = [text]
538
+ ctx.elapsed = DateUtil.nowSystem() - start_time
539
+
540
+ async_sender.send_packet(PacketTypeEnum.TX_DB_CONN, ctx, datas)
541
+
542
+ async def async_interceptor_pool_release():
543
+ ctx = TraceContextManager.getLocalContext()
544
+ if not ctx or not conf.profile_dbc_close:
545
+ return
546
+
547
+ start_time = DateUtil.nowSystem()
548
+ text = 'DB: Close Connection.'
549
+ datas = [' ', ' ', text]
550
+ ctx.elapsed = DateUtil.nowSystem() - start_time
551
+ async_sender.send_packet(PacketTypeEnum.TX_MSG, ctx, datas)
@@ -57,7 +57,8 @@ DEFINITION = {
57
57
  ('psycopg2.extensions', 'instrument_psycopg2_extensions'),
58
58
  ],
59
59
  'database.psycopg3': [
60
- ('psycopg', 'instrument_psycopg3')
60
+ ('psycopg', 'instrument_psycopg'),
61
+ ('psycopg_pool', 'instrument_psycopg_pool'),
61
62
  ],
62
63
 
63
64
  'database.neo4j': [
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: whatap-python
3
- Version: 1.8.10
3
+ Version: 1.8.11
4
4
  Summary: Monitoring and Profiling Service
5
5
  Home-page: https://www.whatap.io
6
6
  Author: whatap
@@ -1,4 +0,0 @@
1
- app = 'Python'
2
- name = 'whatap-python'
3
- version = '1.8.10'
4
- release_date = '20250821'
File without changes
File without changes
File without changes