llm_cost_tracker 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +48 -0
  3. data/README.md +149 -32
  4. data/lib/llm_cost_tracker/budget.rb +7 -19
  5. data/lib/llm_cost_tracker/configuration.rb +52 -10
  6. data/lib/llm_cost_tracker/cost.rb +15 -0
  7. data/lib/llm_cost_tracker/event.rb +24 -0
  8. data/lib/llm_cost_tracker/generators/llm_cost_tracker/prices_generator.rb +20 -0
  9. data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/llm_cost_tracker_prices.yml.erb +36 -0
  10. data/lib/llm_cost_tracker/llm_api_call.rb +56 -44
  11. data/lib/llm_cost_tracker/logging.rb +44 -0
  12. data/lib/llm_cost_tracker/middleware/faraday.rb +15 -12
  13. data/lib/llm_cost_tracker/parsed_usage.rb +45 -0
  14. data/lib/llm_cost_tracker/parsers/anthropic.rb +2 -3
  15. data/lib/llm_cost_tracker/parsers/base.rb +2 -0
  16. data/lib/llm_cost_tracker/parsers/gemini.rb +4 -4
  17. data/lib/llm_cost_tracker/parsers/openai.rb +4 -22
  18. data/lib/llm_cost_tracker/parsers/openai_compatible.rb +12 -8
  19. data/lib/llm_cost_tracker/parsers/openai_usage.rb +33 -0
  20. data/lib/llm_cost_tracker/price_registry.rb +36 -6
  21. data/lib/llm_cost_tracker/pricing.rb +36 -10
  22. data/lib/llm_cost_tracker/railtie.rb +5 -0
  23. data/lib/llm_cost_tracker/report.rb +29 -0
  24. data/lib/llm_cost_tracker/report_data.rb +81 -0
  25. data/lib/llm_cost_tracker/report_formatter.rb +65 -0
  26. data/lib/llm_cost_tracker/storage/active_record_backend.rb +19 -0
  27. data/lib/llm_cost_tracker/storage/active_record_store.rb +11 -11
  28. data/lib/llm_cost_tracker/storage/backends.rb +26 -0
  29. data/lib/llm_cost_tracker/storage/custom_backend.rb +16 -0
  30. data/lib/llm_cost_tracker/storage/log_backend.rb +28 -0
  31. data/lib/llm_cost_tracker/tag_accessors.rb +15 -0
  32. data/lib/llm_cost_tracker/tag_query.rb +38 -0
  33. data/lib/llm_cost_tracker/tags_column.rb +16 -0
  34. data/lib/llm_cost_tracker/tracker.rb +18 -67
  35. data/lib/llm_cost_tracker/unknown_pricing.rb +8 -15
  36. data/lib/llm_cost_tracker/value_object.rb +45 -0
  37. data/lib/llm_cost_tracker/version.rb +1 -1
  38. data/lib/llm_cost_tracker.rb +28 -13
  39. data/lib/tasks/llm_cost_tracker.rake +9 -0
  40. data/llm_cost_tracker.gemspec +1 -1
  41. metadata +22 -3
@@ -6,9 +6,15 @@ require "active_support/notifications"
6
6
  require_relative "llm_cost_tracker/version"
7
7
  require_relative "llm_cost_tracker/configuration"
8
8
  require_relative "llm_cost_tracker/errors"
9
+ require_relative "llm_cost_tracker/logging"
10
+ require_relative "llm_cost_tracker/value_object"
11
+ require_relative "llm_cost_tracker/cost"
12
+ require_relative "llm_cost_tracker/event"
13
+ require_relative "llm_cost_tracker/parsed_usage"
9
14
  require_relative "llm_cost_tracker/price_registry"
10
15
  require_relative "llm_cost_tracker/pricing"
11
16
  require_relative "llm_cost_tracker/parsers/base"
17
+ require_relative "llm_cost_tracker/parsers/openai_usage"
12
18
  require_relative "llm_cost_tracker/parsers/openai"
13
19
  require_relative "llm_cost_tracker/parsers/openai_compatible"
14
20
  require_relative "llm_cost_tracker/parsers/anthropic"
@@ -18,7 +24,14 @@ require_relative "llm_cost_tracker/middleware/faraday"
18
24
  require_relative "llm_cost_tracker/budget"
19
25
  require_relative "llm_cost_tracker/unknown_pricing"
20
26
  require_relative "llm_cost_tracker/event_metadata"
