processOneUsageJSONLFile reads a single usage JSONL file and returns the total AIC accumulated from its records. The file is deferred-closed immediately after open.
(filePath string)
| 629 | // processOneUsageJSONLFile reads a single usage JSONL file and returns the total AIC |
| 630 | // accumulated from its records. The file is deferred-closed immediately after open. |
| 631 | func processOneUsageJSONLFile(filePath string) (total float64, found bool, err error) { |
| 632 | file, err := os.Open(filepath.Clean(filePath)) |
| 633 | if err != nil { |
| 634 | return 0, false, fmt.Errorf("failed to open usage JSONL file %s: %w", filePath, err) |
| 635 | } |
| 636 | defer func() { |
| 637 | if closeErr := file.Close(); closeErr != nil && err == nil { |
| 638 | err = fmt.Errorf("failed to close usage JSONL file %s: %w", filePath, closeErr) |
| 639 | } |
| 640 | }() |
| 641 | |
| 642 | scanner := bufio.NewScanner(file) |
| 643 | scanner.Buffer(make([]byte, 0, 64*1024), 1024*1024) |
| 644 | for scanner.Scan() { |
| 645 | line := strings.TrimSpace(scanner.Text()) |
| 646 | if line == "" || !strings.HasPrefix(line, "{") { |
| 647 | continue |
| 648 | } |
| 649 | |
| 650 | var parsed map[string]any |
| 651 | if jsonErr := json.Unmarshal([]byte(line), &parsed); jsonErr != nil { |
| 652 | continue |
| 653 | } |
| 654 | |
| 655 | usage := extractUsageRecord(parsed["usage"]) |
| 656 | explicitAICredits := usageNumericValue(parsed, usage, "ai_credits", "aiCredits") |
| 657 | if explicitAICredits > 0 { |
| 658 | total += explicitAICredits |
| 659 | found = true |
| 660 | continue |
| 661 | } |
| 662 | explicitAIC := usageNumericValue(parsed, usage, "aic") |
| 663 | if explicitAIC > 0 { |
| 664 | total += explicitAIC |
| 665 | found = true |
| 666 | continue |
| 667 | } |
| 668 | |
| 669 | computedAIC := computeModelInferenceAIC( |
| 670 | usageStringValue(parsed, usage, "provider"), |
| 671 | usageStringValue(parsed, usage, "model"), |
| 672 | int(usageNumericValue(parsed, usage, "input_tokens", "inputTokens")), |
| 673 | int(usageNumericValue(parsed, usage, "output_tokens", "outputTokens")), |
| 674 | int(usageNumericValue(parsed, usage, "cache_read_tokens", "cacheReadTokens")), |
| 675 | int(usageNumericValue(parsed, usage, "cache_write_tokens", "cacheWriteTokens")), |
| 676 | int(usageNumericValue(parsed, usage, "reasoning_tokens", "reasoningTokens")), |
| 677 | ) |
| 678 | if computedAIC > 0 { |
| 679 | total += computedAIC |
| 680 | found = true |
| 681 | } |
| 682 | } |
| 683 | if scanErr := scanner.Err(); scanErr != nil { |
| 684 | return 0, false, fmt.Errorf("error reading usage JSONL file %s: %w", filePath, scanErr) |
| 685 | } |
| 686 | return total, found, nil |
| 687 | } |
| 688 |
no test coverage detected