refactor: 全面集成 slog 日志到 handler、service、middleware
- cmd/main.go: 集成 logger.Init 和日志中间件,替换标准 log 包 - handler 层: 5xx 错误记录完整日志,返回通用消息(防内部信息泄露) - service 层: LLM/图片生成/存储/认证等关键操作补充结构化日志 - auth 中间件: 记录认证失败原因 - generate.go: 后台管线任务使用带 task_id 的 logger
This commit is contained in:
@@ -11,13 +11,13 @@ import (
|
||||
"image/color"
|
||||
"image/png"
|
||||
"io"
|
||||
"log"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gen2d/internal/config"
|
||||
"gen2d/internal/logger"
|
||||
)
|
||||
|
||||
// imgCfg 保存文生图配置,由 main 通过 InitImageGenConfig 注入。
|
||||
@@ -64,21 +64,33 @@ func GenerateImages(ctx context.Context, prompt string, params AssetParams) ([]G
|
||||
count = params.Frames.Directions * params.Frames.FramesPerDirection
|
||||
}
|
||||
|
||||
l := logger.FromCtx(ctx)
|
||||
|
||||
if imgCfg.APIKey != "" {
|
||||
width, height := imgCfg.Width, imgCfg.Height
|
||||
if params.Resolution > 0 {
|
||||
width = params.Resolution
|
||||
height = params.Resolution
|
||||
}
|
||||
log.Println("[inference] calling image gen API")
|
||||
return callImageAPI(ctx, prompt, count, width, height)
|
||||
l.Info("calling image gen API",
|
||||
"model", imgCfg.Model,
|
||||
"count", count,
|
||||
"size", fmt.Sprintf("%dx%d", width, height),
|
||||
)
|
||||
images, err := callImageAPI(ctx, prompt, count, width, height)
|
||||
if err != nil {
|
||||
l.Error("image gen API failed", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
l.Info("image gen API succeeded", "image_count", len(images))
|
||||
return images, nil
|
||||
}
|
||||
|
||||
size := params.Resolution
|
||||
if size <= 0 {
|
||||
size = 64
|
||||
}
|
||||
log.Println("[inference] image API key not configured, using mock")
|
||||
l.Warn("image API key not configured, using mock")
|
||||
return generateMockImages(size, count)
|
||||
}
|
||||
|
||||
@@ -107,10 +119,15 @@ func callImageAPI(ctx context.Context, prompt string, count, width, height int)
|
||||
retryDelay = 5 * time.Second
|
||||
}
|
||||
|
||||
l := logger.FromCtx(ctx)
|
||||
|
||||
var lastErr error
|
||||
for attempt := 0; attempt <= maxRetries; attempt++ {
|
||||
if attempt > 0 {
|
||||
log.Printf("[inference] retrying image API (attempt %d/%d)", attempt, maxRetries)
|
||||
l.Warn("retrying image API",
|
||||
"attempt", attempt,
|
||||
"max_retries", maxRetries,
|
||||
)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, fmt.Errorf("context cancelled during retry: %w", ctx.Err())
|
||||
@@ -128,6 +145,7 @@ func callImageAPI(ctx context.Context, prompt string, count, width, height int)
|
||||
resp, err := imageHTTPClient.Do(req)
|
||||
if err != nil {
|
||||
lastErr = fmt.Errorf("send request: %w", err)
|
||||
l.Warn("image API request failed", "error", lastErr)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -140,8 +158,18 @@ func callImageAPI(ctx context.Context, prompt string, count, width, height int)
|
||||
|
||||
if resp.StatusCode >= 500 {
|
||||
lastErr = fmt.Errorf("image api error %d: %s", resp.StatusCode, string(b))
|
||||
l.Error("image API server error",
|
||||
"status", resp.StatusCode,
|
||||
"body", string(b),
|
||||
"attempt", attempt,
|
||||
)
|
||||
continue
|
||||
}
|
||||
// 4xx 不重试
|
||||
l.Error("image API client error",
|
||||
"status", resp.StatusCode,
|
||||
"body", string(b),
|
||||
)
|
||||
return nil, fmt.Errorf("image api error %d: %s", resp.StatusCode, string(b))
|
||||
}
|
||||
|
||||
@@ -205,10 +233,17 @@ func downloadImage(ctx context.Context, url string) ([]byte, error) {
|
||||
|
||||
// EditImages 图片编辑接口,调用 OpenAI 兼容 Images Edits API(multipart/form-data)。
|
||||
func EditImages(ctx context.Context, imageData []byte, prompt string, count int) ([]GeneratedImage, error) {
|
||||
l := logger.FromCtx(ctx)
|
||||
|
||||
if imgCfg.APIKey == "" {
|
||||
return nil, fmt.Errorf("image API key not configured")
|
||||
}
|
||||
|
||||
l.Info("calling image edit API",
|
||||
"model", imgCfg.Model,
|
||||
"count", count,
|
||||
)
|
||||
|
||||
var buf bytes.Buffer
|
||||
writer := multipart.NewWriter(&buf)
|
||||
|
||||
@@ -239,16 +274,25 @@ func EditImages(ctx context.Context, imageData []byte, prompt string, count int)
|
||||
|
||||
resp, err := imageHTTPClient.Do(req)
|
||||
if err != nil {
|
||||
l.Error("image edit API request failed", "error", err)
|
||||
return nil, fmt.Errorf("send request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
b, _ := io.ReadAll(io.LimitReader(resp.Body, 4096))
|
||||
l.Error("image edit API error", "status", resp.StatusCode, "body", string(b))
|
||||
return nil, fmt.Errorf("image edit api error %d: %s", resp.StatusCode, string(b))
|
||||
}
|
||||
|
||||
return parseImageResponse(ctx, resp.Body, imgCfg.Width, imgCfg.Height)
|
||||
images, err := parseImageResponse(ctx, resp.Body, imgCfg.Width, imgCfg.Height)
|
||||
if err != nil {
|
||||
l.Error("image edit response parse failed", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
l.Info("image edit API succeeded", "image_count", len(images))
|
||||
return images, nil
|
||||
}
|
||||
|
||||
// ======================== 质检 ========================
|
||||
|
||||
Reference in New Issue
Block a user