Commit 41856690519fed26bb9e35095fd8e72d54316497

Authored by tangwang
1 parent 0ea456b2

embedding logs

embeddings/server.py
... ... @@ -14,7 +14,6 @@ import time
14 14 import uuid
15 15 from collections import deque
16 16 from dataclasses import dataclass
17   -from logging.handlers import TimedRotatingFileHandler
18 17 from typing import Any, Dict, List, Optional
19 18  
20 19 import numpy as np
... ... @@ -44,9 +43,7 @@ def configure_embedding_logging() -> None:
44 43 return
45 44  
46 45 log_dir = pathlib.Path("logs")
47   - verbose_dir = log_dir / "verbose"
48 46 log_dir.mkdir(exist_ok=True)
49   - verbose_dir.mkdir(parents=True, exist_ok=True)
50 47  
51 48 log_level = os.getenv("LOG_LEVEL", "INFO").upper()
52 49 numeric_level = getattr(logging, log_level, logging.INFO)
... ... @@ -56,47 +53,18 @@ def configure_embedding_logging() -> None:
56 53 request_filter = _DefaultRequestIdFilter()
57 54  
58 55 root_logger.setLevel(numeric_level)
59   -
60   - file_handler = TimedRotatingFileHandler(
61   - filename=log_dir / "embedding_api.log",
62   - when="midnight",
63   - interval=1,
64   - backupCount=30,
65   - encoding="utf-8",
66   - )
67   - file_handler.setLevel(numeric_level)
68   - file_handler.setFormatter(formatter)
69   - file_handler.addFilter(request_filter)
70   - root_logger.addHandler(file_handler)
71   -
72   - error_handler = TimedRotatingFileHandler(
73   - filename=log_dir / "embedding_api_error.log",
74   - when="midnight",
75   - interval=1,
76   - backupCount=30,
77   - encoding="utf-8",
78   - )
79   - error_handler.setLevel(logging.ERROR)
80   - error_handler.setFormatter(formatter)
81   - error_handler.addFilter(request_filter)
82   - root_logger.addHandler(error_handler)
  56 + root_logger.handlers.clear()
  57 + stream_handler = logging.StreamHandler()
  58 + stream_handler.setLevel(numeric_level)
  59 + stream_handler.setFormatter(formatter)
  60 + stream_handler.addFilter(request_filter)
  61 + root_logger.addHandler(stream_handler)
83 62  
84 63 verbose_logger = logging.getLogger("embedding.verbose")
85 64 verbose_logger.setLevel(numeric_level)
86 65 verbose_logger.handlers.clear()
87   - verbose_logger.propagate = False
88   -
89   - verbose_handler = TimedRotatingFileHandler(
90   - filename=verbose_dir / "embedding_verbose.log",
91   - when="midnight",
92   - interval=1,
93   - backupCount=30,
94   - encoding="utf-8",
95   - )
96   - verbose_handler.setLevel(numeric_level)
97   - verbose_handler.setFormatter(formatter)
98   - verbose_handler.addFilter(request_filter)
99   - verbose_logger.addHandler(verbose_handler)
  66 + # Consolidate verbose logs into the main embedding log stream.
  67 + verbose_logger.propagate = True
100 68  
101 69 root_logger._embedding_logging_configured = True # type: ignore[attr-defined]
102 70  
... ...
frontend/static/css/style.css
... ... @@ -379,7 +379,7 @@ body {
379 379 margin-top: 8px;
380 380 }
381 381  
382   -.product-debug-inline-es-btn {
  382 +.product-debug-inline-result-btn {
383 383 font-family: inherit;
384 384 font-size: 12px;
385 385 padding: 4px 10px;
... ... @@ -390,27 +390,22 @@ body {
390 390 cursor: pointer;
391 391 }
392 392  
393   -.product-debug-inline-es-btn:hover {
  393 +.product-debug-inline-result-btn:hover {
394 394 background: #f0f0f0;
395 395 border-color: #bbb;
396 396 }
397 397  
398   -.product-debug--es-expanded {
  398 +.product-debug--result-expanded {
399 399 max-height: min(70vh, 720px);
400 400 }
401 401  
402   -.product-es-doc-panel {
  402 +.product-result-doc-panel {
403 403 margin-top: 10px;
404 404 padding-top: 8px;
405 405 border-top: 1px dashed #e8e8e8;
406 406 }
407 407  
408   -.product-es-doc-panel-status {
409   - font-size: 12px;
410   - color: #888;
411   -}
412   -
413   -.product-es-doc-pre {
  408 +.product-result-doc-pre {
414 409 margin: 6px 0 0;
415 410 padding: 10px;
416 411 background: #f5f5f5;
... ...
frontend/static/js/app.js
... ... @@ -68,25 +68,25 @@ function initializeApp() {
68 68 // 初始化租户下拉框和分面面板
69 69 console.log('Initializing app...');
70 70 initTenantSelect();
71   - setupProductGridEsDocToggle();
  71 + setupProductGridResultDocToggle();
72 72 const searchInput = document.getElementById('searchInput');
73 73 if (searchInput) {
74 74 searchInput.focus();
75 75 }
76 76 }
77 77  
78   -/** Delegated handler: toggle inline ES raw response under each result card (survives innerHTML refresh on re-search). */
79   -function setupProductGridEsDocToggle() {
  78 +/** Delegated handler: toggle inline current result JSON under each result card (survives innerHTML refresh on re-search). */
  79 +function setupProductGridResultDocToggle() {
80 80 const grid = document.getElementById('productGrid');
81   - if (!grid || grid.dataset.esDocToggleBound === '1') {
  81 + if (!grid || grid.dataset.resultDocToggleBound === '1') {
82 82 return;
83 83 }
84   - grid.dataset.esDocToggleBound = '1';
85   - grid.addEventListener('click', onProductGridEsDocToggleClick);
  84 + grid.dataset.resultDocToggleBound = '1';
  85 + grid.addEventListener('click', onProductGridResultDocToggleClick);
86 86 }
87 87  
88   -async function onProductGridEsDocToggleClick(event) {
89   - const btn = event.target.closest('[data-action="toggle-es-inline-doc"]');
  88 +function onProductGridResultDocToggleClick(event) {
  89 + const btn = event.target.closest('[data-action="toggle-result-inline-doc"]');
90 90 if (!btn) {
91 91 return;
92 92 }
... ... @@ -95,55 +95,27 @@ async function onProductGridEsDocToggleClick(event) {
95 95 if (!debugRoot) {
96 96 return;
97 97 }
98   - const panel = debugRoot.querySelector('.product-es-doc-panel');
99   - const pre = debugRoot.querySelector('.product-es-doc-pre');
100   - const statusEl = debugRoot.querySelector('.product-es-doc-panel-status');
101   - if (!panel || !pre || !statusEl) {
  98 + const panel = debugRoot.querySelector('.product-result-doc-panel');
  99 + const pre = debugRoot.querySelector('.product-result-doc-pre');
  100 + if (!panel || !pre) {
102 101 return;
103 102 }
104 103  
105   - const spuId = btn.getAttribute('data-spu-id') || '';
106   - const tenantId = getTenantId();
107   - const url = `${API_BASE_URL}/search/es-doc/${encodeURIComponent(spuId)}?tenant_id=${encodeURIComponent(tenantId)}`;
108   -
109   - if (debugRoot.dataset.esInlineOpen === '1') {
  104 + if (debugRoot.dataset.resultInlineOpen === '1') {
110 105 panel.setAttribute('hidden', '');
111   - debugRoot.classList.remove('product-debug--es-expanded');
112   - debugRoot.dataset.esInlineOpen = '0';
113   - btn.textContent = '在结果中显示 ES 文档';
  106 + debugRoot.classList.remove('product-debug--result-expanded');
  107 + debugRoot.dataset.resultInlineOpen = '0';
  108 + btn.textContent = '在结果中显示当前结果数据';
114 109 return;
115 110 }
116 111  
117 112 panel.removeAttribute('hidden');
118   - debugRoot.classList.add('product-debug--es-expanded');
119   - debugRoot.dataset.esInlineOpen = '1';
120   - btn.textContent = '隐藏 ES 文档';
121   -
122   - if (pre.textContent.length > 0) {
123   - panel.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
124   - return;
125   - }
126   -
127   - statusEl.style.display = '';
128   - statusEl.textContent = '加载中…';
129   - pre.style.display = 'none';
130   -
131   - try {
132   - const response = await fetch(url);
133   - if (!response.ok) {
134   - const errText = await response.text();
135   - throw new Error(`HTTP ${response.status}: ${errText.slice(0, 200)}`);
136   - }
137   - const data = await response.json();
138   - pre.textContent = customStringify(data);
139   - statusEl.style.display = 'none';
140   - pre.style.display = 'block';
141   - } catch (err) {
142   - console.error('ES doc fetch failed', err);
143   - statusEl.textContent = `加载失败: ${err.message || err}`;
144   - pre.style.display = 'none';
  113 + debugRoot.classList.add('product-debug--result-expanded');
  114 + debugRoot.dataset.resultInlineOpen = '1';
  115 + btn.textContent = '隐藏当前结果数据';
  116 + if (pre.textContent.length === 0) {
  117 + pre.textContent = btn.getAttribute('data-result-json') || '{}';
145 118 }
146   -
147 119 panel.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
148 120 }
149 121  
... ... @@ -213,7 +185,7 @@ function initTenantSelect() {
213 185 });
214 186 // 设置默认值(仅当输入框为空时)
215 187 if (!tenantSelect.value.trim()) {
216   - tenantSelect.value = availableTenants.includes('170') ? '170' : availableTenants[0];
  188 + tenantSelect.value = availableTenants.includes('0') ? '0' : availableTenants[0];
217 189 }
218 190 }
219 191  
... ... @@ -462,6 +434,7 @@ function displayResults(data) {
462 434 });
463 435 }
464 436  
  437 + const resultJson = customStringify(result);
465 438 const rawUrl = `${API_BASE_URL}/search/es-doc/${encodeURIComponent(spuId)}?tenant_id=${encodeURIComponent(tenantId)}`;
466 439  
467 440 debugHtml = `
... ... @@ -475,18 +448,17 @@ function displayResults(data) {
475 448 <div class="product-debug-line">Fused score: ${fusedScore}</div>
476 449 ${titleLines}
477 450 <div class="product-debug-actions">
478   - <button type="button" class="product-debug-inline-es-btn"
479   - data-action="toggle-es-inline-doc"
480   - data-spu-id="${escapeAttr(String(spuId || ''))}">
481   - 在结果中显示 ES 文档
  451 + <button type="button" class="product-debug-inline-result-btn"
  452 + data-action="toggle-result-inline-doc"
  453 + data-result-json="${escapeAttr(resultJson)}">
  454 + 在结果中显示当前结果数据
482 455 </button>
483 456 <a class="product-debug-link" href="${rawUrl}" target="_blank" rel="noopener noreferrer">
484 457 查看 ES 原始文档
485 458 </a>
486 459 </div>
487   - <div class="product-es-doc-panel" hidden>
488   - <div class="product-es-doc-panel-status"></div>
489   - <pre class="product-es-doc-pre"></pre>
  460 + <div class="product-result-doc-panel" hidden>
  461 + <pre class="product-result-doc-pre"></pre>
490 462 </div>
491 463 </div>
492 464 `;
... ...
scripts/start_embedding_service.sh
... ... @@ -138,7 +138,11 @@ fi
138 138 if [[ "${IMAGE_MODEL_ENABLED}" == "1" ]]; then
139 139 echo "Image max inflight: ${IMAGE_MAX_INFLIGHT:-1}"
140 140 fi
141   -echo "Logs: logs/embedding_api.log, logs/embedding_api_error.log, logs/verbose/embedding_verbose.log"
  141 +if [[ "${SERVICE_KIND}" == "image" ]]; then
  142 + echo "Logs: logs/embedding-image.log"
  143 +else
  144 + echo "Logs: logs/embedding.log"
  145 +fi
142 146 echo
143 147 echo "Tips:"
144 148 echo " - Use a single worker (GPU models cannot be safely duplicated across workers)."
... ... @@ -153,12 +157,16 @@ echo
153 157  
154 158 UVICORN_LOG_LEVEL="${EMBEDDING_UVICORN_LOG_LEVEL:-info}"
155 159 UVICORN_ACCESS_LOG="${EMBEDDING_UVICORN_ACCESS_LOG:-true}"
  160 +UVICORN_LOG_CONFIG="${EMBEDDING_UVICORN_LOG_CONFIG:-${PROJECT_ROOT}/config/uvicorn_embedding_logging.json}"
156 161 UVICORN_ARGS=(
157 162 --host "${EMBEDDING_SERVICE_HOST}"
158 163 --port "${EMBEDDING_SERVICE_PORT}"
159 164 --workers 1
160 165 --log-level "${UVICORN_LOG_LEVEL}"
161 166 )
  167 +if [[ -f "${UVICORN_LOG_CONFIG}" ]]; then
  168 + UVICORN_ARGS+=(--log-config "${UVICORN_LOG_CONFIG}")
  169 +fi
162 170 if [[ "${UVICORN_ACCESS_LOG}" == "0" || "${UVICORN_ACCESS_LOG}" == "false" || "${UVICORN_ACCESS_LOG}" == "no" ]]; then
163 171 UVICORN_ARGS+=(--no-access-log)
164 172 fi
... ...