27
+ require_relative "llm_cost_tracker/tags_column"
28
+ require_relative "llm_cost_tracker/tag_query"
29
+ require_relative "llm_cost_tracker/tag_accessors"
30
+ require_relative "llm_cost_tracker/storage/backends"
21
31
  require_relative "llm_cost_tracker/tracker"
32
+ require_relative "llm_cost_tracker/report_data"
33
+ require_relative "llm_cost_tracker/report_formatter"
34
+ require_relative "llm_cost_tracker/report"
22
35
 
23
36
  module LlmCostTracker
24
37
  class << self
@@ -30,6 +43,10 @@ module LlmCostTracker
30
43
  @configuration || CONFIGURATION_MUTEX.synchronize { @configuration ||= Configuration.new }
31
44
  end
32
45
 
46
+ # Configure the gem once during application boot.
47
+ #
48
+ # @yieldparam configuration [LlmCostTracker::Configuration]
49
+ # @return [void]
33
50
  def configure
34
51
  yield(configuration)
35
52
  configuration.normalize_openai_compatible_providers!
@@ -40,7 +57,7 @@ module LlmCostTracker
40
57
  CONFIGURATION_MUTEX.synchronize { @configuration = Configuration.new }
41
58
  end
42
59
 
43
- # Manual tracking for non-Faraday clients
60
+ # Track an LLM request manually for non-Faraday clients.
44
61
  #
45
62
  # LlmCostTracker.track(
46
63
  # provider: :openai,
@@ -50,6 +67,14 @@ module LlmCostTracker
50
67
  # feature: "chat",
51
68
  # user_id: current_user.id
52
69
  # )
70
+ #
71
+ # @param provider [String, Symbol] Provider name, such as :openai or :anthropic.
72
+ # @param model [String] Provider model identifier.
73
+ # @param input_tokens [Integer] Billed input token count.
74
+ # @param output_tokens [Integer] Billed output token count.
75
+ # @param latency_ms [Integer, nil] Optional request latency in milliseconds.
76
+ # @param metadata [Hash] Attribution tags and provider-specific usage metadata.
77
+ # @return [LlmCostTracker::Event] The tracked event.
53
78
  def track(provider:, model:, input_tokens:, output_tokens:, latency_ms: nil, **metadata)
