diff --git a/insta-lab/app/keyword_extractor.py b/insta-lab/app/keyword_extractor.py index 31c10bd..c1102b0 100644 --- a/insta-lab/app/keyword_extractor.py +++ b/insta-lab/app/keyword_extractor.py @@ -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"]), }) saved.append({"id": kid, **kw, "category": category}) + logger.info(f"키워드 추출 완료: category={category!r}, count={len(saved)}") return saved diff --git a/insta-lab/app/main.py b/insta-lab/app/main.py index 06a7dd9..93d1610 100644 --- a/insta-lab/app/main.py +++ b/insta-lab/app/main.py @@ -173,6 +173,7 @@ async def _bg_create_slate(task_id: str, keyword: str, category: str, keyword_id "submitted_at": datetime.now(kst).isoformat(), } 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 db.update_task(task_id, "processing", 70, "Redis 큐 푸시 → Windows worker 대기 중", result_id=sid) except Exception as e: @@ -219,6 +220,7 @@ async def _bg_render(task_id: str, slate_id: int): "submitted_at": datetime.now(kst).isoformat(), } 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 대기 중") except Exception as e: logger.exception("queue push failed") diff --git a/lotto/app/main.py b/lotto/app/main.py index ed6647b..f6e9497 100644 --- a/lotto/app/main.py +++ b/lotto/app/main.py @@ -704,6 +704,7 @@ def api_recommend( metrics = calc_metrics(chosen) overlap = calc_recent_overlap(chosen, draws, last_k=avoid_recent_k) + logger.info(f"추천 생성 완료: numbers={chosen}, tries={tries}, saved={saved['saved']}") return { "id": saved["id"], diff --git a/lotto/app/routers/briefing.py b/lotto/app/routers/briefing.py index e6516b0..103e079 100644 --- a/lotto/app/routers/briefing.py +++ b/lotto/app/routers/briefing.py @@ -1,9 +1,12 @@ """브리핑 저장/조회 + 큐레이터 사용량 엔드포인트.""" +import logging from typing import Any, Dict, List from fastapi import APIRouter, HTTPException from pydantic import BaseModel, Field from .. import db +logger = logging.getLogger(__name__) + router = APIRouter(prefix="/api/lotto") @@ -38,6 +41,7 @@ class BriefingRequest(BaseModel): @router.post("/briefing", status_code=201) def save_briefing(body: BriefingRequest): 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} diff --git a/music-lab/app/main.py b/music-lab/app/main.py index 1b5002d..a5e7954 100644 --- a/music-lab/app/main.py +++ b/music-lab/app/main.py @@ -1,4 +1,5 @@ import json +import logging import os import shutil import uuid @@ -9,6 +10,8 @@ from fastapi.middleware.cors import CORSMiddleware from pydantic import BaseModel from _shared.access_log import install as install_access_log +logger = logging.getLogger(__name__) + from .db import ( init_db, create_task, get_task, @@ -159,9 +162,11 @@ async def generate_music(req: GenerateRequest): task_id = str(uuid.uuid4()) 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) job_type = "suno_generation" if provider == "suno" else "local_generation" 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} diff --git a/stock/app/main.py b/stock/app/main.py index e39c5f1..8f32835 100644 --- a/stock/app/main.py +++ b/stock/app/main.py @@ -256,6 +256,7 @@ def order_stock(req: OrderRequest): if resp.status_code != 200: logger.error(f"Order Error: {resp.status_code}") 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() except ValueError: 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"} 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: resp = requests.post( @@ -298,7 +300,10 @@ def ai_coach(req: AiCoachRequest): if resp.status_code != 200: logger.error(f"Anthropic API error: {resp.status_code}") 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: return JSONResponse(status_code=504, content={"error": "AI API timeout"}) except Exception as e: diff --git a/stock/app/screener/router.py b/stock/app/screener/router.py index 14fdfd8..66994f6 100644 --- a/stock/app/screener/router.py +++ b/stock/app/screener/router.py @@ -4,12 +4,15 @@ from __future__ import annotations import datetime as dt import json +import logging import os import sqlite3 from typing import Optional from fastapi import APIRouter, HTTPException +logger = logging.getLogger(__name__) + from . import schemas from .registry import NODE_REGISTRY, GATE_REGISTRY from .. import webai_cache @@ -246,6 +249,7 @@ def post_run(body: schemas.RunRequest): telegram_payload=schemas.TelegramPayload(**payload), warnings=result.warnings, ) + logger.info(f"Screener 완료: mode={body.mode}, asof={asof.isoformat()}, survivors={result.survivors_count}, top_n={top_n}") # SP-A2 — preview 모드 결과 캐시 저장. if body.mode == "preview": webai_cache.cache_set_screener(body.mode, body.top_n, body.weights, response)