whatap-python 1.8.9.post0__tar.gz → 1.8.14__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.
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/PKG-INFO +1 -1
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/__init__.py +1 -1
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/agent/darwin/amd64/whatap_python +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/agent/darwin/arm64/whatap_python +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/agent/linux/amd64/whatap_python +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/agent/linux/arm64/whatap_python +0 -0
- whatap_python-1.8.14/whatap/build.py +4 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/conf/configuration.py +4 -1
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/counter/__init__.py +2 -2
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/counter/counter_manager.py +12 -5
- whatap_python-1.8.14/whatap/counter/tasks/llm_stat.py +111 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/net/udp_session.py +0 -3
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/application/fastapi.py +1 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/application/wsgi.py +31 -226
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/database/cxoracle.py +2 -2
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/database/mysql.py +2 -3
- whatap_python-1.8.14/whatap/trace/mod/database/neo4j.py +90 -0
- whatap_python-1.8.9.post0/whatap/trace/mod/database/postgresql.py → whatap_python-1.8.14/whatap/trace/mod/database/psycopg2.py +2 -2
- whatap_python-1.8.14/whatap/trace/mod/database/psycopg3.py +359 -0
- whatap_python-1.8.9.post0/whatap/trace/mod/database/toolkit.py → whatap_python-1.8.14/whatap/trace/mod/database/sqlalchemy.py +5 -5
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/database/sqlite3.py +2 -2
- whatap_python-1.8.14/whatap/trace/mod/database/util.py +577 -0
- whatap_python-1.8.14/whatap/trace/mod/httpc/httpx.py +36 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/llm/openai.py +25 -1
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/trace_module_definition.py +10 -2
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap_python.egg-info/PKG-INFO +1 -1
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap_python.egg-info/SOURCES.txt +5 -2
- whatap_python-1.8.9.post0/whatap/build.py +0 -4
- whatap_python-1.8.9.post0/whatap/trace/mod/database/neo4j.py +0 -126
- whatap_python-1.8.9.post0/whatap/trace/mod/httpc/httpx.py +0 -24
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/README.md +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/setup.cfg +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/setup.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/LICENSE +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/README.rst +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/__main__.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/bootstrap/__init__.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/bootstrap/sitecustomize.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/conf/__init__.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/conf/configure.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/conf/license.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/control/__init__.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/counter/tasks/__init__.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/counter/tasks/openfiledescriptor.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/io/__init__.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/io/data_inputx.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/io/data_outputx.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/net/__init__.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/net/async_sender.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/net/packet_enum.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/net/packet_type_enum.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/net/param_def.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/net/stackhelper.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/net/udp_thread.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/pack/__init__.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/pack/logSinkPack.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/pack/pack.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/pack/pack_enum.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/pack/tagCountPack.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/scripts/__init__.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/__init__.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/__init__.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/amqp/__init__.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/amqp/kombu.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/amqp/pika.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/application/__init__.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/application/bottle.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/application/celery.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/application/cherrypy.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/application/django.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/application/django_asgi.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/application/django_py3.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/application/flask.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/application/frappe.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/application/graphql.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/application/nameko.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/application/odoo.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/application/starlette.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/application/tornado.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/database/__init__.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/database/mongo.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/database/redis.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/email/__init__.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/email/smtp.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/httpc/__init__.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/httpc/django.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/httpc/httplib.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/httpc/requests.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/httpc/urllib3.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/llm/__init__.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/logging.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/plugin.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/standalone/__init__.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/standalone/multiple.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/mod/standalone/single.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/simple_trace_context.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/trace_context.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/trace_context_manager.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/trace/trace_import.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/__init__.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/bit_util.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/cardinality/__init__.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/cardinality/hyperloglog.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/cardinality/murmurhash.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/cardinality/registerset.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/compare_util.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/date_util.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/debug_util.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/escape_literal_sql.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/hash_util.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/hexa32.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/int_set.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/ip_util.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/keygen.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/linked_list.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/linked_map.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/metering_util.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/request_double_queue.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/request_queue.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/string_util.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/throttle_util.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/util/userid_util.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/value/__init__.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/value/blob_value.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/value/boolean_value.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/value/decimal_value.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/value/double_summary.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/value/double_value.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/value/float_array.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/value/float_value.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/value/int_array.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/value/ip4_value.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/value/list_value.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/value/long_array.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/value/long_summary.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/value/map_value.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/value/null_value.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/value/number_value.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/value/summary_value.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/value/text_array.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/value/text_hash_value.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/value/text_value.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/value/value.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/value/value_enum.py +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap/whatap.conf +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap_python.egg-info/dependency_links.txt +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap_python.egg-info/entry_points.txt +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap_python.egg-info/not-zip-safe +0 -0
- {whatap_python-1.8.9.post0 → whatap_python-1.8.14}/whatap_python.egg-info/top_level.txt +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -215,6 +215,9 @@ Configuration = {
|
|
|
215
215
|
"log_unhandled_exception": 'false',
|
|
216
216
|
"threadstack_faulthandler": False,
|
|
217
217
|
"max_send_queue_size": 1000,
|
|
218
|
-
"open_file_descriptor_enabled":False,
|
|
218
|
+
"open_file_descriptor_enabled": False,
|
|
219
219
|
"open_file_descriptor_interval":60,
|
|
220
|
+
"counter_thread_enabled": False,
|
|
221
|
+
"llm_stat_enabled" : False,
|
|
222
|
+
"llm_stat_interval" : 5
|
|
220
223
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
from .counter_manager import CounterMgr # CounterMgr 클래스 import
|
|
2
2
|
from whatap import preview_whatap_conf
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
counter_thread_enabled = preview_whatap_conf("counter_thread_enabled")
|
|
5
5
|
|
|
6
|
-
if
|
|
6
|
+
if counter_thread_enabled != 'false':
|
|
7
7
|
mgr = CounterMgr()
|
|
8
8
|
mgr.setDaemon(True)
|
|
9
9
|
mgr.start()
|
|
@@ -3,20 +3,27 @@ import time
|
|
|
3
3
|
import logging
|
|
4
4
|
from threading import Thread
|
|
5
5
|
from .tasks.openfiledescriptor import OpenFileDescriptorTask
|
|
6
|
+
from .tasks.llm_stat import LLMStatTask
|
|
6
7
|
|
|
7
8
|
#현재 디렉토리 아래 tasks 가 있고 그안의 openfiledescriptor.py 파일에 OpenFileDescriptorTask 클래스를 import 하고싶어.
|
|
8
9
|
|
|
9
10
|
class CounterMgr(Thread):
|
|
11
|
+
_instance = None
|
|
10
12
|
def __init__(self):
|
|
11
13
|
super(CounterMgr, self).__init__() # Thread 초기화
|
|
12
14
|
self.tasks = list()
|
|
13
15
|
self.last_executed = {} # 각 task의 마지막 실행 시간을 기록하기 위한 딕셔너리
|
|
14
|
-
|
|
16
|
+
CounterMgr._instance = self
|
|
17
|
+
|
|
15
18
|
def run(self):
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
self.
|
|
19
|
-
|
|
19
|
+
ofd_task = OpenFileDescriptorTask()
|
|
20
|
+
self.tasks.append(ofd_task)
|
|
21
|
+
self.last_executed[ofd_task.name()] = 0 # 각 task의 마지막 실행 시간을 초기화
|
|
22
|
+
|
|
23
|
+
llm_task = LLMStatTask()
|
|
24
|
+
self.tasks.append(llm_task)
|
|
25
|
+
self.last_executed[llm_task.name()] = 0 # 각 task의 마지막 실행 시간을 초기화
|
|
26
|
+
|
|
20
27
|
while True:
|
|
21
28
|
current_time = time.time() # 현재 시간을 초 단위로 가져옴
|
|
22
29
|
time.sleep(1) # 0.1초마다 확인 (부하 줄이기)
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import whatap.net.async_sender as async_sender
|
|
2
|
+
import whatap.io as whatapio
|
|
3
|
+
from whatap.pack import tagCountPack
|
|
4
|
+
from whatap.pack.tagCountPack import TagCountPack
|
|
5
|
+
from whatap.util.hash_util import HashUtil
|
|
6
|
+
from whatap import DateUtil
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import time
|
|
10
|
+
from typing import List, Dict, Tuple
|
|
11
|
+
from collections import defaultdict
|
|
12
|
+
|
|
13
|
+
currentpid = os.getpid()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class LLMStatTask:
|
|
17
|
+
def __init__(self):
|
|
18
|
+
self.llm_stats = {
|
|
19
|
+
'model_calls': defaultdict(int),
|
|
20
|
+
'model_prompt_tokens': defaultdict(int),
|
|
21
|
+
'model_completion_tokens': defaultdict(int)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
def name(self):
|
|
25
|
+
return "LLMStatTask"
|
|
26
|
+
|
|
27
|
+
def interval(self):
|
|
28
|
+
from whatap.conf.configure import Configure as conf
|
|
29
|
+
return int(getattr(conf, 'llm_stat_interval', 5))
|
|
30
|
+
|
|
31
|
+
def process(self):
|
|
32
|
+
from whatap.conf.configure import Configure as conf
|
|
33
|
+
enabled = getattr(conf, 'llm_stat_enabled', False)
|
|
34
|
+
if not enabled:
|
|
35
|
+
return
|
|
36
|
+
|
|
37
|
+
stats = self.get_current_stats()
|
|
38
|
+
|
|
39
|
+
if not stats['model_calls']:
|
|
40
|
+
return
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
p = TagCountPack()
|
|
44
|
+
p.time = DateUtil.now() // 1000 * 1000
|
|
45
|
+
p.Category = "llm_stat"
|
|
46
|
+
p.tags.putAuto("pid", currentpid)
|
|
47
|
+
p.tags.putAuto("!rectype", 2)
|
|
48
|
+
|
|
49
|
+
model_id_list = p.fields.newList("@id")
|
|
50
|
+
model_name_list = p.fields.newList("model_name")
|
|
51
|
+
call_count_list = p.fields.newList("call_count")
|
|
52
|
+
prompt_tokens_list = p.fields.newList("prompt_tokens")
|
|
53
|
+
completion_tokens_list = p.fields.newList("completion_tokens")
|
|
54
|
+
total_tokens_list = p.fields.newList("total_tokens")
|
|
55
|
+
|
|
56
|
+
for model_name, count in stats['model_calls'].items():
|
|
57
|
+
prompt_tokens = stats['model_prompt_tokens'][model_name]
|
|
58
|
+
completion_tokens = stats['model_completion_tokens'][model_name]
|
|
59
|
+
total_tokens = prompt_tokens + completion_tokens
|
|
60
|
+
|
|
61
|
+
model_id_list.addLong(HashUtil.hashFromString(model_name))
|
|
62
|
+
model_name_list.addString(model_name)
|
|
63
|
+
call_count_list.addLong(count)
|
|
64
|
+
prompt_tokens_list.addLong(prompt_tokens)
|
|
65
|
+
completion_tokens_list.addLong(completion_tokens)
|
|
66
|
+
total_tokens_list.addLong(total_tokens)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
p.pcode = getattr(conf, 'PCODE', 0)
|
|
70
|
+
bout = whatapio.DataOutputX()
|
|
71
|
+
bout.writePack(p, None)
|
|
72
|
+
packbytes = bout.toByteArray()
|
|
73
|
+
|
|
74
|
+
async_sender.send_relaypack(packbytes)
|
|
75
|
+
self.reset_stats()
|
|
76
|
+
|
|
77
|
+
except Exception as e:
|
|
78
|
+
import traceback
|
|
79
|
+
traceback.print_exc()
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def get_current_stats(self) -> Dict:
|
|
83
|
+
return {
|
|
84
|
+
'model_calls': dict(self.llm_stats['model_calls']),
|
|
85
|
+
'model_prompt_tokens': dict(self.llm_stats['model_prompt_tokens']),
|
|
86
|
+
'model_completion_tokens': dict(self.llm_stats['model_completion_tokens'])
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
def prepare_model_data(self, model_calls: Dict[str, int]) -> Tuple[List[str], List[int]]:
|
|
90
|
+
if not model_calls:
|
|
91
|
+
return [], []
|
|
92
|
+
|
|
93
|
+
models = list(model_calls.keys())
|
|
94
|
+
call_count = [model_calls[model] for model in models]
|
|
95
|
+
|
|
96
|
+
return models, call_count
|
|
97
|
+
|
|
98
|
+
def update_stats(self, prompt_tokens: int, completion_tokens: int,
|
|
99
|
+
model_name: str):
|
|
100
|
+
self.llm_stats['model_calls'][model_name] += 1
|
|
101
|
+
self.llm_stats['model_prompt_tokens'][model_name] += prompt_tokens
|
|
102
|
+
self.llm_stats['model_completion_tokens'][model_name] += completion_tokens
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def reset_stats(self):
|
|
107
|
+
self.llm_stats = {
|
|
108
|
+
'model_calls': defaultdict(int),
|
|
109
|
+
'model_prompt_tokens': defaultdict(int),
|
|
110
|
+
'model_completion_tokens': defaultdict(int)
|
|
111
|
+
}
|
|
@@ -212,9 +212,6 @@ class UdpSession(object):
|
|
|
212
212
|
datas.append(data)
|
|
213
213
|
|
|
214
214
|
cls.send_packet(PacketTypeEnum.ACTIVE_STACK, None, datas)
|
|
215
|
-
stats = TraceContextManager.getActiveStats()
|
|
216
|
-
datas = [','.join([str(x) for x in stats])]
|
|
217
|
-
cls.send_packet(PacketTypeEnum.ACTIVE_STATS, None, datas)
|
|
218
215
|
else:
|
|
219
216
|
# param pack
|
|
220
217
|
# format: "[packetType], [ctx], [datas: xxxx xxxx xxxx]"
|
|
@@ -77,6 +77,36 @@ def trace_handler(fn, start=False, preload=None):
|
|
|
77
77
|
|
|
78
78
|
return handler
|
|
79
79
|
|
|
80
|
+
def async_trace_handler(fn, start=False, preload=None):
|
|
81
|
+
def handler(func):
|
|
82
|
+
@wraps(func)
|
|
83
|
+
async def wrapper(*args, **kwargs):
|
|
84
|
+
if preload:
|
|
85
|
+
preload(*args, **kwargs)
|
|
86
|
+
|
|
87
|
+
ctx = TraceContextManager.getLocalContext()
|
|
88
|
+
|
|
89
|
+
if not start and not ctx:
|
|
90
|
+
return await fn(*args, **kwargs)
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
callback = await func(*args, **kwargs)
|
|
94
|
+
except Exception as e:
|
|
95
|
+
if ctx and ctx.error_step == e:
|
|
96
|
+
ctx.error_step = None
|
|
97
|
+
raise e
|
|
98
|
+
raise
|
|
99
|
+
else:
|
|
100
|
+
if ctx and ctx.error_step:
|
|
101
|
+
e = ctx.error_step
|
|
102
|
+
ctx.error_step = None
|
|
103
|
+
raise e
|
|
104
|
+
return callback
|
|
105
|
+
|
|
106
|
+
return wrapper
|
|
107
|
+
|
|
108
|
+
return handler
|
|
109
|
+
|
|
80
110
|
|
|
81
111
|
def start_interceptor(ctx):
|
|
82
112
|
if conf.dev:
|
|
@@ -263,6 +293,7 @@ def interceptor_error(status_code, errors, ctx=None):
|
|
|
263
293
|
|
|
264
294
|
|
|
265
295
|
def interceptor_step_error(e, ctx=None):
|
|
296
|
+
from whatap.trace.mod.database.util import extract_db_error_message
|
|
266
297
|
if not ctx:
|
|
267
298
|
ctx = TraceContextManager.getLocalContext()
|
|
268
299
|
if not ctx:
|
|
@@ -301,25 +332,6 @@ def interceptor_step_error(e, ctx=None):
|
|
|
301
332
|
async_sender.send_packet(PacketTypeEnum.TX_MSG, ctx, datas)
|
|
302
333
|
|
|
303
334
|
|
|
304
|
-
def extract_db_error_message(e):
|
|
305
|
-
try:
|
|
306
|
-
# PostgreSQL (psycopg2)
|
|
307
|
-
if hasattr(e, 'pgcode') and hasattr(e, 'pgerror'):
|
|
308
|
-
return str(e.pgerror)
|
|
309
|
-
|
|
310
|
-
# MySQL (PyMySQL, mysql-connector-python)
|
|
311
|
-
if hasattr(e, 'args') and len(e.args) > 1 and isinstance(e.args[1], str):
|
|
312
|
-
return e.args[1]
|
|
313
|
-
|
|
314
|
-
# 기본 에러 메시지
|
|
315
|
-
if hasattr(e, 'args') and len(e.args) > 0:
|
|
316
|
-
if isinstance(e.args[0], str):
|
|
317
|
-
return e.args[0]
|
|
318
|
-
return str(e.args[0])
|
|
319
|
-
|
|
320
|
-
return str(e)
|
|
321
|
-
except:
|
|
322
|
-
return "Unknown database error"
|
|
323
335
|
|
|
324
336
|
|
|
325
337
|
def interceptor_httpc_request(fn, httpc_url, *args, **kwargs):
|
|
@@ -385,213 +397,6 @@ def interceptor_sock_connect(fn, *args, **kwargs):
|
|
|
385
397
|
ctx.socket_connecting = False
|
|
386
398
|
|
|
387
399
|
|
|
388
|
-
def interceptor_db_con(fn, db_info, *args, **kwargs):
|
|
389
|
-
ctx = TraceContextManager.getLocalContext()
|
|
390
|
-
if not ctx:
|
|
391
|
-
return fn(*args, **kwargs)
|
|
392
|
-
|
|
393
|
-
start_time = DateUtil.nowSystem()
|
|
394
|
-
ctx.start_time = start_time
|
|
395
|
-
|
|
396
|
-
ctx.db_opening = True
|
|
397
|
-
try:
|
|
398
|
-
callback = fn(*args, **kwargs)
|
|
399
|
-
finally:
|
|
400
|
-
ctx.db_opening = False
|
|
401
|
-
|
|
402
|
-
if not kwargs:
|
|
403
|
-
kwargs = dict(
|
|
404
|
-
x.split('=') for x in re.sub(r'\s*=\s*', '=', args[0]).split())
|
|
405
|
-
|
|
406
|
-
db_type = db_info.get('type')
|
|
407
|
-
|
|
408
|
-
if db_type == "sqlite":
|
|
409
|
-
text = "sqlite:"
|
|
410
|
-
else:
|
|
411
|
-
text = '{}://'.format(db_type)
|
|
412
|
-
text += kwargs.get('user', '')
|
|
413
|
-
text += "@"
|
|
414
|
-
text += kwargs.get('host', kwargs.get('dsn', ''))
|
|
415
|
-
text += '/'
|
|
416
|
-
|
|
417
|
-
text += kwargs.get('database', kwargs.get('db', kwargs.get('dbname', '')))
|
|
418
|
-
ctx.active_dbc = text
|
|
419
|
-
ctx.lctx['dbc'] = text
|
|
420
|
-
|
|
421
|
-
ctx.active_dbc = 0
|
|
422
|
-
|
|
423
|
-
datas = [text]
|
|
424
|
-
ctx.elapsed = DateUtil.nowSystem() - start_time
|
|
425
|
-
async_sender.send_packet(PacketTypeEnum.TX_DB_CONN, ctx, datas)
|
|
426
|
-
|
|
427
|
-
return callback
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
def addQuoteDict(arg_dict):
|
|
431
|
-
quoted_dict = dict()
|
|
432
|
-
|
|
433
|
-
for k, v in arg_dict.items():
|
|
434
|
-
if isinstance(v, str):
|
|
435
|
-
quoted_dict[k] = "'" + v.replace("'", "\\'") + "'"
|
|
436
|
-
else:
|
|
437
|
-
quoted_dict[k] = v
|
|
438
|
-
|
|
439
|
-
return quoted_dict
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
def addQuoteList(arg_list):
|
|
443
|
-
quoted_list = list()
|
|
444
|
-
|
|
445
|
-
for v in arg_list:
|
|
446
|
-
if isinstance(v, str):
|
|
447
|
-
quoted_list.append("'" + v.replace("'", "\\'") + "'")
|
|
448
|
-
else:
|
|
449
|
-
quoted_list.append("'" + str(v) + "'")
|
|
450
|
-
|
|
451
|
-
return tuple(quoted_list)
|
|
452
|
-
|
|
453
|
-
def neo4jQuery(query,paremeter):
|
|
454
|
-
neo4j_query = query
|
|
455
|
-
|
|
456
|
-
for key, value in paremeter.items():
|
|
457
|
-
placeholder = f"${key}"
|
|
458
|
-
replacement = f"'{str(value)}'"
|
|
459
|
-
neo4j_query = neo4j_query.replace(placeholder, replacement)
|
|
460
|
-
|
|
461
|
-
return neo4j_query
|
|
462
|
-
|
|
463
|
-
def sqliteQuery(query, paremeter):
|
|
464
|
-
sqlite_query = query
|
|
465
|
-
|
|
466
|
-
def quote(v):
|
|
467
|
-
if v is None: return "NULL"
|
|
468
|
-
if isinstance(v, (bytes, bytearray)): return "X'" + v.hex() + "'"
|
|
469
|
-
return "'" + str(v).replace("'", "''") + "'"
|
|
470
|
-
|
|
471
|
-
# 이름 기반: :name / @name / $name (단일 세트)
|
|
472
|
-
if isinstance(paremeter, dict):
|
|
473
|
-
for pfx in (':', '@', '$'):
|
|
474
|
-
for k, v in paremeter.items():
|
|
475
|
-
sqlite_query = sqlite_query.replace(f"{pfx}{k}", quote(v))
|
|
476
|
-
return sqlite_query
|
|
477
|
-
|
|
478
|
-
# 포지셔널 + executemany 분기
|
|
479
|
-
if isinstance(paremeter, (list, tuple)):
|
|
480
|
-
# ── executemany: [tuple|dict, ...] ──
|
|
481
|
-
if isinstance(paremeter, list) and paremeter and isinstance(paremeter[0], (tuple, dict)):
|
|
482
|
-
stmts = []
|
|
483
|
-
for params in paremeter:
|
|
484
|
-
sqlite_query = query
|
|
485
|
-
if isinstance(params, dict):
|
|
486
|
-
for pfx in (':', '@', '$'):
|
|
487
|
-
for k, v in params.items():
|
|
488
|
-
sqlite_query = sqlite_query.replace(f"{pfx}{k}", quote(v))
|
|
489
|
-
else: # tuple
|
|
490
|
-
for i, v in enumerate(params, 1):
|
|
491
|
-
sqlite_query = sqlite_query.replace(f"?{i}", quote(v))
|
|
492
|
-
for v in params:
|
|
493
|
-
sqlite_query = sqlite_query.replace('?', quote(v), 1)
|
|
494
|
-
stmts.append(sqlite_query)
|
|
495
|
-
return ";\n".join(stmts)
|
|
496
|
-
|
|
497
|
-
# ── 단일 포지셔널 세트 (tuple 또는 스칼라 list) ──
|
|
498
|
-
seq = paremeter if isinstance(paremeter, tuple) else tuple(paremeter)
|
|
499
|
-
for i, v in enumerate(seq, 1):
|
|
500
|
-
sqlite_query = sqlite_query.replace(f"?{i}", quote(v))
|
|
501
|
-
for v in seq:
|
|
502
|
-
sqlite_query = sqlite_query.replace('?', quote(v), 1)
|
|
503
|
-
return sqlite_query
|
|
504
|
-
|
|
505
|
-
return sqlite_query
|
|
506
|
-
|
|
507
|
-
def interceptor_db_execute(fn, db_info, *args, **kwargs):
|
|
508
|
-
ctx = TraceContextManager.getLocalContext()
|
|
509
|
-
# sendDebugProfile(ctx, 'interceptor_db_execute step -1')
|
|
510
|
-
self = args[0]
|
|
511
|
-
db_type = db_info.get('type')
|
|
512
|
-
query = None
|
|
513
|
-
|
|
514
|
-
if db_type == "neo4j":
|
|
515
|
-
try:
|
|
516
|
-
query = neo4jQuery(args[1], kwargs)
|
|
517
|
-
except Exception as e:
|
|
518
|
-
pass
|
|
519
|
-
|
|
520
|
-
elif db_type == "sqlite" and len(args) > 2:
|
|
521
|
-
try:
|
|
522
|
-
query = sqliteQuery(args[1],args[2])
|
|
523
|
-
except Exception as e:
|
|
524
|
-
pass
|
|
525
|
-
|
|
526
|
-
else:
|
|
527
|
-
if len(args) > 2 and type(args[2]) == dict and args[2]:
|
|
528
|
-
try:
|
|
529
|
-
query = args[1] % addQuoteDict(args[2])
|
|
530
|
-
except Exception as e:
|
|
531
|
-
pass
|
|
532
|
-
if len(args) > 2 and type(args[2]) in (list, tuple) and args[2]:
|
|
533
|
-
try:
|
|
534
|
-
query = args[1] % addQuoteList(args[2])
|
|
535
|
-
except Exception as e:
|
|
536
|
-
pass
|
|
537
|
-
try:
|
|
538
|
-
if not query:
|
|
539
|
-
query = args[1].decode()
|
|
540
|
-
except Exception as e:
|
|
541
|
-
query = args[1]
|
|
542
|
-
|
|
543
|
-
if not query:
|
|
544
|
-
return fn(*args, **kwargs)
|
|
545
|
-
|
|
546
|
-
start_time = DateUtil.nowSystem()
|
|
547
|
-
ctx.start_time = start_time
|
|
548
|
-
ctx.active_sqlhash = query
|
|
549
|
-
try:
|
|
550
|
-
callback = fn(*args, **kwargs)
|
|
551
|
-
return callback
|
|
552
|
-
except Exception as e:
|
|
553
|
-
interceptor_step_error(e)
|
|
554
|
-
finally:
|
|
555
|
-
datas = [ctx.lctx.get('dbc', ''), query, str(self.rowcount)]
|
|
556
|
-
ctx.elapsed = DateUtil.nowSystem() - start_time
|
|
557
|
-
async_sender.send_packet(PacketTypeEnum.TX_SQL, ctx, datas)
|
|
558
|
-
count = self.rowcount
|
|
559
|
-
|
|
560
|
-
if (count is not None) and (count > -1):
|
|
561
|
-
desc = '{0}: {1}'.format('Fetch count', count)
|
|
562
|
-
datas = [' ', ' ', desc]
|
|
563
|
-
ctx.elapsed = 0
|
|
564
|
-
async_sender.send_packet(PacketTypeEnum.TX_MSG, ctx, datas)
|
|
565
|
-
|
|
566
|
-
ctx.active_sqlhash = 0
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
def interceptor_db_close(fn, *args, **kwargs):
|
|
570
|
-
ctx = TraceContextManager.getLocalContext()
|
|
571
|
-
ctx.db_opening = False
|
|
572
|
-
|
|
573
|
-
if not conf.profile_dbc_close:
|
|
574
|
-
try:
|
|
575
|
-
return fn(*args, **kwargs)
|
|
576
|
-
except Exception as e:
|
|
577
|
-
interceptor_step_error(e)
|
|
578
|
-
finally:
|
|
579
|
-
return
|
|
580
|
-
start_time = DateUtil.nowSystem()
|
|
581
|
-
ctx.start_time = start_time
|
|
582
|
-
|
|
583
|
-
try:
|
|
584
|
-
callback = fn(*args, **kwargs)
|
|
585
|
-
return callback
|
|
586
|
-
except Exception as e:
|
|
587
|
-
interceptor_step_error(e)
|
|
588
|
-
finally:
|
|
589
|
-
text = 'DB: Close Connection.'
|
|
590
|
-
datas = [' ', ' ', text]
|
|
591
|
-
ctx.elapsed = DateUtil.nowSystem() - start_time
|
|
592
|
-
async_sender.send_packet(PacketTypeEnum.TX_MSG, ctx, datas)
|
|
593
|
-
|
|
594
|
-
|
|
595
400
|
check_seq = 1
|
|
596
401
|
|
|
597
402
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from whatap.trace import get_dict
|
|
2
|
-
from whatap.trace.mod.application.wsgi import trace_handler
|
|
3
|
-
|
|
2
|
+
from whatap.trace.mod.application.wsgi import trace_handler
|
|
3
|
+
from whatap.trace.mod.database.util import interceptor_db_con, interceptor_db_execute, interceptor_db_close
|
|
4
4
|
|
|
5
5
|
db_info = {}
|
|
6
6
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from whatap.trace import get_dict
|
|
2
|
-
from whatap.trace.mod.application.wsgi import trace_handler
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
from whatap.trace.mod.application.wsgi import trace_handler
|
|
3
|
+
from whatap.trace.mod.database.util import interceptor_db_con, interceptor_db_execute, interceptor_db_close
|
|
5
4
|
db_info = {}
|
|
6
5
|
|
|
7
6
|
def instrument_MySQLdb(module):
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from whatap.trace.mod.application.wsgi import trace_handler
|
|
2
|
+
from whatap.trace.mod.database.util import interceptor_db_con, interceptor_db_execute, interceptor_db_close
|
|
3
|
+
|
|
4
|
+
db_info = {}
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def instrument_neo4j(module):
|
|
11
|
+
|
|
12
|
+
if hasattr(module, 'GraphDatabase'):
|
|
13
|
+
orig_driver = module.GraphDatabase.driver
|
|
14
|
+
def wrapper(fn):
|
|
15
|
+
@trace_handler(fn)
|
|
16
|
+
def trace(*args, **kwargs):
|
|
17
|
+
db_info = {'type': 'neo4j'}
|
|
18
|
+
|
|
19
|
+
if args:
|
|
20
|
+
db_info['uri'] = args[0]
|
|
21
|
+
|
|
22
|
+
auth = kwargs.get('auth') or (args[1] if len(args) > 1 else None)
|
|
23
|
+
if auth:
|
|
24
|
+
user = getattr(auth, 'principal', None) or (auth[0] if isinstance(auth, tuple) else None)
|
|
25
|
+
if user:
|
|
26
|
+
db_info['user'] = user
|
|
27
|
+
|
|
28
|
+
callback = interceptor_db_con(fn, db_info, *args, **kwargs)
|
|
29
|
+
return callback
|
|
30
|
+
|
|
31
|
+
return trace
|
|
32
|
+
module.GraphDatabase.driver = wrapper(orig_driver)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
if hasattr(module, 'Driver'):
|
|
37
|
+
orig_driver_close = module.Driver.close
|
|
38
|
+
def wrapper(fn):
|
|
39
|
+
@trace_handler(fn)
|
|
40
|
+
def trace(driver, *args, **kwargs):
|
|
41
|
+
callback = interceptor_db_close(fn, driver, *args, **kwargs)
|
|
42
|
+
return callback
|
|
43
|
+
|
|
44
|
+
return trace
|
|
45
|
+
|
|
46
|
+
module.Driver.close = wrapper(orig_driver_close)
|
|
47
|
+
|
|
48
|
+
orig = module.Session.run
|
|
49
|
+
def wrapper(fn):
|
|
50
|
+
@trace_handler(fn)
|
|
51
|
+
def trace(session, *args, **kwargs):
|
|
52
|
+
db_info = {'type': 'neo4j'}
|
|
53
|
+
try:
|
|
54
|
+
setattr(session, 'rowcount', -1)
|
|
55
|
+
except Exception as e:
|
|
56
|
+
raise e
|
|
57
|
+
callback = interceptor_db_execute(fn, db_info, session, *args, **kwargs)
|
|
58
|
+
|
|
59
|
+
return callback
|
|
60
|
+
return trace
|
|
61
|
+
module.Session.run = wrapper(orig)
|
|
62
|
+
|
|
63
|
+
def wrapper(fn):
|
|
64
|
+
@trace_handler(fn)
|
|
65
|
+
def trace(tx, *args, **kwargs):
|
|
66
|
+
session = None
|
|
67
|
+
try:
|
|
68
|
+
session = tx._on_closed.__self__
|
|
69
|
+
except AttributeError:
|
|
70
|
+
return fn(tx, *args, **kwargs)
|
|
71
|
+
db_info = {'type': 'neo4j'}
|
|
72
|
+
try:
|
|
73
|
+
setattr(tx, 'rowcount', -1)
|
|
74
|
+
except Exception:
|
|
75
|
+
pass
|
|
76
|
+
callback = interceptor_db_execute(fn, db_info, tx, *args, **kwargs)
|
|
77
|
+
return callback
|
|
78
|
+
|
|
79
|
+
return trace
|
|
80
|
+
|
|
81
|
+
tx_classes_to_patch = ['Transaction', 'ManagedTransaction', 'BoltTransaction']
|
|
82
|
+
for class_name in tx_classes_to_patch:
|
|
83
|
+
if hasattr(module, class_name):
|
|
84
|
+
TxClass = getattr(module, class_name)
|
|
85
|
+
if hasattr(TxClass, 'run'):
|
|
86
|
+
original_run = getattr(TxClass, 'run')
|
|
87
|
+
setattr(TxClass, 'run', wrapper(original_run))
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from whatap.trace import get_dict
|
|
2
|
-
from whatap.trace.mod.application.wsgi import trace_handler
|
|
3
|
-
|
|
2
|
+
from whatap.trace.mod.application.wsgi import trace_handler
|
|
3
|
+
from whatap.trace.mod.database.util import interceptor_db_con, interceptor_db_execute, interceptor_db_close
|
|
4
4
|
|
|
5
5
|
db_info = {}
|
|
6
6
|
|