54
79
  Tracker.record(
55
80
  provider: provider.to_s,
@@ -64,20 +89,10 @@ module LlmCostTracker
64
89
  private
65
90
 
66
91
  def warn_for_configuration!
67
- return unless (configuration.budget_exceeded_behavior || :notify).to_sym == :block_requests
92
+ return unless configuration.budget_exceeded_behavior == :block_requests
68
93
  return if configuration.active_record?
69
94
 
70
- log_warning(":block_requests requires storage_backend = :active_record; preflight blocking will be skipped.")
71
- end
72
-
73
- def log_warning(message)
74
- message = "[LlmCostTracker] #{message}"
75
-
76
- if defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger
77
- Rails.logger.warn(message)
78
- else
79
- warn message
80
- end
95
+ Logging.warn(":block_requests requires storage_backend = :active_record; preflight blocking will be skipped.")
81
96
  end
82
97
  end
83
98
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :llm_cost_tracker do
4
+ desc "Print an LLM cost report from ActiveRecord storage"
5
+ task report: :environment do
6
+ days = (ENV["DAYS"] || LlmCostTracker::Report::DEFAULT_DAYS).to_i
7
+ puts LlmCostTracker::Report.generate(days: days)
8
+ end
9
+ end
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.description = "Tracks token usage and estimated costs for OpenAI, Anthropic, Google Gemini, " \
13
13
  "OpenRouter, DeepSeek, and OpenAI-compatible calls. " \
14
14
  "Works as Faraday middleware for Ruby clients, with ActiveRecord storage, " \
15
- "per-user/per-feature attribution, budget alerts, and budget enforcement."
15
+ "per-user/per-feature attribution, and budget guardrails."
16
16
  spec.homepage = "https://github.com/sergey-homenko/llm_cost_tracker"
17
17
  spec.license = "MIT"
18
18
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: llm_cost_tracker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergii Khomenko
@@ -142,8 +142,8 @@ dependencies:
142
142
  version: '3.0'
143
143
  description: Tracks token usage and estimated costs for OpenAI, Anthropic, Google
144
144
  Gemini, OpenRouter, DeepSeek, and OpenAI-compatible calls. Works as Faraday middleware
145
- for Ruby clients, with ActiveRecord storage, per-user/per-feature attribution, budget
146
- alerts, and budget enforcement.
145
+ for Ruby clients, with ActiveRecord storage, per-user/per-feature attribution, and
146
+ budget guardrails.
147
147
  email:
148
148
  - sergey@mm.st
149
149
  executables: []
@@ -159,33 +159,52 @@ files:
159
159
  - lib/llm_cost_tracker.rb
160
160
  - lib/llm_cost_tracker/budget.rb
161
161
  - lib/llm_cost_tracker/configuration.rb
162
+ - lib/llm_cost_tracker/cost.rb
162
163
  - lib/llm_cost_tracker/errors.rb
164
+ - lib/llm_cost_tracker/event.rb
163
165
  - lib/llm_cost_tracker/event_metadata.rb
164
166
  - lib/llm_cost_tracker/generators/llm_cost_tracker/add_latency_ms_generator.rb
165
167
  - lib/llm_cost_tracker/generators/llm_cost_tracker/install_generator.rb
168
+ - lib/llm_cost_tracker/generators/llm_cost_tracker/prices_generator.rb
166
169
  - lib/llm_cost_tracker/generators/llm_cost_tracker/templates/add_latency_ms_to_llm_api_calls.rb.erb
167
170
  - lib/llm_cost_tracker/generators/llm_cost_tracker/templates/create_llm_api_calls.rb.erb
168
171
  - lib/llm_cost_tracker/generators/llm_cost_tracker/templates/initializer.rb.erb
172
+ - lib/llm_cost_tracker/generators/llm_cost_tracker/templates/llm_cost_tracker_prices.yml.erb
169
173
  - lib/llm_cost_tracker/generators/llm_cost_tracker/templates/upgrade_llm_api_call_cost_precision.rb.erb
170
174
  - lib/llm_cost_tracker/generators/llm_cost_tracker/templates/upgrade_llm_api_call_tags_to_jsonb.rb.erb
171
175
  - lib/llm_cost_tracker/generators/llm_cost_tracker/upgrade_cost_precision_generator.rb
172
176
  - lib/llm_cost_tracker/generators/llm_cost_tracker/upgrade_tags_to_jsonb_generator.rb
173
177
  - lib/llm_cost_tracker/llm_api_call.rb
178
+ - lib/llm_cost_tracker/logging.rb
174
179
  - lib/llm_cost_tracker/middleware/faraday.rb
180
+ - lib/llm_cost_tracker/parsed_usage.rb
175
181
  - lib/llm_cost_tracker/parsers/anthropic.rb
176
182
  - lib/llm_cost_tracker/parsers/base.rb
177
183
  - lib/llm_cost_tracker/parsers/gemini.rb
178
184
  - lib/llm_cost_tracker/parsers/openai.rb
179
185
  - lib/llm_cost_tracker/parsers/openai_compatible.rb
186
+ - lib/llm_cost_tracker/parsers/openai_usage.rb
180
187
  - lib/llm_cost_tracker/parsers/registry.rb
181
188
  - lib/llm_cost_tracker/price_registry.rb
182
189
  - lib/llm_cost_tracker/prices.json
183
190
  - lib/llm_cost_tracker/pricing.rb
184
191
  - lib/llm_cost_tracker/railtie.rb
192
+ - lib/llm_cost_tracker/report.rb
193
+ - lib/llm_cost_tracker/report_data.rb
194
+ - lib/llm_cost_tracker/report_formatter.rb
195
+ - lib/llm_cost_tracker/storage/active_record_backend.rb
185
196
  - lib/llm_cost_tracker/storage/active_record_store.rb
197
+ - lib/llm_cost_tracker/storage/backends.rb
198
+ - lib/llm_cost_tracker/storage/custom_backend.rb
199
+ - lib/llm_cost_tracker/storage/log_backend.rb
200
+ - lib/llm_cost_tracker/tag_accessors.rb
201
+ - lib/llm_cost_tracker/tag_query.rb
202
+ - lib/llm_cost_tracker/tags_column.rb
186
203
  - lib/llm_cost_tracker/tracker.rb
187
204
  - lib/llm_cost_tracker/unknown_pricing.rb
205
+ - lib/llm_cost_tracker/value_object.rb
188
206
  - lib/llm_cost_tracker/version.rb
207
+ - lib/tasks/llm_cost_tracker.rake
189
208
  - llm_cost_tracker.gemspec
190
209
  homepage: https://github.com/sergey-homenko/llm_cost_tracker
191
210
  licenses: