Commit 41856690519fed26bb9e35095fd8e72d54316497

Authored by tangwang
1 parent 0ea456b2

embedding logs

embeddings/server.py
@@ -14,7 +14,6 @@ import time @@ -14,7 +14,6 @@ import time
14 import uuid 14 import uuid
15 from collections import deque 15 from collections import deque
16 from dataclasses import dataclass 16 from dataclasses import dataclass
17 -from logging.handlers import TimedRotatingFileHandler  
18 from typing import Any, Dict, List, Optional 17 from typing import Any, Dict, List, Optional
19 18
20 import numpy as np 19 import numpy as np
@@ -44,9 +43,7 @@ def configure_embedding_logging() -> None: @@ -44,9 +43,7 @@ def configure_embedding_logging() -> None:
44 return 43 return
45 44
46 log_dir = pathlib.Path("logs") 45 log_dir = pathlib.Path("logs")
47 - verbose_dir = log_dir / "verbose"  
48 log_dir.mkdir(exist_ok=True) 46 log_dir.mkdir(exist_ok=True)
49 - verbose_dir.mkdir(parents=True, exist_ok=True)  
50 47
51 log_level = os.getenv("LOG_LEVEL", "INFO").upper() 48 log_level = os.getenv("LOG_LEVEL", "INFO").upper()
52 numeric_level = getattr(logging, log_level, logging.INFO) 49 numeric_level = getattr(logging, log_level, logging.INFO)
@@ -56,47 +53,18 @@ def configure_embedding_logging() -> None: @@ -56,47 +53,18 @@ def configure_embedding_logging() -> None:
56 request_filter = _DefaultRequestIdFilter() 53 request_filter = _DefaultRequestIdFilter()
57 54
58 root_logger.setLevel(numeric_level) 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 verbose_logger = logging.getLogger("embedding.verbose") 63 verbose_logger = logging.getLogger("embedding.verbose")
85 verbose_logger.setLevel(numeric_level) 64 verbose_logger.setLevel(numeric_level)
86 verbose_logger.handlers.clear() 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 root_logger._embedding_logging_configured = True # type: ignore[attr-defined] 69 root_logger._embedding_logging_configured = True # type: ignore[attr-defined]
102 70
frontend/static/css/style.css
@@ -379,7 +379,7 @@ body { @@ -379,7 +379,7 @@ body {
379 margin-top: 8px; 379 margin-top: 8px;
380 } 380 }
381 381
382 -.product-debug-inline-es-btn { 382 +.product-debug-inline-result-btn {
383 font-family: inherit; 383 font-family: inherit;
384 font-size: 12px; 384 font-size: 12px;
385 padding: 4px 10px; 385 padding: 4px 10px;
@@ -390,27 +390,22 @@ body { @@ -390,27 +390,22 @@ body {
390 cursor: pointer; 390 cursor: pointer;
391 } 391 }
392 392
393 -.product-debug-inline-es-btn:hover { 393 +.product-debug-inline-result-btn:hover {
394 background: #f0f0f0; 394 background: #f0f0f0;
395 border-color: #bbb; 395 border-color: #bbb;
396 } 396 }
397 397
398 -.product-debug--es-expanded { 398 +.product-debug--result-expanded {
399 max-height: min(70vh, 720px); 399 max-height: min(70vh, 720px);
400 } 400 }
401 401
402 -.product-es-doc-panel { 402 +.product-result-doc-panel {
403 margin-top: 10px; 403 margin-top: 10px;
404 padding-top: 8px; 404 padding-top: 8px;
405 border-top: 1px dashed #e8e8e8; 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 margin: 6px 0 0; 409 margin: 6px 0 0;
415 padding: 10px; 410 padding: 10px;
416 background: #f5f5f5; 411 background: #f5f5f5;
frontend/static/js/app.js
@@ -68,25 +68,25 @@ function initializeApp() { @@ -68,25 +68,25 @@ function initializeApp() {
68 // 初始化租户下拉框和分面面板 68 // 初始化租户下拉框和分面面板
69 console.log('Initializing app...'); 69 console.log('Initializing app...');
70 initTenantSelect(); 70 initTenantSelect();
71 - setupProductGridEsDocToggle(); 71 + setupProductGridResultDocToggle();
72 const searchInput = document.getElementById('searchInput'); 72 const searchInput = document.getElementById('searchInput');
73 if (searchInput) { 73 if (searchInput) {
74 searchInput.focus(); 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 const grid = document.getElementById('productGrid'); 80 const grid = document.getElementById('productGrid');
81 - if (!grid || grid.dataset.esDocToggleBound === '1') { 81 + if (!grid || grid.dataset.resultDocToggleBound === '1') {
82 return; 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 if (!btn) { 90 if (!btn) {
91 return; 91 return;
92 } 92 }
@@ -95,55 +95,27 @@ async function onProductGridEsDocToggleClick(event) { @@ -95,55 +95,27 @@ async function onProductGridEsDocToggleClick(event) {
95 if (!debugRoot) { 95 if (!debugRoot) {
96 return; 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 return; 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 panel.setAttribute('hidden', ''); 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 return; 109 return;
115 } 110 }
116 111
117 panel.removeAttribute('hidden'); 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 panel.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); 119 panel.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
148 } 120 }
149 121
@@ -213,7 +185,7 @@ function initTenantSelect() { @@ -213,7 +185,7 @@ function initTenantSelect() {
213 }); 185 });
214 // 设置默认值(仅当输入框为空时) 186 // 设置默认值(仅当输入框为空时)
215 if (!tenantSelect.value.trim()) { 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,6 +434,7 @@ function displayResults(data) {
462 }); 434 });
463 } 435 }
464 436
  437 + const resultJson = customStringify(result);
465 const rawUrl = `${API_BASE_URL}/search/es-doc/${encodeURIComponent(spuId)}?tenant_id=${encodeURIComponent(tenantId)}`; 438 const rawUrl = `${API_BASE_URL}/search/es-doc/${encodeURIComponent(spuId)}?tenant_id=${encodeURIComponent(tenantId)}`;
466 439
467 debugHtml = ` 440 debugHtml = `
@@ -475,18 +448,17 @@ function displayResults(data) { @@ -475,18 +448,17 @@ function displayResults(data) {
475 <div class="product-debug-line">Fused score: ${fusedScore}</div> 448 <div class="product-debug-line">Fused score: ${fusedScore}</div>
476 ${titleLines} 449 ${titleLines}
477 <div class="product-debug-actions"> 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 </button> 455 </button>
483 <a class="product-debug-link" href="${rawUrl}" target="_blank" rel="noopener noreferrer"> 456 <a class="product-debug-link" href="${rawUrl}" target="_blank" rel="noopener noreferrer">
484 查看 ES 原始文档 457 查看 ES 原始文档
485 </a> 458 </a>
486 </div> 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 </div> 462 </div>
491 </div> 463 </div>
492 `; 464 `;
scripts/start_embedding_service.sh
@@ -138,7 +138,11 @@ fi @@ -138,7 +138,11 @@ fi
138 if [[ "${IMAGE_MODEL_ENABLED}" == "1" ]]; then 138 if [[ "${IMAGE_MODEL_ENABLED}" == "1" ]]; then
139 echo "Image max inflight: ${IMAGE_MAX_INFLIGHT:-1}" 139 echo "Image max inflight: ${IMAGE_MAX_INFLIGHT:-1}"
140 fi 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 echo 146 echo
143 echo "Tips:" 147 echo "Tips:"
144 echo " - Use a single worker (GPU models cannot be safely duplicated across workers)." 148 echo " - Use a single worker (GPU models cannot be safely duplicated across workers)."
@@ -153,12 +157,16 @@ echo @@ -153,12 +157,16 @@ echo
153 157
154 UVICORN_LOG_LEVEL="${EMBEDDING_UVICORN_LOG_LEVEL:-info}" 158 UVICORN_LOG_LEVEL="${EMBEDDING_UVICORN_LOG_LEVEL:-info}"
155 UVICORN_ACCESS_LOG="${EMBEDDING_UVICORN_ACCESS_LOG:-true}" 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 UVICORN_ARGS=( 161 UVICORN_ARGS=(
157 --host "${EMBEDDING_SERVICE_HOST}" 162 --host "${EMBEDDING_SERVICE_HOST}"
158 --port "${EMBEDDING_SERVICE_PORT}" 163 --port "${EMBEDDING_SERVICE_PORT}"
159 --workers 1 164 --workers 1
160 --log-level "${UVICORN_LOG_LEVEL}" 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 if [[ "${UVICORN_ACCESS_LOG}" == "0" || "${UVICORN_ACCESS_LOG}" == "false" || "${UVICORN_ACCESS_LOG}" == "no" ]]; then 170 if [[ "${UVICORN_ACCESS_LOG}" == "0" || "${UVICORN_ACCESS_LOG}" == "false" || "${UVICORN_ACCESS_LOG}" == "no" ]]; then
163 UVICORN_ARGS+=(--no-access-log) 171 UVICORN_ARGS+=(--no-access-log)
164 fi 172 fi