Files
hyapi-server/internal/shared/fadada/debug_log.go

141 lines
3.7 KiB
Go
Raw Permalink Normal View History

2026-07-21 15:53:29 +08:00
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
}