feat(P3): 5개 서비스 비즈니스 이벤트 logger.info 보강

This commit is contained in:
2026-05-28 22:38:43 +09:00
parent c5c260aefc
commit 2bfbd1dd93
7 changed files with 23 additions and 1 deletions

View File

@@ -80,6 +80,7 @@ def extract_for_category(category: str, limit: int = KEYWORDS_PER_CATEGORY) -> L
"articles_count": sum(1 for a in articles if kw["keyword"] in a["title"]), "articles_count": sum(1 for a in articles if kw["keyword"] in a["title"]),
}) })
saved.append({"id": kid, **kw, "category": category}) saved.append({"id": kid, **kw, "category": category})
logger.info(f"키워드 추출 완료: category={category!r}, count={len(saved)}")
return saved return saved

View File

@@ -173,6 +173,7 @@ async def _bg_create_slate(task_id: str, keyword: str, category: str, keyword_id
"submitted_at": datetime.now(kst).isoformat(), "submitted_at": datetime.now(kst).isoformat(),
} }
await redis_client.rpush("queue:insta-render", json.dumps(payload)) await redis_client.rpush("queue:insta-render", json.dumps(payload))
logger.info(f"슬레이트 생성 완료: slate_id={sid}, keyword={keyword!r}, category={category!r}")
# 사용자는 GET /api/insta/tasks/{task_id}로 폴링 — worker가 webhook으로 status update # 사용자는 GET /api/insta/tasks/{task_id}로 폴링 — worker가 webhook으로 status update
db.update_task(task_id, "processing", 70, "Redis 큐 푸시 → Windows worker 대기 중", result_id=sid) db.update_task(task_id, "processing", 70, "Redis 큐 푸시 → Windows worker 대기 중", result_id=sid)
except Exception as e: except Exception as e:
@@ -219,6 +220,7 @@ async def _bg_render(task_id: str, slate_id: int):
"submitted_at": datetime.now(kst).isoformat(), "submitted_at": datetime.now(kst).isoformat(),
} }
await redis_client.rpush("queue:insta-render", json.dumps(payload)) await redis_client.rpush("queue:insta-render", json.dumps(payload))
logger.info(f"렌더 큐 푸시 완료: slate_id={slate_id}, task_id={task_id}")
db.update_task(task_id, "processing", 30, "Redis 큐 푸시 → Windows worker 대기 중") db.update_task(task_id, "processing", 30, "Redis 큐 푸시 → Windows worker 대기 중")
except Exception as e: except Exception as e:
logger.exception("queue push failed") logger.exception("queue push failed")

View File

