whatap-python 2.1.4rc1__tar.gz → 2.2.0__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-2.1.4rc1 → whatap_python-2.2.0}/PKG-INFO +1 -1
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/__init__.py +222 -102
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/agent/linux/amd64/whatap_python +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/agent/linux/arm64/whatap_python +0 -0
- whatap_python-2.2.0/whatap/build.py +4 -0
- whatap_python-2.2.0/whatap/conf/configuration.py +444 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/conf/configure.py +55 -0
- whatap_python-2.2.0/whatap/counter/__init__.py +36 -0
- whatap_python-2.2.0/whatap/counter/tasks/base_task.py +35 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/counter/tasks/llm_evaluator_task.py +56 -10
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/counter/tasks/llm_log_sink_task.py +85 -19
- whatap_python-2.2.0/whatap/counter/tasks/llm_stat_task.py +138 -0
- whatap_python-2.2.0/whatap/llm/__init__.py +70 -0
- whatap_python-2.2.0/whatap/llm/api/__init__.py +20 -0
- whatap_python-2.2.0/whatap/llm/api/agent_name.py +83 -0
- {whatap_python-2.1.4rc1/whatap/llm → whatap_python-2.2.0/whatap/llm/api}/prompt_meta.py +31 -4
- whatap_python-2.2.0/whatap/llm/api/session.py +175 -0
- whatap_python-2.2.0/whatap/llm/api/turn.py +88 -0
- whatap_python-2.2.0/whatap/llm/api/user.py +176 -0
- whatap_python-2.2.0/whatap/llm/api/workflow.py +115 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/evaluators/__init__.py +4 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/evaluators/base.py +15 -11
- whatap_python-2.2.0/whatap/llm/evaluators/builtins/_json_repair.py +106 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/evaluators/builtins/combined_judge.py +7 -4
- whatap_python-2.2.0/whatap/llm/evaluators/builtins/judge_factories.py +90 -0
- whatap_python-2.2.0/whatap/llm/evaluators/builtins/llm_judge.py +248 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/evaluators/builtins/pii_leak.py +5 -20
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/evaluators/builtins/url_scan.py +21 -22
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/evaluators/registry.py +91 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/evaluators/scope.py +22 -2
- whatap_python-2.2.0/whatap/llm/instrument/__init__.py +32 -0
- whatap_python-2.2.0/whatap/llm/instrument/_boundary.py +492 -0
- whatap_python-2.2.0/whatap/llm/instrument/agent.py +35 -0
- whatap_python-2.2.0/whatap/llm/instrument/llm_api.py +89 -0
- whatap_python-2.2.0/whatap/llm/instrument/workflow.py +42 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/log_sink_packs/llm_log_sink_pack.py +32 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/log_sink_packs/llm_tx_status.py +51 -0
- whatap_python-2.2.0/whatap/llm/orchestration/__init__.py +16 -0
- whatap_python-2.2.0/whatap/llm/orchestration/hermes/__init__.py +143 -0
- whatap_python-2.2.0/whatap/llm/orchestration/hermes/gateway.py +172 -0
- whatap_python-2.2.0/whatap/llm/orchestration/hermes/kanban.py +353 -0
- whatap_python-2.2.0/whatap/llm/orchestration/langgraph/__init__.py +134 -0
- whatap_python-2.2.0/whatap/llm/pricing.py +187 -0
- whatap_python-2.2.0/whatap/llm/providers/anthropic/__init__.py +72 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/providers/anthropic/messages/messages_context.py +48 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/providers/anthropic/messages/messages_extractor.py +53 -0
- whatap_python-2.2.0/whatap/llm/providers/anthropic/messages/messages_stream.py +162 -0
- whatap_python-2.2.0/whatap/llm/providers/interceptor.py +349 -0
- whatap_python-2.2.0/whatap/llm/providers/openai/__init__.py +110 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/providers/openai/chat/chat_context.py +6 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/providers/openai/content_parser.py +4 -1
- whatap_python-2.2.0/whatap/llm/providers/stream_accumulator.py +287 -0
- whatap_python-2.2.0/whatap/llm/providers/workflow.py +681 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/stats/__init__.py +6 -0
- whatap_python-2.2.0/whatap/llm/stats/active_agent_stat.py +93 -0
- whatap_python-2.2.0/whatap/llm/stats/active_stat.py +83 -0
- whatap_python-2.2.0/whatap/llm/stats/actx_stat.py +80 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/stats/base_stat.py +6 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/stats/eval_stat.py +1 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/stats/pii_leak_eval_stat.py +2 -1
- whatap_python-2.2.0/whatap/llm/stats/traj_actx_stat.py +84 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/stats/url_scan_eval_stat.py +2 -1
- whatap_python-2.2.0/whatap/net/async_sender.py +313 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/net/packet_enum.py +1 -1
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/net/param_def.py +11 -0
- whatap_python-2.2.0/whatap/net/udp_session.py +790 -0
- whatap_python-2.2.0/whatap/net/udp_thread.py +103 -0
- whatap_python-2.2.0/whatap/trace/mod/application/fastapi/instrumentation.py +403 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/application/fastapi/scope.py +17 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/application/wsgi.py +19 -1
- whatap_python-2.2.0/whatap/trace/mod/hook_service_patterns.py +26 -0
- whatap_python-2.2.0/whatap/trace/mod/httpc/util.py +689 -0
- whatap_python-2.2.0/whatap/trace/mod/pattern_targets.py +137 -0
- whatap_python-2.2.0/whatap/trace/mod/plugin.py +47 -0
- whatap_python-2.2.0/whatap/trace/mod/process/subprocess_spawn.py +390 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/standalone/multiple.py +2 -1
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/standalone/single.py +2 -1
- whatap_python-2.2.0/whatap/trace/mod/thread_context.py +202 -0
- whatap_python-2.2.0/whatap/trace/mod/workflow_plugin.py +33 -0
- whatap_python-2.2.0/whatap/trace/mtrace_env.py +368 -0
- whatap_python-2.2.0/whatap/trace/patch.py +98 -0
- whatap_python-2.2.0/whatap/trace/trace_context.py +330 -0
- whatap_python-2.2.0/whatap/trace/trace_context_manager.py +1005 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/trace_error.py +8 -2
- whatap_python-2.2.0/whatap/trace/trace_import.py +136 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/trace_module_definition.py +28 -0
- whatap_python-2.2.0/whatap/util/cardinality/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap_python.egg-info/PKG-INFO +1 -1
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap_python.egg-info/SOURCES.txt +31 -3
- whatap_python-2.1.4rc1/tests/test_stream_ttft.py +0 -192
- whatap_python-2.1.4rc1/whatap/build.py +0 -4
- whatap_python-2.1.4rc1/whatap/conf/configuration.py +0 -284
- whatap_python-2.1.4rc1/whatap/counter/__init__.py +0 -14
- whatap_python-2.1.4rc1/whatap/counter/tasks/base_task.py +0 -26
- whatap_python-2.1.4rc1/whatap/counter/tasks/llm_stat_task.py +0 -78
- whatap_python-2.1.4rc1/whatap/llm/__init__.py +0 -17
- whatap_python-2.1.4rc1/whatap/llm/evaluators/builtins/llm_judge.py +0 -516
- whatap_python-2.1.4rc1/whatap/llm/pricing.py +0 -236
- whatap_python-2.1.4rc1/whatap/llm/providers/anthropic/__init__.py +0 -37
- whatap_python-2.1.4rc1/whatap/llm/providers/interceptor.py +0 -232
- whatap_python-2.1.4rc1/whatap/llm/providers/openai/__init__.py +0 -133
- whatap_python-2.1.4rc1/whatap/llm/providers/stream_accumulator.py +0 -139
- whatap_python-2.1.4rc1/whatap/llm/stats/active_stat.py +0 -86
- whatap_python-2.1.4rc1/whatap/llm/stats/meter.py +0 -18
- whatap_python-2.1.4rc1/whatap/net/async_sender.py +0 -107
- whatap_python-2.1.4rc1/whatap/net/udp_session.py +0 -396
- whatap_python-2.1.4rc1/whatap/net/udp_thread.py +0 -54
- whatap_python-2.1.4rc1/whatap/trace/mod/application/fastapi/instrumentation.py +0 -204
- whatap_python-2.1.4rc1/whatap/trace/mod/hook_service_patterns.py +0 -72
- whatap_python-2.1.4rc1/whatap/trace/mod/httpc/util.py +0 -388
- whatap_python-2.1.4rc1/whatap/trace/mod/plugin.py +0 -84
- whatap_python-2.1.4rc1/whatap/trace/trace_context.py +0 -212
- whatap_python-2.1.4rc1/whatap/trace/trace_context_manager.py +0 -255
- whatap_python-2.1.4rc1/whatap/trace/trace_import.py +0 -99
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/README.md +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/pyproject.toml +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/setup.cfg +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/setup.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/LICENSE +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/README.rst +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/__main__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/agent/darwin/amd64/whatap_python +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/agent/darwin/arm64/whatap_python +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/agent/windows/whatap_python.exe +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/bootstrap/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/bootstrap/sitecustomize.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/conf/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/conf/license.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/control/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/counter/counter_manager.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/counter/tasks/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/counter/tasks/openfiledescriptor.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/io/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/io/data_inputx.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/io/data_outputx.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/definitions.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/evaluators/builtins/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/evaluators/builtins/answer_relevance.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/evaluators/builtins/factuality.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/evaluators/builtins/hallucination.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/evaluators/builtins/prompt_injection.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/evaluators/builtins/toxicity.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/evaluators/sampler.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/features.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/log_sink_packs/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/log_sink_packs/llm_input_message.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/log_sink_packs/llm_output_message.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/log_sink_packs/llm_step_eval_status.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/log_sink_packs/llm_step_status.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/log_sink_packs/llm_system_message.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/log_sink_packs/llm_tool_calls.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/log_sink_packs/llm_tool_results.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/providers/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/providers/anthropic/messages/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/providers/anthropic/messages/messages.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/providers/openai/chat/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/providers/openai/chat/chat.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/providers/openai/chat/chat_extractor.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/providers/openai/completions/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/providers/openai/completions/completions.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/providers/openai/completions/completions_context.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/providers/openai/completions/completions_extractor.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/providers/openai/embeddings/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/providers/openai/embeddings/embeddings.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/providers/openai/embeddings/embeddings_context.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/providers/openai/embeddings/embeddings_extractor.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/providers/openai/responses/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/providers/openai/responses/responses.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/providers/openai/responses/responses_context.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/providers/openai/responses/responses_extractor.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/stats/answer_relevance_eval_stat.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/stats/api_status_stat.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/stats/combined_judge_eval_stat.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/stats/error_stat.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/stats/factuality_eval_stat.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/stats/feature_stat.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/stats/finish_stat.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/stats/hallucination_eval_stat.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/stats/perf_stat.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/stats/prompt_injection_eval_stat.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/stats/token_usage_stat.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/llm/stats/toxicity_eval_stat.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/net/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/net/packet_type_enum.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/net/stackhelper.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/pack/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/pack/logSinkPack.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/pack/pack.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/pack/pack_enum.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/pack/tagCountPack.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/scripts/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/amqp/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/amqp/kombu.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/amqp/pika.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/application/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/application/bottle.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/application/celery.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/application/cherrypy.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/application/django.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/application/django_asgi.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/application/django_py3.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/application/fastapi/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/application/fastapi/endpoint.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/application/fastapi/exception_log.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/application/fastapi/transaction.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/application/flask.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/application/frappe.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/application/graphql.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/application/nameko.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/application/odoo.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/application/starlette.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/application/tornado.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/database/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/database/cxoracle.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/database/mongo.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/database/mysql.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/database/neo4j.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/database/psycopg2.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/database/psycopg3.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/database/redis.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/database/sqlalchemy.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/database/sqlite3.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/database/util.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/email/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/email/smtp.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/httpc/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/httpc/django.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/httpc/httplib.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/httpc/httpx.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/httpc/requests.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/httpc/urllib3.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/mod/logging.py +0 -0
- {whatap_python-2.1.4rc1/whatap/trace/mod/standalone → whatap_python-2.2.0/whatap/trace/mod/process}/__init__.py +0 -0
- {whatap_python-2.1.4rc1/whatap/util → whatap_python-2.2.0/whatap/trace/mod/standalone}/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/simple_trace_context.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/trace/trace_handler.py +0 -0
- {whatap_python-2.1.4rc1/whatap/util/cardinality → whatap_python-2.2.0/whatap/util}/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/util/bit_util.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/util/cardinality/hyperloglog.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/util/cardinality/murmurhash.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/util/cardinality/registerset.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/util/compare_util.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/util/date_util.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/util/debug_util.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/util/escape_literal_sql.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/util/frame_util.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/util/hash_util.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/util/hexa32.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/util/int_set.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/util/ip_util.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/util/keygen.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/util/linked_list.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/util/linked_map.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/util/metering_util.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/util/request_double_queue.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/util/request_queue.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/util/string_util.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/util/throttle_util.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/util/userid_util.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/value/__init__.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/value/blob_value.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/value/boolean_value.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/value/decimal_value.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/value/double_summary.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/value/double_value.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/value/float_array.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/value/float_value.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/value/int_array.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/value/ip4_value.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/value/list_value.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/value/long_array.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/value/long_summary.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/value/map_value.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/value/null_value.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/value/number_value.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/value/summary_value.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/value/text_array.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/value/text_hash_value.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/value/text_value.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/value/value.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/value/value_enum.py +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap/whatap.conf +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap_python.egg-info/dependency_links.txt +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap_python.egg-info/entry_points.txt +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap_python.egg-info/not-zip-safe +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap_python.egg-info/requires.txt +0 -0
- {whatap_python-2.1.4rc1 → whatap_python-2.2.0}/whatap_python.egg-info/top_level.txt +0 -0
|
@@ -117,6 +117,37 @@ def whatap_print(*args):
|
|
|
117
117
|
message = " ".join(args)
|
|
118
118
|
print(message)
|
|
119
119
|
|
|
120
|
+
|
|
121
|
+
def whatap_error_log(msg, log_id='WHATAP_AGENT_ERROR'):
|
|
122
|
+
"""에이전트 시작 오류를 프로세스 로그(stdout)와 hook.log 양쪽에 동일하게 노출한다.
|
|
123
|
+
|
|
124
|
+
hook.log FileHandler 는 Configure.load(display=True)->Logger() 시점에 붙는데,
|
|
125
|
+
go() 스레드가 config() 보다 먼저 도는 경로(자동 attach)나 start_agent 경로에서는
|
|
126
|
+
아직 핸들러가 없을 수 있다. 그 경우에도 오류가 유실되지 않도록, 핸들러가 없으면
|
|
127
|
+
whatap-hook.log 에 직접 append 한다."""
|
|
128
|
+
# 1) 프로세스 로그 (사용자 애플리케이션 stdout)
|
|
129
|
+
whatap_print(msg)
|
|
130
|
+
|
|
131
|
+
# 2) hook.log
|
|
132
|
+
try:
|
|
133
|
+
if logging.handlers:
|
|
134
|
+
logging.error(msg, extra={'id': log_id})
|
|
135
|
+
return
|
|
136
|
+
except Exception:
|
|
137
|
+
pass
|
|
138
|
+
|
|
139
|
+
# FileHandler 미부착: whatap-hook.log 에 직접 기록
|
|
140
|
+
try:
|
|
141
|
+
logs_dir = os.environ.get('WHATAP_LOGS') or \
|
|
142
|
+
os.path.join(os.environ.get('WHATAP_HOME', '.'), 'logs')
|
|
143
|
+
if not os.path.exists(logs_dir):
|
|
144
|
+
os.makedirs(logs_dir)
|
|
145
|
+
with open(os.path.join(logs_dir, LOG_FILE_NAME), 'a') as f:
|
|
146
|
+
f.write('[{0}] : {1} - {2}\n'.format(
|
|
147
|
+
time.strftime(LOGGING_DATE_FORMAT), log_id, msg))
|
|
148
|
+
except Exception as e:
|
|
149
|
+
whatap_print('WHATAP: hook.log write failed: {}'.format(e))
|
|
150
|
+
|
|
120
151
|
class Logger(object):
|
|
121
152
|
def __init__(self):
|
|
122
153
|
self.logger = logging
|
|
@@ -291,6 +322,18 @@ def config(home):
|
|
|
291
322
|
from whatap.conf.license import License
|
|
292
323
|
conf.PCODE = License.getProjectCode(conf.license)
|
|
293
324
|
|
|
325
|
+
# LLM 채널은 자기 프로젝트 코드를 가진다. LLM 트랜잭션(is_llm=1)은 LLM Go Agent
|
|
326
|
+
# 소켓으로만 나가므로 결합 좌표에 APM PCODE 를 실으면 서버가 호출자를 엉뚱한
|
|
327
|
+
# 프로젝트에서 찾는다(conf.pcode_of 참조). getProjectCode 는 키 문자열 파싱이라
|
|
328
|
+
# 서버 왕복이 없고, apm_enabled=false 인 LLM 전용 배포에서도 해소된다.
|
|
329
|
+
llm_key = str(getattr(conf, 'llm_accesskey', '') or '').strip()
|
|
330
|
+
if llm_key:
|
|
331
|
+
try:
|
|
332
|
+
from whatap.conf.license import License
|
|
333
|
+
conf.LLM_PCODE = License.getProjectCode(llm_key)
|
|
334
|
+
except Exception as e:
|
|
335
|
+
whatap_print('WHATAP: LLM PCODE RESOLVE ERROR: {}'.format(e))
|
|
336
|
+
|
|
294
337
|
import whatap.counter
|
|
295
338
|
|
|
296
339
|
hooks(home)
|
|
@@ -366,47 +409,61 @@ def hooks(home):
|
|
|
366
409
|
from whatap.trace.mod.logging import instrument_logging
|
|
367
410
|
instrument_logging(logging_module)
|
|
368
411
|
|
|
412
|
+
# 한 모듈에 여러 패턴 계열(스텝=instrument_plugin / 워크플로우=instrument_workflow
|
|
413
|
+
# / 트랜잭션=instrument_service)이 공존할 수 있도록, IMPORT_HOOKS[모듈]에
|
|
414
|
+
# 인스트루먼터를 각자의 class_defs 와 함께 리스트로 누적한다. 과거엔 단일 dict 라
|
|
415
|
+
# 뒤 계열이 앞을 덮어써서 같은 모듈에 두 패턴(예: predict=트랜잭션 + 헬퍼=스텝)을
|
|
416
|
+
# 못 걸었다.
|
|
417
|
+
def _register_pattern_hook(module_name, class_def, def_name, mod_path):
|
|
418
|
+
if not PLUGIN.get(module_name):
|
|
419
|
+
PLUGIN[module_name] = []
|
|
420
|
+
if class_def not in PLUGIN[module_name]:
|
|
421
|
+
PLUGIN[module_name].append(class_def) # 호환용(외부 참조)
|
|
422
|
+
existing = IMPORT_HOOKS.get(module_name)
|
|
423
|
+
if isinstance(existing, list):
|
|
424
|
+
entry_list = existing
|
|
425
|
+
elif isinstance(existing, dict):
|
|
426
|
+
entry_list = [existing]
|
|
427
|
+
IMPORT_HOOKS[module_name] = entry_list
|
|
428
|
+
else:
|
|
429
|
+
entry_list = []
|
|
430
|
+
IMPORT_HOOKS[module_name] = entry_list
|
|
431
|
+
for e in entry_list:
|
|
432
|
+
if isinstance(e, dict) and e.get('def') == def_name \
|
|
433
|
+
and e.get('module') == mod_path:
|
|
434
|
+
e.setdefault('class_defs', []).append(class_def)
|
|
435
|
+
return
|
|
436
|
+
entry_list.append({'def': def_name, 'module': mod_path,
|
|
437
|
+
'class_defs': [class_def]})
|
|
438
|
+
|
|
369
439
|
if conf.hook_method_patterns:
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
module_name, class_def
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
'mod',
|
|
390
|
-
key)}
|
|
391
|
-
|
|
392
|
-
# 서비스(트랜잭션) 진입점 자동 래핑 (conf 방법). hook_method_patterns 와 같은
|
|
393
|
-
# import-hook 플러밍, 래퍼만 트랜잭션 open/close (whatap.trace.mod.hook_service_patterns).
|
|
394
|
-
# @method_profiling 을 소스 수정 없이 conf 로 적용하는 경로.
|
|
440
|
+
for pattern in conf.hook_method_patterns.split(','):
|
|
441
|
+
pattern = pattern.strip()
|
|
442
|
+
if not pattern or ':' not in pattern:
|
|
443
|
+
continue
|
|
444
|
+
module_name, class_def = pattern.split(':', 1)
|
|
445
|
+
_register_pattern_hook(module_name.strip(), class_def.strip(),
|
|
446
|
+
'instrument_plugin', 'whatap.trace.mod.plugin')
|
|
447
|
+
|
|
448
|
+
# LLM 워크플로우 경계 자동 래핑 (conf 방법). 래퍼만 워크플로우 open/close.
|
|
449
|
+
if conf.workflow_method_patterns:
|
|
450
|
+
for pattern in conf.workflow_method_patterns.split(','):
|
|
451
|
+
pattern = pattern.strip()
|
|
452
|
+
if not pattern or ':' not in pattern:
|
|
453
|
+
continue
|
|
454
|
+
module_name, class_def = pattern.split(':', 1)
|
|
455
|
+
_register_pattern_hook(module_name.strip(), class_def.strip(),
|
|
456
|
+
'instrument_workflow', 'whatap.trace.mod.workflow_plugin')
|
|
457
|
+
|
|
458
|
+
# 서비스(트랜잭션) 진입점 자동 래핑 (conf 방법). @method_profiling 의 conf 버전.
|
|
395
459
|
if conf.hook_service_patterns:
|
|
396
460
|
for pattern in conf.hook_service_patterns.split(','):
|
|
397
461
|
pattern = pattern.strip()
|
|
398
462
|
if not pattern or ':' not in pattern:
|
|
399
463
|
continue
|
|
400
464
|
module_name, class_def = pattern.split(':', 1)
|
|
401
|
-
module_name
|
|
402
|
-
|
|
403
|
-
if not PLUGIN.get(module_name):
|
|
404
|
-
PLUGIN[module_name] = []
|
|
405
|
-
PLUGIN[module_name].append(class_def)
|
|
406
|
-
# 대상 모듈이 PLUGIN 에 등록되면 ImportFinder 가 class_defs 패키징.
|
|
407
|
-
IMPORT_HOOKS[module_name] = {
|
|
408
|
-
'def': 'instrument_service',
|
|
409
|
-
'module': 'whatap.trace.mod.hook_service_patterns'}
|
|
465
|
+
_register_pattern_hook(module_name.strip(), class_def.strip(),
|
|
466
|
+
'instrument_service', 'whatap.trace.mod.hook_service_patterns')
|
|
410
467
|
|
|
411
468
|
if conf.standalone_enabled:
|
|
412
469
|
if conf.standalone_type == 'multiple-transaction':
|
|
@@ -420,9 +477,43 @@ def hooks(home):
|
|
|
420
477
|
logging.debug(e, extra={'id': 'PLUGIN ERROR'})
|
|
421
478
|
finally:
|
|
422
479
|
sys.meta_path.insert(0, ImportFinder())
|
|
480
|
+
_instrument_already_imported()
|
|
423
481
|
logging.debug('WHATAP AGENT START!', extra={'id': 'WA000'})
|
|
424
482
|
|
|
425
483
|
|
|
484
|
+
def _instrument_already_imported():
|
|
485
|
+
"""finder 설치 시점에 **이미 import 돼 있던** 훅 대상을 직접 계측한다.
|
|
486
|
+
|
|
487
|
+
``ImportFinder.find_spec`` 은 import 시스템이 ``sys.modules`` 미스일 때만 호출하므로,
|
|
488
|
+
finder 설치보다 먼저 로드된 모듈은 훅이 영원히 안 걸린다. 그리고 이 에이전트는 자기
|
|
489
|
+
부팅에 필요한 모듈(``subprocess`` — 최상단 import, 데몬 기동에 사용)을 finder 설치
|
|
490
|
+
**전에** 로드하므로, 그 대상은 DEFINITION 에 등록해도 계측되지 않는다.
|
|
491
|
+
|
|
492
|
+
앱이 우회할 수 없는 종류의 구멍이다(앱이 할 수 있는 건 에이전트 내부 instrument_*
|
|
493
|
+
함수를 대신 호출하는 것뿐이고, 그건 자동계측을 쓰는 의미를 없앤다).
|
|
494
|
+
|
|
495
|
+
``load_module`` 을 그대로 재사용하므로 정상 import 경로와 완전히 같은 처리를 받는다
|
|
496
|
+
(엔트리 리스트/class_defs 패키징 포함). instrument_* 는 멱등이어야 한다 — 이 스윕과 이후의
|
|
497
|
+
재-import 가 같은 대상을 두 번 건드릴 수 있다.
|
|
498
|
+
"""
|
|
499
|
+
try:
|
|
500
|
+
from whatap.trace.trace_import import load_module
|
|
501
|
+
except Exception as e:
|
|
502
|
+
logging.info("pre-imported sweep unavailable: %s: %s",
|
|
503
|
+
e.__class__.__name__, e, exc_info=True)
|
|
504
|
+
return
|
|
505
|
+
for fullname in list(IMPORT_HOOKS.keys()):
|
|
506
|
+
module = sys.modules.get(fullname)
|
|
507
|
+
if module is None:
|
|
508
|
+
continue
|
|
509
|
+
try:
|
|
510
|
+
load_module(module, fullname)
|
|
511
|
+
except Exception as e:
|
|
512
|
+
# 계측 실패는 조용히 넘기면 "데이터가 안 보인다" 로만 드러난다.
|
|
513
|
+
logging.info("failed to inject pre-imported %s: %s: %s",
|
|
514
|
+
fullname, e.__class__.__name__, e, exc_info=True)
|
|
515
|
+
|
|
516
|
+
|
|
426
517
|
def agent():
|
|
427
518
|
home = 'WHATAP_HOME'
|
|
428
519
|
whatap_home = os.environ.get(home)
|
|
@@ -451,9 +542,18 @@ def agent():
|
|
|
451
542
|
t.start()
|
|
452
543
|
|
|
453
544
|
if llm_enabled == 'true':
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
545
|
+
# llm_enabled=true 라도 LLM 채널 자격증명(llm_accesskey)이 없으면 LLM
|
|
546
|
+
# 에이전트를 띄우지 않는다. (env 로 플래그만 켜진 경우의 오작동 방지 —
|
|
547
|
+
# llm_accesskey/LLM 서버 호스트 없이 LLM 모드로 도는 것을 막는다.)
|
|
548
|
+
llm_accesskey = (preview_whatap_conf("llm_accesskey")
|
|
549
|
+
or os.environ.get("llm_accesskey"))
|
|
550
|
+
if llm_accesskey:
|
|
551
|
+
t = threading.Thread(target=go, kwargs={'llm': True})
|
|
552
|
+
t.setDaemon(True)
|
|
553
|
+
t.start()
|
|
554
|
+
else:
|
|
555
|
+
whatap_print("WHATAP: llm_enabled=true 이나 llm_accesskey 가 "
|
|
556
|
+
"없어 LLM 에이전트 기동을 건너뜁니다")
|
|
457
557
|
|
|
458
558
|
config(home)
|
|
459
559
|
|
|
@@ -472,6 +572,17 @@ AGENT_NAME = 'whatap_python'
|
|
|
472
572
|
|
|
473
573
|
|
|
474
574
|
def go(batch=False, opts={}, llm=False):
|
|
575
|
+
# LLM 에이전트는 Linux/macOS 를 지원한다(전용 whatap_python 이
|
|
576
|
+
# $WHATAP_HOME/<os>/<arch> 에 배포됨 — linux/darwin × amd64/arm64).
|
|
577
|
+
# 그 외 OS(Windows 등)는 전용 바이너리가 없으므로 우회적 "binary not found"
|
|
578
|
+
# 대신 명시적으로 LLM 기동을 차단하고 알린다.
|
|
579
|
+
if llm and platform.system().lower() not in ('linux', 'darwin'):
|
|
580
|
+
whatap_error_log(
|
|
581
|
+
'WHATAP: LLM agent is supported on Linux/macOS only '
|
|
582
|
+
'(current OS: {0}); skipping LLM agent start'.format(platform.system()),
|
|
583
|
+
log_id='WHATAP_LLM_UNSUPPORTED_OS')
|
|
584
|
+
return
|
|
585
|
+
|
|
475
586
|
newenv=os.environ.copy()
|
|
476
587
|
newenv['WHATAP_VERSION'] = build.version
|
|
477
588
|
newenv['whatap.start'] = str(DateUtil.now())
|
|
@@ -532,47 +643,78 @@ def go(batch=False, opts={}, llm=False):
|
|
|
532
643
|
|
|
533
644
|
# Windows uses .exe extension
|
|
534
645
|
agent_binary_name = AGENT_NAME + '.exe' if sys.platform == 'win32' else AGENT_NAME
|
|
535
|
-
dest_agent = os.path.join(home_path, agent_binary_name)
|
|
536
646
|
|
|
537
|
-
#
|
|
538
|
-
#
|
|
539
|
-
#
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
647
|
+
# LLM mode (Unix/Linux) runs a dedicated whatap_python binary that ships
|
|
648
|
+
# separately under $WHATAP_HOME/<os>/<arch>/ (e.g. $WHATAP_HOME/linux/amd64).
|
|
649
|
+
# It is executed in place from there rather than deployed from the bundled
|
|
650
|
+
# package into $WHATAP_HOME/whatap_python, which the APM agent uses (the two
|
|
651
|
+
# are now distinct binaries and would otherwise clobber each other).
|
|
652
|
+
run_in_place = llm and sys.platform != 'win32'
|
|
653
|
+
|
|
654
|
+
if run_in_place:
|
|
655
|
+
source_cwd = os.path.join(home_path, platform.system().lower(), ARCH[platform.machine()])
|
|
656
|
+
source_agent = os.path.join(source_cwd, agent_binary_name)
|
|
657
|
+
if not os.path.exists(source_agent):
|
|
658
|
+
raise FileNotFoundError(
|
|
659
|
+
'LLM agent binary not found: {0} '
|
|
660
|
+
'(place the LLM {1} under $WHATAP_HOME/{2}/{3}/)'.format(
|
|
661
|
+
source_agent, agent_binary_name,
|
|
662
|
+
platform.system().lower(), ARCH[platform.machine()]))
|
|
663
|
+
# Ensure executable (best effort; ignore on read-only locations)
|
|
664
|
+
if not os.access(source_agent, os.X_OK):
|
|
665
|
+
try:
|
|
666
|
+
os.chmod(source_agent, 0o755)
|
|
667
|
+
except OSError as e:
|
|
668
|
+
whatap_print('WHATAP: chmod LLM agent binary failed: %s' % e)
|
|
669
|
+
agent_cmd = source_agent
|
|
552
670
|
else:
|
|
553
|
-
|
|
671
|
+
dest_agent = os.path.join(home_path, agent_binary_name)
|
|
554
672
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
673
|
+
# Try to remove existing binary
|
|
674
|
+
# Windows: File may still be locked even after waiting, ignore error and use existing binary
|
|
675
|
+
# Unix/Linux: Removal should always succeed
|
|
676
|
+
needs_deployment = False
|
|
677
|
+
if os.path.exists(dest_agent):
|
|
678
|
+
try:
|
|
679
|
+
os.remove(dest_agent)
|
|
680
|
+
needs_deployment = True
|
|
681
|
+
except (OSError, PermissionError) as e:
|
|
682
|
+
if sys.platform == 'win32':
|
|
683
|
+
# Windows: File is still locked, use existing binary
|
|
684
|
+
pass
|
|
685
|
+
else:
|
|
686
|
+
# Unix/Linux: This should not happen
|
|
687
|
+
raise
|
|
688
|
+
else:
|
|
689
|
+
needs_deployment = True
|
|
561
690
|
|
|
562
|
-
|
|
691
|
+
# Windows doesn't use architecture subdirectories (only single x64 binary for now)
|
|
692
|
+
if sys.platform == 'win32':
|
|
693
|
+
source_cwd = os.path.join(os.path.dirname(__file__), 'agent', 'windows')
|
|
694
|
+
else:
|
|
695
|
+
source_cwd = os.path.join(os.path.join(os.path.dirname(__file__), 'agent'), platform.system().lower(),
|
|
696
|
+
ARCH[platform.machine()])
|
|
563
697
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
#
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
698
|
+
source_agent = os.path.join(source_cwd, agent_binary_name)
|
|
699
|
+
|
|
700
|
+
# Deploy agent binary only if needed
|
|
701
|
+
if needs_deployment:
|
|
702
|
+
# Try symlink first (Unix/Linux or Windows with proper permissions)
|
|
703
|
+
try:
|
|
704
|
+
os.symlink(source_agent, dest_agent)
|
|
705
|
+
except (OSError, NotImplementedError):
|
|
706
|
+
# Fallback to copy on Windows or when symlink fails
|
|
707
|
+
import shutil
|
|
708
|
+
shutil.copy2(source_agent, dest_agent)
|
|
709
|
+
# Make executable on Unix-like systems
|
|
710
|
+
if sys.platform != 'win32':
|
|
711
|
+
os.chmod(dest_agent, 0o755)
|
|
712
|
+
|
|
713
|
+
# Windows uses absolute path, Unix/Linux uses relative path
|
|
714
|
+
if sys.platform == 'win32':
|
|
715
|
+
agent_cmd = os.path.join(home_path, agent_binary_name)
|
|
716
|
+
else:
|
|
717
|
+
agent_cmd = './{0}'.format(agent_binary_name)
|
|
576
718
|
|
|
577
719
|
sockfile_path = os.path.join(home_path, 'run')
|
|
578
720
|
if not os.path.exists(sockfile_path):
|
|
@@ -581,12 +723,6 @@ def go(batch=False, opts={}, llm=False):
|
|
|
581
723
|
newenv['WHATAP_PID_FILE'] = file_name
|
|
582
724
|
newenv['PYTHON_PARENT_APP_PID'] = str(os.getpid())
|
|
583
725
|
|
|
584
|
-
# Windows uses absolute path, Unix/Linux uses relative path
|
|
585
|
-
if sys.platform == 'win32':
|
|
586
|
-
agent_cmd = os.path.join(home_path, agent_binary_name)
|
|
587
|
-
else:
|
|
588
|
-
agent_cmd = './{0}'.format(agent_binary_name)
|
|
589
|
-
|
|
590
726
|
# Windows: Run in background with DETACHED_PROCESS
|
|
591
727
|
# Unix/Linux: Run in background with start_new_session
|
|
592
728
|
# 실행 인자 구성
|
|
@@ -657,7 +793,10 @@ def go(batch=False, opts={}, llm=False):
|
|
|
657
793
|
except Exception as e:
|
|
658
794
|
import traceback
|
|
659
795
|
traceback.print_exc()
|
|
660
|
-
|
|
796
|
+
# hook.log + 프로세스 로그 양쪽에 동일하게 노출
|
|
797
|
+
whatap_error_log(
|
|
798
|
+
'WHATAP: {0} AGENT ERROR: {1}'.format('LLM' if llm else 'APM', e),
|
|
799
|
+
log_id='WHATAP_LLM_AGENT_ERROR' if llm else 'WHATAP_AGENT_ERROR')
|
|
661
800
|
else:
|
|
662
801
|
whatap_print('WHATAP: AGENT UP! (process name: {}{})\n'.format(AGENT_NAME, ' --llm' if llm else ''))
|
|
663
802
|
|
|
@@ -695,8 +834,8 @@ def _service_trace(fn, service_name=None):
|
|
|
695
834
|
"""fn 을 하나의 트랜잭션(TX_START~TX_END)으로 감싼 래퍼를 반환한다.
|
|
696
835
|
|
|
697
836
|
``@method_profiling`` 데코레이터와 conf ``hook_service_patterns``
|
|
698
|
-
(whatap.trace.mod.hook_service_patterns) 의 **공용 코어**. 여기엔 agent() 부팅이
|
|
699
|
-
|
|
837
|
+
(whatap.trace.mod.hook_service_patterns) 의 **공용 코어**. 여기엔 agent() 부팅이 없다
|
|
838
|
+
(데코레이터/부트 경로가 각자 처리).
|
|
700
839
|
|
|
701
840
|
코루틴 함수는 동기 래퍼로 감싸면 트랜잭션이 start_interceptor → 코루틴 생성 →
|
|
702
841
|
end_interceptor 로 즉시 열렸다 닫히고, 실제 본문은 호출자가 await 할 때 트랜잭션
|
|
@@ -772,26 +911,7 @@ def _service_trace(fn, service_name=None):
|
|
|
772
911
|
|
|
773
912
|
|
|
774
913
|
def method_profiling(fn):
|
|
775
|
-
|
|
776
|
-
# 공개 API 라, 예외 재전파/컨텍스트 정리/async 지원으로 바꾸면 기존 사용자의
|
|
777
|
-
# 동작이 달라진다. 해당 수정은 dev 에 있고 정식 머지 때 함께 들어온다.
|
|
778
|
-
def trace(*args, **kwargs):
|
|
779
|
-
callback = None
|
|
780
|
-
try:
|
|
781
|
-
ctx = TraceContext()
|
|
782
|
-
ctx.service_name=fn.__name__
|
|
783
|
-
start_interceptor(ctx)
|
|
784
|
-
callback = fn(*args, **kwargs)
|
|
785
|
-
except Exception as e:
|
|
786
|
-
ctx = TraceContextManager.getLocalContext()
|
|
787
|
-
interceptor_step_error(e, ctx=ctx)
|
|
788
|
-
interceptor_error_log(ctx.id, e, fn, args, kwargs)
|
|
789
|
-
logging.debug('WHATAP(@method_profiling): ' + str(e),
|
|
790
|
-
extra={'id': 'WA776'}, exc_info=True)
|
|
791
|
-
finally:
|
|
792
|
-
ctx = TraceContextManager.getLocalContext()
|
|
793
|
-
end_interceptor(ctx=ctx)
|
|
794
|
-
return callback
|
|
914
|
+
trace = _service_trace(fn)
|
|
795
915
|
|
|
796
916
|
if not os.environ.get('whatap.enabled'):
|
|
797
917
|
agent()
|
|
Binary file
|
|
Binary file
|