Skip to main content
Glama
token_tracker.py9.87 kB
""" Token tracking utility for LLM usage monitoring and pricing calculations. Tracks input/output tokens for each LLM call and provides comprehensive usage statistics for cost analysis. """ import threading from typing import Dict, Any, List, Optional from datetime import datetime from dataclasses import dataclass, field @dataclass class TokenUsage: """Individual token usage record for a single LLM call.""" timestamp: datetime tool_name: str method_name: str model: str input_tokens: int output_tokens: int total_tokens: int cost_estimate: float = 0.0 call_duration: float = 0.0 @dataclass class TokenSummary: """Summary of token usage across all tools.""" total_calls: int = 0 total_input_tokens: int = 0 total_output_tokens: int = 0 total_tokens: int = 0 total_cost_estimate: float = 0.0 tool_breakdown: Dict[str, Dict[str, Any]] = field(default_factory=dict) model_breakdown: Dict[str, Dict[str, Any]] = field(default_factory=dict) class TokenTracker: """ Thread-safe token tracking system for monitoring LLM usage. Tracks all LLM calls across the application and provides detailed usage statistics for pricing calculations. """ def __init__(self): """Initialize the token tracker.""" self._lock = threading.Lock() self._usage_records: List[TokenUsage] = [] self._tool_stats: Dict[str, Dict[str, Any]] = {} self._model_stats: Dict[str, Dict[str, Any]] = {} # Token pricing (per 1M tokens) - update as needed self._pricing = { "gemini-2.5-flash": {"input": 0.075, "output": 0.30}, # $0.075/$0.30 per 1M tokens "gemini-1.5-flash": {"input": 0.075, "output": 0.30}, "gemini-1.5-pro": {"input": 1.25, "output": 5.00}, "gpt-4": {"input": 30.0, "output": 60.0}, "gpt-3.5-turbo": {"input": 0.5, "output": 1.5}, } def track_call( self, tool_name: str, method_name: str, model: str, input_tokens: int, output_tokens: int, call_duration: float = 0.0 ) -> None: """ Track a single LLM call with token usage. Args: tool_name: Name of the tool making the call method_name: Name of the method being called model: LLM model used input_tokens: Number of input tokens output_tokens: Number of output tokens call_duration: Duration of the call in seconds """ with self._lock: total_tokens = input_tokens + output_tokens # Calculate cost estimate cost_estimate = 0.0 if model in self._pricing: pricing = self._pricing[model] input_cost = (input_tokens / 1_000_000) * pricing["input"] output_cost = (output_tokens / 1_000_000) * pricing["output"] cost_estimate = input_cost + output_cost # Create usage record usage = TokenUsage( timestamp=datetime.now(), tool_name=tool_name, method_name=method_name, model=model, input_tokens=input_tokens, output_tokens=output_tokens, total_tokens=total_tokens, cost_estimate=cost_estimate, call_duration=call_duration ) self._usage_records.append(usage) # Update tool statistics if tool_name not in self._tool_stats: self._tool_stats[tool_name] = { "total_calls": 0, "total_input_tokens": 0, "total_output_tokens": 0, "total_tokens": 0, "total_cost": 0.0, "methods": {} } tool_stats = self._tool_stats[tool_name] tool_stats["total_calls"] += 1 tool_stats["total_input_tokens"] += input_tokens tool_stats["total_output_tokens"] += output_tokens tool_stats["total_tokens"] += total_tokens tool_stats["total_cost"] += cost_estimate # Update method statistics if method_name not in tool_stats["methods"]: tool_stats["methods"][method_name] = { "calls": 0, "input_tokens": 0, "output_tokens": 0, "total_tokens": 0, "cost": 0.0 } method_stats = tool_stats["methods"][method_name] method_stats["calls"] += 1 method_stats["input_tokens"] += input_tokens method_stats["output_tokens"] += output_tokens method_stats["total_tokens"] += total_tokens method_stats["cost"] += cost_estimate # Update model statistics if model not in self._model_stats: self._model_stats[model] = { "total_calls": 0, "total_input_tokens": 0, "total_output_tokens": 0, "total_tokens": 0, "total_cost": 0.0 } model_stats = self._model_stats[model] model_stats["total_calls"] += 1 model_stats["total_input_tokens"] += input_tokens model_stats["total_output_tokens"] += output_tokens model_stats["total_tokens"] += total_tokens model_stats["total_cost"] += cost_estimate def get_summary(self) -> TokenSummary: """ Get comprehensive token usage summary. Returns: TokenSummary with detailed usage statistics """ with self._lock: total_calls = len(self._usage_records) total_input_tokens = sum(record.input_tokens for record in self._usage_records) total_output_tokens = sum(record.output_tokens for record in self._usage_records) total_tokens = total_input_tokens + total_output_tokens total_cost = sum(record.cost_estimate for record in self._usage_records) return TokenSummary( total_calls=total_calls, total_input_tokens=total_input_tokens, total_output_tokens=total_output_tokens, total_tokens=total_tokens, total_cost_estimate=total_cost, tool_breakdown=self._tool_stats.copy(), model_breakdown=self._model_stats.copy() ) def get_tool_usage(self, tool_name: str) -> Optional[Dict[str, Any]]: """ Get usage statistics for a specific tool. Args: tool_name: Name of the tool Returns: Dictionary with tool usage statistics or None if not found """ with self._lock: return self._tool_stats.get(tool_name) def get_model_usage(self, model: str) -> Optional[Dict[str, Any]]: """ Get usage statistics for a specific model. Args: model: Name of the model Returns: Dictionary with model usage statistics or None if not found """ with self._lock: return self._model_stats.get(model) def clear(self) -> None: """Clear all tracking data.""" with self._lock: self._usage_records.clear() self._tool_stats.clear() self._model_stats.clear() def print_summary(self) -> None: """Print a formatted summary of token usage.""" summary = self.get_summary() print("\n" + "="*80) print("LLM TOKEN USAGE SUMMARY") print("="*80) print(f"Total LLM Calls: {summary.total_calls}") print(f"Total Input Tokens: {summary.total_input_tokens:,}") print(f"Total Output Tokens: {summary.total_output_tokens:,}") print(f"Total Tokens: {summary.total_tokens:,}") print(f"Estimated Cost: ${summary.total_cost_estimate:.4f}") print() if summary.tool_breakdown: print("TOOL BREAKDOWN:") print("-" * 40) for tool_name, stats in summary.tool_breakdown.items(): print(f"{tool_name}:") print(f" Calls: {stats['total_calls']}") print(f" Input Tokens: {stats['total_input_tokens']:,}") print(f" Output Tokens: {stats['total_output_tokens']:,}") print(f" Total Tokens: {stats['total_tokens']:,}") print(f" Cost: ${stats['total_cost']:.4f}") if stats['methods']: print(" Methods:") for method, method_stats in stats['methods'].items(): print(f" {method}: {method_stats['calls']} calls, {method_stats['total_tokens']:,} tokens, ${method_stats['cost']:.4f}") print() if summary.model_breakdown: print("MODEL BREAKDOWN:") print("-" * 40) for model, stats in summary.model_breakdown.items(): print(f"{model}:") print(f" Calls: {stats['total_calls']}") print(f" Input Tokens: {stats['total_input_tokens']:,}") print(f" Output Tokens: {stats['total_output_tokens']:,}") print(f" Total Tokens: {stats['total_tokens']:,}") print(f" Cost: ${stats['total_cost']:.4f}") print() print("="*80) # Global token tracker instance token_tracker = TokenTracker()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/connectaman/Pitchlense-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server