v1.0.78: log panel in UI + /api/log endpoint + _log() buffer

This commit is contained in:
2026-07-27 13:50:57 +04:00
parent 6c8d852f6c
commit 07aa2115d4
3 changed files with 46 additions and 10 deletions
+25 -9
View File
@@ -1,5 +1,6 @@
from flask import Blueprint, current_app, jsonify, request
import uuid
import collections
from api.http_client import HttpClient, detect_endpoint
from operations.get_services import get_services, get_service_detail
@@ -11,6 +12,15 @@ bp = Blueprint("api_test", __name__)
AUTOTEST_PREFIX = "autotest-"
# Кольцевой буфер логов (показываются в UI)
_log_lines = collections.deque(maxlen=200)
def _log(msg):
"""Пишет и в stdout (для gunicorn), и в буфер (для UI)."""
print(msg, flush=True)
_log_lines.append(msg)
def _with_prefix(name):
name = (name or "").strip() or "instance"
@@ -102,28 +112,28 @@ def api_params(op_id):
try:
instance_uid = request.args.get("instanceUid")
op_name = request.args.get("opName")
print(f"[api_params] op_id={op_id} instanceUid={instance_uid!r} opName={op_name!r}", flush=True)
_log(f"[api_params] op_id={op_id} instanceUid={instance_uid!r} opName={op_name!r}")
if instance_uid and op_name:
print(f"[api_params] PREVIEW branch: creating operation for instance={instance_uid}", flush=True)
_log(f"[api_params] PREVIEW branch: creating operation for instance={instance_uid}")
# Создать pending-операцию чтобы прочитать ТЕКУЩИЕ значения параметров инстанса
op_payload = {"instanceUid": instance_uid, "svcOperationId": op_id, "operation": op_name}
op_resp = _client().post("/instanceOperations", op_payload)
preview_op_uid = _find_uid(op_resp) or _uid_from_location(op_resp.get("_location", ""))
print(f"[api_params] preview_op_uid={preview_op_uid!r}", flush=True)
_log(f"[api_params] preview_op_uid={preview_op_uid!r}")
if not preview_op_uid:
return jsonify({"error": "Не удалось создать preview-операцию"}), 500
op_data = _client().get(f"/instanceOperations/{preview_op_uid}")
cfs_params = op_data.get("instanceOperation", {}).get("cfsParams", [])
print(f"[api_params] cfsParams count={len(cfs_params)}", flush=True)
_log(f"[api_params] cfsParams count={len(cfs_params)}")
result = []
for p in cfs_params:
dd = p.get("dataDescriptor")
pv = p.get("paramValue")
dv = p.get("defaultValue")
print(f"[api_params] {p.get('svcOperationCfsParam')}: paramValue={pv!r} defaultValue={dv!r}", flush=True)
_log(f"[api_params] {p.get('svcOperationCfsParam')}: paramValue={pv!r} defaultValue={dv!r}")
result.append({
"svcOperationCfsParamId": p["svcOperationCfsParamId"],
"name": p.get("svcOperationCfsParam", ""),
@@ -133,11 +143,11 @@ def api_params(op_id):
"valueList": p.get("valueList"),
"dataDescriptor": {k: {"dataType": v.get("dataType",""), "valueList": v.get("valueList",""), "isRequired": v.get("isRequired", False)} for k, v in dd.items()} if isinstance(dd, dict) else None,
})
print(f"[api_params] PREVIEW returning {len(result)} params", flush=True)
_log(f"[api_params] PREVIEW returning {len(result)} params")
return jsonify({"params": result, "previewOpUid": preview_op_uid})
# Без instanceUid — шаблонные значения по умолчанию
print(f"[api_params] DEFAULT branch: template defaults", flush=True)
_log(f"[api_params] DEFAULT branch: template defaults")
data = _client().get(f"/instanceOperations/default/{op_id}")
params = data["svcOperation"]["cfsParams"]
result = []
@@ -152,11 +162,11 @@ def api_params(op_id):
"valueList": p.get("valueList"),
"dataDescriptor": {k: {"dataType": v.get("dataType",""), "valueList": v.get("valueList",""), "isRequired": v.get("isRequired", False)} for k, v in dd.items()} if isinstance(dd, dict) else None,
})
print(f"[api_params] DEFAULT returning {len(result)} params", flush=True)
_log(f"[api_params] DEFAULT returning {len(result)} params")
return jsonify({"params": result})
except Exception as e:
import traceback
print(f"[api_params] EXCEPTION: {e}", flush=True)
_log(f"[api_params] EXCEPTION: {e}")
traceback.print_exc()
return jsonify({"error": str(e)}), 500
@@ -326,6 +336,12 @@ def api_test_status(op_uid):
return jsonify({"error": str(e)}), 500
@bp.route("/api/log")
def api_log():
"""Отдать последние строки лога для UI-панели."""
return jsonify(list(_log_lines))
def _find_uid(resp):
"""Извлечь instanceUid или instanceOperationUid из ответа API."""
if isinstance(resp, dict):