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,63 @@
|
|
|
1
|
+
import traceback
|
|
2
|
+
from whatap import logging
|
|
3
|
+
from whatap.trace.trace_handler import trace_handler
|
|
4
|
+
from whatap.trace.trace_error import interceptor_error
|
|
5
|
+
from whatap.trace.mod.application.wsgi import interceptor
|
|
6
|
+
from whatap.trace.trace_context_manager import TraceContextManager
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def instrument(module):
|
|
10
|
+
root = module.http.root
|
|
11
|
+
AppClass = root.__class__
|
|
12
|
+
original_call = AppClass.__call__
|
|
13
|
+
|
|
14
|
+
def wrapper(fn):
|
|
15
|
+
@trace_handler(fn, True)
|
|
16
|
+
def trace(self, environ, start_response):
|
|
17
|
+
def custom_start_response(status, headers, exc_info=None):
|
|
18
|
+
ctx = TraceContextManager.getLocalContext()
|
|
19
|
+
try:
|
|
20
|
+
ctx.status = int(status.split()[0])
|
|
21
|
+
except Exception as e:
|
|
22
|
+
logging.warning('[ODOO] status parse failed: %s' % e, extra={'id': 'ODOO001'})
|
|
23
|
+
ctx.status = 0
|
|
24
|
+
return start_response(status, headers, exc_info)
|
|
25
|
+
try:
|
|
26
|
+
callback = interceptor(fn, self, environ, custom_start_response)
|
|
27
|
+
except Exception as e:
|
|
28
|
+
interceptor_error(
|
|
29
|
+
500 , #해당 status 값은 에러 처리용으로만 사용됩니다.
|
|
30
|
+
[e.__class__.__name__, str(e)]
|
|
31
|
+
)
|
|
32
|
+
raise
|
|
33
|
+
return callback
|
|
34
|
+
|
|
35
|
+
return trace
|
|
36
|
+
|
|
37
|
+
AppClass.__call__ = wrapper(original_call)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
"""
|
|
41
|
+
Odoo 16+ HttpDispatcher.handle_error 패치
|
|
42
|
+
"""
|
|
43
|
+
Dispatcher = getattr(module.http, 'HttpDispatcher', None)
|
|
44
|
+
|
|
45
|
+
if Dispatcher:
|
|
46
|
+
original_handle_error = Dispatcher.handle_error
|
|
47
|
+
|
|
48
|
+
def wrapper(fn):
|
|
49
|
+
@trace_handler(fn)
|
|
50
|
+
def trace(self,exception):
|
|
51
|
+
ctx = TraceContextManager.getLocalContext()
|
|
52
|
+
interceptor_error(
|
|
53
|
+
500, # 해당 status 값은 에러 처리용으로만 사용됩니다.
|
|
54
|
+
[exception.__class__.__name__,
|
|
55
|
+
str(exception)],
|
|
56
|
+
ctx=ctx
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
callback = fn(self, exception)
|
|
60
|
+
return callback
|
|
61
|
+
|
|
62
|
+
return trace
|
|
63
|
+
Dispatcher.handle_error = wrapper(Dispatcher.handle_error)
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import whatap.net.async_sender as async_sender
|
|
2
|
+
from whatap.trace.trace_context import TraceContext
|
|
3
|
+
from whatap.trace.trace_context_manager import TraceContextManager
|
|
4
|
+
from whatap.net.packet_type_enum import PacketTypeEnum
|
|
5
|
+
from whatap.util.date_util import DateUtil
|
|
6
|
+
from whatap.util.userid_util import UseridUtil as userid_util
|
|
7
|
+
from whatap.trace.trace_error import interceptor_step_error
|
|
8
|
+
from whatap.trace.mod.application.wsgi import \
|
|
9
|
+
start_interceptor,end_interceptor
|
|
10
|
+
from whatap.conf.configure import Configure as conf
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def intercept_websocket(web_socket, data: str):
|
|
16
|
+
try:
|
|
17
|
+
ctx = TraceContext()
|
|
18
|
+
|
|
19
|
+
scope = web_socket.scope
|
|
20
|
+
headers = dict(scope.get("headers", [])) # headers는 리스트(tuple) 형태
|
|
21
|
+
query_string = scope.get("query_string", b'').decode()
|
|
22
|
+
client = scope.get("client", ("0.0.0.0", 0))
|
|
23
|
+
|
|
24
|
+
# 기본 ctx 설정
|
|
25
|
+
ctx.service_name = scope.get("path", "WebSocket")
|
|
26
|
+
if query_string:
|
|
27
|
+
ctx.service_name += f"?{query_string}"
|
|
28
|
+
ctx.http_method = "WEBSOCKET"
|
|
29
|
+
ctx.remoteIp = client[0]
|
|
30
|
+
ctx.port = client[1]
|
|
31
|
+
|
|
32
|
+
# User-Agent, Referer 추출 (바이트를 디코딩)
|
|
33
|
+
ctx.userAgentString = headers.get(b'user-agent', b'').decode()
|
|
34
|
+
ctx.referer = headers.get(b'referer', b'').decode()
|
|
35
|
+
|
|
36
|
+
# userid 관련
|
|
37
|
+
if conf.trace_user_enabled:
|
|
38
|
+
if conf.trace_user_using_ip:
|
|
39
|
+
ctx.userid = ctx.remoteIp
|
|
40
|
+
else:
|
|
41
|
+
ctx.userid, ctx._rawuserid = userid_util.getUserId([scope], ctx.remoteIp)
|
|
42
|
+
|
|
43
|
+
# 트랜잭션 전파 관련
|
|
44
|
+
mstt = headers.get(f"HTTP_{conf._trace_mtrace_caller_key}".encode(), b'').decode()
|
|
45
|
+
if mstt:
|
|
46
|
+
ctx.setTransfer(mstt)
|
|
47
|
+
if conf.stat_mtrace_enabled:
|
|
48
|
+
val = headers.get(f"HTTP_{conf._trace_mtrace_info_key}".encode(), b'').decode()
|
|
49
|
+
if val:
|
|
50
|
+
ctx.setTransferInfo(val)
|
|
51
|
+
txid = headers.get(f"HTTP_{conf._trace_mtrace_callee_key}".encode(), b'').decode()
|
|
52
|
+
if txid:
|
|
53
|
+
ctx.setTxid(txid)
|
|
54
|
+
|
|
55
|
+
poid = headers.get(f"HTTP_{conf._trace_mtrace_caller_poid_key}".encode(), b'').decode()
|
|
56
|
+
if poid:
|
|
57
|
+
ctx.mcaller_poid = poid
|
|
58
|
+
|
|
59
|
+
start_interceptor(ctx)
|
|
60
|
+
|
|
61
|
+
start_time = DateUtil.nowSystem()
|
|
62
|
+
ctx.start_time = start_time
|
|
63
|
+
ctx.error = 0
|
|
64
|
+
ctx.elapsed = 0
|
|
65
|
+
|
|
66
|
+
datas = [ctx.remoteIp, ctx.port, ctx.elapsed, ctx.error]
|
|
67
|
+
async_sender.send_packet(PacketTypeEnum.TX_WEB_SOCKET, ctx, datas)
|
|
68
|
+
|
|
69
|
+
except Exception as e:
|
|
70
|
+
interceptor_step_error(e)
|
|
71
|
+
finally:
|
|
72
|
+
end_interceptor(ctx=ctx)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def instrument_starlette_websocket(module):
|
|
76
|
+
|
|
77
|
+
if not conf.trace_websocket_enabled:
|
|
78
|
+
return
|
|
79
|
+
|
|
80
|
+
OriginalWebSocket = module.WebSocket
|
|
81
|
+
if getattr(OriginalWebSocket, "_whatap_patched", False):
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
#original_accept = OriginalWebSocket.accept
|
|
85
|
+
original_send_text = OriginalWebSocket.send_text
|
|
86
|
+
original_send_bytes = OriginalWebSocket.send_bytes
|
|
87
|
+
original_send_json = OriginalWebSocket.send_json
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# # 연결 시점도 래핑은 하지만, APM 인터셉트는 하지 않음
|
|
91
|
+
# async def wrapped_accept(self, *args, **kwargs):
|
|
92
|
+
# try:
|
|
93
|
+
# pass
|
|
94
|
+
# except Exception as e:
|
|
95
|
+
# interceptor_step_error(e)
|
|
96
|
+
# return await original_accept(self, *args, **kwargs)
|
|
97
|
+
|
|
98
|
+
async def wrapped_send_text(self, data: str):
|
|
99
|
+
try:
|
|
100
|
+
intercept_websocket(self, data)
|
|
101
|
+
except Exception as e:
|
|
102
|
+
interceptor_step_error(e)
|
|
103
|
+
return await original_send_text(self, data)
|
|
104
|
+
|
|
105
|
+
async def wrapped_send_bytes(self, data: bytes):
|
|
106
|
+
try:
|
|
107
|
+
intercept_websocket(self, None)
|
|
108
|
+
except Exception as e:
|
|
109
|
+
interceptor_step_error(e)
|
|
110
|
+
return await original_send_bytes(self, data)
|
|
111
|
+
|
|
112
|
+
async def wrapped_send_json(self, data: Any):
|
|
113
|
+
try:
|
|
114
|
+
intercept_websocket(self, None)
|
|
115
|
+
except Exception as e:
|
|
116
|
+
interceptor_step_error(e)
|
|
117
|
+
return await original_send_json(self, data)
|
|
118
|
+
|
|
119
|
+
#OriginalWebSocket.accept = wrapped_accept
|
|
120
|
+
OriginalWebSocket.send_text = wrapped_send_text
|
|
121
|
+
OriginalWebSocket.send_bytes = wrapped_send_bytes
|
|
122
|
+
OriginalWebSocket.send_json = wrapped_send_json
|
|
123
|
+
OriginalWebSocket._whatap_patched = True
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
import whatap.net.async_sender as async_sender
|
|
3
|
+
from whatap.net.packet_type_enum import PacketTypeEnum
|
|
4
|
+
from whatap.util.userid_util import UseridUtil as userid_util
|
|
5
|
+
from whatap.trace.trace_context import TraceContext
|
|
6
|
+
from whatap.trace.trace_context_manager import TraceContextManager
|
|
7
|
+
from whatap.util.date_util import DateUtil
|
|
8
|
+
from whatap.conf.configure import Configure as conf
|
|
9
|
+
from whatap.trace.trace_handler import trace_handler
|
|
10
|
+
from whatap.trace.trace_error import interceptor_error
|
|
11
|
+
from whatap.trace.mod.application.wsgi import \
|
|
12
|
+
start_interceptor, end_interceptor, isIgnore
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def parseServiceName(environ):
|
|
16
|
+
return environ.get('PATH_INFO', '')
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def instrument(module):
|
|
20
|
+
def wrapper(fn):
|
|
21
|
+
async def trace(*args, **kwargs):
|
|
22
|
+
request = args[0].request
|
|
23
|
+
environ = {
|
|
24
|
+
'HTTP_HOST': request.host,
|
|
25
|
+
'PATH_INFO': request.path,
|
|
26
|
+
'QUERY_STRING': request.query_arguments,
|
|
27
|
+
'REMOTE_ADDR': request.remote_ip,
|
|
28
|
+
'HTTP_USER_AGENT': request.headers.get('User-Agent', ''),
|
|
29
|
+
'HTTP_REFERER': request.headers.get('Referer', ''),
|
|
30
|
+
'REQUEST_METHOD': request.method
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
for header_name, value in request.headers.items():
|
|
34
|
+
key = 'HTTP_' + header_name.upper().replace('-', '_')
|
|
35
|
+
environ[key] = value
|
|
36
|
+
|
|
37
|
+
async def run():
|
|
38
|
+
await interceptor((fn, environ), *args, **kwargs)
|
|
39
|
+
|
|
40
|
+
from tornado.ioloop import IOLoop
|
|
41
|
+
IOLoop.current().add_callback(run)
|
|
42
|
+
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
return trace
|
|
46
|
+
|
|
47
|
+
module.RequestHandler._execute = wrapper(module.RequestHandler._execute)
|
|
48
|
+
|
|
49
|
+
def wrapper(fn):
|
|
50
|
+
@trace_handler(fn)
|
|
51
|
+
def trace(*args, **kwargs):
|
|
52
|
+
callback = fn(*args, **kwargs)
|
|
53
|
+
|
|
54
|
+
e = args[1]
|
|
55
|
+
status_code = args[0]._status_code
|
|
56
|
+
errors = [e.__class__.__name__, str(e)]
|
|
57
|
+
interceptor_error(status_code, errors)
|
|
58
|
+
return callback
|
|
59
|
+
|
|
60
|
+
return trace
|
|
61
|
+
|
|
62
|
+
module.RequestHandler._handle_request_exception = wrapper(
|
|
63
|
+
module.RequestHandler._handle_request_exception)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
async def interceptor(rn_environ, *args, **kwargs):
|
|
67
|
+
if not isinstance(rn_environ, tuple):
|
|
68
|
+
rn_environ = (rn_environ, args[1])
|
|
69
|
+
fn, environ = rn_environ
|
|
70
|
+
|
|
71
|
+
ctx = TraceContext()
|
|
72
|
+
ctx.host = environ.get('HTTP_HOST', '').split(':')[0]
|
|
73
|
+
ctx.service_name = parseServiceName(environ)
|
|
74
|
+
ctx.http_method = environ.get('REQUEST_METHOD', '')
|
|
75
|
+
ctx.remoteIp = userid_util.getRemoteAddr(args)
|
|
76
|
+
ctx.userAgentString = environ.get('HTTP_USER_AGENT', '')
|
|
77
|
+
ctx.referer = environ.get('HTTP_REFERER', '')
|
|
78
|
+
|
|
79
|
+
if conf.trace_user_enabled:
|
|
80
|
+
if conf.trace_user_using_ip:
|
|
81
|
+
ctx.userid = userid_util.getRemoteAddr(args)
|
|
82
|
+
else:
|
|
83
|
+
ctx.userid, ctx._rawuserid = userid_util.getUserId(args, ctx.remoteIp)
|
|
84
|
+
|
|
85
|
+
mstt = environ.get('HTTP_{}'.format(
|
|
86
|
+
conf._trace_mtrace_caller_key.upper().replace('-', '_')), '')
|
|
87
|
+
|
|
88
|
+
if mstt:
|
|
89
|
+
ctx.setTransfer(mstt)
|
|
90
|
+
if conf.stat_mtrace_enabled:
|
|
91
|
+
val = environ.get('HTTP_{}'.format(
|
|
92
|
+
conf._trace_mtrace_info_key.upper().replace('-', '_')), '')
|
|
93
|
+
if val and len(val):
|
|
94
|
+
ctx.setTransferInfo(val)
|
|
95
|
+
pass
|
|
96
|
+
|
|
97
|
+
myid = environ.get('HTTP_{}'.format(
|
|
98
|
+
conf._trace_mtrace_callee_key.upper().replace('-', '_')), '')
|
|
99
|
+
if myid:
|
|
100
|
+
ctx.setTxid(myid)
|
|
101
|
+
caller_poid = environ.get('HTTP_{}'.format(
|
|
102
|
+
conf._trace_mtrace_caller_poid_key.upper().replace('-', '_')), '')
|
|
103
|
+
|
|
104
|
+
if caller_poid:
|
|
105
|
+
ctx.mcaller_poid = caller_poid
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
if isIgnore(ctx.service_name):
|
|
109
|
+
ctx.is_ignored = True
|
|
110
|
+
TraceContextManager.end(ctx.id)
|
|
111
|
+
callback = fn(*args, **kwargs)
|
|
112
|
+
if inspect.isawaitable(callback):
|
|
113
|
+
return await callback
|
|
114
|
+
return callback
|
|
115
|
+
except Exception:
|
|
116
|
+
pass
|
|
117
|
+
|
|
118
|
+
start_interceptor(ctx)
|
|
119
|
+
|
|
120
|
+
try:
|
|
121
|
+
callback = fn(*args, **kwargs)
|
|
122
|
+
if inspect.isawaitable(callback):
|
|
123
|
+
callback = await callback
|
|
124
|
+
|
|
125
|
+
query_string = environ.get('QUERY_STRING', '')
|
|
126
|
+
if query_string:
|
|
127
|
+
ctx.service_name += '?{}'.format(query_string)
|
|
128
|
+
|
|
129
|
+
if ctx.service_name.find('.') > -1 and ctx.service_name.split('.')[
|
|
130
|
+
1] in conf.web_static_content_extensions:
|
|
131
|
+
ctx.isStaticContents = 'true'
|
|
132
|
+
|
|
133
|
+
handler = args[0]
|
|
134
|
+
status_code = getattr(handler, '_status_code', 200)
|
|
135
|
+
if status_code >= 400:
|
|
136
|
+
errors = [
|
|
137
|
+
callback.__class__.__name__ if callback else 'Unknown',
|
|
138
|
+
getattr(callback, 'reason_phrase', '')
|
|
139
|
+
]
|
|
140
|
+
interceptor_error(status_code, errors, ctx=ctx)
|
|
141
|
+
|
|
142
|
+
else:
|
|
143
|
+
ctx.status = status_code
|
|
144
|
+
|
|
145
|
+
if conf.profile_http_header_enabled:
|
|
146
|
+
keys = []
|
|
147
|
+
for key, value in environ.items():
|
|
148
|
+
if key.startswith('HTTP_'):
|
|
149
|
+
keys.append(key)
|
|
150
|
+
keys.sort()
|
|
151
|
+
|
|
152
|
+
text = ''
|
|
153
|
+
for key in keys:
|
|
154
|
+
text += '{}={}\n'.format(key.split('HTTP_')[1].lower(),
|
|
155
|
+
environ[key])
|
|
156
|
+
|
|
157
|
+
datas = ['HTTP-HEADERS', 'HTTP-HEADERS', text]
|
|
158
|
+
ctx.start_time = DateUtil.nowSystem()
|
|
159
|
+
async_sender.send_packet(PacketTypeEnum.TX_MSG, ctx, datas)
|
|
160
|
+
|
|
161
|
+
return callback
|
|
162
|
+
finally:
|
|
163
|
+
end_interceptor(ctx=ctx)
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import traceback
|
|
3
|
+
import threading
|
|
4
|
+
|
|
5
|
+
from whatap.conf.configure import Configure as conf
|
|
6
|
+
from whatap.net.packet_type_enum import PacketTypeEnum
|
|
7
|
+
import whatap.net.async_sender as async_sender
|
|
8
|
+
from whatap.trace.trace_context import TraceContext
|
|
9
|
+
from whatap.trace.trace_context_manager import TraceContextManager
|
|
10
|
+
from whatap.util.date_util import DateUtil
|
|
11
|
+
from whatap.util.hash_util import HashUtil
|
|
12
|
+
from whatap.util.userid_util import UseridUtil as userid_util
|
|
13
|
+
from whatap import logging
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def isEventlet():
|
|
17
|
+
greenlet = sys.modules.get('greenlet')
|
|
18
|
+
|
|
19
|
+
if greenlet:
|
|
20
|
+
current = greenlet.getcurrent()
|
|
21
|
+
if current is not None and current.parent:
|
|
22
|
+
print('thread:', threading.get_ident(), 'greenlet:', id(current.parent))
|
|
23
|
+
traceback.print_stack()
|
|
24
|
+
return True
|
|
25
|
+
else:
|
|
26
|
+
return False
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
from whatap.trace.trace_error import interceptor_error
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def start_interceptor(ctx):
|
|
34
|
+
if conf.dev:
|
|
35
|
+
logging.debug('start transaction id(seq): {}'.format(ctx.id),
|
|
36
|
+
extra={'id': 'WA111'})
|
|
37
|
+
print('start transaction id(seq): {}'.format(ctx.id), dict(extra={'id': 'WA111'}))
|
|
38
|
+
|
|
39
|
+
start_time = DateUtil.nowSystem()
|
|
40
|
+
ctx.start_time = start_time
|
|
41
|
+
|
|
42
|
+
if ctx.service_name and not ctx.service_hash:
|
|
43
|
+
ctx.service_hash = HashUtil.hashFromString(ctx.service_name)
|
|
44
|
+
|
|
45
|
+
datas = [ctx.host,
|
|
46
|
+
ctx.service_name,
|
|
47
|
+
ctx.remoteIp,
|
|
48
|
+
ctx.userAgentString,
|
|
49
|
+
ctx.referer,
|
|
50
|
+
ctx.userid,
|
|
51
|
+
ctx.isStaticContents,
|
|
52
|
+
ctx.http_method
|
|
53
|
+
]
|
|
54
|
+
# print("start_interceptor txid:", ctx.id)
|
|
55
|
+
async_sender.send_packet(PacketTypeEnum.TX_START, ctx, datas)
|
|
56
|
+
|
|
57
|
+
return ctx
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def end_interceptor(thread_id=None, ctx=None):
|
|
61
|
+
if not ctx:
|
|
62
|
+
ctx = TraceContextManager.getContext(
|
|
63
|
+
thread_id) if thread_id else TraceContextManager.getLocalContext()
|
|
64
|
+
if not ctx:
|
|
65
|
+
return
|
|
66
|
+
|
|
67
|
+
if conf.dev:
|
|
68
|
+
logging.debug('end transaction id(seq): {}'.format(ctx.id),
|
|
69
|
+
extra={'id': 'WA112'})
|
|
70
|
+
print('end transaction id(seq): {}'.format(ctx.id),
|
|
71
|
+
dict(extra={'id': 'WA112'}))
|
|
72
|
+
|
|
73
|
+
start_time = DateUtil.nowSystem()
|
|
74
|
+
ctx.start_time = start_time
|
|
75
|
+
|
|
76
|
+
datas = [ctx.host, ctx.service_name, ctx.mtid, ctx.mdepth, ctx.mcaller_txid,
|
|
77
|
+
ctx.mcaller_pcode, ctx.mcaller_spec, str(ctx.mcaller_url_hash), ctx.mcaller_poid, ctx.status,
|
|
78
|
+
ctx.is_llm, ctx.mcaller_step_id]
|
|
79
|
+
ctx.elapsed = DateUtil.nowSystem() - start_time
|
|
80
|
+
|
|
81
|
+
async_sender.send_packet(PacketTypeEnum.TX_END, ctx, datas)
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
from whatap.counter.tasks.llm_log_sink_task import send_llm_tx_status
|
|
85
|
+
send_llm_tx_status(ctx)
|
|
86
|
+
from whatap.counter.tasks.llm_stat_task import LlmStatTask
|
|
87
|
+
if LlmStatTask._instance:
|
|
88
|
+
LlmStatTask._instance.flush_last_error(ctx)
|
|
89
|
+
except Exception:
|
|
90
|
+
pass
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def parseServiceName(environ):
|
|
94
|
+
return environ.get('PATH_INFO', '')
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def isIgnore(service_name):
|
|
98
|
+
if conf.trace_ignore_url_prefix and service_name.startswith(conf.trace_ignore_url_prefix):
|
|
99
|
+
return True
|
|
100
|
+
|
|
101
|
+
if conf.trace_ignore_url_set and service_name in conf.trace_ignore_url_set:
|
|
102
|
+
return True
|
|
103
|
+
|
|
104
|
+
return False
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def interceptor(rn_environ, *args, **kwargs):
|
|
108
|
+
if not isinstance(rn_environ, tuple):
|
|
109
|
+
rn_environ = (rn_environ, args[1])
|
|
110
|
+
fn, environ = rn_environ
|
|
111
|
+
|
|
112
|
+
ctx = TraceContext()
|
|
113
|
+
ctx.host = environ.get('HTTP_HOST', '').split(':')[0]
|
|
114
|
+
ctx.service_name = parseServiceName(environ)
|
|
115
|
+
ctx.http_method = environ.get('REQUEST_METHOD', '')
|
|
116
|
+
ctx.remoteIp = userid_util.getRemoteAddr(args)
|
|
117
|
+
|
|
118
|
+
ctx.userAgentString = environ.get('HTTP_USER_AGENT', '')
|
|
119
|
+
ctx.referer = environ.get('HTTP_REFERER', '')
|
|
120
|
+
|
|
121
|
+
if conf.trace_user_enabled:
|
|
122
|
+
if conf.trace_user_using_ip:
|
|
123
|
+
ctx.userid = userid_util.getRemoteAddr(args)
|
|
124
|
+
else:
|
|
125
|
+
ctx.userid, ctx._rawuserid = userid_util.getUserId(args, ctx.remoteIp)
|
|
126
|
+
|
|
127
|
+
mstt = environ.get('HTTP_{}'.format(
|
|
128
|
+
conf._trace_mtrace_caller_key.upper().replace('-', '_')), '')
|
|
129
|
+
|
|
130
|
+
if mstt:
|
|
131
|
+
ctx.setTransfer(mstt)
|
|
132
|
+
if conf.stat_mtrace_enabled:
|
|
133
|
+
val = environ.get('HTTP_{}'.format(
|
|
134
|
+
conf._trace_mtrace_info_key.upper().replace('-', '_')), '')
|
|
135
|
+
if val and len(val):
|
|
136
|
+
ctx.setTransferInfo(val)
|
|
137
|
+
pass
|
|
138
|
+
|
|
139
|
+
myid = environ.get('HTTP_{}'.format(
|
|
140
|
+
conf._trace_mtrace_callee_key.upper().replace('-', '_')), '')
|
|
141
|
+
if myid:
|
|
142
|
+
ctx.setTxid(myid)
|
|
143
|
+
caller_poid = environ.get('HTTP_{}'.format(
|
|
144
|
+
conf._trace_mtrace_caller_poid_key.upper().replace('-', '_')), '')
|
|
145
|
+
|
|
146
|
+
if caller_poid:
|
|
147
|
+
ctx.mcaller_poid = caller_poid
|
|
148
|
+
|
|
149
|
+
try:
|
|
150
|
+
if isIgnore(ctx.service_name):
|
|
151
|
+
ctx.is_ignored = True
|
|
152
|
+
TraceContextManager.end(ctx.id)
|
|
153
|
+
return fn(*args, **kwargs)
|
|
154
|
+
except Exception as e:
|
|
155
|
+
pass
|
|
156
|
+
|
|
157
|
+
start_interceptor(ctx)
|
|
158
|
+
|
|
159
|
+
try:
|
|
160
|
+
|
|
161
|
+
callback = fn(*args, **kwargs)
|
|
162
|
+
query_string = environ.get('QUERY_STRING', '')
|
|
163
|
+
if query_string:
|
|
164
|
+
ctx.service_name += '?{}'.format(query_string)
|
|
165
|
+
|
|
166
|
+
if ctx.service_name.find('.') > -1 and ctx.service_name.split('.')[
|
|
167
|
+
1] in conf.web_static_content_extensions:
|
|
168
|
+
ctx.isStaticContents = 'true'
|
|
169
|
+
|
|
170
|
+
if getattr(callback, 'status_code', None):
|
|
171
|
+
status_code = callback.status_code
|
|
172
|
+
|
|
173
|
+
if (status_code >= 400):
|
|
174
|
+
errors = [callback.__class__.__name__, callback.reason_phrase]
|
|
175
|
+
interceptor_error(status_code, errors, ctx=ctx)
|
|
176
|
+
|
|
177
|
+
if conf.profile_http_header_enabled:
|
|
178
|
+
keys = []
|
|
179
|
+
for key, value in environ.items():
|
|
180
|
+
if key.startswith('HTTP_'):
|
|
181
|
+
keys.append(key)
|
|
182
|
+
keys.sort()
|
|
183
|
+
|
|
184
|
+
text = ''
|
|
185
|
+
for key in keys:
|
|
186
|
+
text += '{}={}\n'.format(key.split('HTTP_')[1].lower(),
|
|
187
|
+
environ[key])
|
|
188
|
+
|
|
189
|
+
datas = ['HTTP-HEADERS', 'HTTP-HEADERS', text]
|
|
190
|
+
ctx.start_time = DateUtil.nowSystem()
|
|
191
|
+
async_sender.send_packet(PacketTypeEnum.TX_MSG, ctx, datas)
|
|
192
|
+
return callback
|
|
193
|
+
finally:
|
|
194
|
+
end_interceptor(ctx=ctx)
|
|
195
|
+
|
|
File without changes
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from whatap.trace import get_dict
|
|
2
|
+
from whatap.trace.trace_handler import trace_handler
|
|
3
|
+
from whatap.trace.mod.database.util import interceptor_db_con, interceptor_db_execute, interceptor_db_close
|
|
4
|
+
|
|
5
|
+
db_info = {}
|
|
6
|
+
|
|
7
|
+
def _preload_oracle_db_info(*args, **kwargs):
|
|
8
|
+
global db_info
|
|
9
|
+
db_info = {'type': 'oracle'}
|
|
10
|
+
db_info.update(kwargs)
|
|
11
|
+
|
|
12
|
+
def instrument_oracle_client(module):
|
|
13
|
+
|
|
14
|
+
def wrapper(fn):
|
|
15
|
+
@trace_handler(fn, preload=_preload_oracle_db_info)
|
|
16
|
+
def trace(*args, **kwargs):
|
|
17
|
+
callback = interceptor_db_con(fn, db_info, *args, **kwargs)
|
|
18
|
+
return callback
|
|
19
|
+
|
|
20
|
+
return trace
|
|
21
|
+
|
|
22
|
+
if hasattr(module, "connect"):
|
|
23
|
+
module.connect = wrapper(module.connect)
|
|
24
|
+
|
|
25
|
+
def wrapper(fn):
|
|
26
|
+
@trace_handler(fn)
|
|
27
|
+
def trace(*args, **kwargs):
|
|
28
|
+
callback = interceptor_db_close(fn, *args, **kwargs)
|
|
29
|
+
return callback
|
|
30
|
+
|
|
31
|
+
return trace
|
|
32
|
+
|
|
33
|
+
if hasattr(module, "Connection") and hasattr(module.Connection, "close"):
|
|
34
|
+
get_dict(module.Connection)['close'] = wrapper(
|
|
35
|
+
module.Connection.close)
|
|
36
|
+
|
|
37
|
+
# def wrapper(fn):
|
|
38
|
+
# @trace_handler(fn)
|
|
39
|
+
# def trace(*args, **kwargs):
|
|
40
|
+
# callback = interceptor_db_execute(fn, db_info, *args, **kwargs)
|
|
41
|
+
# return callback
|
|
42
|
+
#
|
|
43
|
+
# return trace
|
|
44
|
+
#
|
|
45
|
+
# if hasattr(module, 'Cursor') and hasattr(module.Cursor, "execute"):
|
|
46
|
+
# get_dict(module.Cursor)['execute'] = wrapper(module.Cursor.execute)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|