fadd
This commit is contained in:
140
internal/shared/fadada/debug_log.go
Normal file
140
internal/shared/fadada/debug_log.go
Normal file
@@ -0,0 +1,140 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user