@@ -704,6 +704,7 @@ def api_recommend(
metrics = calc_metrics(chosen) metrics = calc_metrics(chosen)
overlap = calc_recent_overlap(chosen, draws, last_k=avoid_recent_k) overlap = calc_recent_overlap(chosen, draws, last_k=avoid_recent_k)
logger.info(f"추천 생성 완료: numbers={chosen}, tries={tries}, saved={saved['saved']}")
return { return {
"id": saved["id"], "id": saved["id"],

View File

@@ -1,9 +1,12 @@
"""브리핑 저장/조회 + 큐레이터 사용량 엔드포인트.""" """브리핑 저장/조회 + 큐레이터 사용량 엔드포인트."""
import logging
from typing import Any, Dict, List from typing import Any, Dict, List
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from .. import db from .. import db
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/lotto") router = APIRouter(prefix="/api/lotto")
@@ -38,6 +41,7 @@ class BriefingRequest(BaseModel):
@router.post("/briefing", status_code=201) @router.post("/briefing", status_code=201)
def save_briefing(body: BriefingRequest): def save_briefing(body: BriefingRequest):
bid = db.save_briefing(body.model_dump()) bid = db.save_briefing(body.model_dump())
logger.info(f"브리핑 저장 완료: id={bid}, draw_no={body.draw_no}, model={body.model!r}, input_tokens={body.tokens_input}, output_tokens={body.tokens_output}")
return {"ok": True, "id": bid} return {"ok": True, "id": bid}

View File

@@ -1,4 +1,5 @@
import json import json
import logging
import os import os
import shutil import shutil
import uuid import uuid
@@ -9,6 +10,8 @@ from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel from pydantic import BaseModel
from _shared.access_log import install as install_access_log from _shared.access_log import install as install_access_log
logger = logging.getLogger(__name__)
from .db import ( from .db import (
init_db, init_db,
create_task, get_task, create_task, get_task,
@@ -159,9 +162,11 @@ async def generate_music(req: GenerateRequest):
task_id = str(uuid.uuid4()) task_id = str(uuid.uuid4())
params = req.model_dump() params = req.model_dump()
logger.info(f"음악 생성 요청: provider={provider}, title={req.title!r}, genre={req.genre!r}, task_id={task_id}")
create_task(task_id, params, provider=provider) create_task(task_id, params, provider=provider)
job_type = "suno_generation" if provider == "suno" else "local_generation" job_type = "suno_generation" if provider == "suno" else "local_generation"
await _push_render_job(task_id, job_type, params) await _push_render_job(task_id, job_type, params)
logger.info(f"음악 생성 큐 푸시 완료: task_id={task_id}, job_type={job_type}")
return {"task_id": task_id, "provider": provider} return {"task_id": task_id, "provider": provider}

View File

@@ -256,6 +256,7 @@ def order_stock(req: OrderRequest):
if resp.status_code != 200: if resp.status_code != 200:
logger.error(f"Order Error: {resp.status_code}") logger.error(f"Order Error: {resp.status_code}")
return JSONResponse(status_code=resp.status_code, content=resp.json()) return JSONResponse(status_code=resp.status_code, content=resp.json())
logger.info(f"Order Response: {req.action} {req.ticker} x{req.quantity} → OK")
return resp.json() return resp.json()
except ValueError: except ValueError:
status = resp.status_code if resp is not None else 502 status = resp.status_code if resp is not None else 502
@@ -279,6 +280,7 @@ def ai_coach(req: AiCoachRequest):
allowed_models = {"claude-haiku-4-5-20251001", "claude-sonnet-4-6"} allowed_models = {"claude-haiku-4-5-20251001", "claude-sonnet-4-6"}
model = req.model if req.model in allowed_models else "claude-haiku-4-5-20251001" model = req.model if req.model in allowed_models else "claude-haiku-4-5-20251001"
logger.info(f"AI Coach 호출: model={model}, prompt_len={len(req.prompt)}")
try: try:
resp = requests.post( resp = requests.post(
@@ -298,7 +300,10 @@ def ai_coach(req: AiCoachRequest):
if resp.status_code != 200: if resp.status_code != 200:
logger.error(f"Anthropic API error: {resp.status_code}") logger.error(f"Anthropic API error: {resp.status_code}")
return JSONResponse(status_code=resp.status_code, content={"error": "AI API error"}) return JSONResponse(status_code=resp.status_code, content={"error": "AI API error"})
return resp.json() data = resp.json()
usage = data.get("usage", {})
logger.info(f"AI Coach 응답 완료: model={model}, input={usage.get('input_tokens', '?')}, output={usage.get('output_tokens', '?')}")
return data
except requests.Timeout: except requests.Timeout:
return JSONResponse(status_code=504, content={"error": "AI API timeout"}) return JSONResponse(status_code=504, content={"error": "AI API timeout"})
except Exception as e: except Exception as e:

View File

@@ -4,12 +4,15 @@ from __future__ import annotations
import datetime as dt import datetime as dt
import json import json
import logging
import os import os
import sqlite3 import sqlite3
from typing import Optional from typing import Optional
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
logger = logging.getLogger(__name__)
from . import schemas from . import schemas
from .registry import NODE_REGISTRY, GATE_REGISTRY from .registry import NODE_REGISTRY, GATE_REGISTRY
from .. import webai_cache from .. import webai_cache
@@ -246,6 +249,7 @@ def post_run(body: schemas.RunRequest):
telegram_payload=schemas.TelegramPayload(**payload), telegram_payload=schemas.TelegramPayload(**payload),
warnings=result.warnings, warnings=result.warnings,
) )
logger.info(f"Screener 완료: mode={body.mode}, asof={asof.isoformat()}, survivors={result.survivors_count}, top_n={top_n}")
# SP-A2 — preview 모드 결과 캐시 저장. # SP-A2 — preview 모드 결과 캐시 저장.
if body.mode == "preview": if body.mode == "preview":
webai_cache.cache_set_screener(body.mode, body.top_n, body.weights, response) webai_cache.cache_set_screener(body.mode, body.top_n, body.weights, response)