diff --git a/internal/logging/gin_logger.go b/internal/logging/gin_logger.go index 9bfef8adc..2dfbcfc25 100644 --- a/internal/logging/gin_logger.go +++ b/internal/logging/gin_logger.go @@ -73,17 +73,15 @@ func GinLogrusLogger() gin.HandlerFunc { method := c.Request.Method errorMessage := c.Errors.ByType(gin.ErrorTypePrivate).String() + if requestID == "" { + requestID = "--------" + } logLine := fmt.Sprintf("%3d | %13v | %15s | %-7s \"%s\"", statusCode, latency, clientIP, method, path) if errorMessage != "" { logLine = logLine + " | " + errorMessage } - var entry *log.Entry - if requestID != "" { - entry = log.WithField("request_id", requestID) - } else { - entry = log.WithField("request_id", "--------") - } + entry := log.WithField("request_id", requestID) switch { case statusCode >= http.StatusInternalServerError: diff --git a/internal/logging/global_logger.go b/internal/logging/global_logger.go index f9942b860..a588bea45 100644 --- a/internal/logging/global_logger.go +++ b/internal/logging/global_logger.go @@ -40,25 +40,22 @@ func (m *LogFormatter) Format(entry *log.Entry) ([]byte, error) { timestamp := entry.Time.Format("2006-01-02 15:04:05") message := strings.TrimRight(entry.Message, "\r\n") - reqID := "" + reqID := "--------" if id, ok := entry.Data["request_id"].(string); ok && id != "" { reqID = id } - callerFile := "unknown" - callerLine := 0 - if entry.Caller != nil { - callerFile = filepath.Base(entry.Caller.File) - callerLine = entry.Caller.Line + level := entry.Level.String() + if level == "warning" { + level = "warn" } - - levelStr := fmt.Sprintf("%-5s", entry.Level.String()) + levelStr := fmt.Sprintf("%-5s", level) var formatted string - if reqID != "" { - formatted = fmt.Sprintf("[%s] [%s] [%s:%d] | %s | %s\n", timestamp, levelStr, callerFile, callerLine, reqID, message) + if entry.Caller != nil { + formatted = fmt.Sprintf("[%s] [%s] [%s] [%s:%d] %s\n", timestamp, reqID, levelStr, filepath.Base(entry.Caller.File), entry.Caller.Line, message) } else { - formatted = fmt.Sprintf("[%s] [%s] [%s:%d] %s\n", timestamp, levelStr, callerFile, callerLine, message) + formatted = fmt.Sprintf("[%s] [%s] [%s] %s\n", timestamp, reqID, levelStr, message) } buffer.WriteString(formatted) diff --git a/internal/runtime/executor/usage_helpers.go b/internal/runtime/executor/usage_helpers.go index 5669d9bc2..78581b827 100644 --- a/internal/runtime/executor/usage_helpers.go +++ b/internal/runtime/executor/usage_helpers.go @@ -275,20 +275,13 @@ func parseClaudeStreamUsage(line []byte) (usage.Detail, bool) { return detail, true } -func parseGeminiCLIUsage(data []byte) usage.Detail { - usageNode := gjson.ParseBytes(data) - node := usageNode.Get("response.usageMetadata") - if !node.Exists() { - node = usageNode.Get("response.usage_metadata") - } - if !node.Exists() { - return usage.Detail{} - } +func parseGeminiFamilyUsageDetail(node gjson.Result) usage.Detail { detail := usage.Detail{ InputTokens: node.Get("promptTokenCount").Int(), OutputTokens: node.Get("candidatesTokenCount").Int(), ReasoningTokens: node.Get("thoughtsTokenCount").Int(), TotalTokens: node.Get("totalTokenCount").Int(), + CachedTokens: node.Get("cachedContentTokenCount").Int(), } if detail.TotalTokens == 0 { detail.TotalTokens = detail.InputTokens + detail.OutputTokens + detail.ReasoningTokens @@ -296,6 +289,18 @@ func parseGeminiCLIUsage(data []byte) usage.Detail { return detail } +func parseGeminiCLIUsage(data []byte) usage.Detail { + usageNode := gjson.ParseBytes(data) + node := usageNode.Get("response.usageMetadata") + if !node.Exists() { + node = usageNode.Get("response.usage_metadata") + } + if !node.Exists() { + return usage.Detail{} + } + return parseGeminiFamilyUsageDetail(node) +} + func parseGeminiUsage(data []byte) usage.Detail { usageNode := gjson.ParseBytes(data) node := usageNode.Get("usageMetadata") @@ -305,16 +310,7 @@ func parseGeminiUsage(data []byte) usage.Detail { if !node.Exists() { return usage.Detail{} } - detail := usage.Detail{ - InputTokens: node.Get("promptTokenCount").Int(), - OutputTokens: node.Get("candidatesTokenCount").Int(), - ReasoningTokens: node.Get("thoughtsTokenCount").Int(), - TotalTokens: node.Get("totalTokenCount").Int(), - } - if detail.TotalTokens == 0 { - detail.TotalTokens = detail.InputTokens + detail.OutputTokens + detail.ReasoningTokens - } - return detail + return parseGeminiFamilyUsageDetail(node) } func parseGeminiStreamUsage(line []byte) (usage.Detail, bool) { @@ -329,16 +325,7 @@ func parseGeminiStreamUsage(line []byte) (usage.Detail, bool) { if !node.Exists() { return usage.Detail{}, false } - detail := usage.Detail{ - InputTokens: node.Get("promptTokenCount").Int(), - OutputTokens: node.Get("candidatesTokenCount").Int(), - ReasoningTokens: node.Get("thoughtsTokenCount").Int(), - TotalTokens: node.Get("totalTokenCount").Int(), - } - if detail.TotalTokens == 0 { - detail.TotalTokens = detail.InputTokens + detail.OutputTokens + detail.ReasoningTokens - } - return detail, true + return parseGeminiFamilyUsageDetail(node), true } func parseGeminiCLIStreamUsage(line []byte) (usage.Detail, bool) { @@ -353,16 +340,7 @@ func parseGeminiCLIStreamUsage(line []byte) (usage.Detail, bool) { if !node.Exists() { return usage.Detail{}, false } - detail := usage.Detail{ - InputTokens: node.Get("promptTokenCount").Int(), - OutputTokens: node.Get("candidatesTokenCount").Int(), - ReasoningTokens: node.Get("thoughtsTokenCount").Int(), - TotalTokens: node.Get("totalTokenCount").Int(), - } - if detail.TotalTokens == 0 { - detail.TotalTokens = detail.InputTokens + detail.OutputTokens + detail.ReasoningTokens - } - return detail, true + return parseGeminiFamilyUsageDetail(node), true } func parseAntigravityUsage(data []byte) usage.Detail { @@ -377,16 +355,7 @@ func parseAntigravityUsage(data []byte) usage.Detail { if !node.Exists() { return usage.Detail{} } - detail := usage.Detail{ - InputTokens: node.Get("promptTokenCount").Int(), - OutputTokens: node.Get("candidatesTokenCount").Int(), - ReasoningTokens: node.Get("thoughtsTokenCount").Int(), - TotalTokens: node.Get("totalTokenCount").Int(), - } - if detail.TotalTokens == 0 { - detail.TotalTokens = detail.InputTokens + detail.OutputTokens + detail.ReasoningTokens - } - return detail + return parseGeminiFamilyUsageDetail(node) } func parseAntigravityStreamUsage(line []byte) (usage.Detail, bool) { @@ -404,16 +373,7 @@ func parseAntigravityStreamUsage(line []byte) (usage.Detail, bool) { if !node.Exists() { return usage.Detail{}, false } - detail := usage.Detail{ - InputTokens: node.Get("promptTokenCount").Int(), - OutputTokens: node.Get("candidatesTokenCount").Int(), - ReasoningTokens: node.Get("thoughtsTokenCount").Int(), - TotalTokens: node.Get("totalTokenCount").Int(), - } - if detail.TotalTokens == 0 { - detail.TotalTokens = detail.InputTokens + detail.OutputTokens + detail.ReasoningTokens - } - return detail, true + return parseGeminiFamilyUsageDetail(node), true } var stopChunkWithoutUsage sync.Map