ExtractJSONMetrics extracts metrics from streaming JSON log lines
(line string, verbose bool)
| 41 | |
| 42 | // ExtractJSONMetrics extracts metrics from streaming JSON log lines |
| 43 | func ExtractJSONMetrics(line string, verbose bool) LogMetrics { |
| 44 | var metrics LogMetrics |
| 45 | |
| 46 | // Trim the line first |
| 47 | trimmed := strings.TrimSpace(line) |
| 48 | if trimmed == "" { |
| 49 | return metrics |
| 50 | } |
| 51 | |
| 52 | metricsLog.Printf("Extracting metrics from JSON line: line_length=%d", len(trimmed)) |
| 53 | |
| 54 | // If the line isn't a clean JSON object, try to extract a JSON object substring |
| 55 | jsonStr := trimmed |
| 56 | if !strings.HasPrefix(trimmed, "{") || !strings.HasSuffix(trimmed, "}") { |
| 57 | // Find first '{' and last '}' and attempt to parse that slice |
| 58 | open := strings.Index(trimmed, "{") |
| 59 | close := strings.LastIndex(trimmed, "}") |
| 60 | if open == -1 || close == -1 || close <= open { |
| 61 | return metrics |
| 62 | } |
| 63 | jsonStr = trimmed[open : close+1] |
| 64 | } |
| 65 | |
| 66 | // Try to parse as generic JSON |
| 67 | var jsonData map[string]any |
| 68 | if err := json.Unmarshal([]byte(jsonStr), &jsonData); err != nil { |
| 69 | // If parsing fails, try a relaxed approach: sometimes logs contain a JSON-like object with single quotes |
| 70 | // Replace single quotes with double quotes as a last resort (not ideal, but helpful for noisy logs) |
| 71 | relaxed := strings.ReplaceAll(jsonStr, "'", "\"") |
| 72 | if err2 := json.Unmarshal([]byte(relaxed), &jsonData); err2 != nil { |
| 73 | return metrics |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | // Extract token usage from various possible fields and structures |
| 78 | if tokens := ExtractJSONTokenUsage(jsonData); tokens > 0 { |
| 79 | metrics.TokenUsage = tokens |
| 80 | } |
| 81 | |
| 82 | // Extract cost information from various possible fields |
| 83 | if cost := ExtractJSONCost(jsonData); cost > 0 { |
| 84 | metrics.EstimatedCost = cost |
| 85 | } |
| 86 | |
| 87 | return metrics |
| 88 | } |
| 89 | |
| 90 | // ExtractJSONTokenUsage extracts token usage from JSON data |
| 91 | func ExtractJSONTokenUsage(data map[string]any) int { |