whatap-python 1.8.11__tar.gz → 1.8.12__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 (147) hide show
  1. {whatap_python-1.8.11 → whatap_python-1.8.12}/PKG-INFO +1 -1
  2. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/__init__.py +1 -1
  3. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/agent/linux/amd64/whatap_python +0 -0
  4. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/agent/linux/arm64/whatap_python +0 -0
  5. whatap_python-1.8.12/whatap/build.py +4 -0
  6. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/conf/configuration.py +4 -1
  7. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/counter/__init__.py +2 -2
  8. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/counter/counter_manager.py +12 -5
  9. whatap_python-1.8.12/whatap/counter/tasks/llm_stat.py +111 -0
  10. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/application/wsgi.py +30 -0
  11. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/database/psycopg3.py +32 -12
  12. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/llm/openai.py +25 -1
  13. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap_python.egg-info/PKG-INFO +1 -1
  14. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap_python.egg-info/SOURCES.txt +1 -0
  15. whatap_python-1.8.11/whatap/build.py +0 -4
  16. {whatap_python-1.8.11 → whatap_python-1.8.12}/README.md +0 -0
  17. {whatap_python-1.8.11 → whatap_python-1.8.12}/setup.cfg +0 -0
  18. {whatap_python-1.8.11 → whatap_python-1.8.12}/setup.py +0 -0
  19. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/LICENSE +0 -0
  20. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/README.rst +0 -0
  21. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/__main__.py +0 -0
  22. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/agent/darwin/amd64/whatap_python +0 -0
  23. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/agent/darwin/arm64/whatap_python +0 -0
  24. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/bootstrap/__init__.py +0 -0
  25. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/bootstrap/sitecustomize.py +0 -0
  26. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/conf/__init__.py +0 -0
  27. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/conf/configure.py +0 -0
  28. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/conf/license.py +0 -0
  29. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/control/__init__.py +0 -0
  30. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/counter/tasks/__init__.py +0 -0
  31. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/counter/tasks/openfiledescriptor.py +0 -0
  32. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/io/__init__.py +0 -0
  33. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/io/data_inputx.py +0 -0
  34. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/io/data_outputx.py +0 -0
  35. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/net/__init__.py +0 -0
  36. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/net/async_sender.py +0 -0
  37. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/net/packet_enum.py +0 -0
  38. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/net/packet_type_enum.py +0 -0
  39. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/net/param_def.py +0 -0
  40. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/net/stackhelper.py +0 -0
  41. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/net/udp_session.py +0 -0
  42. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/net/udp_thread.py +0 -0
  43. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/pack/__init__.py +0 -0
  44. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/pack/logSinkPack.py +0 -0
  45. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/pack/pack.py +0 -0
  46. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/pack/pack_enum.py +0 -0
  47. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/pack/tagCountPack.py +0 -0
  48. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/scripts/__init__.py +0 -0
  49. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/__init__.py +0 -0
  50. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/__init__.py +0 -0
  51. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/amqp/__init__.py +0 -0
  52. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/amqp/kombu.py +0 -0
  53. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/amqp/pika.py +0 -0
  54. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/application/__init__.py +0 -0
  55. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/application/bottle.py +0 -0
  56. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/application/celery.py +0 -0
  57. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/application/cherrypy.py +0 -0
  58. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/application/django.py +0 -0
  59. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/application/django_asgi.py +0 -0
  60. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/application/django_py3.py +0 -0
  61. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/application/fastapi.py +0 -0
  62. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/application/flask.py +0 -0
  63. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/application/frappe.py +0 -0
  64. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/application/graphql.py +0 -0
  65. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/application/nameko.py +0 -0
  66. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/application/odoo.py +0 -0
  67. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/application/starlette.py +0 -0
  68. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/application/tornado.py +0 -0
  69. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/database/__init__.py +0 -0
  70. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/database/cxoracle.py +0 -0
  71. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/database/mongo.py +0 -0
  72. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/database/mysql.py +0 -0
  73. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/database/neo4j.py +0 -0
  74. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/database/psycopg2.py +0 -0
  75. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/database/redis.py +0 -0
  76. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/database/sqlalchemy.py +0 -0
  77. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/database/sqlite3.py +0 -0
  78. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/database/util.py +0 -0
  79. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/email/__init__.py +0 -0
  80. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/email/smtp.py +0 -0
  81. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/httpc/__init__.py +0 -0
  82. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/httpc/django.py +0 -0
  83. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/httpc/httplib.py +0 -0
  84. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/httpc/httpx.py +0 -0
  85. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/httpc/requests.py +0 -0
  86. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/httpc/urllib3.py +0 -0
  87. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/llm/__init__.py +0 -0
  88. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/logging.py +0 -0
  89. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/plugin.py +0 -0
  90. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/standalone/__init__.py +0 -0
  91. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/standalone/multiple.py +0 -0
  92. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/mod/standalone/single.py +0 -0
  93. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/simple_trace_context.py +0 -0
  94. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/trace_context.py +0 -0
  95. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/trace_context_manager.py +0 -0
  96. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/trace_import.py +0 -0
  97. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/trace/trace_module_definition.py +0 -0
  98. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/__init__.py +0 -0
  99. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/bit_util.py +0 -0
  100. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/cardinality/__init__.py +0 -0
  101. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/cardinality/hyperloglog.py +0 -0
  102. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/cardinality/murmurhash.py +0 -0
  103. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/cardinality/registerset.py +0 -0
  104. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/compare_util.py +0 -0
  105. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/date_util.py +0 -0
  106. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/debug_util.py +0 -0
  107. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/escape_literal_sql.py +0 -0
  108. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/hash_util.py +0 -0
  109. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/hexa32.py +0 -0
  110. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/int_set.py +0 -0
  111. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/ip_util.py +0 -0
  112. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/keygen.py +0 -0
  113. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/linked_list.py +0 -0
  114. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/linked_map.py +0 -0
  115. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/metering_util.py +0 -0
  116. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/request_double_queue.py +0 -0
  117. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/request_queue.py +0 -0
  118. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/string_util.py +0 -0
  119. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/throttle_util.py +0 -0
  120. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/util/userid_util.py +0 -0
  121. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/value/__init__.py +0 -0
  122. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/value/blob_value.py +0 -0
  123. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/value/boolean_value.py +0 -0
  124. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/value/decimal_value.py +0 -0
  125. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/value/double_summary.py +0 -0
  126. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/value/double_value.py +0 -0
  127. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/value/float_array.py +0 -0
  128. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/value/float_value.py +0 -0
  129. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/value/int_array.py +0 -0
  130. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/value/ip4_value.py +0 -0
  131. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/value/list_value.py +0 -0
  132. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/value/long_array.py +0 -0
  133. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/value/long_summary.py +0 -0
  134. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/value/map_value.py +0 -0
  135. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/value/null_value.py +0 -0
  136. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/value/number_value.py +0 -0
  137. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/value/summary_value.py +0 -0
  138. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/value/text_array.py +0 -0
  139. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/value/text_hash_value.py +0 -0
  140. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/value/text_value.py +0 -0
  141. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/value/value.py +0 -0
  142. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/value/value_enum.py +0 -0
  143. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap/whatap.conf +0 -0
  144. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap_python.egg-info/dependency_links.txt +0 -0
  145. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap_python.egg-info/entry_points.txt +0 -0
  146. {whatap_python-1.8.11 → whatap_python-1.8.12}/whatap_python.egg-info/not-zip-safe +0 -0
  147. {whatap_python-1.8.11 → whatap_python-1.8.12}/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.11
