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.
Files changed (227) hide show
  1. whatap/LICENSE +0 -0
  2. whatap/README.rst +49 -0
  3. whatap/__init__.py +923 -0
  4. whatap/__main__.py +4 -0
  5. whatap/agent/darwin/amd64/whatap_python +0 -0
  6. whatap/agent/darwin/arm64/whatap_python +0 -0
  7. whatap/agent/linux/amd64/whatap_python +0 -0
  8. whatap/agent/linux/arm64/whatap_python +0 -0
  9. whatap/agent/windows/whatap_python.exe +0 -0
  10. whatap/bootstrap/__init__.py +0 -0
  11. whatap/bootstrap/sitecustomize.py +19 -0
  12. whatap/build.py +4 -0
  13. whatap/conf/__init__.py +0 -0
  14. whatap/conf/configuration.py +280 -0
  15. whatap/conf/configure.py +105 -0
  16. whatap/conf/license.py +49 -0
  17. whatap/control/__init__.py +0 -0
  18. whatap/counter/__init__.py +14 -0
  19. whatap/counter/counter_manager.py +45 -0
  20. whatap/counter/tasks/__init__.py +3 -0
  21. whatap/counter/tasks/base_task.py +26 -0
  22. whatap/counter/tasks/llm_evaluator_task.py +501 -0
  23. whatap/counter/tasks/llm_log_sink_task.py +309 -0
  24. whatap/counter/tasks/llm_stat_task.py +78 -0
  25. whatap/counter/tasks/openfiledescriptor.py +67 -0
  26. whatap/io/__init__.py +1 -0
  27. whatap/io/data_inputx.py +161 -0
  28. whatap/io/data_outputx.py +262 -0
  29. whatap/llm/__init__.py +17 -0
  30. whatap/llm/definitions.py +43 -0
  31. whatap/llm/evaluators/__init__.py +136 -0
  32. whatap/llm/evaluators/base.py +114 -0
  33. whatap/llm/evaluators/builtins/__init__.py +91 -0
  34. whatap/llm/evaluators/builtins/answer_relevance.py +46 -0
  35. whatap/llm/evaluators/builtins/combined_judge.py +271 -0
  36. whatap/llm/evaluators/builtins/factuality.py +71 -0
  37. whatap/llm/evaluators/builtins/hallucination.py +97 -0
  38. whatap/llm/evaluators/builtins/llm_judge.py +516 -0
  39. whatap/llm/evaluators/builtins/pii_leak.py +214 -0
  40. whatap/llm/evaluators/builtins/prompt_injection.py +71 -0
  41. whatap/llm/evaluators/builtins/toxicity.py +53 -0
  42. whatap/llm/evaluators/builtins/url_scan.py +194 -0
  43. whatap/llm/evaluators/registry.py +192 -0
  44. whatap/llm/evaluators/sampler.py +83 -0
  45. whatap/llm/evaluators/scope.py +334 -0
  46. whatap/llm/features.py +66 -0
  47. whatap/llm/log_sink_packs/__init__.py +9 -0
  48. whatap/llm/log_sink_packs/llm_input_message.py +16 -0
  49. whatap/llm/log_sink_packs/llm_log_sink_pack.py +72 -0
  50. whatap/llm/log_sink_packs/llm_output_message.py +19 -0
  51. whatap/llm/log_sink_packs/llm_step_eval_status.py +94 -0
  52. whatap/llm/log_sink_packs/llm_step_status.py +118 -0
  53. whatap/llm/log_sink_packs/llm_system_message.py +16 -0
  54. whatap/llm/log_sink_packs/llm_tool_calls.py +44 -0
  55. whatap/llm/log_sink_packs/llm_tool_results.py +16 -0
  56. whatap/llm/log_sink_packs/llm_tx_status.py +108 -0
  57. whatap/llm/pricing.py +236 -0
  58. whatap/llm/prompt_meta.py +288 -0
  59. whatap/llm/providers/__init__.py +0 -0
  60. whatap/llm/providers/anthropic/__init__.py +37 -0
  61. whatap/llm/providers/anthropic/messages/__init__.py +0 -0
  62. whatap/llm/providers/anthropic/messages/messages.py +70 -0
  63. whatap/llm/providers/anthropic/messages/messages_context.py +76 -0
  64. whatap/llm/providers/anthropic/messages/messages_extractor.py +126 -0
  65. whatap/llm/providers/interceptor.py +182 -0
  66. whatap/llm/providers/openai/__init__.py +133 -0
  67. whatap/llm/providers/openai/chat/__init__.py +0 -0
  68. whatap/llm/providers/openai/chat/chat.py +82 -0
  69. whatap/llm/providers/openai/chat/chat_context.py +78 -0
  70. whatap/llm/providers/openai/chat/chat_extractor.py +127 -0
  71. whatap/llm/providers/openai/completions/__init__.py +0 -0
  72. whatap/llm/providers/openai/completions/completions.py +70 -0
  73. whatap/llm/providers/openai/completions/completions_context.py +31 -0
  74. whatap/llm/providers/openai/completions/completions_extractor.py +61 -0
  75. whatap/llm/providers/openai/content_parser.py +41 -0
  76. whatap/llm/providers/openai/embeddings/__init__.py +0 -0
  77. whatap/llm/providers/openai/embeddings/embeddings.py +59 -0
  78. whatap/llm/providers/openai/embeddings/embeddings_context.py +25 -0
  79. whatap/llm/providers/openai/embeddings/embeddings_extractor.py +26 -0
  80. whatap/llm/providers/openai/responses/__init__.py +0 -0
  81. whatap/llm/providers/openai/responses/responses.py +70 -0
  82. whatap/llm/providers/openai/responses/responses_context.py +88 -0
  83. whatap/llm/providers/openai/responses/responses_extractor.py +126 -0
  84. whatap/llm/providers/stream_accumulator.py +73 -0
  85. whatap/llm/stats/__init__.py +35 -0
  86. whatap/llm/stats/active_stat.py +86 -0
  87. whatap/llm/stats/answer_relevance_eval_stat.py +10 -0
  88. whatap/llm/stats/api_status_stat.py +35 -0
  89. whatap/llm/stats/base_stat.py +107 -0
  90. whatap/llm/stats/combined_judge_eval_stat.py +11 -0
  91. whatap/llm/stats/error_stat.py +59 -0
  92. whatap/llm/stats/eval_stat.py +225 -0
  93. whatap/llm/stats/factuality_eval_stat.py +10 -0
  94. whatap/llm/stats/feature_stat.py +104 -0
  95. whatap/llm/stats/finish_stat.py +105 -0
  96. whatap/llm/stats/hallucination_eval_stat.py +10 -0
  97. whatap/llm/stats/meter.py +18 -0
  98. whatap/llm/stats/perf_stat.py +117 -0
  99. whatap/llm/stats/pii_leak_eval_stat.py +12 -0
  100. whatap/llm/stats/prompt_injection_eval_stat.py +10 -0
  101. whatap/llm/stats/token_usage_stat.py +133 -0
  102. whatap/llm/stats/toxicity_eval_stat.py +10 -0
  103. whatap/llm/stats/url_scan_eval_stat.py +12 -0
  104. whatap/net/__init__.py +0 -0
  105. whatap/net/async_sender.py +107 -0
  106. whatap/net/packet_enum.py +44 -0
  107. whatap/net/packet_type_enum.py +31 -0
  108. whatap/net/param_def.py +69 -0
  109. whatap/net/stackhelper.py +87 -0
  110. whatap/net/udp_session.py +394 -0
  111. whatap/net/udp_thread.py +54 -0
  112. whatap/pack/__init__.py +0 -0
  113. whatap/pack/logSinkPack.py +77 -0
  114. whatap/pack/pack.py +34 -0
  115. whatap/pack/pack_enum.py +41 -0
  116. whatap/pack/tagCountPack.py +61 -0
  117. whatap/scripts/__init__.py +208 -0
  118. whatap/trace/__init__.py +12 -0
  119. whatap/trace/mod/__init__.py +0 -0
  120. whatap/trace/mod/amqp/__init__.py +0 -0
  121. whatap/trace/mod/amqp/kombu.py +122 -0
  122. whatap/trace/mod/amqp/pika.py +62 -0
  123. whatap/trace/mod/application/__init__.py +0 -0
  124. whatap/trace/mod/application/bottle.py +34 -0
  125. whatap/trace/mod/application/celery.py +81 -0
  126. whatap/trace/mod/application/cherrypy.py +30 -0
  127. whatap/trace/mod/application/django.py +287 -0
  128. whatap/trace/mod/application/django_asgi.py +266 -0
  129. whatap/trace/mod/application/django_py3.py +251 -0
  130. whatap/trace/mod/application/fastapi/__init__.py +31 -0
  131. whatap/trace/mod/application/fastapi/endpoint.py +73 -0
  132. whatap/trace/mod/application/fastapi/exception_log.py +63 -0
  133. whatap/trace/mod/application/fastapi/instrumentation.py +204 -0
  134. whatap/trace/mod/application/fastapi/scope.py +115 -0
  135. whatap/trace/mod/application/fastapi/transaction.py +67 -0
  136. whatap/trace/mod/application/flask.py +52 -0
  137. whatap/trace/mod/application/frappe.py +224 -0
  138. whatap/trace/mod/application/graphql.py +170 -0
  139. whatap/trace/mod/application/nameko.py +39 -0
  140. whatap/trace/mod/application/odoo.py +63 -0
  141. whatap/trace/mod/application/starlette.py +126 -0
  142. whatap/trace/mod/application/tornado.py +163 -0
  143. whatap/trace/mod/application/wsgi.py +195 -0
  144. whatap/trace/mod/database/__init__.py +0 -0
  145. whatap/trace/mod/database/cxoracle.py +49 -0
  146. whatap/trace/mod/database/mongo.py +169 -0
  147. whatap/trace/mod/database/mysql.py +80 -0
  148. whatap/trace/mod/database/neo4j.py +90 -0
  149. whatap/trace/mod/database/psycopg2.py +45 -0
  150. whatap/trace/mod/database/psycopg3.py +359 -0
  151. whatap/trace/mod/database/redis.py +122 -0
  152. whatap/trace/mod/database/sqlalchemy.py +213 -0
  153. whatap/trace/mod/database/sqlite3.py +130 -0
  154. whatap/trace/mod/database/util.py +630 -0
  155. whatap/trace/mod/email/__init__.py +0 -0
  156. whatap/trace/mod/email/smtp.py +78 -0
  157. whatap/trace/mod/httpc/__init__.py +0 -0
  158. whatap/trace/mod/httpc/django.py +31 -0
  159. whatap/trace/mod/httpc/httplib.py +70 -0
  160. whatap/trace/mod/httpc/httpx.py +62 -0
  161. whatap/trace/mod/httpc/requests.py +20 -0
  162. whatap/trace/mod/httpc/urllib3.py +27 -0
  163. whatap/trace/mod/httpc/util.py +388 -0
  164. whatap/trace/mod/logging.py +161 -0
  165. whatap/trace/mod/plugin.py +84 -0
  166. whatap/trace/mod/standalone/__init__.py +0 -0
  167. whatap/trace/mod/standalone/multiple.py +293 -0
  168. whatap/trace/mod/standalone/single.py +135 -0
  169. whatap/trace/simple_trace_context.py +18 -0
  170. whatap/trace/trace_context.py +212 -0
  171. whatap/trace/trace_context_manager.py +244 -0
  172. whatap/trace/trace_error.py +84 -0
  173. whatap/trace/trace_handler.py +89 -0
  174. whatap/trace/trace_import.py +91 -0
  175. whatap/trace/trace_module_definition.py +156 -0
  176. whatap/util/__init__.py +0 -0
  177. whatap/util/bit_util.py +49 -0
  178. whatap/util/cardinality/__init__.py +0 -0
  179. whatap/util/cardinality/hyperloglog.py +84 -0
  180. whatap/util/cardinality/murmurhash.py +20 -0
  181. whatap/util/cardinality/registerset.py +60 -0
  182. whatap/util/compare_util.py +19 -0
  183. whatap/util/date_util.py +55 -0
  184. whatap/util/debug_util.py +73 -0
  185. whatap/util/escape_literal_sql.py +233 -0
  186. whatap/util/frame_util.py +20 -0
  187. whatap/util/hash_util.py +103 -0
  188. whatap/util/hexa32.py +66 -0
  189. whatap/util/int_set.py +199 -0
  190. whatap/util/ip_util.py +63 -0
  191. whatap/util/keygen.py +11 -0
  192. whatap/util/linked_list.py +113 -0
  193. whatap/util/linked_map.py +359 -0
  194. whatap/util/metering_util.py +103 -0
  195. whatap/util/request_double_queue.py +68 -0
  196. whatap/util/request_queue.py +60 -0
  197. whatap/util/string_util.py +20 -0
  198. whatap/util/throttle_util.py +99 -0
  199. whatap/util/userid_util.py +134 -0
  200. whatap/value/__init__.py +1 -0
  201. whatap/value/blob_value.py +38 -0
  202. whatap/value/boolean_value.py +33 -0
  203. whatap/value/decimal_value.py +36 -0
  204. whatap/value/double_summary.py +86 -0
  205. whatap/value/double_value.py +33 -0
  206. whatap/value/float_array.py +42 -0
  207. whatap/value/float_value.py +34 -0
  208. whatap/value/int_array.py +42 -0
  209. whatap/value/ip4_value.py +50 -0
  210. whatap/value/list_value.py +105 -0
  211. whatap/value/long_array.py +44 -0
  212. whatap/value/long_summary.py +83 -0
  213. whatap/value/map_value.py +154 -0
  214. whatap/value/null_value.py +21 -0
  215. whatap/value/number_value.py +33 -0
  216. whatap/value/summary_value.py +39 -0
  217. whatap/value/text_array.py +58 -0
  218. whatap/value/text_hash_value.py +37 -0
  219. whatap/value/text_value.py +43 -0
  220. whatap/value/value.py +26 -0
  221. whatap/value/value_enum.py +80 -0
  222. whatap/whatap.conf +14 -0
  223. whatap_python-2.1.0.dist-info/METADATA +87 -0
  224. whatap_python-2.1.0.dist-info/RECORD +227 -0
  225. whatap_python-2.1.0.dist-info/WHEEL +5 -0
  226. whatap_python-2.1.0.dist-info/entry_points.txt +6 -0
  227. whatap_python-2.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,212 @@
