llm_cost_tracker 0.6.1 → 0.7.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -0
- data/README.md +13 -12
- data/app/assets/llm_cost_tracker/application.css +3 -0
- data/app/controllers/llm_cost_tracker/application_controller.rb +22 -4
- data/app/controllers/llm_cost_tracker/calls_controller.rb +6 -11
- data/app/controllers/llm_cost_tracker/dashboard_controller.rb +2 -1
- data/app/controllers/llm_cost_tracker/data_quality_controller.rb +5 -1
- data/app/controllers/llm_cost_tracker/models_controller.rb +0 -1
- data/app/controllers/llm_cost_tracker/tags_controller.rb +1 -8
- data/app/helpers/llm_cost_tracker/application_helper.rb +2 -1
- data/app/helpers/llm_cost_tracker/dashboard_filter_helper.rb +1 -2
- data/app/helpers/llm_cost_tracker/dashboard_filter_options_helper.rb +1 -1
- data/app/helpers/llm_cost_tracker/dashboard_query_helper.rb +10 -27
- data/app/helpers/llm_cost_tracker/token_usage_helper.rb +58 -0
- data/app/models/llm_cost_tracker/ingestion/event.rb +13 -0
- data/app/models/llm_cost_tracker/ingestion/lease.rb +11 -0
- data/app/models/llm_cost_tracker/ledger/call.rb +45 -0
- data/app/models/llm_cost_tracker/ledger/call_metrics.rb +66 -0
- data/app/models/llm_cost_tracker/ledger/period/grouping.rb +71 -0
- data/app/models/llm_cost_tracker/ledger/period/total.rb +13 -0
- data/app/models/llm_cost_tracker/ledger/tags/accessors.rb +19 -0
- data/app/services/llm_cost_tracker/dashboard/data_quality.rb +111 -94
- data/app/services/llm_cost_tracker/dashboard/date_range.rb +2 -2
- data/app/services/llm_cost_tracker/dashboard/filter.rb +7 -18
- data/app/services/llm_cost_tracker/dashboard/overview_stats.rb +58 -67
- data/app/services/llm_cost_tracker/dashboard/pagination.rb +59 -0
- data/app/services/llm_cost_tracker/dashboard/params.rb +26 -0
- data/app/services/llm_cost_tracker/dashboard/provider_breakdown.rb +18 -20
- data/app/services/llm_cost_tracker/dashboard/spend_anomaly.rb +4 -13
- data/app/services/llm_cost_tracker/dashboard/tag_breakdown.rb +28 -61
- data/app/services/llm_cost_tracker/dashboard/tag_key_explorer.rb +8 -37
- data/app/services/llm_cost_tracker/dashboard/time_series.rb +1 -1
- data/app/services/llm_cost_tracker/dashboard/top_models.rb +12 -47
- data/app/views/llm_cost_tracker/calls/index.html.erb +12 -18
- data/app/views/llm_cost_tracker/calls/show.html.erb +30 -32
- data/app/views/llm_cost_tracker/dashboard/index.html.erb +17 -19
- data/app/views/llm_cost_tracker/data_quality/index.html.erb +108 -135
- data/app/views/llm_cost_tracker/models/index.html.erb +8 -9
- data/app/views/llm_cost_tracker/shared/setup_required.html.erb +13 -2
- data/app/views/llm_cost_tracker/tags/show.html.erb +20 -20
- data/config/routes.rb +1 -1
- data/lib/llm_cost_tracker/assets.rb +0 -6
- data/lib/llm_cost_tracker/budget.rb +10 -24
- data/lib/llm_cost_tracker/capture/stream.rb +9 -0
- data/lib/llm_cost_tracker/capture/stream_collector.rb +182 -0
- data/lib/llm_cost_tracker/{integrations → capture}/stream_tracker.rb +40 -72
- data/lib/llm_cost_tracker/configuration/instrumentation.rb +3 -7
- data/lib/llm_cost_tracker/configuration.rb +30 -45
- data/lib/llm_cost_tracker/doctor/capture_verifier.rb +61 -0
- data/lib/llm_cost_tracker/doctor/check.rb +7 -0
- data/lib/llm_cost_tracker/doctor/ingestion_check.rb +22 -61
- data/lib/llm_cost_tracker/doctor/price_check.rb +60 -0
- data/lib/llm_cost_tracker/doctor.rb +66 -79
- data/lib/llm_cost_tracker/engine.rb +0 -3
- data/lib/llm_cost_tracker/errors.rb +4 -15
- data/lib/llm_cost_tracker/event.rb +6 -6
- data/lib/llm_cost_tracker/generators/llm_cost_tracker/add_token_usage_generator.rb +42 -0
- data/lib/llm_cost_tracker/generators/llm_cost_tracker/install_generator.rb +2 -0
- data/lib/llm_cost_tracker/generators/llm_cost_tracker/prices_generator.rb +7 -7
- data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/add_period_totals_to_llm_cost_tracker.rb.erb +5 -5
- data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/add_token_usage_to_llm_api_calls.rb.erb +22 -0
- data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/create_llm_api_calls.rb.erb +15 -14
- data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/initializer.rb.erb +1 -21
- data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/upgrade_llm_api_call_cost_precision.rb.erb +12 -1
- data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/upgrade_llm_api_call_tags_to_jsonb.rb.erb +2 -2
- data/lib/llm_cost_tracker/{storage/active_record_inbox_batch.rb → ingestion/batch.rb} +21 -20
- data/lib/llm_cost_tracker/ingestion/inbox.rb +105 -0
- data/lib/llm_cost_tracker/{storage/active_record_ingestor_lease.rb → ingestion/lease_claim.rb} +5 -7
- data/lib/llm_cost_tracker/{storage/active_record_ingestor.rb → ingestion/worker.rb} +38 -48
- data/lib/llm_cost_tracker/ingestion.rb +129 -0
- data/lib/llm_cost_tracker/integrations/anthropic.rb +52 -34
- data/lib/llm_cost_tracker/integrations/base.rb +73 -34
- data/lib/llm_cost_tracker/integrations/openai.rb +45 -39
- data/lib/llm_cost_tracker/integrations/ruby_llm.rb +40 -30
- data/lib/llm_cost_tracker/integrations.rb +43 -0
- data/lib/llm_cost_tracker/ledger/period/totals.rb +66 -0
- data/lib/llm_cost_tracker/{storage/active_record_periods.rb → ledger/period.rb} +2 -2
- data/lib/llm_cost_tracker/ledger/rollups/batch.rb +43 -0
- data/lib/llm_cost_tracker/ledger/rollups/upsert_sql.rb +46 -0
- data/lib/llm_cost_tracker/ledger/rollups.rb +87 -0
- data/lib/llm_cost_tracker/ledger/schema/adapter.rb +51 -0
- data/lib/llm_cost_tracker/ledger/schema/calls.rb +101 -0
- data/lib/llm_cost_tracker/ledger/schema/period_totals.rb +32 -0
- data/lib/llm_cost_tracker/ledger/store.rb +60 -0
- data/lib/llm_cost_tracker/ledger/tags/query.rb +29 -0
- data/lib/llm_cost_tracker/ledger/tags/sql.rb +33 -0
- data/lib/llm_cost_tracker/ledger.rb +13 -0
- data/lib/llm_cost_tracker/logging.rb +3 -6
- data/lib/llm_cost_tracker/middleware/faraday.rb +35 -36
- data/lib/llm_cost_tracker/parsers/anthropic.rb +38 -27
- data/lib/llm_cost_tracker/parsers/base.rb +10 -19
- data/lib/llm_cost_tracker/parsers/gemini.rb +15 -16
- data/lib/llm_cost_tracker/parsers/openai_usage.rb +24 -19
- data/lib/llm_cost_tracker/parsers/sse.rb +4 -7
- data/lib/llm_cost_tracker/parsers.rb +20 -0
- data/lib/llm_cost_tracker/prices.json +52 -11
- data/lib/llm_cost_tracker/pricing/components.rb +37 -0
- data/lib/llm_cost_tracker/pricing/effective_prices.rb +40 -50
- data/lib/llm_cost_tracker/pricing/explainer.rb +12 -23
- data/lib/llm_cost_tracker/pricing/lookup.rb +24 -25
- data/lib/llm_cost_tracker/pricing/registry.rb +156 -0
- data/lib/llm_cost_tracker/pricing/sync/fetcher.rb +107 -0
- data/lib/llm_cost_tracker/pricing/sync/registry_diff.rb +53 -0
- data/lib/llm_cost_tracker/pricing/sync/registry_loader.rb +63 -0
- data/lib/llm_cost_tracker/pricing/sync/registry_writer.rb +31 -0
- data/lib/llm_cost_tracker/pricing/sync.rb +143 -0
- data/lib/llm_cost_tracker/pricing/unknown.rb +46 -0
- data/lib/llm_cost_tracker/pricing.rb +33 -32
- data/lib/llm_cost_tracker/railtie.rb +7 -10
- data/lib/llm_cost_tracker/report/data.rb +72 -0
- data/lib/llm_cost_tracker/report/formatter.rb +69 -0
- data/lib/llm_cost_tracker/report.rb +8 -10
- data/lib/llm_cost_tracker/retention.rb +27 -10
- data/lib/llm_cost_tracker/tags/context.rb +35 -0
- data/lib/llm_cost_tracker/tags/key.rb +18 -0
- data/lib/llm_cost_tracker/tags/sanitizer.rb +68 -0
- data/lib/llm_cost_tracker/token_usage.rb +67 -0
- data/lib/llm_cost_tracker/tracker.rb +38 -70
- data/lib/llm_cost_tracker/usage_capture.rb +37 -0
- data/lib/llm_cost_tracker/version.rb +1 -1
- data/lib/llm_cost_tracker.rb +56 -90
- data/lib/tasks/llm_cost_tracker.rake +18 -13
- metadata +85 -99
- data/app/services/llm_cost_tracker/dashboard/data_quality_aggregate.rb +0 -81
- data/app/services/llm_cost_tracker/pagination.rb +0 -57
- data/lib/llm_cost_tracker/active_record_adapter.rb +0 -49
- data/lib/llm_cost_tracker/capture_verifier.rb +0 -71
- data/lib/llm_cost_tracker/configuration/storage_backend.rb +0 -26
- data/lib/llm_cost_tracker/cost.rb +0 -12
- data/lib/llm_cost_tracker/doctor/capture_check.rb +0 -39
- data/lib/llm_cost_tracker/engine_compatibility.rb +0 -15
- data/lib/llm_cost_tracker/event_metadata.rb +0 -52
- data/lib/llm_cost_tracker/generators/llm_cost_tracker/add_usage_breakdown_generator.rb +0 -29
- data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/add_usage_breakdown_to_llm_api_calls.rb.erb +0 -29
- data/lib/llm_cost_tracker/inbox_event.rb +0 -9
- data/lib/llm_cost_tracker/ingestor_lease.rb +0 -9
- data/lib/llm_cost_tracker/integrations/object_reader.rb +0 -56
- data/lib/llm_cost_tracker/integrations/registry.rb +0 -73
- data/lib/llm_cost_tracker/llm_api_call.rb +0 -60
- data/lib/llm_cost_tracker/llm_api_call_metrics.rb +0 -63
- data/lib/llm_cost_tracker/parameter_hash.rb +0 -33
- data/lib/llm_cost_tracker/parsed_usage.rb +0 -72
- data/lib/llm_cost_tracker/parsers/registry.rb +0 -58
- data/lib/llm_cost_tracker/period_grouping.rb +0 -69
- data/lib/llm_cost_tracker/period_total.rb +0 -9
- data/lib/llm_cost_tracker/price_freshness.rb +0 -38
- data/lib/llm_cost_tracker/price_registry.rb +0 -144
- data/lib/llm_cost_tracker/price_sync/fetcher.rb +0 -104
- data/lib/llm_cost_tracker/price_sync/registry_diff.rb +0 -51
- data/lib/llm_cost_tracker/price_sync/registry_loader.rb +0 -61
- data/lib/llm_cost_tracker/price_sync/registry_writer.rb +0 -29
- data/lib/llm_cost_tracker/price_sync.rb +0 -144
- data/lib/llm_cost_tracker/report_data.rb +0 -94
- data/lib/llm_cost_tracker/report_formatter.rb +0 -67
- data/lib/llm_cost_tracker/request_url.rb +0 -20
- data/lib/llm_cost_tracker/storage/active_record_backend.rb +0 -166
- data/lib/llm_cost_tracker/storage/active_record_connection_cleanup.rb +0 -13
- data/lib/llm_cost_tracker/storage/active_record_inbox.rb +0 -165
- data/lib/llm_cost_tracker/storage/active_record_period_totals.rb +0 -84
- data/lib/llm_cost_tracker/storage/active_record_rollup_batch.rb +0 -41
- data/lib/llm_cost_tracker/storage/active_record_rollup_upsert_sql.rb +0 -42
- data/lib/llm_cost_tracker/storage/active_record_rollups.rb +0 -146
- data/lib/llm_cost_tracker/storage/active_record_store.rb +0 -145
- data/lib/llm_cost_tracker/storage/custom_backend.rb +0 -32
- data/lib/llm_cost_tracker/storage/dispatcher.rb +0 -45
- data/lib/llm_cost_tracker/storage/log_backend.rb +0 -38
- data/lib/llm_cost_tracker/storage/registry.rb +0 -63
- data/lib/llm_cost_tracker/stream_capture.rb +0 -7
- data/lib/llm_cost_tracker/stream_collector.rb +0 -199
- data/lib/llm_cost_tracker/tag_accessors.rb +0 -15
- data/lib/llm_cost_tracker/tag_context.rb +0 -52
- data/lib/llm_cost_tracker/tag_key.rb +0 -16
- data/lib/llm_cost_tracker/tag_query.rb +0 -43
- data/lib/llm_cost_tracker/tag_sanitizer.rb +0 -81
- data/lib/llm_cost_tracker/tag_sql.rb +0 -34
- data/lib/llm_cost_tracker/tags_column.rb +0 -103
- data/lib/llm_cost_tracker/unknown_pricing.rb +0 -54
- data/lib/llm_cost_tracker/usage_breakdown.rb +0 -30
- data/lib/llm_cost_tracker/value_helpers.rb +0 -40
metadata
CHANGED
|
@@ -1,15 +1,35 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: llm_cost_tracker
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sergii Khomenko
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-04-
|
|
11
|
+
date: 2026-04-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: activerecord
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '7.1'
|
|
20
|
+
- - "<"
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: '9.0'
|
|
23
|
+
type: :runtime
|
|
24
|
+
prerelease: false
|
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
26
|
+
requirements:
|
|
27
|
+
- - ">="
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '7.1'
|
|
30
|
+
- - "<"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '9.0'
|
|
13
33
|
- !ruby/object:Gem::Dependency
|
|
14
34
|
name: activesupport
|
|
15
35
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -65,7 +85,7 @@ dependencies:
|
|
|
65
85
|
- !ruby/object:Gem::Version
|
|
66
86
|
version: '3.0'
|
|
67
87
|
- !ruby/object:Gem::Dependency
|
|
68
|
-
name:
|
|
88
|
+
name: railties
|
|
69
89
|
requirement: !ruby/object:Gem::Requirement
|
|
70
90
|
requirements:
|
|
71
91
|
- - ">="
|
|
@@ -74,7 +94,7 @@ dependencies:
|
|
|
74
94
|
- - "<"
|
|
75
95
|
- !ruby/object:Gem::Version
|
|
76
96
|
version: '9.0'
|
|
77
|
-
type: :
|
|
97
|
+
type: :runtime
|
|
78
98
|
prerelease: false
|
|
79
99
|
version_requirements: !ruby/object:Gem::Requirement
|
|
80
100
|
requirements:
|
|
@@ -99,25 +119,19 @@ dependencies:
|
|
|
99
119
|
- !ruby/object:Gem::Version
|
|
100
120
|
version: '1.16'
|
|
101
121
|
- !ruby/object:Gem::Dependency
|
|
102
|
-
name:
|
|
122
|
+
name: pg
|
|
103
123
|
requirement: !ruby/object:Gem::Requirement
|
|
104
124
|
requirements:
|
|
105
|
-
- - "
|
|
106
|
-
- !ruby/object:Gem::Version
|
|
107
|
-
version: '7.1'
|
|
108
|
-
- - "<"
|
|
125
|
+
- - "~>"
|
|
109
126
|
- !ruby/object:Gem::Version
|
|
110
|
-
version: '
|
|
127
|
+
version: '1.6'
|
|
111
128
|
type: :development
|
|
112
129
|
prerelease: false
|
|
113
130
|
version_requirements: !ruby/object:Gem::Requirement
|
|
114
131
|
requirements:
|
|
115
|
-
- - "
|
|
116
|
-
- !ruby/object:Gem::Version
|
|
117
|
-
version: '7.1'
|
|
118
|
-
- - "<"
|
|
132
|
+
- - "~>"
|
|
119
133
|
- !ruby/object:Gem::Version
|
|
120
|
-
version: '
|
|
134
|
+
version: '1.6'
|
|
121
135
|
- !ruby/object:Gem::Dependency
|
|
122
136
|
name: rake
|
|
123
137
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -188,26 +202,6 @@ dependencies:
|
|
|
188
202
|
- - "~>"
|
|
189
203
|
- !ruby/object:Gem::Version
|
|
190
204
|
version: '0.8'
|
|
191
|
-
- !ruby/object:Gem::Dependency
|
|
192
|
-
name: sqlite3
|
|
193
|
-
requirement: !ruby/object:Gem::Requirement
|
|
194
|
-
requirements:
|
|
195
|
-
- - ">="
|
|
196
|
-
- !ruby/object:Gem::Version
|
|
197
|
-
version: '1.4'
|
|
198
|
-
- - "<"
|
|
199
|
-
- !ruby/object:Gem::Version
|
|
200
|
-
version: '3.0'
|
|
201
|
-
type: :development
|
|
202
|
-
prerelease: false
|
|
203
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
204
|
-
requirements:
|
|
205
|
-
- - ">="
|
|
206
|
-
- !ruby/object:Gem::Version
|
|
207
|
-
version: '1.4'
|
|
208
|
-
- - "<"
|
|
209
|
-
- !ruby/object:Gem::Version
|
|
210
|
-
version: '3.0'
|
|
211
205
|
- !ruby/object:Gem::Dependency
|
|
212
206
|
name: webmock
|
|
213
207
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -224,8 +218,9 @@ dependencies:
|
|
|
224
218
|
version: '3.0'
|
|
225
219
|
description: Tracks token usage, latency, and estimated costs for RubyLLM, OpenAI,
|
|
226
220
|
Anthropic, Google Gemini, OpenRouter, DeepSeek, and OpenAI-compatible APIs. Works
|
|
227
|
-
through Faraday middleware or explicit track/track_stream
|
|
228
|
-
storage, tag-based attribution, price sync tasks, and
|
|
221
|
+
through Rails SDK integrations, Faraday middleware, or explicit track/track_stream
|
|
222
|
+
helpers, with ActiveRecord storage, tag-based attribution, price sync tasks, and
|
|
223
|
+
budget guardrails.
|
|
229
224
|
email:
|
|
230
225
|
- sergey@mm.st
|
|
231
226
|
executables: []
|
|
@@ -253,18 +248,26 @@ files:
|
|
|
253
248
|
- app/helpers/llm_cost_tracker/dashboard_filter_options_helper.rb
|
|
254
249
|
- app/helpers/llm_cost_tracker/dashboard_query_helper.rb
|
|
255
250
|
- app/helpers/llm_cost_tracker/pagination_helper.rb
|
|
251
|
+
- app/helpers/llm_cost_tracker/token_usage_helper.rb
|
|
252
|
+
- app/models/llm_cost_tracker/ingestion/event.rb
|
|
253
|
+
- app/models/llm_cost_tracker/ingestion/lease.rb
|
|
254
|
+
- app/models/llm_cost_tracker/ledger/call.rb
|
|
255
|
+
- app/models/llm_cost_tracker/ledger/call_metrics.rb
|
|
256
|
+
- app/models/llm_cost_tracker/ledger/period/grouping.rb
|
|
257
|
+
- app/models/llm_cost_tracker/ledger/period/total.rb
|
|
258
|
+
- app/models/llm_cost_tracker/ledger/tags/accessors.rb
|
|
256
259
|
- app/services/llm_cost_tracker/dashboard/data_quality.rb
|
|
257
|
-
- app/services/llm_cost_tracker/dashboard/data_quality_aggregate.rb
|
|
258
260
|
- app/services/llm_cost_tracker/dashboard/date_range.rb
|
|
259
261
|
- app/services/llm_cost_tracker/dashboard/filter.rb
|
|
260
262
|
- app/services/llm_cost_tracker/dashboard/overview_stats.rb
|
|
263
|
+
- app/services/llm_cost_tracker/dashboard/pagination.rb
|
|
264
|
+
- app/services/llm_cost_tracker/dashboard/params.rb
|
|
261
265
|
- app/services/llm_cost_tracker/dashboard/provider_breakdown.rb
|
|
262
266
|
- app/services/llm_cost_tracker/dashboard/spend_anomaly.rb
|
|
263
267
|
- app/services/llm_cost_tracker/dashboard/tag_breakdown.rb
|
|
264
268
|
- app/services/llm_cost_tracker/dashboard/tag_key_explorer.rb
|
|
265
269
|
- app/services/llm_cost_tracker/dashboard/time_series.rb
|
|
266
270
|
- app/services/llm_cost_tracker/dashboard/top_models.rb
|
|
267
|
-
- app/services/llm_cost_tracker/pagination.rb
|
|
268
271
|
- app/views/layouts/llm_cost_tracker/application.html.erb
|
|
269
272
|
- app/views/llm_cost_tracker/calls/index.html.erb
|
|
270
273
|
- app/views/llm_cost_tracker/calls/show.html.erb
|
|
@@ -284,28 +287,27 @@ files:
|
|
|
284
287
|
- app/views/llm_cost_tracker/tags/show.html.erb
|
|
285
288
|
- config/routes.rb
|
|
286
289
|
- lib/llm_cost_tracker.rb
|
|
287
|
-
- lib/llm_cost_tracker/active_record_adapter.rb
|
|
288
290
|
- lib/llm_cost_tracker/assets.rb
|
|
289
291
|
- lib/llm_cost_tracker/budget.rb
|
|
290
|
-
- lib/llm_cost_tracker/
|
|
292
|
+
- lib/llm_cost_tracker/capture/stream.rb
|
|
293
|
+
- lib/llm_cost_tracker/capture/stream_collector.rb
|
|
294
|
+
- lib/llm_cost_tracker/capture/stream_tracker.rb
|
|
291
295
|
- lib/llm_cost_tracker/configuration.rb
|
|
292
296
|
- lib/llm_cost_tracker/configuration/instrumentation.rb
|
|
293
|
-
- lib/llm_cost_tracker/configuration/storage_backend.rb
|
|
294
|
-
- lib/llm_cost_tracker/cost.rb
|
|
295
297
|
- lib/llm_cost_tracker/doctor.rb
|
|
296
|
-
- lib/llm_cost_tracker/doctor/
|
|
298
|
+
- lib/llm_cost_tracker/doctor/capture_verifier.rb
|
|
299
|
+
- lib/llm_cost_tracker/doctor/check.rb
|
|
297
300
|
- lib/llm_cost_tracker/doctor/ingestion_check.rb
|
|
301
|
+
- lib/llm_cost_tracker/doctor/price_check.rb
|
|
298
302
|
- lib/llm_cost_tracker/engine.rb
|
|
299
|
-
- lib/llm_cost_tracker/engine_compatibility.rb
|
|
300
303
|
- lib/llm_cost_tracker/errors.rb
|
|
301
304
|
- lib/llm_cost_tracker/event.rb
|
|
302
|
-
- lib/llm_cost_tracker/event_metadata.rb
|
|
303
305
|
- lib/llm_cost_tracker/generators/llm_cost_tracker/add_ingestion_generator.rb
|
|
304
306
|
- lib/llm_cost_tracker/generators/llm_cost_tracker/add_latency_ms_generator.rb
|
|
305
307
|
- lib/llm_cost_tracker/generators/llm_cost_tracker/add_period_totals_generator.rb
|
|
306
308
|
- lib/llm_cost_tracker/generators/llm_cost_tracker/add_provider_response_id_generator.rb
|
|
307
309
|
- lib/llm_cost_tracker/generators/llm_cost_tracker/add_streaming_generator.rb
|
|
308
|
-
- lib/llm_cost_tracker/generators/llm_cost_tracker/
|
|
310
|
+
- lib/llm_cost_tracker/generators/llm_cost_tracker/add_token_usage_generator.rb
|
|
309
311
|
- lib/llm_cost_tracker/generators/llm_cost_tracker/install_generator.rb
|
|
310
312
|
- lib/llm_cost_tracker/generators/llm_cost_tracker/prices_generator.rb
|
|
311
313
|
- lib/llm_cost_tracker/generators/llm_cost_tracker/templates/add_ingestion_to_llm_cost_tracker.rb.erb
|
|
@@ -313,85 +315,69 @@ files:
|
|
|
313
315
|
- lib/llm_cost_tracker/generators/llm_cost_tracker/templates/add_period_totals_to_llm_cost_tracker.rb.erb
|
|
314
316
|
- lib/llm_cost_tracker/generators/llm_cost_tracker/templates/add_provider_response_id_to_llm_api_calls.rb.erb
|
|
315
317
|
- lib/llm_cost_tracker/generators/llm_cost_tracker/templates/add_streaming_to_llm_api_calls.rb.erb
|
|
316
|
-
- lib/llm_cost_tracker/generators/llm_cost_tracker/templates/
|
|
318
|
+
- lib/llm_cost_tracker/generators/llm_cost_tracker/templates/add_token_usage_to_llm_api_calls.rb.erb
|
|
317
319
|
- lib/llm_cost_tracker/generators/llm_cost_tracker/templates/create_llm_api_calls.rb.erb
|
|
318
320
|
- lib/llm_cost_tracker/generators/llm_cost_tracker/templates/initializer.rb.erb
|
|
319
321
|
- lib/llm_cost_tracker/generators/llm_cost_tracker/templates/upgrade_llm_api_call_cost_precision.rb.erb
|
|
320
322
|
- lib/llm_cost_tracker/generators/llm_cost_tracker/templates/upgrade_llm_api_call_tags_to_jsonb.rb.erb
|
|
321
323
|
- lib/llm_cost_tracker/generators/llm_cost_tracker/upgrade_cost_precision_generator.rb
|
|
322
324
|
- lib/llm_cost_tracker/generators/llm_cost_tracker/upgrade_tags_to_jsonb_generator.rb
|
|
323
|
-
- lib/llm_cost_tracker/
|
|
324
|
-
- lib/llm_cost_tracker/
|
|
325
|
+
- lib/llm_cost_tracker/ingestion.rb
|
|
326
|
+
- lib/llm_cost_tracker/ingestion/batch.rb
|
|
327
|
+
- lib/llm_cost_tracker/ingestion/inbox.rb
|
|
328
|
+
- lib/llm_cost_tracker/ingestion/lease_claim.rb
|
|
329
|
+
- lib/llm_cost_tracker/ingestion/worker.rb
|
|
330
|
+
- lib/llm_cost_tracker/integrations.rb
|
|
325
331
|
- lib/llm_cost_tracker/integrations/anthropic.rb
|
|
326
332
|
- lib/llm_cost_tracker/integrations/base.rb
|
|
327
|
-
- lib/llm_cost_tracker/integrations/object_reader.rb
|
|
328
333
|
- lib/llm_cost_tracker/integrations/openai.rb
|
|
329
|
-
- lib/llm_cost_tracker/integrations/registry.rb
|
|
330
334
|
- lib/llm_cost_tracker/integrations/ruby_llm.rb
|
|
331
|
-
- lib/llm_cost_tracker/
|
|
332
|
-
- lib/llm_cost_tracker/
|
|
333
|
-
- lib/llm_cost_tracker/
|
|
335
|
+
- lib/llm_cost_tracker/ledger.rb
|
|
336
|
+
- lib/llm_cost_tracker/ledger/period.rb
|
|
337
|
+
- lib/llm_cost_tracker/ledger/period/totals.rb
|
|
338
|
+
- lib/llm_cost_tracker/ledger/rollups.rb
|
|
339
|
+
- lib/llm_cost_tracker/ledger/rollups/batch.rb
|
|
340
|
+
- lib/llm_cost_tracker/ledger/rollups/upsert_sql.rb
|
|
341
|
+
- lib/llm_cost_tracker/ledger/schema/adapter.rb
|
|
342
|
+
- lib/llm_cost_tracker/ledger/schema/calls.rb
|
|
343
|
+
- lib/llm_cost_tracker/ledger/schema/period_totals.rb
|
|
344
|
+
- lib/llm_cost_tracker/ledger/store.rb
|
|
345
|
+
- lib/llm_cost_tracker/ledger/tags/query.rb
|
|
346
|
+
- lib/llm_cost_tracker/ledger/tags/sql.rb
|
|
334
347
|
- lib/llm_cost_tracker/logging.rb
|
|
335
348
|
- lib/llm_cost_tracker/middleware/faraday.rb
|
|
336
|
-
- lib/llm_cost_tracker/
|
|
337
|
-
- lib/llm_cost_tracker/parsed_usage.rb
|
|
349
|
+
- lib/llm_cost_tracker/parsers.rb
|
|
338
350
|
- lib/llm_cost_tracker/parsers/anthropic.rb
|
|
339
351
|
- lib/llm_cost_tracker/parsers/base.rb
|
|
340
352
|
- lib/llm_cost_tracker/parsers/gemini.rb
|
|
341
353
|
- lib/llm_cost_tracker/parsers/openai.rb
|
|
342
354
|
- lib/llm_cost_tracker/parsers/openai_compatible.rb
|
|
343
355
|
- lib/llm_cost_tracker/parsers/openai_usage.rb
|
|
344
|
-
- lib/llm_cost_tracker/parsers/registry.rb
|
|
345
356
|
- lib/llm_cost_tracker/parsers/sse.rb
|
|
346
|
-
- lib/llm_cost_tracker/period_grouping.rb
|
|
347
|
-
- lib/llm_cost_tracker/period_total.rb
|
|
348
|
-
- lib/llm_cost_tracker/price_freshness.rb
|
|
349
|
-
- lib/llm_cost_tracker/price_registry.rb
|
|
350
|
-
- lib/llm_cost_tracker/price_sync.rb
|
|
351
|
-
- lib/llm_cost_tracker/price_sync/fetcher.rb
|
|
352
|
-
- lib/llm_cost_tracker/price_sync/registry_diff.rb
|
|
353
|
-
- lib/llm_cost_tracker/price_sync/registry_loader.rb
|
|
354
|
-
- lib/llm_cost_tracker/price_sync/registry_writer.rb
|
|
355
357
|
- lib/llm_cost_tracker/prices.json
|
|
356
358
|
- lib/llm_cost_tracker/pricing.rb
|
|
359
|
+
- lib/llm_cost_tracker/pricing/components.rb
|
|
357
360
|
- lib/llm_cost_tracker/pricing/effective_prices.rb
|
|
358
361
|
- lib/llm_cost_tracker/pricing/explainer.rb
|
|
359
362
|
- lib/llm_cost_tracker/pricing/lookup.rb
|
|
363
|
+
- lib/llm_cost_tracker/pricing/registry.rb
|
|
364
|
+
- lib/llm_cost_tracker/pricing/sync.rb
|
|
365
|
+
- lib/llm_cost_tracker/pricing/sync/fetcher.rb
|
|
366
|
+
- lib/llm_cost_tracker/pricing/sync/registry_diff.rb
|
|
367
|
+
- lib/llm_cost_tracker/pricing/sync/registry_loader.rb
|
|
368
|
+
- lib/llm_cost_tracker/pricing/sync/registry_writer.rb
|
|
369
|
+
- lib/llm_cost_tracker/pricing/unknown.rb
|
|
360
370
|
- lib/llm_cost_tracker/railtie.rb
|
|
361
371
|
- lib/llm_cost_tracker/report.rb
|
|
362
|
-
- lib/llm_cost_tracker/
|
|
363
|
-
- lib/llm_cost_tracker/
|
|
364
|
-
- lib/llm_cost_tracker/request_url.rb
|
|
372
|
+
- lib/llm_cost_tracker/report/data.rb
|
|
373
|
+
- lib/llm_cost_tracker/report/formatter.rb
|
|
365
374
|
- lib/llm_cost_tracker/retention.rb
|
|
366
|
-
- lib/llm_cost_tracker/
|
|
367
|
-
- lib/llm_cost_tracker/
|
|
368
|
-
- lib/llm_cost_tracker/
|
|
369
|
-
- lib/llm_cost_tracker/
|
|
370
|
-
- lib/llm_cost_tracker/storage/active_record_ingestor.rb
|
|
371
|
-
- lib/llm_cost_tracker/storage/active_record_ingestor_lease.rb
|
|
372
|
-
- lib/llm_cost_tracker/storage/active_record_period_totals.rb
|
|
373
|
-
- lib/llm_cost_tracker/storage/active_record_periods.rb
|
|
374
|
-
- lib/llm_cost_tracker/storage/active_record_rollup_batch.rb
|
|
375
|
-
- lib/llm_cost_tracker/storage/active_record_rollup_upsert_sql.rb
|
|
376
|
-
- lib/llm_cost_tracker/storage/active_record_rollups.rb
|
|
377
|
-
- lib/llm_cost_tracker/storage/active_record_store.rb
|
|
378
|
-
- lib/llm_cost_tracker/storage/custom_backend.rb
|
|
379
|
-
- lib/llm_cost_tracker/storage/dispatcher.rb
|
|
380
|
-
- lib/llm_cost_tracker/storage/log_backend.rb
|
|
381
|
-
- lib/llm_cost_tracker/storage/registry.rb
|
|
382
|
-
- lib/llm_cost_tracker/stream_capture.rb
|
|
383
|
-
- lib/llm_cost_tracker/stream_collector.rb
|
|
384
|
-
- lib/llm_cost_tracker/tag_accessors.rb
|
|
385
|
-
- lib/llm_cost_tracker/tag_context.rb
|
|
386
|
-
- lib/llm_cost_tracker/tag_key.rb
|
|
387
|
-
- lib/llm_cost_tracker/tag_query.rb
|
|
388
|
-
- lib/llm_cost_tracker/tag_sanitizer.rb
|
|
389
|
-
- lib/llm_cost_tracker/tag_sql.rb
|
|
390
|
-
- lib/llm_cost_tracker/tags_column.rb
|
|
375
|
+
- lib/llm_cost_tracker/tags/context.rb
|
|
376
|
+
- lib/llm_cost_tracker/tags/key.rb
|
|
377
|
+
- lib/llm_cost_tracker/tags/sanitizer.rb
|
|
378
|
+
- lib/llm_cost_tracker/token_usage.rb
|
|
391
379
|
- lib/llm_cost_tracker/tracker.rb
|
|
392
|
-
- lib/llm_cost_tracker/
|
|
393
|
-
- lib/llm_cost_tracker/usage_breakdown.rb
|
|
394
|
-
- lib/llm_cost_tracker/value_helpers.rb
|
|
380
|
+
- lib/llm_cost_tracker/usage_capture.rb
|
|
395
381
|
- lib/llm_cost_tracker/version.rb
|
|
396
382
|
- lib/tasks/llm_cost_tracker.rake
|
|
397
383
|
homepage: https://github.com/sergey-homenko/llm_cost_tracker
|
|
@@ -421,5 +407,5 @@ requirements: []
|
|
|
421
407
|
rubygems_version: 3.5.22
|
|
422
408
|
signing_key:
|
|
423
409
|
specification_version: 4
|
|
424
|
-
summary:
|
|
410
|
+
summary: Rails-native LLM usage and cost tracking with ActiveRecord storage
|
|
425
411
|
test_files: []
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module LlmCostTracker
|
|
4
|
-
module Dashboard
|
|
5
|
-
class DataQualityAggregate
|
|
6
|
-
class << self
|
|
7
|
-
def call(scope:)
|
|
8
|
-
model = scope.klass
|
|
9
|
-
expressions = aggregate_expressions(scope, model:)
|
|
10
|
-
values = Array(scope.unscope(:order).pick(*expressions.values))
|
|
11
|
-
|
|
12
|
-
expressions.keys.zip(values).to_h
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
private
|
|
16
|
-
|
|
17
|
-
def aggregate_expressions(scope, model:)
|
|
18
|
-
usage_breakdown_present = model.usage_breakdown_columns?
|
|
19
|
-
usage_breakdown_cost_present = model.usage_breakdown_cost_columns?
|
|
20
|
-
|
|
21
|
-
expressions = {
|
|
22
|
-
total_calls: Arel.sql("COUNT(*)"),
|
|
23
|
-
unknown_pricing_count: conditional_count_expression("total_cost IS NULL"),
|
|
24
|
-
tagged_calls_count: tagged_calls_expression(model)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if model.latency_column?
|
|
28
|
-
expressions[:missing_latency_count] = conditional_count_expression("latency_ms IS NULL")
|
|
29
|
-
end
|
|
30
|
-
expressions[:streaming_count] = conditional_count_expression("stream") if model.stream_column?
|
|
31
|
-
if model.stream_column? && model.usage_source_column?
|
|
32
|
-
expressions[:streaming_missing_usage_count] =
|
|
33
|
-
conditional_count_expression("stream AND (usage_source = 'unknown' OR usage_source IS NULL)")
|
|
34
|
-
end
|
|
35
|
-
if model.provider_response_id_column?
|
|
36
|
-
expressions[:missing_provider_response_id_count] =
|
|
37
|
-
conditional_count_expression("provider_response_id IS NULL OR provider_response_id = ''")
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
usage_sum_columns(usage_breakdown_present, usage_breakdown_cost_present).each do |column|
|
|
41
|
-
expressions[column] = sum_expression(scope, column)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
expressions
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def usage_sum_columns(usage_breakdown_present, usage_breakdown_cost_present)
|
|
48
|
-
columns = %i[input_tokens output_tokens input_cost output_cost]
|
|
49
|
-
if usage_breakdown_present
|
|
50
|
-
columns += %i[cache_read_input_tokens cache_write_input_tokens hidden_output_tokens]
|
|
51
|
-
end
|
|
52
|
-
columns += %i[cache_read_input_cost cache_write_input_cost] if usage_breakdown_cost_present
|
|
53
|
-
columns
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def conditional_count_expression(predicate)
|
|
57
|
-
Arel.sql("COALESCE(SUM(CASE WHEN #{predicate} THEN 1 ELSE 0 END), 0)")
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def tagged_calls_expression(model)
|
|
61
|
-
table = model.quoted_table_name
|
|
62
|
-
column = "#{table}.#{model.connection.quote_column_name('tags')}"
|
|
63
|
-
|
|
64
|
-
Arel.sql(case
|
|
65
|
-
when model.tags_jsonb_column?
|
|
66
|
-
"COALESCE(SUM(CASE WHEN #{column} <> '{}'::jsonb THEN 1 ELSE 0 END), 0)"
|
|
67
|
-
when model.tags_mysql_json_column?
|
|
68
|
-
"COALESCE(SUM(CASE WHEN JSON_LENGTH(#{column}) > 0 THEN 1 ELSE 0 END), 0)"
|
|
69
|
-
else
|
|
70
|
-
"COALESCE(SUM(CASE WHEN #{column} IS NOT NULL AND #{column} <> '' " \
|
|
71
|
-
"AND #{column} <> '{}' THEN 1 ELSE 0 END), 0)"
|
|
72
|
-
end)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def sum_expression(scope, column)
|
|
76
|
-
Arel.sql("COALESCE(SUM(#{scope.connection.quote_column_name(column)}), 0)")
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
end
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module LlmCostTracker
|
|
4
|
-
class Pagination
|
|
5
|
-
DEFAULT_PER = 50
|
|
6
|
-
MAX_PER = 200
|
|
7
|
-
MIN_PAGE = 1
|
|
8
|
-
|
|
9
|
-
attr_reader :page, :per
|
|
10
|
-
|
|
11
|
-
def self.call(params)
|
|
12
|
-
params = LlmCostTracker::ParameterHash.with_indifferent_access(params)
|
|
13
|
-
new(
|
|
14
|
-
page: integer_param(params, :page, default: MIN_PAGE, min: MIN_PAGE),
|
|
15
|
-
per: integer_param(params, :per, default: DEFAULT_PER, min: 1, max: MAX_PER)
|
|
16
|
-
)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def self.integer_param(params, key, default:, min:, max: nil)
|
|
20
|
-
value = Integer(params[key], 10)
|
|
21
|
-
value = [value, min].max
|
|
22
|
-
value = [value, max].min if max
|
|
23
|
-
value
|
|
24
|
-
rescue ArgumentError, TypeError
|
|
25
|
-
default
|
|
26
|
-
end
|
|
27
|
-
private_class_method :integer_param
|
|
28
|
-
|
|
29
|
-
def initialize(page:, per:)
|
|
30
|
-
@page = page
|
|
31
|
-
@per = per
|
|
32
|
-
freeze
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def limit
|
|
36
|
-
per
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def offset
|
|
40
|
-
(page - 1) * per
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def prev_page?
|
|
44
|
-
page > MIN_PAGE
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def next_page?(total_count)
|
|
48
|
-
offset + per < total_count.to_i
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def total_pages(total_count)
|
|
52
|
-
return MIN_PAGE if total_count.to_i <= 0
|
|
53
|
-
|
|
54
|
-
[(total_count.to_f / per).ceil, MIN_PAGE].max
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module LlmCostTracker
|
|
4
|
-
module ActiveRecordAdapter
|
|
5
|
-
MYSQL_ADAPTERS = %w[
|
|
6
|
-
ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter
|
|
7
|
-
ActiveRecord::ConnectionAdapters::Mysql2Adapter
|
|
8
|
-
ActiveRecord::ConnectionAdapters::TrilogyAdapter
|
|
9
|
-
].freeze
|
|
10
|
-
POSTGRESQL_ADAPTERS = %w[
|
|
11
|
-
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
|
|
12
|
-
].freeze
|
|
13
|
-
SQLITE_ADAPTERS = %w[
|
|
14
|
-
ActiveRecord::ConnectionAdapters::SQLite3Adapter
|
|
15
|
-
].freeze
|
|
16
|
-
MYSQL_PATTERN = /mysql|trilogy|mariadb/i
|
|
17
|
-
POSTGRESQL_PATTERN = /postgres/i
|
|
18
|
-
SQLITE_PATTERN = /sqlite/i
|
|
19
|
-
|
|
20
|
-
class << self
|
|
21
|
-
def mysql?(value) = adapter_instance?(value, MYSQL_ADAPTERS) || adapter_name(value).match?(MYSQL_PATTERN)
|
|
22
|
-
|
|
23
|
-
def postgresql?(value)
|
|
24
|
-
adapter_instance?(value, POSTGRESQL_ADAPTERS) || adapter_name(value).match?(POSTGRESQL_PATTERN)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def sqlite?(value) = adapter_instance?(value, SQLITE_ADAPTERS) || adapter_name(value).match?(SQLITE_PATTERN)
|
|
28
|
-
|
|
29
|
-
private
|
|
30
|
-
|
|
31
|
-
def adapter_instance?(value, class_names)
|
|
32
|
-
class_names.any? do |class_name|
|
|
33
|
-
adapter_class = constantize(class_name)
|
|
34
|
-
adapter_class && value.is_a?(adapter_class)
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def constantize(name)
|
|
39
|
-
name.split("::").reduce(Object) { |namespace, part| namespace.const_get(part, false) }
|
|
40
|
-
rescue NameError
|
|
41
|
-
nil
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def adapter_name(value)
|
|
45
|
-
value.respond_to?(:adapter_name) ? value.adapter_name.to_s : value.to_s
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "storage/dispatcher"
|
|
4
|
-
|
|
5
|
-
module LlmCostTracker
|
|
6
|
-
class CaptureVerifier
|
|
7
|
-
Check = Data.define(:status, :name, :message)
|
|
8
|
-
|
|
9
|
-
class << self
|
|
10
|
-
def call = new.checks
|
|
11
|
-
|
|
12
|
-
def report(checks = call)
|
|
13
|
-
(["LLM Cost Tracker capture verification"] + checks.map { |check| format_check(check) }).join("\n")
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def healthy?(checks = call)
|
|
17
|
-
checks.none? { |check| check.status == :error }
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
private
|
|
21
|
-
|
|
22
|
-
def format_check(check)
|
|
23
|
-
"[#{check.status}] #{check.name}: #{check.message}"
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def checks
|
|
28
|
-
[
|
|
29
|
-
enabled_check,
|
|
30
|
-
*integration_checks,
|
|
31
|
-
*storage_checks
|
|
32
|
-
].compact
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
private
|
|
36
|
-
|
|
37
|
-
def enabled_check
|
|
38
|
-
return Check.new(:ok, "tracking", "enabled") if LlmCostTracker.configuration.enabled
|
|
39
|
-
|
|
40
|
-
Check.new(:error, "tracking", "disabled; set config.enabled = true before verifying capture")
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def integration_checks
|
|
44
|
-
enabled = LlmCostTracker.configuration.instrumented_integrations
|
|
45
|
-
if enabled.empty?
|
|
46
|
-
return [
|
|
47
|
-
Check.new(:ok, "sdk integrations", "none enabled; Faraday middleware and manual capture remain available")
|
|
48
|
-
]
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
LlmCostTracker::Integrations.checks.map do |check|
|
|
52
|
-
Check.new(check.status, "sdk integration #{check.name}", check.message)
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def storage_checks
|
|
57
|
-
backend = LlmCostTracker::Storage::Registry.fetch(LlmCostTracker.configuration.storage_backend)
|
|
58
|
-
unless backend.respond_to?(:verify)
|
|
59
|
-
return [
|
|
60
|
-
Check.new(:warn, "storage", "#{LlmCostTracker.configuration.storage_backend} backend has no verifier")
|
|
61
|
-
]
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
backend.verify.map do |check|
|
|
65
|
-
Check.new(check.status, check.name, check.message)
|
|
66
|
-
end
|
|
67
|
-
rescue LlmCostTracker::Error => e
|
|
68
|
-
[Check.new(:error, "storage", e.message)]
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module LlmCostTracker
|
|
4
|
-
module ConfigurationStorageBackend
|
|
5
|
-
def storage_backend=(value)
|
|
6
|
-
ensure_shared_configuration_mutable!
|
|
7
|
-
@storage_backend = normalize_storage_backend(value)
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
private
|
|
11
|
-
|
|
12
|
-
def normalize_storage_backend(value)
|
|
13
|
-
value = :log if value.nil?
|
|
14
|
-
value = value.to_sym
|
|
15
|
-
return value if self.class::STORAGE_BACKENDS.include?(value)
|
|
16
|
-
return value if defined?(Storage::Registry) && Storage::Registry.registered?(value)
|
|
17
|
-
|
|
18
|
-
names = if defined?(Storage::Registry)
|
|
19
|
-
Storage::Registry.names
|
|
20
|
-
else
|
|
21
|
-
self.class::STORAGE_BACKENDS
|
|
22
|
-
end
|
|
23
|
-
raise Error, "Unknown storage_backend: #{value.inspect}. Use one of: #{names.join(', ')}"
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module LlmCostTracker
|
|
4
|
-
class Doctor
|
|
5
|
-
class CaptureCheck
|
|
6
|
-
def self.call(check_class)
|
|
7
|
-
new(check_class).call
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def initialize(check_class)
|
|
11
|
-
@check_class = check_class
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def call
|
|
15
|
-
config = LlmCostTracker.configuration
|
|
16
|
-
return disabled_check unless config.enabled
|
|
17
|
-
return integrations_check(config.instrumented_integrations) if config.instrumented_integrations.any?
|
|
18
|
-
|
|
19
|
-
check(:ok, "no SDK integrations enabled; Faraday middleware and manual capture remain available")
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
private
|
|
23
|
-
|
|
24
|
-
attr_reader :check_class
|
|
25
|
-
|
|
26
|
-
def disabled_check
|
|
27
|
-
check(:warn, "tracking is disabled; set config.enabled = true to record calls")
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def integrations_check(integrations)
|
|
31
|
-
check(:ok, "SDK integrations enabled: #{integrations.join(', ')}")
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def check(status, message)
|
|
35
|
-
check_class.new(status, "capture", message)
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module LlmCostTracker
|
|
4
|
-
module EngineCompatibility
|
|
5
|
-
REQUIRED_RAILS_VERSION = Gem::Version.new("7.1.0")
|
|
6
|
-
|
|
7
|
-
class << self
|
|
8
|
-
def check_rails_version!(version)
|
|
9
|
-
return if Gem::Version.new(version) >= REQUIRED_RAILS_VERSION
|
|
10
|
-
|
|
11
|
-
raise LlmCostTracker::Error, "LlmCostTracker::Engine requires Rails 7.1+"
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|