3
+ Version: 1.8.12
4
4
  Summary: Monitoring and Profiling Service
5
5
  Home-page: https://www.whatap.io
6
6
  Author: whatap
@@ -57,7 +57,7 @@ def preview_whatap_conf(option_name:str):
57
57
  현재 preview_whatap_conf 를 사용중인 옵션
58
58
  - ignore_whatap_stdout (False)
59
59
  - standalone_enabled (False)
60
- - open_file_descriptor_enabled (False)
60
+ - counter_thread_enabled (False)
61
61
  """
62
62
  value = 'false'
63
63
  try:
@@ -0,0 +1,4 @@
1
+ app = 'Python'
2
+ name = 'whatap-python'
3
+ version = '1.8.12'
4
+ release_date = '20250912'
@@ -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
- open_file_descriptor_enabled = preview_whatap_conf("open_file_descriptor_enabled")
4
+ counter_thread_enabled = preview_whatap_conf("counter_thread_enabled")
5
5
 
6
- if open_file_descriptor_enabled != 'false':
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
- # OpenFileDescriptorTask 인스턴스 생성 후 tasks에 추가
17
- task = OpenFileDescriptorTask()
18
- self.tasks.append(task)
19
- self.last_executed[task.name()] = 0 # 각 task의 마지막 실행 시간을 초기화
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
+ }
@@ -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:
@@ -1,6 +1,6 @@
1
1
  import inspect
2
2
 
3
- from whatap.trace.mod.application.wsgi import trace_handler
3
+ from whatap.trace.mod.application.wsgi import trace_handler, async_trace_handler
4
4
  from whatap.trace.mod.database.util import (
5
5
  interceptor_db_con, interceptor_db_execute, interceptor_db_close,
6
6
  async_interceptor_db_con, async_interceptor_db_execute, async_interceptor_db_close,
@@ -236,7 +236,7 @@ def _sync_wrapper(fn):
236
236
 
237
237
 
238
238
  def _async_wrapper(fn):
239
- @trace_handler(fn)
239
+ @async_trace_handler(fn)
240
240
  async def wrapper(*args, **kwargs):
241
241
  if _is_called_by_pool():
242
242
  return await fn(*args, **kwargs)
@@ -278,7 +278,6 @@ def _get_conn_info(connection):
278
278
 
279
279
 
280
280
  def _pool_getconn_wrapper(original_getconn):
281
- @trace_handler(original_getconn)
282
281
  def wrapper(self, *args, **kwargs):
283
282
  connection = original_getconn(self, *args, **kwargs)
284
283
  conn_info = _get_conn_info(connection)
@@ -291,16 +290,34 @@ def _pool_getconn_wrapper(original_getconn):
291
290
  return wrapper
292
291
 
293
292
 
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)
293
+ class AsyncConnectionProxy:
294
+ """AsyncConnectionPool.connection()이 반환하는 proxy 객체를 래핑"""
295
+
296
+ def __init__(self, proxy):
297
+ self._proxy = proxy
298
+ self._wrapped_connection = None
299
+
300
+ async def __aenter__(self):
301
+ connection = await self._proxy.__aenter__()
298
302
  conn_info = _get_conn_info(connection)
299
303
  db_info = {"type": "postgresql", "pool": True, **conn_info}
300
-
301
304
  await async_interceptor_pool_get(db_info)
302
305
 
303
- return AsyncConnection(connection, db_info)
306
+ self._wrapped_connection = AsyncConnection(connection, db_info)
307
+ return self._wrapped_connection
308
+
309
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
310
+ if self._wrapped_connection:
311
+ await async_interceptor_pool_release()
312
+ return await self._proxy.__aexit__(exc_type, exc_val, exc_tb)
313
+
314
+
315
+ def _async_pool_connection_wrapper(original_connection):
316
+ """AsyncConnectionPool.connection() 메서드를 래핑"""
317
+
318
+ def wrapper(self, *args, **kwargs):
319
+ proxy = original_connection(self, *args, **kwargs)
320
+ return AsyncConnectionProxy(proxy)
304
321
 
305
322
  return wrapper
306
323
 
@@ -315,7 +332,10 @@ def instrument_psycopg(module):
315
332
 
316
333
  def instrument_psycopg_pool(pool_module):
317
334
  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)
335
+ if hasattr(pool_module.ConnectionPool, 'getconn'):
336
+ pool_module.ConnectionPool.getconn = _pool_getconn_wrapper(pool_module.ConnectionPool.getconn)
321
337
 
338
+ if hasattr(pool_module, 'AsyncConnectionPool'):
339
+ if hasattr(pool_module.AsyncConnectionPool, 'connection'):
340
+ original_connection = pool_module.AsyncConnectionPool.connection
341
+ pool_module.AsyncConnectionPool.connection = _async_pool_connection_wrapper(original_connection)
@@ -3,8 +3,9 @@ import logging
3
3
 
4
4
  from openai import OpenAIError
5
5
 
6
- from whatap import DateUtil, conf
6
+ from whatap import DateUtil
7
7
  from whatap.pack import logSinkPack
8
+ from whatap.conf.configure import Configure as conf
8
9
  from whatap.trace.trace_context_manager import TraceContextManager
9
10
  from whatap.trace.mod.application.wsgi import trace_handler
10
11
 
@@ -37,6 +38,7 @@ def __send_llm_pack(metadata):
37
38
  'prompt_tokens': metadata.get('prompt_tokens'),
38
39
  'completion_tokens': metadata.get('completion_tokens'),
39
40
  'total_tokens': metadata.get('total_tokens'),
41
+ '@step_id' : ctx.mcallee
40
42
  }
41
43
 
42
44
  fields.update(llm_fields)
@@ -60,6 +62,28 @@ def __send_llm_pack(metadata):
60
62
  tags = {k: v for k, v in tags.items() if v is not None}
61
63
  fields = {k: v for k, v in fields.items() if v is not None}
62
64
 
65
+
66
+ # 4. LLM 통계 데이터 추가 (성공한 경우에만)
67
+ if metadata.get('success', False):
68
+ enabled = getattr(conf, 'llm_stat_enabled', False)
69
+ if not enabled:
70
+ return
71
+
72
+ try:
73
+ from whatap.counter.counter_manager import CounterMgr
74
+ prompt_tokens = metadata.get('prompt_tokens', 0) or 0
75
+ completion_tokens = metadata.get('completion_tokens', 0) or 0
76
+ model_name = metadata.get('model', 'unknown')
77
+
78
+ # 글로벌 카운터 매니저 인스턴스에서 LLM 태스크 찾아서 업데이트
79
+ if hasattr(CounterMgr, '_instance') and CounterMgr._instance:
80
+ for task in CounterMgr._instance.tasks:
81
+ if hasattr(task, 'update_stats') and task.name() == 'LLMStatTask':
82
+ task.update_stats(prompt_tokens, completion_tokens, model_name)
83
+ break
84
+ except Exception as e:
85
+ pass
86
+
63
87
  p = logSinkPack.getLogSinkPack(
64
88
  t=DateUtil.now(),
65
89
  category="LLMResponse",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: whatap-python
3
- Version: 1.8.11
3
+ Version: 1.8.12
4
4
  Summary: Monitoring and Profiling Service
5
5
  Home-page: https://www.whatap.io
6
6
  Author: whatap
@@ -21,6 +21,7 @@ whatap/control/__init__.py
21
21
  whatap/counter/__init__.py
22
22
  whatap/counter/counter_manager.py
23
23
  whatap/counter/tasks/__init__.py
24
+ whatap/counter/tasks/llm_stat.py
24
25
  whatap/counter/tasks/openfiledescriptor.py
25
26
  whatap/io/__init__.py
26
27
  whatap/io/data_inputx.py
@@ -1,4 +0,0 @@
1
- app = 'Python'
2
- name = 'whatap-python'
3
- version = '1.8.11'
4
- release_date = '20250901'
File without changes
File without changes
File without changes