1
+ import threading
2
+ import time
3
+
4
+ from whatap.conf.configure import Configure as conf
5
+ from whatap.trace.trace_context_manager import TraceContextManager
6
+ from whatap.util.date_util import DateUtil
7
+ from whatap.util.hexa32 import Hexa32
8
+ from whatap.util.hash_util import HashUtil
9
+
10
+ from whatap.util.linked_map import LinkedMap
11
+ try:
12
+ from resource import getrusage, RUSAGE_SELF
13
+ HAS_RESOURCE = True
14
+ except ImportError:
15
+ # resource module is not available on Windows
16
+ HAS_RESOURCE = False
17
+ import os
18
+
19
+
20
+ class TraceContext(object):
21
+ transfer_id = None
22
+ transfer_info = None
23
+
24
+ def __init__(self):
25
+ self.host = ''
26
+ self.elapsed = 0
27
+
28
+ self.isStaticContents = 'false'
29
+
30
+ self.id = TraceContextManager.getId()
31
+ self.thread = threading.current_thread()
32
+ self.thread_id = self.thread.ident
33
+ TraceContextManager.start(self)
34
+
35
+ self.pid = os.getpid()
36
+
37
+ self.start_time = 0
38
+ self.start_cpu = 0
39
+ self.start_malloc = 0
40
+
41
+ self.status = 0
42
+ self.asgi_response = None
43
+ self.service_hash = 0
44
+ self.service_name = ''
45
+ self.remoteIp = ''
46
+ self.error = 0
47
+ self.error_step = ''
48
+ self.http_method = ''
49
+ self.http_query = ''
50
+ self.http_content_type = ''
51
+
52
+ self.sql_count = 0
53
+ self.sql_time = 0
54
+ self.sql_insert = 0
55
+ self.sql_update = 0
56
+ self.sql_delete = 0
57
+ self.sql_select = 0
58
+ self.sql_others = 0
59
+
60
+ self.executed_sqlhash = 0
61
+ self.active_sqlhash = 0
62
+ self.active_dbc = 0
63
+ self.active_crud = 0
64
+
65
+ self.httpc_checked = False
66
+ self.httpc_count = 0
67
+ self.httpc_time = 0
68
+ self.httpc_url = ''
69
+
70
+ self.active_httpc_hash = 0
71
+ self.active_httpc_start_time = 0
72
+ self.httpc_host = ''
73
+ self.httpc_port = 0
74
+
75
+ self.mtid = 0
76
+ self.mdepth = 0
77
+ self.mcallee = 0
78
+
79
+ self.mcaller_txid = 0
80
+ self.mcaller_pcode = 0
81
+ self.mcaller_spec = ''
82
+ self.mcaller_url = ''
83
+ self.mcaller_poid = ''
84
+ self.transfer_poid = None
85
+
86
+ self.userid = ''
87
+ self._rawuserid = ''
88
+ self.userAgent = 0
89
+ self.userAgentString = ''
90
+ self.referer = ''
91
+ self.login = ''
92
+ self.userTransaction = 0
93
+ self.debug_sql_call = False
94
+ self.lastSqlStep = None
95
+ self.profileActive = 0
96
+
97
+ self.jdbc_updated = False
98
+ self.jdbc_update_record = 0
99
+ self.jdbc_identity = 0
100
+ self.jdbc_commit = 0
101
+ self.resultSql = LinkedMap()
102
+
103
+ self.rs_count = 0
104
+ self.rs_time = 0
105
+ self.db_opening = False
106
+ self.socket_connecting = False
107
+
108
+ self.mcaller_url_hash = 0
109
+ self.mcaller_step_id = 0
110
+
111
+ self.step_id = 0
112
+
113
+ self.lctx = {}
114
+ self.is_ignored = False
115
+ self.driver = ''
116
+ self.is_llm = 0
117
+ self._llm_httpc_pending = False
118
+ self._llm_httpc_url = ''
119
+ self._llm_operation_type = ''
120
+ self._llm_model = ''
121
+ self._llm_provider = ''
122
+
123
+ def getElapsedTime(self, time=None):
124
+ if not time:
125
+ time = DateUtil.now()
126
+ return time - self.start_time
127
+
128
+ def getCpuTime(self):
129
+ return int(time.time())
130
+
131
+ def getMemory(self):
132
+ # https://docs.python.org/3/library/resource.html?highlight=resource#resource-usage
133
+ if HAS_RESOURCE:
134
+ return int(getrusage(RUSAGE_SELF)[3] + getrusage(RUSAGE_SELF)[4])
135
+ else:
136
+ # Windows fallback: use psutil if available, otherwise return 0
137
+ try:
138
+ import psutil
139
+ process = psutil.Process(os.getpid())
140
+ mem_info = process.memory_info()
141
+ return int(mem_info.rss / 1024) # Convert bytes to KB
142
+ except ImportError:
143
+ return 0
144
+
145
+ def resetStartTime(self):
146
+ self.start_time = 0
147
+
148
+ def transfer(self):
149
+ if self.transfer_id:
150
+ return self.transfer_id
151
+
152
+ sb = []
153
+ sb.append(Hexa32.toString32(self.mtid))
154
+ sb.append(str(self.mdepth + 1))
155
+ sb.append(Hexa32.toString32(self.id))
156
+ sb.append(Hexa32.toString32(self.step_id) if self.step_id else '0')
157
+ transfer_id = ','.join(sb)
158
+ return transfer_id
159
+
160
+ def transferInfo(self):
161
+ if self.transfer_info:
162
+ return self.transfer_info
163
+
164
+ sb = []
165
+ sb.append(str(conf.mtrace_spec))
166
+ sb.append(str(self.service_hash))
167
+
168
+ transfer_info = ','.join(sb)
169
+ return transfer_info
170
+
171
+ def setTransfer(self, headerString):
172
+ x = headerString.find(',')
173
+ if x > 0:
174
+ self.mtid = Hexa32.toLong32(headerString[0:x])
175
+ y = headerString.find(',', x + 1)
176
+ if y > 0:
177
+ self.mdepth = int(headerString[x + 1:y])
178
+ z = headerString.find(',', y + 1)
179
+
180
+ if z < 0:
181
+ self.mcaller_txid = Hexa32.toLong32(headerString[y + 1:])
182
+ else:
183
+ self.mcaller_txid = Hexa32.toLong32(headerString[y + 1: z])
184
+ w = headerString.find(',', z + 1)
185
+ if w < 0:
186
+ step_id_str = headerString[z + 1:]
187
+ else:
188
+ step_id_str = headerString[z + 1: w]
189
+ if step_id_str and step_id_str != '0':
190
+ self.mcaller_step_id = Hexa32.toLong32(step_id_str)
191
+
192
+ def setTransferInfo(self, headerString):
193
+ x = headerString.index(',')
194
+ s1 = headerString[0: x]
195
+ self.mcaller_spec = s1
196
+ self.mcaller_url_hash = headerString[x + 1:]
197
+
198
+ def setTxid(self, myid):
199
+ old_id = self.id
200
+ new_id = Hexa32.toLong32(myid)
201
+ self.id = new_id
202
+ TraceContextManager.entry.remove(old_id)
203
+ TraceContextManager.entry.put(new_id, self)
204
+
205
+ def transferPOID(self):
206
+ if not self.transfer_poid:
207
+ self.transfer_poid = ",".join(
208
+ (Hexa32.toString32(conf.PCODE),
209
+ Hexa32.toString32(HashUtil.hashFromString(conf.OKIND) if isinstance(conf.OKIND, str) else conf.OKIND),
210
+ Hexa32.toString32(int(conf.OID))))
211
+
212
+ return self.transfer_poid
@@ -0,0 +1,244 @@
1
+ import os, sys
2
+ import random
3
+ import threading
4
+ import time
5
+ import uuid
6
+ import random
7
+ from collections import defaultdict
8
+ from ctypes import c_int64
9
+ from urllib.parse import urlparse
10
+ from whatap import logging
11
+ from whatap.conf.configure import Configure as conf
12
+ from whatap.io.data_inputx import DataInputX
13
+ from whatap.io.data_outputx import DataOutputX
14
+ from whatap.util.linked_map import LinkedMap
15
+ from whatap.util.hash_util import HashUtil
16
+ from whatap.util.frame_util import set_greenlet_info
17
+
18
+ import whatap.util.date_util as date_util
19
+ if sys.version_info >= (3, 7):
20
+ import contextvars
21
+ else:
22
+ contextvars = None
23
+
24
+ class TraceContextManager(object):
25
+ entry = LinkedMap()
26
+ local = threading.local()
27
+ if contextvars:
28
+ ## python3.7+ support contextvars
29
+ ## contextvars support compatibility with threading.local()
30
+ whatap_coroutine_context = contextvars.ContextVar("whatap_coroutine_context", default=None)
31
+ node = uuid.getnode()
32
+ clock_seq = random.randrange(1 << 14)
33
+ dbpool = LinkedMap()
34
+
35
+ @classmethod
36
+ def keys(cls):
37
+ return cls.entry.keys()
38
+
39
+ @classmethod
40
+ def size(cls):
41
+ return cls.entry.size()
42
+
43
+ @classmethod
44
+ def getActiveCount(cls):
45
+ act = [0 for _ in range(3)]
46
+ try:
47
+ en = cls.entry.values()
48
+ while en.hasMoreElements():
49
+ ctx = en.nextElement()
50
+ elapsed = ctx.getElapsedTime()
51
+ if elapsed < conf.trace_active_transaction_yellow_time:
52
+ act[0] += 1
53
+ elif elapsed < conf.trace_active_transaction_red_time:
54
+ act[1] += 1
55
+ else:
56
+ act[2] += 1
57
+
58
+ except Exception as e:
59
+ logging.debug(e, extra={'id': 'WA310'}, exc_info=True)
60
+
61
+ return act
62
+
63
+ _host_hash_cache = {}
64
+
65
+ @classmethod
66
+ def _get_host_hash(cls, url):
67
+ cached = cls._host_hash_cache.get(url)
68
+ if cached is not None:
69
+ return cached
70
+ try:
71
+ url_str = str(url)
72
+ if '://' not in url_str:
73
+ url_str = 'http://' + url_str
74
+ host = urlparse(url_str).hostname
75
+ if not host:
76
+ return 0
77
+ h = HashUtil.hashFromString(host)
78
+ if len(cls._host_hash_cache) < 1000:
79
+ cls._host_hash_cache[url] = h
80
+ return h
81
+ except Exception:
82
+ return 0
83
+
84
+ @classmethod
85
+ def getActiveStats(cls):
86
+ act = [0 for _ in range(5)]
87
+ httpc_detail = defaultdict(lambda: {'actx': 0, 'acts': [0, 0, 0]})
88
+ now = date_util.DateUtil.nowSystem()
89
+ try:
90
+ en = cls.entry.values()
91
+ while en.hasMoreElements():
92
+ ctx = en.nextElement()
93
+ if ctx.active_sqlhash:
94
+ act[1] += 1 # sql
95
+ elif ctx.active_httpc_hash:
96
+ act[2] += 1 # httpc
97
+ host_hash = cls._get_host_hash(ctx.active_httpc_hash)
98
+ if host_hash:
99
+ stats = httpc_detail[host_hash]
100
+ stats['actx'] += 1
101
+ start_time = getattr(ctx, 'active_httpc_start_time', 0)
102
+ if start_time > 0:
103
+ elapsed_sec = int(now - start_time) // 1000
104
+ if elapsed_sec <= 2:
105
+ stats['acts'][0] += 1
106
+ elif elapsed_sec <= 7:
107
+ stats['acts'][1] += 1
108
+ else:
109
+ stats['acts'][2] += 1
110
+ elif ctx.db_opening:
111
+ act[3] += 1 # dbc
112
+ elif ctx.socket_connecting:
113
+ act[4] += 1 # socket
114
+ else:
115
+ act[0] += 1 # method
116
+ except Exception as e:
117
+ logging.debug(e, extra={'id': 'WA311'}, exc_info=True)
118
+ return act, httpc_detail
119
+
120
+ @classmethod
121
+ def getContextEnumeration(cls):
122
+ return cls.entry.values()
123
+
124
+ @classmethod
125
+ def getContext(cls, key):
126
+ return cls.entry.get(key)
127
+
128
+ @classmethod
129
+ def getLocalContext(cls):
130
+ ##python3.7+ support contextvars
131
+ ##if contextvars is imported, use contextvars first
132
+ if contextvars:
133
+ return cls.whatap_coroutine_context.get()
134
+
135
+ if not bool(cls.local.__dict__):
136
+ cls.local.context = None
137
+ return cls.local.context
138
+
139
+ @classmethod
140
+ def setLocalContext(cls, o):
141
+ o.thread = threading.current_thread()
142
+ o.thread_id = o.thread.ident
143
+
144
+ # greenlet 환경이면 greenlet 정보 저장
145
+ set_greenlet_info(o)
146
+
147
+ if contextvars:
148
+ cls.whatap_coroutine_context.set(o)
149
+ cls.local.context = o
150
+
151
+ @classmethod
152
+ def getId(cls):
153
+ uuid1 = uuid.uuid1(TraceContextManager.node, TraceContextManager.clock_seq)
154
+ key = (uuid1.int >> 64 & 0xffffffffffffffff) ^ (uuid1.int << 64 & 0xffffffffffffffff)
155
+ return c_int64(key).value
156
+
157
+ @classmethod
158
+ def start(cls, o):
159
+ key = o.id
160
+ if contextvars:
161
+ cls.whatap_coroutine_context.set(o)
162
+ cls.local.context = o
163
+ cls.entry.put(key, o)
164
+
165
+ return key
166
+
167
+ @classmethod
168
+ def parseThreadId(cls, key):
169
+ o = cls.entry.get(key)
170
+ if o:
171
+ return o.thread_id, o.pid
172
+ else:
173
+ return None, None
174
+
175
+ @classmethod
176
+ def end(cls, key):
177
+ cls.local.context = None
178
+ cls.entry.remove(key)
179
+
180
+ @classmethod
181
+ def getTxProfile(cls, n):
182
+ ctx = cls.getLocalContext()
183
+ if not ctx:
184
+ return None
185
+ return ctx.profile.getLastSteps(n)
186
+
187
+ @classmethod
188
+ def getCurrentThreadId(cls):
189
+ greenlet = sys.modules.get('greenlet')
190
+
191
+ if greenlet:
192
+ current = greenlet.getcurrent()
193
+ if current is not None and current.parent:
194
+ return id(current.parent)
195
+ return threading.get_ident()
196
+
197
+ @classmethod
198
+ def getDBConnPool(cls):
199
+ d = dict()
200
+ keyvalueEnumer = cls.dbpool.entries()
201
+ while keyvalueEnumer.hasMoreElements():
202
+ en = keyvalueEnumer.nextElement()
203
+ d[en.getKey()] = en.getValue()
204
+ return d
205
+
206
+ @classmethod
207
+ def addDBPoolIdle(cls, url, isCheckIn = False):
208
+ if not cls.dbpool.containsKey(url):
209
+ cls.dbpool.put(url,[0, 0])
210
+
211
+ newstat = cls.dbpool.get(url)
212
+ if isCheckIn:
213
+ newstat[0] -= 1
214
+ if newstat[0] < 0:
215
+ newstat[0] = 0
216
+ newstat[1] += 1
217
+
218
+ cls.dbpool.put(url, newstat)
219
+ return
220
+
221
+ @classmethod
222
+ def removeDBPoolIdle(cls, url):
223
+ if not cls.dbpool.containsKey(url):
224
+ cls.dbpool.put(url,[0, 0])
225
+ return
226
+ newstat = cls.dbpool.get(url)
227
+ if newstat:
228
+ newstat[1] -= 1
229
+ if newstat[1] < 0:
230
+ newstat[1] = 0
231
+ cls.dbpool.put(url, newstat)
232
+
233
+ @classmethod
234
+ def addDBPoolActive(cls, url):
235
+ if not cls.dbpool.containsKey(url):
236
+ cls.dbpool.put(url,[0, 0])
237
+ newstat = cls.dbpool.get(url)
238
+ if newstat:
239
+ newstat[0] += 1
240
+ newstat[1] -= 1
241
+ if newstat[1] < 0:
242
+ newstat[1] = 0
243
+ cls.dbpool.put(url, newstat)
244
+ return
@@ -0,0 +1,84 @@
1
+ import os
2
+ import traceback
3
+
4
+ from whatap.conf.configure import Configure as conf
5
+ from whatap.net.packet_type_enum import PacketTypeEnum
6
+ import whatap.net.async_sender as async_sender
7
+ from whatap.trace.trace_context_manager import TraceContextManager
8
+ from whatap.util.date_util import DateUtil
9
+ from whatap.util.frame_util import get_current_frame
10
+
11
+
12
+ def sendDebugProfile(ctx, msg):
13
+ if ctx:
14
+ ctx.elapsed = 0
15
+ datas = [' ', ' ', 'DEBUG: ' + msg]
16
+ async_sender.send_packet(PacketTypeEnum.TX_MSG, ctx, datas)
17
+
18
+
19
+ def interceptor_error(status_code, errors, ctx=None):
20
+ if not ctx:
21
+ ctx = TraceContextManager.getLocalContext()
22
+ if not ctx:
23
+ return
24
+ ctx.status = status_code
25
+ if status_code >= 400 and not ctx.error:
26
+ ctx.error = 1
27
+
28
+ error = ''
29
+ frame = get_current_frame(ctx)
30
+ if not frame:
31
+ return
32
+
33
+ for stack in traceback.extract_stack(frame):
34
+ line = stack[0]
35
+ line_num = stack[1]
36
+ method_name = stack[2]
37
+
38
+ if 'whatap' + os.sep + 'trace' in line or 'threading.py' in line:
39
+ continue
40
+ error += '{} ({}:{})\n'.format(method_name, line, line_num)
41
+
42
+ errors.append(error)
43
+
44
+ async_sender.send_packet(PacketTypeEnum.TX_ERROR, ctx, errors)
45
+
46
+
47
+ def interceptor_step_error(e, ctx=None):
48
+ from whatap.trace.mod.database.util import extract_db_error_message
49
+ if not ctx:
50
+ ctx = TraceContextManager.getLocalContext()
51
+ if not ctx:
52
+ return
53
+ ctx.error_step = e
54
+ if not ctx.error:
55
+ ctx.error = 1
56
+
57
+ errors = []
58
+ errors.append(e.__class__.__name__)
59
+
60
+ error_message = extract_db_error_message(e)
61
+ errors.append(error_message)
62
+
63
+ error = ''
64
+ frame = get_current_frame(ctx)
65
+ if not frame:
66
+ return
67
+
68
+ for stack in traceback.extract_stack(frame):
69
+ line = stack[0]
70
+ line_num = stack[1]
71
+ method_name = stack[2]
72
+
73
+ if 'whatap' + os.sep + 'trace' in line or 'threading.py' in line:
74
+ continue
75
+ error += '{} ({}:{})\n'.format(method_name, line, line_num)
76
+
77
+ errors.append(error)
78
+ async_sender.send_packet(PacketTypeEnum.TX_ERROR, ctx, errors)
79
+
80
+ if conf.profile_exception_stack:
81
+ desc = '\n'.join(errors)
82
+ datas = [' ', ' ', desc]
83
+ ctx.start_time = DateUtil.nowSystem()
84
+ async_sender.send_packet(PacketTypeEnum.TX_MSG, ctx, datas)
@@ -0,0 +1,89 @@
1
+ from functools import wraps
2
+ from whatap.trace.trace_context_manager import TraceContextManager
3
+
4
+
5
+ def _in_eval_worker():
6
+ """평가 워커 안에서 호출되었고 + judge tracking 옵션이 켜져있는지.
7
+
8
+ 옵션 ``llm_eval_track_judge_calls`` (기본 False) 로 토글:
9
+ - False (기본): judge 호출은 intercept 우회 (short-circuit) → 메트릭/logsink 에 안 잡힘
10
+ - True : judge 호출도 intercept 가 정상 동작 → llm_step_status + 메트릭에 잡힘
11
+
12
+ 재귀 방지는 ``LlmEvaluatorTask.enqueue`` 의 동일 가드로 차단됨.
13
+ Conf 값이 string 'true'/'false' 일 수도 있어 (Configure.setProperty 의 reload 버그)
14
+ 안전하게 string interpret.
15
+ """
16
+ try:
17
+ from whatap.conf.configure import Configure as conf
18
+ val = getattr(conf, 'llm_eval_track_judge_calls', False)
19
+ if isinstance(val, str):
20
+ enabled = val.strip().lower() in ('true', 'yes', '1', 'on')
21
+ else:
22
+ enabled = bool(val)
23
+ if not enabled:
24
+ return False
25
+ from whatap.counter.tasks.llm_evaluator_task import _is_in_evaluator_worker
26
+ return _is_in_evaluator_worker()
27
+ except Exception:
28
+ return False
29
+
30
+
31
+ def trace_handler(fn, start=False, preload=None):
32
+ def handler(func):
33
+ @wraps(func)
34
+ def wrapper(*args, **kwargs):
35
+ if preload:
36
+ preload(*args, **kwargs)
37
+
38
+ ctx = TraceContextManager.getLocalContext()
39
+
40
+ if not start and not ctx and not _in_eval_worker():
41
+ return fn(*args, **kwargs)
42
+
43
+ try:
44
+ callback = func(*args, **kwargs)
45
+ except Exception as e:
46
+ if ctx and ctx.error_step == e:
47
+ ctx.error_step = None
48
+ raise e
49
+ raise
50
+ else:
51
+ if ctx and ctx.error_step:
52
+ e = ctx.error_step
53
+ ctx.error_step = None
54
+ raise e
55
+ return callback
56
+
57
+ return wrapper
58
+
59
+ return handler
60
+
61
+ def async_trace_handler(fn, start=False, preload=None):
62
+ def handler(func):
63
+ @wraps(func)
64
+ async def wrapper(*args, **kwargs):
65
+ if preload:
66
+ preload(*args, **kwargs)
67
+
68
+ ctx = TraceContextManager.getLocalContext()
69
+
70
+ if not start and not ctx and not _in_eval_worker():
71
+ return await fn(*args, **kwargs)
72
+
73
+ try:
74
+ callback = await func(*args, **kwargs)
75
+ except Exception as e:
76
+ if ctx and ctx.error_step == e:
77
+ ctx.error_step = None
78
+ raise e
79
+ raise
80
+ else:
81
+ if ctx and ctx.error_step:
82
+ e = ctx.error_step
83
+ ctx.error_step = None
84
+ raise e
85
+ return callback
86
+
87
+ return wrapper
88
+
89
+ return handler