Files
hyapi-server/internal/shared/fadada/debug_log.go
2026-07-21 15:53:29 +08:00

141 lines
3.7 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package fadada
import (
"fmt"
"os"
"path/filepath"
"strings"
"sync"
"time"
)
// debug 日志:将每次法大大 OpenAPI 调用的 cURL 命令 + 响应落盘到 logs/fadada/<date>/fadada.log
// 用于排查 /sign-task/create-with-template 等接口的实际请求/响应(如免验证签不生效)。
// 敏感字段AppSecret不会出现在日志里AccessToken / Sign 会以明文写入以便复现。
const (
debugLogDir = "logs/fadada"
debugLogFile = "fadada.log"
debugMaxBytes = 10 * 1024 * 1024 // 单文件 10MB 后截断覆盖(轮转保持简单)
)
var (
debugLogMu sync.Mutex
debugLogFilePtr *os.File
debugLogDate string
debugLogSize int64
)
// writeDebugLog 把一次 API 调用的请求与响应追加到当日日志文件。
// 调用方需保证 headers / body / respBody 不包含 AppSecret法大大签名里只有时间戳参与secret 本身不出现在 header/body 中)。
func writeDebugLog(method, fullURL string, headers map[string]string, body string, httpStatus int, respBody string, requestID string) {
if strings.TrimSpace(fullURL) == "" {
return
}
entry := buildDebugEntry(method, fullURL, headers, body, httpStatus, respBody, requestID)
debugLogMu.Lock()
defer debugLogMu.Unlock()
if err := openDebugLogFileLocked(); err != nil {
// 日志失败不影响业务
return
}
n, _ := debugLogFilePtr.WriteString(entry)
debugLogSize += int64(n)
if debugLogSize >= debugMaxBytes {
_ = debugLogFilePtr.Close()
debugLogFilePtr = nil
debugLogSize = 0
}
}
func openDebugLogFileLocked() error {
today := time.Now().Format("2006-01-02")
if debugLogFilePtr != nil && debugLogDate == today {
return nil
}
if debugLogFilePtr != nil {
_ = debugLogFilePtr.Close()
}
dateDir := filepath.Join(debugLogDir, today)
if err := os.MkdirAll(dateDir, 0o755); err != nil {
return err
}
full := filepath.Join(dateDir, debugLogFile)
f, err := os.OpenFile(full, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644)
if err != nil {
return err
}
if info, err := f.Stat(); err == nil {
debugLogSize = info.Size()
} else {
debugLogSize = 0
}
debugLogFilePtr = f
debugLogDate = today
return nil
}
// buildDebugEntry 生成一段可读的日志条目cURL 命令 + 响应)。
func buildDebugEntry(method, fullURL string, headers map[string]string, body string, httpStatus int, respBody string, requestID string) string {
now := time.Now().Format("2006-01-02 15:04:05.000")
var sb strings.Builder
sb.WriteString("\n==================== ")
sb.WriteString(now)
sb.WriteString(" ====================\n")
// ---- cURL ----
sb.WriteString("curl -sS -X ")
sb.WriteString(strings.ToUpper(strings.TrimSpace(method)))
sb.WriteString(" '")
sb.WriteString(fullURL)
sb.WriteString("'")
for _, k := range sortedHeaderKeys(headers) {
sb.WriteString(" \\\n -H '")
sb.WriteString(k)
sb.WriteString(": ")
sb.WriteString(headers[k])
sb.WriteString("'")
}
if strings.TrimSpace(body) != "" {
sb.WriteString(" \\\n --data-urlencode 'bizContent=")
sb.WriteString(body)
sb.WriteString("'")
}
sb.WriteString("\n")
// ---- RESPONSE ----
sb.WriteString("--- RESPONSE ---\n")
sb.WriteString("HTTP ")
sb.WriteString(fmt.Sprintf("%d", httpStatus))
if requestID != "" {
sb.WriteString(" requestId=")
sb.WriteString(requestID)
}
sb.WriteString("\n")
sb.WriteString("body: ")
sb.WriteString(respBody)
sb.WriteString("\n")
return sb.String()
}
func sortedHeaderKeys(headers map[string]string) []string {
keys := make([]string, 0, len(headers))
for k := range headers {
keys = append(keys, k)
}
// 简单冒泡,依赖少
for i := 0; i < len(keys); i++ {
for j := i + 1; j < len(keys); j++ {
if keys[i] > keys[j] {
keys[i], keys[j] = keys[j], keys[i]
}
}
}
return keys
}