MiroFish / internal /proxy /logging.go
pjpjq's picture
feat(space): 部署 notion-manager 并启用密码保护
5d65746 verified
Raw
History Blame Contribute Delete
5.17 kB
package proxy
import (
"bytes"
"encoding/json"
"io"
"log"
"os"
"path/filepath"
"strings"
"sync"
"sync/atomic"
)
var debugLoggingEnabled atomic.Bool
var apiInputLoggingEnabled atomic.Bool
var apiOutputLoggingEnabled atomic.Bool
var notionRequestLoggingEnabled atomic.Bool
var notionResponseLoggingEnabled atomic.Bool
var globalLogWriter = newDebugFilterWriter()
var debugLogTags = []string{
"[debug]",
"[bridge]",
"[session]",
"[thinking]",
"[req]",
"[search]",
"[upload-debug]",
}
type debugFilterWriter struct {
mu sync.RWMutex
out io.Writer
file *os.File
}
func newDebugFilterWriter() *debugFilterWriter {
return &debugFilterWriter{
out: os.Stderr,
}
}
func init() {
debugLoggingEnabled.Store(true)
log.SetOutput(globalLogWriter)
}
func (w *debugFilterWriter) Write(p []byte) (int, error) {
if !DebugLoggingEnabled() && isDebugLogLine(p) {
return len(p), nil
}
w.mu.RLock()
out := w.out
w.mu.RUnlock()
if out == nil {
out = os.Stderr
}
return out.Write(p)
}
func (w *debugFilterWriter) SetOutputPath(path string) error {
path = strings.TrimSpace(path)
target := io.Writer(os.Stderr)
var file *os.File
if path != "" {
dir := filepath.Dir(path)
if dir != "." && dir != "" {
if err := os.MkdirAll(dir, 0755); err != nil {
return err
}
}
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
return err
}
target = f
file = f
}
w.mu.Lock()
oldFile := w.file
w.out = target
w.file = file
w.mu.Unlock()
if oldFile != nil && oldFile != file {
_ = oldFile.Close()
}
return nil
}
func isDebugLogLine(p []byte) bool {
line := string(p)
for _, tag := range debugLogTags {
if strings.Contains(line, tag) {
return true
}
}
return false
}
func SetDebugLoggingEnabled(enabled bool) {
debugLoggingEnabled.Store(enabled)
}
func DebugLoggingEnabled() bool {
return debugLoggingEnabled.Load()
}
func ConfigureLogOutput(path string) error {
return globalLogWriter.SetOutputPath(path)
}
func SetAPILogInputEnabled(enabled bool) {
apiInputLoggingEnabled.Store(enabled)
}
func APILogInputEnabled() bool {
return apiInputLoggingEnabled.Load()
}
func SetAPILogOutputEnabled(enabled bool) {
apiOutputLoggingEnabled.Store(enabled)
}
func APILogOutputEnabled() bool {
return apiOutputLoggingEnabled.Load()
}
func SetNotionRequestLoggingEnabled(enabled bool) {
notionRequestLoggingEnabled.Store(enabled)
}
func NotionRequestLoggingEnabled() bool {
return notionRequestLoggingEnabled.Load()
}
func SetNotionResponseLoggingEnabled(enabled bool) {
notionResponseLoggingEnabled.Store(enabled)
}
func NotionResponseLoggingEnabled() bool {
return notionResponseLoggingEnabled.Load()
}
func LogAPIInputJSON(requestID, label string, v interface{}) {
if !APILogInputEnabled() {
return
}
logJSONPayload("[api-in]", requestID, label, v)
}
func LogAPIInputJSONBytes(requestID, label string, raw []byte) {
if !APILogInputEnabled() {
return
}
logJSONBytesPayload("[api-in]", requestID, label, raw)
}
func LogAPIInputText(requestID, label, text string) {
if !APILogInputEnabled() {
return
}
logTextPayload("[api-in]", requestID, label, text)
}
func LogAPIOutputJSON(requestID, label string, v interface{}) {
if !APILogOutputEnabled() {
return
}
logJSONPayload("[api-out]", requestID, label, v)
}
func LogAPIOutputText(requestID, label, text string) {
if !APILogOutputEnabled() {
return
}
logTextPayload("[api-out]", requestID, label, text)
}
func LogNotionRequestJSON(requestID, label string, v interface{}) {
if !NotionRequestLoggingEnabled() {
return
}
logJSONPayload("[notion-req]", requestID, label, v)
}
func LogNotionResponseJSON(requestID, label string, v interface{}) {
if !NotionResponseLoggingEnabled() {
return
}
logJSONPayload("[notion-resp]", requestID, label, v)
}
func LogNotionResponseJSONBytes(requestID, label string, raw []byte) {
if !NotionResponseLoggingEnabled() {
return
}
logJSONBytesPayload("[notion-resp]", requestID, label, raw)
}
func LogNotionResponseText(requestID, label, text string) {
if !NotionResponseLoggingEnabled() {
return
}
logTextPayload("[notion-resp]", requestID, label, text)
}
func logJSONPayload(tag, requestID, label string, v interface{}) {
raw, err := json.MarshalIndent(v, "", " ")
if err != nil {
log.Printf("%s %s %s marshal error: %v", tag, requestID, label, err)
return
}
logTextPayload(tag, requestID, label, string(raw))
}
func logJSONBytesPayload(tag, requestID, label string, raw []byte) {
var buf bytes.Buffer
if err := json.Indent(&buf, raw, "", " "); err == nil {
logTextPayload(tag, requestID, label, buf.String())
return
}
logTextPayload(tag, requestID, label, string(raw))
}
func logTextPayload(tag, requestID, label, text string) {
label = strings.TrimSpace(label)
requestID = strings.TrimSpace(requestID)
if requestID != "" && label != "" {
log.Printf("%s %s %s\n%s", tag, requestID, label, text)
return
}
if requestID != "" {
log.Printf("%s %s\n%s", tag, requestID, text)
return
}
if label != "" {
log.Printf("%s %s\n%s", tag, label, text)
return
}
log.Printf("%s\n%s", tag, text)
}