ruby_llm-monitoring 0.1.0
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 +7 -0
- data/README.md +179 -0
- data/Rakefile +8 -0
- data/app/assets/stylesheets/ruby_llm/monitoring/application.css +15 -0
- data/app/assets/stylesheets/ruby_llm/monitoring/bulma.min.css +3 -0
- data/app/controllers/ruby_llm/monitoring/alerts_controller.rb +7 -0
- data/app/controllers/ruby_llm/monitoring/application_controller.rb +12 -0
- data/app/controllers/ruby_llm/monitoring/metrics_controller.rb +91 -0
- data/app/helpers/ruby_llm/monitoring/alerts_helper.rb +4 -0
- data/app/helpers/ruby_llm/monitoring/application_helper.rb +6 -0
- data/app/helpers/ruby_llm/monitoring/metrics_helper.rb +7 -0
- data/app/javascript/ruby_llm/monitoring/application.js +5 -0
- data/app/javascript/ruby_llm/monitoring/controllers/application.js +11 -0
- data/app/javascript/ruby_llm/monitoring/controllers/chart_controller.js +93 -0
- data/app/javascript/ruby_llm/monitoring/controllers/index.js +4 -0
- data/app/jobs/ruby_llm/monitoring/application_job.rb +6 -0
- data/app/mailers/ruby_llm/monitoring/alert_mailer.rb +13 -0
- data/app/mailers/ruby_llm/monitoring/application_mailer.rb +8 -0
- data/app/models/concerns/ruby_llm/monitoring/alertable.rb +53 -0
- data/app/models/ruby_llm/monitoring/application_record.rb +7 -0
- data/app/models/ruby_llm/monitoring/event.rb +22 -0
- data/app/views/layouts/ruby_llm/monitoring/application.html.erb +29 -0
- data/app/views/layouts/ruby_llm/monitoring/mailer.html.erb +13 -0
- data/app/views/layouts/ruby_llm/monitoring/mailer.text.erb +1 -0
- data/app/views/ruby_llm/monitoring/alert_mailer/alert_notification.html.erb +1 -0
- data/app/views/ruby_llm/monitoring/alert_mailer/alert_notification.text.erb +1 -0
- data/app/views/ruby_llm/monitoring/alerts/_alert.html.erb +2 -0
- data/app/views/ruby_llm/monitoring/alerts/index.html.erb +26 -0
- data/app/views/ruby_llm/monitoring/application/_flashes.html.erb +9 -0
- data/app/views/ruby_llm/monitoring/application/_nav.html.erb +12 -0
- data/app/views/ruby_llm/monitoring/application/_pagination.html.erb +7 -0
- data/app/views/ruby_llm/monitoring/application/_tabs.html.erb +6 -0
- data/app/views/ruby_llm/monitoring/metrics/_filters.html.erb +25 -0
- data/app/views/ruby_llm/monitoring/metrics/_totals.html.erb +51 -0
- data/app/views/ruby_llm/monitoring/metrics/index.html.erb +16 -0
- data/config/importmap.rb +8 -0
- data/config/routes.rb +6 -0
- data/db/migrate/20251208171258_create_ruby_llm_monitoring_events.rb +70 -0
- data/lib/ruby_llm/monitoring/channel_registry.rb +19 -0
- data/lib/ruby_llm/monitoring/channels/base.rb +11 -0
- data/lib/ruby_llm/monitoring/channels/email.rb +18 -0
- data/lib/ruby_llm/monitoring/channels/slack.rb +18 -0
- data/lib/ruby_llm/monitoring/engine.rb +61 -0
- data/lib/ruby_llm/monitoring/event_subscriber.rb +20 -0
- data/lib/ruby_llm/monitoring/version.rb +5 -0
- data/lib/ruby_llm/monitoring.rb +24 -0
- data/lib/tasks/ruby_llm/monitoring_tasks.rake +4 -0
- metadata +185 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 8823877c782a9d6e67c1aa975c2ed5f64312735141d456e7408d03b7fee0356f
|
|
4
|
+
data.tar.gz: 9568944cf43cbd83acbb4a455e240f7241515b74f38290547847e6cabe0b8a9d
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: b53443b86fca0140c277a54f9738cd100886b409b3aecf594626223d2dfcdd97d77518494b1e7f40696190b4d7a988fe3b2142f4f2d3dcf0f2f9b3930ceb256a
|
|
7
|
+
data.tar.gz: 36fcc184799318b6c70d2233cf5ecb598d52449bf7cbee71d7ec6f1d79949aca5c5f1482ee42b99f364c7a502de59fed09e64dbed240523fbe9d8e57429e089c
|
data/README.md
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# RubyLLM::Monitoring
|
|
2
|
+
|
|
3
|
+
Monitor your LLM usage within your Rails application.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
> [!NOTE]
|
|
8
|
+
> This engine relies on [RubyLLM](https://github.com/crmne/ruby_llm). Make sure you have it installed and configured.
|
|
9
|
+
|
|
10
|
+
Add this line to your application's Gemfile:
|
|
11
|
+
|
|
12
|
+
```ruby
|
|
13
|
+
gem "ruby_llm-monitoring"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
And then execute:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
$ bundle
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
To copy and migrate RubyLLM::Monitoring's migrations, run:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
$ rails ruby_llm_monitoring:install:migrations db:migrate
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
And then mount the engine in your `config/routes.rb`:
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
Rails.application.routes.draw do
|
|
32
|
+
# ...
|
|
33
|
+
|
|
34
|
+
mount RubyLLM::Monitoring::Engine, at: "/monitoring"
|
|
35
|
+
end
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Now you should be able to browse to `/monitoring` and monitor your LLM usage.
|
|
39
|
+
|
|
40
|
+

|
|
41
|
+

|
|
42
|
+
|
|
43
|
+
### Authentication and authorization
|
|
44
|
+
|
|
45
|
+
RubyLLM::Monitoring leaves authentication and authorization to the user. If no authentication is enforced, `/monitoring` will be available to everyone.
|
|
46
|
+
|
|
47
|
+
To enforce authentication, you can use route [constraints](https://guides.rubyonrails.org/routing.html#advanced-constraints), or set up a HTTP Basic auth middleware.
|
|
48
|
+
|
|
49
|
+
For example, if you're using devise, you can do this:
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
# config/routes.rb
|
|
53
|
+
authenticate :user do
|
|
54
|
+
mount RubyLLM::Monitoring::Engine, at: "/monitoring"
|
|
55
|
+
end
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
See more examples [here](https://github.com/heartcombo/devise/wiki/How-To%3A-Define-resource-actions-that-require-authentication-using-routes.rb).
|
|
59
|
+
|
|
60
|
+
However, if you're using Rails' default authentication generator, or an authentication solution that doesn't provide constraints, you need to roll out your own solution:
|
|
61
|
+
|
|
62
|
+
```ruby
|
|
63
|
+
# config/routes.rb
|
|
64
|
+
constraints ->(request) { Constraints::Auth.authenticated?(request) } do
|
|
65
|
+
mount RubyLLM::Monitoring::Engine, at: "/monitoring"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# lib/constraints/auth.rb
|
|
69
|
+
class Constraints::Auth
|
|
70
|
+
def self.authenticated?(request)
|
|
71
|
+
cookies = ActionDispatch::Cookies::CookieJar.build(request, request.cookies)
|
|
72
|
+
|
|
73
|
+
Session.find_by id: cookies.signed[:session_id]
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
You can also set up a HTTP Basic auth middleware in the engine:
|
|
79
|
+
|
|
80
|
+
```ruby
|
|
81
|
+
# config/initializers/ruby_llm-monitoring.rb
|
|
82
|
+
RubyLLM::Monitoring::Engine.middleware.use(Rack::Auth::Basic) do |username, password|
|
|
83
|
+
ActiveSupport::SecurityUtils.secure_compare(Rails.application.credentials.ruby_llm_monitoring_username, username) &
|
|
84
|
+
ActiveSupport::SecurityUtils.secure_compare(Rails.application.credentials.ruby_llm_monitoring_password, password)
|
|
85
|
+
end
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Alerts
|
|
89
|
+
|
|
90
|
+
RubyLLM::Monitoring can send alerts when certain conditions are met. Useful for monitoring cost, errors, etc.
|
|
91
|
+
|
|
92
|
+
### Configuration
|
|
93
|
+
|
|
94
|
+
In `config/initializers/ruby_llm_monitoring.rb`, you can set the notification channels and alert rules:
|
|
95
|
+
|
|
96
|
+
```ruby
|
|
97
|
+
RubyLLM::Monitoring.channels = {
|
|
98
|
+
email: { to: "team@example.com" },
|
|
99
|
+
slack: { webhook_url: ENV["SLACK_WEBHOOK_URL"] },
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# Default cooldown between repeated alerts (optional, defaults to 5 minutes)
|
|
103
|
+
RubyLLM::Monitoring.alert_cooldown = 15.minutes
|
|
104
|
+
|
|
105
|
+
RubyLLM::Monitoring.alert_rules += [{
|
|
106
|
+
time_range: -> { 1.hour.ago.. },
|
|
107
|
+
rule: ->(events) { events.where.not(exception_class: nil).count > 10 },
|
|
108
|
+
channels: [:slack],
|
|
109
|
+
message: { text: "More than 10 errors in the last hour" }
|
|
110
|
+
}, {
|
|
111
|
+
time_range: -> { Time.current.at_beginning_of_month.. },
|
|
112
|
+
rule: ->(events) { events.sum(:cost) >= 500 },
|
|
113
|
+
channels: [:email, :slack],
|
|
114
|
+
message: { text: "More than $500 spent this month" }
|
|
115
|
+
}]
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Rule options
|
|
119
|
+
|
|
120
|
+
| Option | Required | Description |
|
|
121
|
+
| ------------ | -------- | --------------------------------------------------------------------------- |
|
|
122
|
+
| `time_range` | Yes | Lambda returning a range for filtering events (e.g., `-> { 1.hour.ago.. }`) |
|
|
123
|
+
| `rule` | Yes | Lambda receiving events scope, returns true to trigger alert |
|
|
124
|
+
| `channels` | Yes | Array of channel names to notify |
|
|
125
|
+
| `message` | Yes | Hash with `:text` key for the alert message |
|
|
126
|
+
| `id` | No | Identifier for debugging and cooldown tracking |
|
|
127
|
+
| `cooldown` | No | Override default cooldown for this rule |
|
|
128
|
+
|
|
129
|
+
### Built-in channels
|
|
130
|
+
|
|
131
|
+
#### Slack
|
|
132
|
+
|
|
133
|
+
```ruby
|
|
134
|
+
RubyLLM::Monitoring.channels = {
|
|
135
|
+
slack: {
|
|
136
|
+
webhook_url: ENV["SLACK_WEBHOOK_URL"]
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
#### Email
|
|
142
|
+
|
|
143
|
+
```ruby
|
|
144
|
+
RubyLLM::Monitoring.channels = {
|
|
145
|
+
email: {
|
|
146
|
+
to: "team@example.com",
|
|
147
|
+
from: "alerts@example.com", # optional
|
|
148
|
+
subject: "LLM Alert" # optional
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Custom channels
|
|
154
|
+
|
|
155
|
+
Register custom notification channels:
|
|
156
|
+
|
|
157
|
+
```ruby
|
|
158
|
+
class PagerDutyChannel < RubyLLM::Monitoring::Channels::Base
|
|
159
|
+
def self.deliver(message, config)
|
|
160
|
+
# Your implementation
|
|
161
|
+
# message[:text] contains the alert text
|
|
162
|
+
# config contains channel configuration
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
RubyLLM::Monitoring.channel_registry.register(:pagerduty, PagerDutyChannel)
|
|
167
|
+
|
|
168
|
+
RubyLLM::Monitoring.channels = {
|
|
169
|
+
pagerduty: { api_key: ENV["PAGERDUTY_API_KEY"] }
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Contributing
|
|
174
|
+
|
|
175
|
+
You can open an issue or a PR in GitHub.
|
|
176
|
+
|
|
177
|
+
## License
|
|
178
|
+
|
|
179
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
|
3
|
+
* listed below.
|
|
4
|
+
*
|
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
|
7
|
+
*
|
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
|
11
|
+
* It is generally better to create a new file per style scope.
|
|
12
|
+
*
|
|
13
|
+
*= require_tree .
|
|
14
|
+
*= require_self
|
|
15
|
+
*/
|