refactor(gemini-web): Standardize logging with logrus

This commit is contained in:
hkfires
2025-09-24 22:13:10 +08:00
parent d4f5ec2492
commit c76b8785f8
5 changed files with 37 additions and 140 deletions

1
.gitignore vendored
View File

@@ -12,4 +12,3 @@ AGENTS.md
CLAUDE.md CLAUDE.md
*.exe *.exe
temp/* temp/*
.serena/

View File

@@ -12,6 +12,8 @@ import (
"regexp" "regexp"
"strings" "strings"
"time" "time"
log "github.com/sirupsen/logrus"
) )
type httpOptions struct { type httpOptions struct {
@@ -103,7 +105,7 @@ func getAccessToken(baseCookies map[string]string, proxy string, verbose bool, i
} }
trySets = append(trySets, merged) trySets = append(trySets, merged)
} else if verbose { } else if verbose {
Debug("Skipping base cookies: __Secure-1PSIDTS missing") log.Debug("Skipping base cookies: __Secure-1PSIDTS missing")
} }
} }
@@ -130,7 +132,7 @@ func getAccessToken(baseCookies map[string]string, proxy string, verbose bool, i
resp, mergedCookies, err := sendInitRequest(cookies, proxy, insecure) resp, mergedCookies, err := sendInitRequest(cookies, proxy, insecure)
if err != nil { if err != nil {
if verbose { if verbose {
Warning("Failed init request: %v", err) log.Warnf("Failed init request: %v", err)
} }
continue continue
} }
@@ -143,7 +145,7 @@ func getAccessToken(baseCookies map[string]string, proxy string, verbose bool, i
if len(matches) >= 2 { if len(matches) >= 2 {
token := matches[1] token := matches[1]
if verbose { if verbose {
Success("Gemini access token acquired.") log.Infof("Gemini access token acquired.")
} }
return token, mergedCookies, nil return token, mergedCookies, nil
} }
@@ -212,3 +214,27 @@ func (r *constReader) Read(p []byte) (int, error) {
} }
func stringsReader(s string) io.Reader { return &constReader{s: s} } func stringsReader(s string) io.Reader { return &constReader{s: s} }
func MaskToken28(s string) string {
n := len(s)
if n == 0 {
return ""
}
if n < 20 {
return strings.Repeat("*", n)
}
midStart := n/2 - 2
if midStart < 8 {
midStart = 8
}
if midStart+4 > n-8 {
midStart = n - 8 - 4
if midStart < 8 {
midStart = 8
}
}
prefixByte := s[:8]
middle := s[midStart : midStart+4]
suffix := s[n-8:]
return prefixByte + strings.Repeat("*", 4) + middle + strings.Repeat("*", 4) + suffix
}

View File

@@ -10,6 +10,8 @@ import (
"regexp" "regexp"
"strings" "strings"
"time" "time"
log "github.com/sirupsen/logrus"
) )
// GeminiClient is the async http client interface (Go port) // GeminiClient is the async http client interface (Go port)
@@ -79,7 +81,7 @@ func (c *GeminiClient) Init(timeoutSec float64, verbose bool) error {
c.Timeout = time.Duration(timeoutSec * float64(time.Second)) c.Timeout = time.Duration(timeoutSec * float64(time.Second))
if verbose { if verbose {
Success("Gemini client initialized successfully.") log.Infof("Gemini client initialized successfully.")
} }
return nil return nil
} }

View File

@@ -1,131 +0,0 @@
package geminiwebapi
import (
"fmt"
"os"
"strings"
log "github.com/sirupsen/logrus"
)
// init honors GEMINI_WEBAPI_LOG to keep parity with the Python client.
func init() {
if lvl := os.Getenv("GEMINI_WEBAPI_LOG"); lvl != "" {
SetLogLevel(lvl)
}
}
// SetLogLevel adjusts logging verbosity using CLI-style strings.
func SetLogLevel(level string) {
switch strings.ToUpper(level) {
case "TRACE":
log.SetLevel(log.TraceLevel)
case "DEBUG":
log.SetLevel(log.DebugLevel)
case "INFO":
log.SetLevel(log.InfoLevel)
case "WARNING", "WARN":
log.SetLevel(log.WarnLevel)
case "ERROR":
log.SetLevel(log.ErrorLevel)
case "CRITICAL", "FATAL":
log.SetLevel(log.FatalLevel)
default:
log.SetLevel(log.InfoLevel)
}
}
func prefix(format string) string { return "[gemini_webapi] " + format }
func Debug(format string, v ...any) { log.Debugf(prefix(format), v...) }
// DebugRaw logs without the module prefix; use sparingly for messages
// that should integrate with global formatting without extra tags.
func DebugRaw(format string, v ...any) { log.Debugf(format, v...) }
func Info(format string, v ...any) { log.Infof(prefix(format), v...) }
func Warning(format string, v ...any) { log.Warnf(prefix(format), v...) }
func Error(format string, v ...any) { log.Errorf(prefix(format), v...) }
func Success(format string, v ...any) { log.Infof(prefix("SUCCESS "+format), v...) }
// MaskToken28 returns a fixed-length (28) masked representation showing:
// first 8 chars + 8 asterisks + 4 middle chars + last 8 chars.
// If the input is shorter than 20 characters, it returns a fully masked string
// of length min(len(s), 28).
func MaskToken28(s string) string {
n := len(s)
if n == 0 {
return ""
}
if n < 20 {
return strings.Repeat("*", n)
}
// Pick 4 middle characters around the center
midStart := n/2 - 2
if midStart < 8 {
midStart = 8
}
if midStart+4 > n-8 {
midStart = n - 8 - 4
if midStart < 8 {
midStart = 8
}
}
prefixByte := s[:8]
middle := s[midStart : midStart+4]
suffix := s[n-8:]
return prefixByte + strings.Repeat("*", 4) + middle + strings.Repeat("*", 4) + suffix
}
// BuildUpstreamRequestLog builds a compact preview string for upstream request logging.
func BuildUpstreamRequestLog(account string, contextOn bool, useTags, explicitContext bool, prompt string, filesCount int, reuse bool, metaLen int, gem *Gem) string {
var sb strings.Builder
sb.WriteString("\n\n=== GEMINI WEB UPSTREAM ===\n")
sb.WriteString(fmt.Sprintf("account: %s\n", account))
if contextOn {
sb.WriteString("context_mode: on\n")
} else {
sb.WriteString("context_mode: off\n")
}
if reuse {
sb.WriteString("reuseIdx: 1\n")
} else {
sb.WriteString("reuseIdx: 0\n")
}
sb.WriteString(fmt.Sprintf("useTags: %t\n", useTags))
sb.WriteString(fmt.Sprintf("metadata_len: %d\n", metaLen))
if explicitContext {
sb.WriteString("explicit_context: true\n")
} else {
sb.WriteString("explicit_context: false\n")
}
if filesCount > 0 {
sb.WriteString(fmt.Sprintf("files: %d\n", filesCount))
}
if gem != nil {
sb.WriteString("gem:\n")
if gem.ID != "" {
sb.WriteString(fmt.Sprintf(" id: %s\n", gem.ID))
}
if gem.Name != "" {
sb.WriteString(fmt.Sprintf(" name: %s\n", gem.Name))
}
sb.WriteString(fmt.Sprintf(" predefined: %t\n", gem.Predefined))
} else {
sb.WriteString("gem: none\n")
}
chunks := ChunkByRunes(prompt, 4096)
preview := prompt
truncated := false
if len(chunks) > 1 {
preview = chunks[0]
truncated = true
}
sb.WriteString("prompt_preview:\n")
sb.WriteString(preview)
if truncated {
sb.WriteString("\n... [truncated]\n")
}
return sb.String()
}

View File

@@ -20,6 +20,7 @@ import (
"github.com/router-for-me/CLIProxyAPI/v6/internal/interfaces" "github.com/router-for-me/CLIProxyAPI/v6/internal/interfaces"
"github.com/router-for-me/CLIProxyAPI/v6/internal/misc" "github.com/router-for-me/CLIProxyAPI/v6/internal/misc"
log "github.com/sirupsen/logrus"
"github.com/tidwall/gjson" "github.com/tidwall/gjson"
) )
@@ -58,7 +59,7 @@ func (i Image) Save(path string, filename string, cookies map[string]string, ver
filename = m[1] filename = m[1]
} else { } else {
if verbose { if verbose {
Warning("Invalid filename: %s", filename) log.Warnf("Invalid filename: %s", filename)
} }
if skipInvalidFilename { if skipInvalidFilename {
return "", nil return "", nil
@@ -125,7 +126,7 @@ func (i Image) Save(path string, filename string, cookies map[string]string, ver
return "", fmt.Errorf("error downloading image: %d %s", resp.StatusCode, resp.Status) return "", fmt.Errorf("error downloading image: %d %s", resp.StatusCode, resp.Status)
} }
if ct := resp.Header.Get("Content-Type"); ct != "" && !strings.Contains(strings.ToLower(ct), "image") { if ct := resp.Header.Get("Content-Type"); ct != "" && !strings.Contains(strings.ToLower(ct), "image") {
Warning("Content type of %s is not image, but %s.", filename, ct) log.Warnf("Content type of %s is not image, but %s.", filename, ct)
} }
if path == "" { if path == "" {
path = "temp" path = "temp"
@@ -144,7 +145,7 @@ func (i Image) Save(path string, filename string, cookies map[string]string, ver
return "", err return "", err
} }
if verbose { if verbose {
Info("Image saved as %s", dest) log.Infof("Image saved as %s", dest)
} }
abspath, _ := filepath.Abs(dest) abspath, _ := filepath.Abs(dest)
return abspath, nil return abspath, nil