log refactor

This commit is contained in:
2026-05-12 19:30:15 +03:00
parent 1d59df2233
commit b17b5333c7
84 changed files with 5827 additions and 3908 deletions

View File

@@ -24,6 +24,7 @@ from typing import Any, Dict, List, Optional, Set, Tuple, Callable
from sqlalchemy.orm import Session
from ...core.logger import logger, belief_scope
from ...core.cot_logger import MarkerLogger
from ...core.config_manager import ConfigManager
from ...models.translate import (
TranslationJob,
@@ -39,6 +40,7 @@ from ...core.superset_client import SupersetClient
from .dictionary import DictionaryManager
from .preview import DEFAULT_EXECUTION_PROMPT_TEMPLATE
log = MarkerLogger("TranslationExecutor")
# #region MAX_RETRIES_PER_BATCH [C:1] [TYPE Constant] [SEMANTICS translate,executor,retry]
MAX_RETRIES_PER_BATCH = 3
@@ -83,7 +85,7 @@ class TranslationExecutor:
if not job:
raise ValueError(f"Job '{run.job_id}' not found for run '{run.id}'")
logger.reason("Starting translation execution", {
log.reason("Starting translation execution", payload={
"run_id": run.id,
"job_id": job.id,
"batch_size": job.batch_size,
@@ -103,7 +105,7 @@ class TranslationExecutor:
# Preview-based: fetch rows from the accepted preview session
source_rows = self._fetch_source_rows(job.id, run.id)
if not source_rows:
logger.explore("No source rows to translate", {"run_id": run.id})
log.explore("No source rows to translate", payload={"run_id": run.id}, error="Preview produced 0 source rows for translation")
run.status = "COMPLETED"
run.completed_at = datetime.now(timezone.utc)
self.db.flush()
@@ -119,7 +121,7 @@ class TranslationExecutor:
for i in range(0, total_rows, batch_size)
]
logger.reason(f"Processing {len(batches)} batches", {
log.reason(f"Processing {len(batches)} batches", payload={
"run_id": run.id,
"total_rows": total_rows,
"batch_size": batch_size,
@@ -163,7 +165,7 @@ class TranslationExecutor:
run.completed_at = datetime.now(timezone.utc)
self.db.flush()
logger.reflect("Translation execution complete", {
log.reflect("Translation execution complete", payload={
"run_id": run.id,
"status": run.status,
"total": total_rows,
@@ -193,7 +195,7 @@ class TranslationExecutor:
.first()
)
if not session:
logger.explore("No accepted preview session found", {"job_id": job_id})
log.explore("No accepted preview session found", error="Preview session has no accepted rows", payload={"job_id": job_id})
return []
# Fetch APPROVED or all records from the session
@@ -216,7 +218,7 @@ class TranslationExecutor:
"source_data": rec.source_data or {},
})
logger.reason(f"Fetched {len(source_rows)} source rows from preview", {
log.reason(f"Fetched {len(source_rows)} source rows from preview", payload={
"run_id": run_id,
"session_id": session.id,
})
@@ -278,7 +280,8 @@ class TranslationExecutor:
headers={"Content-Type": "application/json"},
)
except Exception as e:
logger.explore("Chart data API failed during full fetch", {
log.explore("Chart data API failed during full fetch", error="Chart data API error",
payload={
"offset": len(all_rows),
"error": str(e),
})
@@ -292,7 +295,7 @@ class TranslationExecutor:
break # No more data
all_rows.extend(rows)
logger.reason(f"Fetched {len(rows)} rows (total: {len(all_rows)})", {
log.reason(f"Fetched {len(rows)} rows (total: {len(all_rows)})", payload={
"offset": len(all_rows) - len(rows),
})
@@ -319,7 +322,7 @@ class TranslationExecutor:
"approved_translation": None,
})
logger.reason(f"Prepared {len(source_rows)} source rows for full translation", {
log.reason(f"Prepared {len(source_rows)} source rows for full translation", payload={
"job_id": job.id,
})
return source_rows
@@ -416,7 +419,7 @@ class TranslationExecutor:
self.db.flush()
batch_latency = int((time.monotonic() - batch_start) * 1000)
logger.reason(f"Batch {batch_index} complete", {
log.reason(f"Batch {batch_index} complete", payload={
"batch_id": batch_id,
"latency_ms": batch_latency,
**result,
@@ -490,7 +493,8 @@ class TranslationExecutor:
except Exception as e:
last_error = str(e)
retries += 1
logger.explore(f"LLM call failed (attempt {attempt})", {
log.explore("LLM call failed", error="LLM call failed, retrying",
payload={
"batch_id": batch_id,
"error": last_error,
"attempt": attempt,
@@ -498,7 +502,8 @@ class TranslationExecutor:
if attempt < MAX_RETRIES_PER_BATCH:
time.sleep(2 ** attempt) # Exponential backoff
else:
logger.explore("LLM call exhausted retries", {
log.explore("LLM call exhausted retries", error="LLM retries exhausted",
payload={
"batch_id": batch_id,
"last_error": last_error,
})
@@ -527,7 +532,8 @@ class TranslationExecutor:
translations = self._parse_llm_response(llm_response, len(batch_rows))
except ValueError as e:
# Parse failure — mark all rows as SKIPPED
logger.explore("LLM response parse failed", {
log.explore("LLM response parse failed", error="Failed to parse LLM JSON response",
payload={
"batch_id": batch_id,
"error": str(e),
"response_preview": llm_response[:500] if llm_response else "",
@@ -693,7 +699,7 @@ class TranslationExecutor:
if provider_type in ("openai", "openai_compatible"):
payload["response_format"] = {"type": "json_object"}
logger.reason(
log.reason(
f"LLM request model={payload.get('model')} "
f"provider_type={provider_type} "
f"response_format={'yes' if 'response_format' in payload else 'no'} "
@@ -701,11 +707,11 @@ class TranslationExecutor:
)
response = http_requests.post(url, headers=headers, json=payload, timeout=180)
if not response.ok:
logger.explore(
f"LLM API error status={response.status_code} "
f"model={payload.get('model')} "
f"body={response.text[:2000]}"
)
log.explore("LLM API error", error=f"LLM API returned status {response.status_code}", payload={
"status_code": response.status_code,
"model": payload.get('model'),
"body": response.text[:2000],
})
response.raise_for_status()
data = response.json()
@@ -717,7 +723,8 @@ class TranslationExecutor:
if not content:
# Log full response for diagnostics
finish_reason = choices[0].get("finish_reason", "unknown")
logger.explore("LLM returned empty content", {
log.explore("LLM returned empty content", error="Empty response from LLM",
payload={
"finish_reason": finish_reason,
"model": payload.get("model"),
"prompt_len": len(prompt),