whatap-python 2.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- whatap/LICENSE +0 -0
- whatap/README.rst +49 -0
- whatap/__init__.py +923 -0
- whatap/__main__.py +4 -0
- whatap/agent/darwin/amd64/whatap_python +0 -0
- whatap/agent/darwin/arm64/whatap_python +0 -0
- whatap/agent/linux/amd64/whatap_python +0 -0
- whatap/agent/linux/arm64/whatap_python +0 -0
- whatap/agent/windows/whatap_python.exe +0 -0
- whatap/bootstrap/__init__.py +0 -0
- whatap/bootstrap/sitecustomize.py +19 -0
- whatap/build.py +4 -0
- whatap/conf/__init__.py +0 -0
- whatap/conf/configuration.py +280 -0
- whatap/conf/configure.py +105 -0
- whatap/conf/license.py +49 -0
- whatap/control/__init__.py +0 -0
- whatap/counter/__init__.py +14 -0
- whatap/counter/counter_manager.py +45 -0
- whatap/counter/tasks/__init__.py +3 -0
- whatap/counter/tasks/base_task.py +26 -0
- whatap/counter/tasks/llm_evaluator_task.py +501 -0
- whatap/counter/tasks/llm_log_sink_task.py +309 -0
- whatap/counter/tasks/llm_stat_task.py +78 -0
- whatap/counter/tasks/openfiledescriptor.py +67 -0
- whatap/io/__init__.py +1 -0
- whatap/io/data_inputx.py +161 -0
- whatap/io/data_outputx.py +262 -0
- whatap/llm/__init__.py +17 -0
- whatap/llm/definitions.py +43 -0
- whatap/llm/evaluators/__init__.py +136 -0
- whatap/llm/evaluators/base.py +114 -0
- whatap/llm/evaluators/builtins/__init__.py +91 -0
- whatap/llm/evaluators/builtins/answer_relevance.py +46 -0
- whatap/llm/evaluators/builtins/combined_judge.py +271 -0
- whatap/llm/evaluators/builtins/factuality.py +71 -0
- whatap/llm/evaluators/builtins/hallucination.py +97 -0
- whatap/llm/evaluators/builtins/llm_judge.py +516 -0
- whatap/llm/evaluators/builtins/pii_leak.py +214 -0
- whatap/llm/evaluators/builtins/prompt_injection.py +71 -0
- whatap/llm/evaluators/builtins/toxicity.py +53 -0
- whatap/llm/evaluators/builtins/url_scan.py +194 -0
- whatap/llm/evaluators/registry.py +192 -0
- whatap/llm/evaluators/sampler.py +83 -0
- whatap/llm/evaluators/scope.py +334 -0
- whatap/llm/features.py +66 -0
- whatap/llm/log_sink_packs/__init__.py +9 -0
- whatap/llm/log_sink_packs/llm_input_message.py +16 -0
- whatap/llm/log_sink_packs/llm_log_sink_pack.py +72 -0
- whatap/llm/log_sink_packs/llm_output_message.py +19 -0
- whatap/llm/log_sink_packs/llm_step_eval_status.py +94 -0
- whatap/llm/log_sink_packs/llm_step_status.py +118 -0
- whatap/llm/log_sink_packs/llm_system_message.py +16 -0
- whatap/llm/log_sink_packs/llm_tool_calls.py +44 -0
- whatap/llm/log_sink_packs/llm_tool_results.py +16 -0
- whatap/llm/log_sink_packs/llm_tx_status.py +108 -0
- whatap/llm/pricing.py +236 -0
- whatap/llm/prompt_meta.py +288 -0
- whatap/llm/providers/__init__.py +0 -0
- whatap/llm/providers/anthropic/__init__.py +37 -0
- whatap/llm/providers/anthropic/messages/__init__.py +0 -0
- whatap/llm/providers/anthropic/messages/messages.py +70 -0
- whatap/llm/providers/anthropic/messages/messages_context.py +76 -0
- whatap/llm/providers/anthropic/messages/messages_extractor.py +126 -0
- whatap/llm/providers/interceptor.py +182 -0
- whatap/llm/providers/openai/__init__.py +133 -0
- whatap/llm/providers/openai/chat/__init__.py +0 -0
- whatap/llm/providers/openai/chat/chat.py +82 -0
- whatap/llm/providers/openai/chat/chat_context.py +78 -0
- whatap/llm/providers/openai/chat/chat_extractor.py +127 -0
- whatap/llm/providers/openai/completions/__init__.py +0 -0
- whatap/llm/providers/openai/completions/completions.py +70 -0
- whatap/llm/providers/openai/completions/completions_context.py +31 -0
- whatap/llm/providers/openai/completions/completions_extractor.py +61 -0
- whatap/llm/providers/openai/content_parser.py +41 -0
- whatap/llm/providers/openai/embeddings/__init__.py +0 -0
- whatap/llm/providers/openai/embeddings/embeddings.py +59 -0
- whatap/llm/providers/openai/embeddings/embeddings_context.py +25 -0
- whatap/llm/providers/openai/embeddings/embeddings_extractor.py +26 -0
- whatap/llm/providers/openai/responses/__init__.py +0 -0
- whatap/llm/providers/openai/responses/responses.py +70 -0
- whatap/llm/providers/openai/responses/responses_context.py +88 -0
- whatap/llm/providers/openai/responses/responses_extractor.py +126 -0
- whatap/llm/providers/stream_accumulator.py +73 -0
- whatap/llm/stats/__init__.py +35 -0
- whatap/llm/stats/active_stat.py +86 -0
- whatap/llm/stats/answer_relevance_eval_stat.py +10 -0
- whatap/llm/stats/api_status_stat.py +35 -0
- whatap/llm/stats/base_stat.py +107 -0
- whatap/llm/stats/combined_judge_eval_stat.py +11 -0
- whatap/llm/stats/error_stat.py +59 -0
- whatap/llm/stats/eval_stat.py +225 -0
- whatap/llm/stats/factuality_eval_stat.py +10 -0
- whatap/llm/stats/feature_stat.py +104 -0
- whatap/llm/stats/finish_stat.py +105 -0
- whatap/llm/stats/hallucination_eval_stat.py +10 -0
- whatap/llm/stats/meter.py +18 -0
- whatap/llm/stats/perf_stat.py +117 -0
- whatap/llm/stats/pii_leak_eval_stat.py +12 -0
- whatap/llm/stats/prompt_injection_eval_stat.py +10 -0
- whatap/llm/stats/token_usage_stat.py +133 -0
- whatap/llm/stats/toxicity_eval_stat.py +10 -0
- whatap/llm/stats/url_scan_eval_stat.py +12 -0
- whatap/net/__init__.py +0 -0
- whatap/net/async_sender.py +107 -0
- whatap/net/packet_enum.py +44 -0
- whatap/net/packet_type_enum.py +31 -0
- whatap/net/param_def.py +69 -0
- whatap/net/stackhelper.py +87 -0
- whatap/net/udp_session.py +394 -0
- whatap/net/udp_thread.py +54 -0
- whatap/pack/__init__.py +0 -0
- whatap/pack/logSinkPack.py +77 -0
- whatap/pack/pack.py +34 -0
- whatap/pack/pack_enum.py +41 -0
- whatap/pack/tagCountPack.py +61 -0
- whatap/scripts/__init__.py +208 -0
- whatap/trace/__init__.py +12 -0
- whatap/trace/mod/__init__.py +0 -0
- whatap/trace/mod/amqp/__init__.py +0 -0
- whatap/trace/mod/amqp/kombu.py +122 -0
- whatap/trace/mod/amqp/pika.py +62 -0
- whatap/trace/mod/application/__init__.py +0 -0
- whatap/trace/mod/application/bottle.py +34 -0
- whatap/trace/mod/application/celery.py +81 -0
- whatap/trace/mod/application/cherrypy.py +30 -0
- whatap/trace/mod/application/django.py +287 -0
- whatap/trace/mod/application/django_asgi.py +266 -0
- whatap/trace/mod/application/django_py3.py +251 -0
- whatap/trace/mod/application/fastapi/__init__.py +31 -0
- whatap/trace/mod/application/fastapi/endpoint.py +73 -0
- whatap/trace/mod/application/fastapi/exception_log.py +63 -0
- whatap/trace/mod/application/fastapi/instrumentation.py +204 -0
- whatap/trace/mod/application/fastapi/scope.py +115 -0
- whatap/trace/mod/application/fastapi/transaction.py +67 -0
- whatap/trace/mod/application/flask.py +52 -0
- whatap/trace/mod/application/frappe.py +224 -0
- whatap/trace/mod/application/graphql.py +170 -0
- whatap/trace/mod/application/nameko.py +39 -0
- whatap/trace/mod/application/odoo.py +63 -0
- whatap/trace/mod/application/starlette.py +126 -0
- whatap/trace/mod/application/tornado.py +163 -0
- whatap/trace/mod/application/wsgi.py +195 -0
- whatap/trace/mod/database/__init__.py +0 -0
- whatap/trace/mod/database/cxoracle.py +49 -0
- whatap/trace/mod/database/mongo.py +169 -0
- whatap/trace/mod/database/mysql.py +80 -0
- whatap/trace/mod/database/neo4j.py +90 -0
- whatap/trace/mod/database/psycopg2.py +45 -0
- whatap/trace/mod/database/psycopg3.py +359 -0
- whatap/trace/mod/database/redis.py +122 -0
- whatap/trace/mod/database/sqlalchemy.py +213 -0
- whatap/trace/mod/database/sqlite3.py +130 -0
- whatap/trace/mod/database/util.py +630 -0
- whatap/trace/mod/email/__init__.py +0 -0
- whatap/trace/mod/email/smtp.py +78 -0
- whatap/trace/mod/httpc/__init__.py +0 -0
- whatap/trace/mod/httpc/django.py +31 -0
- whatap/trace/mod/httpc/httplib.py +70 -0
- whatap/trace/mod/httpc/httpx.py +62 -0
- whatap/trace/mod/httpc/requests.py +20 -0
- whatap/trace/mod/httpc/urllib3.py +27 -0
- whatap/trace/mod/httpc/util.py +388 -0
- whatap/trace/mod/logging.py +161 -0
- whatap/trace/mod/plugin.py +84 -0
- whatap/trace/mod/standalone/__init__.py +0 -0
- whatap/trace/mod/standalone/multiple.py +293 -0
- whatap/trace/mod/standalone/single.py +135 -0
- whatap/trace/simple_trace_context.py +18 -0
- whatap/trace/trace_context.py +212 -0
- whatap/trace/trace_context_manager.py +244 -0
- whatap/trace/trace_error.py +84 -0
- whatap/trace/trace_handler.py +89 -0
- whatap/trace/trace_import.py +91 -0
- whatap/trace/trace_module_definition.py +156 -0
- whatap/util/__init__.py +0 -0
- whatap/util/bit_util.py +49 -0
- whatap/util/cardinality/__init__.py +0 -0
- whatap/util/cardinality/hyperloglog.py +84 -0
- whatap/util/cardinality/murmurhash.py +20 -0
- whatap/util/cardinality/registerset.py +60 -0
- whatap/util/compare_util.py +19 -0
- whatap/util/date_util.py +55 -0
- whatap/util/debug_util.py +73 -0
- whatap/util/escape_literal_sql.py +233 -0
- whatap/util/frame_util.py +20 -0
- whatap/util/hash_util.py +103 -0
- whatap/util/hexa32.py +66 -0
- whatap/util/int_set.py +199 -0
- whatap/util/ip_util.py +63 -0
- whatap/util/keygen.py +11 -0
- whatap/util/linked_list.py +113 -0
- whatap/util/linked_map.py +359 -0
- whatap/util/metering_util.py +103 -0
- whatap/util/request_double_queue.py +68 -0
- whatap/util/request_queue.py +60 -0
- whatap/util/string_util.py +20 -0
- whatap/util/throttle_util.py +99 -0
- whatap/util/userid_util.py +134 -0
- whatap/value/__init__.py +1 -0
- whatap/value/blob_value.py +38 -0
- whatap/value/boolean_value.py +33 -0
- whatap/value/decimal_value.py +36 -0
- whatap/value/double_summary.py +86 -0
- whatap/value/double_value.py +33 -0
- whatap/value/float_array.py +42 -0
- whatap/value/float_value.py +34 -0
- whatap/value/int_array.py +42 -0
- whatap/value/ip4_value.py +50 -0
- whatap/value/list_value.py +105 -0
- whatap/value/long_array.py +44 -0
- whatap/value/long_summary.py +83 -0
- whatap/value/map_value.py +154 -0
- whatap/value/null_value.py +21 -0
- whatap/value/number_value.py +33 -0
- whatap/value/summary_value.py +39 -0
- whatap/value/text_array.py +58 -0
- whatap/value/text_hash_value.py +37 -0
- whatap/value/text_value.py +43 -0
- whatap/value/value.py +26 -0
- whatap/value/value_enum.py +80 -0
- whatap/whatap.conf +14 -0
- whatap_python-2.1.0.dist-info/METADATA +87 -0
- whatap_python-2.1.0.dist-info/RECORD +227 -0
- whatap_python-2.1.0.dist-info/WHEEL +5 -0
- whatap_python-2.1.0.dist-info/entry_points.txt +6 -0
- whatap_python-2.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
from collections import defaultdict
|
|
2
|
+
|
|
3
|
+
from whatap.llm.stats.base_stat import BaseStat
|
|
4
|
+
from whatap.util.hash_util import HashUtil
|
|
5
|
+
|
|
6
|
+
_TOKEN_TYPES = [
|
|
7
|
+
'input_tokens', 'output_tokens', 'cached_tokens', 'reasoning_tokens',
|
|
8
|
+
'cache_creation_input_tokens', 'cache_read_input_tokens',
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
_TOKEN_COST_MAP = {
|
|
12
|
+
'input_tokens': 'input_cost',
|
|
13
|
+
'output_tokens': 'output_cost',
|
|
14
|
+
'cached_tokens': 'cached_cost',
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TokenUsageStat(BaseStat):
|
|
19
|
+
_category = "llm_token_usage"
|
|
20
|
+
_is_listed = True
|
|
21
|
+
|
|
22
|
+
def _empty_stats(self):
|
|
23
|
+
return {
|
|
24
|
+
'calls': defaultdict(int),
|
|
25
|
+
'tokens': defaultdict(lambda: defaultdict(int)),
|
|
26
|
+
'token_costs': defaultdict(lambda: defaultdict(float)),
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
def _get_keys(self, stats):
|
|
30
|
+
# call 은 집계됐지만 토큰이 전부 0 인 key (에러 응답, usage 미수신 스트리밍
|
|
31
|
+
# 등) 는 제외한다. 포함하면 _build_fields_listed 에서 한 row 도 추가되지
|
|
32
|
+
# 않아 평행 배열이 비어 있는 채로 pack 이 송출되고, 백엔드에서 빈 칸 row 로
|
|
33
|
+
# 나타난다.
|
|
34
|
+
tokens = stats['tokens']
|
|
35
|
+
return [k for k in stats['calls'].keys()
|
|
36
|
+
if any(v > 0 for v in tokens[k].values())]
|
|
37
|
+
|
|
38
|
+
def update_stats(self, input_tokens, output_tokens,
|
|
39
|
+
model_name, host='', operation_type='default', url='',
|
|
40
|
+
cached_tokens=0, reasoning_tokens=0,
|
|
41
|
+
cache_creation_input_tokens=0, cache_read_input_tokens=0,
|
|
42
|
+
input_cost=0.0, output_cost=0.0, cached_cost=0.0,
|
|
43
|
+
prompt_version='v1'):
|
|
44
|
+
key = (model_name or 'unknown', host or '', operation_type or 'default',
|
|
45
|
+
url or '', prompt_version or 'v1')
|
|
46
|
+
with self._lock:
|
|
47
|
+
self._stats['calls'][key] += 1
|
|
48
|
+
t = self._stats['tokens'][key]
|
|
49
|
+
t['input_tokens'] += input_tokens
|
|
50
|
+
t['output_tokens'] += output_tokens
|
|
51
|
+
t['cached_tokens'] += cached_tokens
|
|
52
|
+
t['reasoning_tokens'] += reasoning_tokens
|
|
53
|
+
t['cache_creation_input_tokens'] += cache_creation_input_tokens
|
|
54
|
+
t['cache_read_input_tokens'] += cache_read_input_tokens
|
|
55
|
+
c = self._stats['token_costs'][key]
|
|
56
|
+
c['input_cost'] += input_cost
|
|
57
|
+
c['output_cost'] += output_cost
|
|
58
|
+
c['cached_cost'] += cached_cost
|
|
59
|
+
|
|
60
|
+
def update_from_pack(self, pack):
|
|
61
|
+
self.update_stats(
|
|
62
|
+
pack.input_tokens or 0,
|
|
63
|
+
pack.output_tokens or 0,
|
|
64
|
+
pack.model or 'unknown',
|
|
65
|
+
host=pack.provider or '',
|
|
66
|
+
operation_type=pack.operation_type or 'default',
|
|
67
|
+
url=pack.url or '',
|
|
68
|
+
cached_tokens=pack.cached_tokens or 0,
|
|
69
|
+
reasoning_tokens=pack.reasoning_tokens or 0,
|
|
70
|
+
cache_creation_input_tokens=pack.cache_creation_input_tokens or 0,
|
|
71
|
+
cache_read_input_tokens=pack.cache_read_input_tokens or 0,
|
|
72
|
+
input_cost=pack.input_cost or 0.0,
|
|
73
|
+
output_cost=pack.output_cost or 0.0,
|
|
74
|
+
cached_cost=pack.cached_cost or 0.0,
|
|
75
|
+
prompt_version=getattr(pack, 'prompt_version', 'v1') or 'v1',
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
def _build_fields_listed(self, pack, stats, keys, pid):
|
|
79
|
+
"""리스트형 메트릭. 모든 key 의 (token_type) row 를 평행 배열로 평탄화.
|
|
80
|
+
|
|
81
|
+
Layout:
|
|
82
|
+
- 키 차원 (row 단위): pid / model / provider / operation_type / url / prompt_version
|
|
83
|
+
- 토큰 차원 (row 단위): tokens / tokens_count / tokens_cost / @id
|
|
84
|
+
|
|
85
|
+
key-level scalar 은 두지 않는다:
|
|
86
|
+
- call_count / error_count / stream_count → llm_perf_stat 으로 이전
|
|
87
|
+
- total_tokens / total_cost → tokens_count / tokens_cost list 합으로
|
|
88
|
+
백엔드에서 도출 (리스트 평행 배열에서 "첫 row 에만 값" 표현은 의미가
|
|
89
|
+
깨지고, 이미 list 필드로 derivable 이라 중복)
|
|
90
|
+
"""
|
|
91
|
+
# 평행 배열 column 들
|
|
92
|
+
id_list = pack.fields.newList("@id")
|
|
93
|
+
pid_list = pack.fields.newList("pid")
|
|
94
|
+
model_list = pack.fields.newList("model")
|
|
95
|
+
provider_list = pack.fields.newList("provider")
|
|
96
|
+
op_type_list = pack.fields.newList("operation_type")
|
|
97
|
+
url_list = pack.fields.newList("url")
|
|
98
|
+
prompt_version_list = pack.fields.newList("prompt_version")
|
|
99
|
+
|
|
100
|
+
tokens_list = pack.fields.newList("tokens")
|
|
101
|
+
tokens_count_list = pack.fields.newList("tokens_count")
|
|
102
|
+
tokens_cost_list = pack.fields.newList("tokens_cost")
|
|
103
|
+
|
|
104
|
+
for key in keys:
|
|
105
|
+
try:
|
|
106
|
+
model, provider, op_type, url, prompt_version = key
|
|
107
|
+
except ValueError:
|
|
108
|
+
model, provider, op_type, url = key
|
|
109
|
+
prompt_version = 'v1'
|
|
110
|
+
|
|
111
|
+
t = stats['tokens'][key]
|
|
112
|
+
c = stats['token_costs'][key]
|
|
113
|
+
|
|
114
|
+
for token_type in _TOKEN_TYPES:
|
|
115
|
+
count = t.get(token_type, 0)
|
|
116
|
+
if count <= 0:
|
|
117
|
+
continue
|
|
118
|
+
|
|
119
|
+
# 토큰 차원
|
|
120
|
+
id_list.addLong(HashUtil.hashFromString(
|
|
121
|
+
"{}:{}:{}:{}:{}".format(model, provider, op_type, prompt_version, token_type)))
|
|
122
|
+
tokens_list.addString(token_type)
|
|
123
|
+
tokens_count_list.addLong(count)
|
|
124
|
+
cost_key = _TOKEN_COST_MAP.get(token_type)
|
|
125
|
+
tokens_cost_list.addFloat(round(c.get(cost_key, 0.0), 6) if cost_key else 0.0)
|
|
126
|
+
|
|
127
|
+
# 키 차원 (모든 row 에 반복)
|
|
128
|
+
pid_list.addLong(pid)
|
|
129
|
+
model_list.addString(model)
|
|
130
|
+
provider_list.addString(provider)
|
|
131
|
+
op_type_list.addString(op_type)
|
|
132
|
+
url_list.addString(url)
|
|
133
|
+
prompt_version_list.addString(prompt_version)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""llm_eval_toxicity 카테고리 — Toxicity 평가 점수 히스토그램.
|
|
2
|
+
|
|
3
|
+
11-bucket 분포 (value0~value10). 자세한 동작은 ``eval_stat.ScoreHistogramStat``
|
|
4
|
+
docstring 참고.
|
|
5
|
+
"""
|
|
6
|
+
from whatap.llm.stats.eval_stat import ScoreHistogramStat
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ToxicityEvalStat(ScoreHistogramStat):
|
|
10
|
+
_category = 'llm_eval_toxicity'
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""llm_eval_url_scan 카테고리 — URL Scan suspicious 점수 히스토그램.
|
|
2
|
+
|
|
3
|
+
11-bucket 분포 (value0~value10). 자세한 동작은 ``eval_stat.ScoreHistogramStat``
|
|
4
|
+
docstring 참고.
|
|
5
|
+
|
|
6
|
+
값 의미: 0.0 = URL 없거나 모두 안전, 1.0 = 모든 URL 이 suspicious.
|
|
7
|
+
"""
|
|
8
|
+
from whatap.llm.stats.eval_stat import ScoreHistogramStat
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class URLScanEvalStat(ScoreHistogramStat):
|
|
12
|
+
_category = 'llm_eval_url_scan'
|
whatap/net/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
import queue, time, threading
|
|
3
|
+
from . import udp_session
|
|
4
|
+
from whatap.conf.configure import Configure as conf
|
|
5
|
+
from whatap.trace.simple_trace_context import SimpleTraceContext
|
|
6
|
+
from whatap.net.packet_type_enum import PacketTypeEnum
|
|
7
|
+
|
|
8
|
+
q = queue.Queue(conf.max_send_queue_size)
|
|
9
|
+
|
|
10
|
+
from enum import Enum
|
|
11
|
+
class SendType(Enum):
|
|
12
|
+
DATAS = 1
|
|
13
|
+
RELAY = 2
|
|
14
|
+
LLM_RELAY = 3
|
|
15
|
+
LLM_FLUSH = 4
|
|
16
|
+
|
|
17
|
+
_LLM_IDLE_FLUSH_SEC = 0.1
|
|
18
|
+
|
|
19
|
+
_STEP_TYPES = {
|
|
20
|
+
PacketTypeEnum.TX_DB_CONN, PacketTypeEnum.TX_DB_FETCH,
|
|
21
|
+
PacketTypeEnum.TX_SQL, PacketTypeEnum.TX_HTTPC,
|
|
22
|
+
PacketTypeEnum.TX_ERROR, PacketTypeEnum.TX_MSG,
|
|
23
|
+
PacketTypeEnum.TX_METHOD,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def send_packet( packet_type, ctx, datas=[]):
|
|
28
|
+
|
|
29
|
+
ctx = SimpleTraceContext(ctx)
|
|
30
|
+
|
|
31
|
+
# deep coopy TraceContext object before adding it to the queue, preventing potential data overwriting issues caused by concurrent modifications
|
|
32
|
+
copied_ctx = ctx.getDeepCopiedContext()
|
|
33
|
+
_initThread()
|
|
34
|
+
global q
|
|
35
|
+
if q.full():
|
|
36
|
+
return
|
|
37
|
+
q.put((SendType.DATAS, (packet_type, copied_ctx, datas)))
|
|
38
|
+
|
|
39
|
+
def send_relaypack( packbytes):
|
|
40
|
+
_initThread()
|
|
41
|
+
global q
|
|
42
|
+
if q.full():
|
|
43
|
+
return
|
|
44
|
+
q.put((SendType.RELAY, packbytes))
|
|
45
|
+
|
|
46
|
+
def send_llm_relaypack( packbytes):
|
|
47
|
+
"""LLM 데이터 전용. LLM Go Agent 소켓으로만 전송."""
|
|
48
|
+
_initThread()
|
|
49
|
+
global q
|
|
50
|
+
if q.full():
|
|
51
|
+
return
|
|
52
|
+
q.put((SendType.LLM_RELAY, packbytes))
|
|
53
|
+
|
|
54
|
+
def flush_llm_relaypack():
|
|
55
|
+
"""LLM 버퍼 명시적 flush 요청. 큐를 거치므로 이전에 enqueue된 LLM_RELAY들이 모두 처리된 뒤 flush된다."""
|
|
56
|
+
_initThread()
|
|
57
|
+
global q
|
|
58
|
+
if q.full():
|
|
59
|
+
return
|
|
60
|
+
q.put((SendType.LLM_FLUSH, None))
|
|
61
|
+
|
|
62
|
+
def startWhatapThread():
|
|
63
|
+
def __sendPackets():
|
|
64
|
+
global q
|
|
65
|
+
while True:
|
|
66
|
+
try:
|
|
67
|
+
packet_env = q.get(timeout=_LLM_IDLE_FLUSH_SEC)
|
|
68
|
+
except queue.Empty:
|
|
69
|
+
# idle 상태에서 LLM 버퍼에 남아있는 데이터 flush
|
|
70
|
+
udp_session.UdpSession.flush_llm_buffer()
|
|
71
|
+
continue
|
|
72
|
+
if not packet_env:
|
|
73
|
+
continue
|
|
74
|
+
sendType,params = packet_env
|
|
75
|
+
if sendType == SendType.DATAS:
|
|
76
|
+
packet_type, ctx, datas = params
|
|
77
|
+
udp_session.UdpSession.send_packet(packet_type, ctx, datas)
|
|
78
|
+
elif sendType == SendType.RELAY:
|
|
79
|
+
packbytes = params
|
|
80
|
+
udp_session.UdpSession.send_relaypack(packbytes)
|
|
81
|
+
elif sendType == SendType.LLM_RELAY:
|
|
82
|
+
packbytes = params
|
|
83
|
+
udp_session.UdpSession.send_llm_relaypack(packbytes)
|
|
84
|
+
elif sendType == SendType.LLM_FLUSH:
|
|
85
|
+
udp_session.UdpSession.flush_llm_buffer()
|
|
86
|
+
t = threading.Thread(target=__sendPackets)
|
|
87
|
+
t.setDaemon(True)
|
|
88
|
+
t.start()
|
|
89
|
+
|
|
90
|
+
_lock = threading.Lock()
|
|
91
|
+
_initialized = False
|
|
92
|
+
|
|
93
|
+
def _initThread():
|
|
94
|
+
global _lock, _initialized
|
|
95
|
+
if _initialized:
|
|
96
|
+
return
|
|
97
|
+
try:
|
|
98
|
+
if _initialized:
|
|
99
|
+
return
|
|
100
|
+
_lock.acquire()
|
|
101
|
+
if _initialized:
|
|
102
|
+
return
|
|
103
|
+
_initialized=True
|
|
104
|
+
startWhatapThread()
|
|
105
|
+
finally:
|
|
106
|
+
_lock.release()
|
|
107
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
class PacketEnum(object):
|
|
2
|
+
PACKET_BUFFER_SIZE = 48 * 1024
|
|
3
|
+
PACKET_SEND_BUFFER_SIZE = 64 * 1024
|
|
4
|
+
DATA_SIZE_LIMIT = 30*1024 +1
|
|
5
|
+
|
|
6
|
+
SERVER = "127.0.0.1"
|
|
7
|
+
PORT = 6600
|
|
8
|
+
PACKET_VERSION = 20106
|
|
9
|
+
|
|
10
|
+
# PACKET_HEADER
|
|
11
|
+
PACKET_HEADER_TYPE_POS = 0
|
|
12
|
+
PACKET_HEADER_TYPE_SIZE = 1
|
|
13
|
+
|
|
14
|
+
PACKET_HEADER_VERSION_POS = 1
|
|
15
|
+
PACKET_HEADER_VERSION_SIZE = 4
|
|
16
|
+
|
|
17
|
+
PACKET_HEADER_LEN_POS = 5
|
|
18
|
+
PACKET_HEADER_LEN_SIZE = 4
|
|
19
|
+
|
|
20
|
+
# PACKET_BODY
|
|
21
|
+
PACKET_BODY_ID_POS = 9
|
|
22
|
+
PACKET_BODY_ID_SIZE = 8
|
|
23
|
+
|
|
24
|
+
PACKET_BODY_START_TIME_POS = 17
|
|
25
|
+
PACKET_BODY_START_TIME_SIZE = 8
|
|
26
|
+
|
|
27
|
+
PACKET_BODY_ELAPSED_POS = 25
|
|
28
|
+
PACKET_BODY_ELAPSED_SIZE = 4
|
|
29
|
+
|
|
30
|
+
PACKET_BODY_CPU_POS = 29
|
|
31
|
+
PACKET_BODY_CPU_SIZE = 8
|
|
32
|
+
|
|
33
|
+
PACKET_BODY_MEMOERY_POS = 37
|
|
34
|
+
PACKET_BODY_MEMOERY_SIZE = 8
|
|
35
|
+
|
|
36
|
+
PACKET_BODY_THREAD_ID_POS = 45
|
|
37
|
+
PACKET_BODY_THREAD_ID_SIZE = 8
|
|
38
|
+
|
|
39
|
+
PACKET_BODY_TRACE_DATA_POS = 53
|
|
40
|
+
|
|
41
|
+
# PACKET_SIZE
|
|
42
|
+
PACKET_HEADER_SIZE = PACKET_HEADER_TYPE_SIZE + PACKET_HEADER_VERSION_SIZE + PACKET_HEADER_LEN_SIZE
|
|
43
|
+
PACKET_BODY_REQUIRED_SIZE = PACKET_BODY_ID_SIZE + PACKET_BODY_START_TIME_SIZE + PACKET_BODY_ELAPSED_SIZE \
|
|
44
|
+
+ PACKET_BODY_CPU_SIZE + PACKET_BODY_MEMOERY_SIZE + PACKET_BODY_THREAD_ID_SIZE
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
class PacketTypeEnum(object):
|
|
2
|
+
TX_BLANK = 0
|
|
3
|
+
TX_START = 1
|
|
4
|
+
TX_DB_CONN = 2
|
|
5
|
+
TX_DB_FETCH = 3
|
|
6
|
+
TX_SQL = 4
|
|
7
|
+
TX_SQL_START = 5
|
|
8
|
+
TX_SQL_END = 6
|
|
9
|
+
|
|
10
|
+
TX_HTTPC = 7
|
|
11
|
+
TX_HTTPC_START = 8
|
|
12
|
+
TX_HTTPC_END = 9
|
|
13
|
+
|
|
14
|
+
TX_ERROR = 10
|
|
15
|
+
TX_MSG = 11
|
|
16
|
+
TX_METHOD = 12
|
|
17
|
+
|
|
18
|
+
# secure msg
|
|
19
|
+
TX_SECURE_MSG = 13
|
|
20
|
+
|
|
21
|
+
TX_WEB_SOCKET = 16
|
|
22
|
+
TX_END = 255
|
|
23
|
+
|
|
24
|
+
TX_PARAM = 30
|
|
25
|
+
ACTIVE_STACK = 40
|
|
26
|
+
ACTIVE_STATS = 41
|
|
27
|
+
DBCONN_POOL = 42
|
|
28
|
+
|
|
29
|
+
EVENT = 50
|
|
30
|
+
|
|
31
|
+
RELAY_PACK = 244
|
whatap/net/param_def.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
class ParamDef(object):
|
|
2
|
+
KEEPALIVE = 1
|
|
3
|
+
AGENT_BOOT_ENV = 2
|
|
4
|
+
CONFIGURE_UPDATE = 3
|
|
5
|
+
CONFIGURE_GET = 4
|
|
6
|
+
COMPO_VERSIONS = 5
|
|
7
|
+
THREAD_LIST = 7
|
|
8
|
+
THREAD_DETAIL = 8
|
|
9
|
+
GET_ACTIVE_STACK = 9
|
|
10
|
+
HEAP_HISTO = 10
|
|
11
|
+
LOADED_CLASS_LIST = 11
|
|
12
|
+
GET_ENV = 12
|
|
13
|
+
SYSTEM_GC = 13
|
|
14
|
+
SET_CONFIG = 14
|
|
15
|
+
OPEN_SOCKET_LIST = 15
|
|
16
|
+
LOADED_CLASS_DETAIL = 16
|
|
17
|
+
LOADED_CLASS_REDEFINE = 17
|
|
18
|
+
AGENT_JAR_LIST = 18
|
|
19
|
+
AGENT_JAR_SAVE = 19
|
|
20
|
+
AGENT_JAR_DELETE = 20
|
|
21
|
+
RESET_STRING_SENT_MARK = 21
|
|
22
|
+
AGENT_LOG_LIST = 22
|
|
23
|
+
AGENT_LOG_READ = 23
|
|
24
|
+
THREAD_CONTROL = 24
|
|
25
|
+
GET_ACTIVE_TRANSACTION_LIST = 25
|
|
26
|
+
GET_ACTIVE_TRANSACTION_DETAIL = 26
|
|
27
|
+
GET_TOPOLOGY = 27
|
|
28
|
+
INFRA_NET_STAT=28
|
|
29
|
+
INFRA_PS_EF=29
|
|
30
|
+
INFRA_DOCKER_LIST=30
|
|
31
|
+
INFRA_REMOTE_CMD=33
|
|
32
|
+
INFRA_PEER_LIST = 34
|
|
33
|
+
INFRA_AGENT_UPDATE = 36
|
|
34
|
+
AGENT_DUMP_LIST = 31
|
|
35
|
+
AGENT_DUMP_READ = 32
|
|
36
|
+
AGENT_STAT = 35
|
|
37
|
+
JVM_THREAD_DUMP = 37
|
|
38
|
+
JVM_HEAP_DUMP = 38
|
|
39
|
+
KUBENETES = 39
|
|
40
|
+
GET_ACTIVE_STATS = 40
|
|
41
|
+
GET_DBCONN_POOL = 41
|
|
42
|
+
MODULE_DEPENDENCY = 101
|
|
43
|
+
DBX_INFO = 201
|
|
44
|
+
DBX_SETTINGS = 202
|
|
45
|
+
DBX_USER_SCRIPT = 207
|
|
46
|
+
DBX_SCRIPT_LIST = 208
|
|
47
|
+
DBX_SCRIPT_SQL = 209
|
|
48
|
+
DBX_KILL_SESSION = 210
|
|
49
|
+
DBX_GET_ALERT = 211
|
|
50
|
+
DBX_SET_ALERT = 212
|
|
51
|
+
DBX_PLAN = 213
|
|
52
|
+
DBX_SESSION_LIST = 214
|
|
53
|
+
DBX_SET_CPUCORES = 215
|
|
54
|
+
DBX_SESSION_STAT = 203
|
|
55
|
+
DBX_SESSION_EVENT = 204
|
|
56
|
+
DBX_TOPSTAT = 205
|
|
57
|
+
DBX_TOPEVENT = 206
|
|
58
|
+
CONFIG_DBC = 301
|
|
59
|
+
METHOD_PERF_STAT = 302
|
|
60
|
+
BLOCKING_DETECT = 303
|
|
61
|
+
CW_INFO = 401
|
|
62
|
+
CW_EVENTS = 402
|
|
63
|
+
CW_CREDENTIAL = 403
|
|
64
|
+
CW_REGIONS = 404
|
|
65
|
+
CW_METRIC_NAMES = 405
|
|
66
|
+
CW_AWS_RESOURCE_IDS = 406
|
|
67
|
+
CW_STATISTICS = 407
|
|
68
|
+
CW_UNITS = 408
|
|
69
|
+
CW_METRICS = 409
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import shlex
|
|
2
|
+
import faulthandler
|
|
3
|
+
import tempfile
|
|
4
|
+
import os
|
|
5
|
+
class StackParser:
|
|
6
|
+
|
|
7
|
+
parsers = {}
|
|
8
|
+
@staticmethod
|
|
9
|
+
def onNewParser(parser):
|
|
10
|
+
StackParser.parsers[parser.getThreadId()] =parser
|
|
11
|
+
|
|
12
|
+
@staticmethod
|
|
13
|
+
def listAll():
|
|
14
|
+
for p in StackParser.parsers:
|
|
15
|
+
yield p
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
def find(cls, thread_id):
|
|
19
|
+
if thread_id in cls.parsers:
|
|
20
|
+
p = cls.parsers.get(thread_id)
|
|
21
|
+
return p.iterateStacks()
|
|
22
|
+
else:
|
|
23
|
+
return iter([])
|
|
24
|
+
|
|
25
|
+
@staticmethod
|
|
26
|
+
def parse():
|
|
27
|
+
with tempfile.NamedTemporaryFile() as buf:
|
|
28
|
+
faulthandler.dump_traceback(buf)
|
|
29
|
+
if buf.tell() < 1:
|
|
30
|
+
return
|
|
31
|
+
buf.seek(0)
|
|
32
|
+
stackdump = buf.read().decode("utf-8")
|
|
33
|
+
stackParser = None
|
|
34
|
+
for stack in stackdump.split('\n'):
|
|
35
|
+
if not stack:
|
|
36
|
+
stackParser.onComplete()
|
|
37
|
+
stackParser = None
|
|
38
|
+
continue
|
|
39
|
+
if not stackParser:
|
|
40
|
+
stackParser = StackParser(stack)
|
|
41
|
+
else:
|
|
42
|
+
stackParser.add(stack)
|
|
43
|
+
|
|
44
|
+
def __init__(self, threadBegin):
|
|
45
|
+
self.__stacks = []
|
|
46
|
+
tokens = shlex.split(threadBegin)
|
|
47
|
+
if tokens and len(tokens) > 2:
|
|
48
|
+
try:
|
|
49
|
+
if 'Thread' == tokens[0] and int(tokens[1],0) > 0:
|
|
50
|
+
threadid = int(tokens[1],0)
|
|
51
|
+
self.__threadid = threadid
|
|
52
|
+
|
|
53
|
+
StackParser.onNewParser(self)
|
|
54
|
+
elif 'Current' == tokens[0] and 'thread' == tokens[1] and int(tokens[2],0):
|
|
55
|
+
threadid = int(tokens[2],0)
|
|
56
|
+
self.__threadid = threadid
|
|
57
|
+
|
|
58
|
+
StackParser.onNewParser(self)
|
|
59
|
+
except ValueError:
|
|
60
|
+
pass
|
|
61
|
+
|
|
62
|
+
def getThreadId(self):
|
|
63
|
+
return self.__threadid
|
|
64
|
+
|
|
65
|
+
def add(self, line):
|
|
66
|
+
tokens = shlex.split(line)
|
|
67
|
+
if len(tokens) == 6:
|
|
68
|
+
_, module, _, lineno, _, method = tokens
|
|
69
|
+
self.__stacks.append((module.strip(','), lineno, method))
|
|
70
|
+
|
|
71
|
+
def iterateStacks(self):
|
|
72
|
+
return iter(self.__stacks)
|
|
73
|
+
|
|
74
|
+
def toString(self):
|
|
75
|
+
return """Thread: {}
|
|
76
|
+
{}""".format(self.__threadid, "\n".join([ "{} {} {}".format(stack[0],stack[1],stack[2]) for stack in self.__stacks]))
|
|
77
|
+
|
|
78
|
+
def onComplete(self):
|
|
79
|
+
pass
|
|
80
|
+
|
|
81
|
+
def getThreadStackFaultHandler( thread_id):
|
|
82
|
+
StackParser.parse()
|
|
83
|
+
for line, line_num, method_name in StackParser.find(thread_id):
|
|
84
|
+
if 'whatap' + os.sep + 'trace' in line or 'threading.py' in line:
|
|
85
|
+
continue
|
|
86
|
+
yield '{} ({}:{})\n'.format(method_name, line, line_num)
|
|
87
|
+
|