toad-eye 1.0.0 → 2.0.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.
Files changed (57) hide show
  1. package/README.md +132 -87
  2. package/dist/alerts/channels.d.ts +2 -0
  3. package/dist/alerts/channels.js +81 -0
  4. package/dist/alerts/conditions.d.ts +29 -0
  5. package/dist/alerts/conditions.js +147 -0
  6. package/dist/alerts/grafana.d.ts +5 -0
  7. package/dist/alerts/grafana.js +19 -0
  8. package/dist/alerts/index.d.ts +5 -0
  9. package/dist/alerts/index.js +12 -0
  10. package/dist/alerts/manager.d.ts +13 -0
  11. package/dist/alerts/manager.js +87 -0
  12. package/dist/alerts/types.d.ts +46 -0
  13. package/dist/alerts/types.js +1 -0
  14. package/dist/cli.js +72 -1
  15. package/dist/index.d.ts +6 -2
  16. package/dist/index.js +3 -1
  17. package/dist/instrumentations/anthropic.d.ts +1 -0
  18. package/dist/instrumentations/anthropic.js +54 -0
  19. package/dist/instrumentations/create.d.ts +11 -0
  20. package/dist/instrumentations/create.js +67 -0
  21. package/dist/instrumentations/gemini.d.ts +1 -0
  22. package/dist/instrumentations/gemini.js +48 -0
  23. package/dist/instrumentations/openai.d.ts +1 -0
  24. package/dist/instrumentations/openai.js +58 -0
  25. package/dist/instrumentations/registry.d.ts +5 -0
  26. package/dist/instrumentations/registry.js +31 -0
  27. package/dist/instrumentations/types.d.ts +29 -0
  28. package/dist/instrumentations/types.js +1 -0
  29. package/dist/metrics.js +31 -16
  30. package/dist/pricing.d.ts +24 -0
  31. package/dist/pricing.js +52 -0
  32. package/dist/spans.d.ts +1 -1
  33. package/dist/spans.js +46 -20
  34. package/dist/tracer.d.ts +4 -1
  35. package/dist/tracer.js +9 -0
  36. package/dist/types/attributes.d.ts +36 -0
  37. package/dist/types/attributes.js +38 -0
  38. package/dist/types/config.d.ts +20 -0
  39. package/dist/types/config.js +1 -0
  40. package/dist/types/index.d.ts +17 -0
  41. package/dist/types/index.js +13 -0
  42. package/dist/types/metrics.d.ts +25 -0
  43. package/dist/types/metrics.js +23 -0
  44. package/dist/types/providers.d.ts +5 -0
  45. package/dist/types/providers.js +1 -0
  46. package/dist/types/spans.d.ts +19 -0
  47. package/dist/types/spans.js +1 -0
  48. package/dist/types.d.ts +60 -25
  49. package/dist/types.js +47 -21
  50. package/package.json +17 -6
  51. package/templates/alerts.example.yml +54 -0
  52. package/templates/docker-compose.yml +1 -2
  53. package/templates/grafana/dashboards/cost-breakdown.json +208 -0
  54. package/templates/grafana/dashboards/error-drilldown.json +188 -0
  55. package/templates/grafana/dashboards/latency-analysis.json +134 -0
  56. package/templates/grafana/dashboards/llm-overview.json +161 -30
  57. package/templates/grafana/dashboards/model-comparison.json +143 -0
@@ -7,14 +7,115 @@
7
7
  "links": [],
8
8
  "panels": [
9
9
  {
10
- "title": "Request rate (per minute)",
10
+ "title": "Total Requests",
11
+ "type": "stat",
12
+ "gridPos": { "h": 4, "w": 6, "x": 0, "y": 0 },
13
+ "datasource": { "type": "prometheus", "uid": "prometheus" },
14
+ "targets": [
15
+ {
16
+ "expr": "sum(gen_ai_client_requests_total{gen_ai_provider_name=~\"$provider\", gen_ai_request_model=~\"$model\"})",
17
+ "refId": "A"
18
+ }
19
+ ],
20
+ "fieldConfig": {
21
+ "defaults": {
22
+ "unit": "short",
23
+ "thresholds": {
24
+ "steps": [
25
+ { "color": "green", "value": null },
26
+ { "color": "yellow", "value": 1000 },
27
+ { "color": "red", "value": 10000 }
28
+ ]
29
+ }
30
+ },
31
+ "overrides": []
32
+ }
33
+ },
34
+ {
35
+ "title": "Error Rate %",
36
+ "type": "stat",
37
+ "gridPos": { "h": 4, "w": 6, "x": 6, "y": 0 },
38
+ "datasource": { "type": "prometheus", "uid": "prometheus" },
39
+ "targets": [
40
+ {
41
+ "expr": "sum(gen_ai_client_errors_total{gen_ai_provider_name=~\"$provider\", gen_ai_request_model=~\"$model\"}) / sum(gen_ai_client_requests_total{gen_ai_provider_name=~\"$provider\", gen_ai_request_model=~\"$model\"}) * 100",
42
+ "refId": "A"
43
+ }
44
+ ],
45
+ "fieldConfig": {
46
+ "defaults": {
47
+ "unit": "percent",
48
+ "thresholds": {
49
+ "steps": [
50
+ { "color": "green", "value": null },
51
+ { "color": "yellow", "value": 5 },
52
+ { "color": "red", "value": 20 }
53
+ ]
54
+ }
55
+ },
56
+ "overrides": []
57
+ }
58
+ },
59
+ {
60
+ "title": "Avg Latency",
61
+ "type": "stat",
62
+ "gridPos": { "h": 4, "w": 6, "x": 12, "y": 0 },
63
+ "datasource": { "type": "prometheus", "uid": "prometheus" },
64
+ "targets": [
65
+ {
66
+ "expr": "sum(rate(gen_ai_client_operation_duration_milliseconds_sum{gen_ai_provider_name=~\"$provider\", gen_ai_request_model=~\"$model\"}[5m])) / sum(rate(gen_ai_client_operation_duration_milliseconds_count{gen_ai_provider_name=~\"$provider\", gen_ai_request_model=~\"$model\"}[5m]))",
67
+ "refId": "A"
68
+ }
69
+ ],
70
+ "fieldConfig": {
71
+ "defaults": {
72
+ "unit": "ms",
73
+ "thresholds": {
74
+ "steps": [
75
+ { "color": "green", "value": null },
76
+ { "color": "yellow", "value": 1000 },
77
+ { "color": "red", "value": 5000 }
78
+ ]
79
+ }
80
+ },
81
+ "overrides": []
82
+ }
83
+ },
84
+ {
85
+ "title": "Total Cost",
86
+ "type": "stat",
87
+ "gridPos": { "h": 4, "w": 6, "x": 18, "y": 0 },
88
+ "datasource": { "type": "prometheus", "uid": "prometheus" },
89
+ "targets": [
90
+ {
91
+ "expr": "sum(gen_ai_client_request_cost_USD_sum{gen_ai_provider_name=~\"$provider\", gen_ai_request_model=~\"$model\"})",
92
+ "refId": "A"
93
+ }
94
+ ],
95
+ "fieldConfig": {
96
+ "defaults": {
97
+ "unit": "currencyUSD",
98
+ "thresholds": {
99
+ "steps": [
100
+ { "color": "green", "value": null },
101
+ { "color": "yellow", "value": 10 },
102
+ { "color": "red", "value": 100 }
103
+ ]
104
+ }
105
+ },
106
+ "overrides": []
107
+ }
108
+ },
109
+ {
110
+ "title": "Request Rate per minute",
11
111
  "type": "timeseries",
12
- "gridPos": { "h": 8, "w": 12, "x": 0, "y": 0 },
112
+ "gridPos": { "h": 8, "w": 12, "x": 0, "y": 4 },
13
113
  "datasource": { "type": "prometheus", "uid": "prometheus" },
14
114
  "targets": [
15
115
  {
16
- "expr": "sum(rate(llm_requests_total[1m])) by (provider) * 60",
17
- "legendFormat": "{{ provider }}"
116
+ "expr": "sum(rate(gen_ai_client_requests_total{gen_ai_provider_name=~\"$provider\", gen_ai_request_model=~\"$model\"}[1m])) by (gen_ai_provider_name) * 60",
117
+ "legendFormat": "{{ gen_ai_provider_name }}",
118
+ "refId": "A"
18
119
  }
19
120
  ],
20
121
  "fieldConfig": {
@@ -26,14 +127,15 @@
26
127
  }
27
128
  },
28
129
  {
29
- "title": "Error rate (per minute)",
130
+ "title": "Error Rate per minute",
30
131
  "type": "timeseries",
31
- "gridPos": { "h": 8, "w": 12, "x": 12, "y": 0 },
132
+ "gridPos": { "h": 8, "w": 12, "x": 12, "y": 4 },
32
133
  "datasource": { "type": "prometheus", "uid": "prometheus" },
33
134
  "targets": [
34
135
  {
35
- "expr": "sum(rate(llm_errors_total[1m])) by (provider) * 60",
36
- "legendFormat": "{{ provider }}"
136
+ "expr": "sum(rate(gen_ai_client_errors_total{gen_ai_provider_name=~\"$provider\", gen_ai_request_model=~\"$model\"}[1m])) by (gen_ai_provider_name) * 60",
137
+ "legendFormat": "{{ gen_ai_provider_name }}",
138
+ "refId": "A"
37
139
  }
38
140
  ],
39
141
  "fieldConfig": {
@@ -48,22 +150,24 @@
48
150
  {
49
151
  "title": "Latency p50 / p95 (ms)",
50
152
  "type": "timeseries",
51
- "gridPos": { "h": 8, "w": 12, "x": 0, "y": 8 },
153
+ "gridPos": { "h": 8, "w": 12, "x": 0, "y": 12 },
52
154
  "datasource": { "type": "prometheus", "uid": "prometheus" },
53
155
  "targets": [
54
156
  {
55
- "expr": "histogram_quantile(0.50, sum(rate(llm_request_duration_milliseconds_bucket[1m])) by (le, provider))",
56
- "legendFormat": "p50 {{ provider }}"
157
+ "expr": "histogram_quantile(0.50, sum(rate(gen_ai_client_operation_duration_milliseconds_bucket{gen_ai_provider_name=~\"$provider\", gen_ai_request_model=~\"$model\"}[5m])) by (le))",
158
+ "legendFormat": "p50",
159
+ "refId": "A"
57
160
  },
58
161
  {
59
- "expr": "histogram_quantile(0.95, sum(rate(llm_request_duration_milliseconds_bucket[1m])) by (le, provider))",
60
- "legendFormat": "p95 {{ provider }}"
162
+ "expr": "histogram_quantile(0.95, sum(rate(gen_ai_client_operation_duration_milliseconds_bucket{gen_ai_provider_name=~\"$provider\", gen_ai_request_model=~\"$model\"}[5m])) by (le))",
163
+ "legendFormat": "p95",
164
+ "refId": "B"
61
165
  }
62
166
  ],
63
167
  "fieldConfig": {
64
168
  "defaults": {
65
169
  "unit": "ms",
66
- "custom": { "drawStyle": "line", "fillOpacity": 10, "lineWidth": 2 }
170
+ "custom": { "drawStyle": "line", "fillOpacity": 15, "lineWidth": 2 }
67
171
  },
68
172
  "overrides": []
69
173
  }
@@ -71,12 +175,13 @@
71
175
  {
72
176
  "title": "Cost per minute (USD)",
73
177
  "type": "timeseries",
74
- "gridPos": { "h": 8, "w": 12, "x": 12, "y": 8 },
178
+ "gridPos": { "h": 8, "w": 12, "x": 12, "y": 12 },
75
179
  "datasource": { "type": "prometheus", "uid": "prometheus" },
76
180
  "targets": [
77
181
  {
78
- "expr": "sum(rate(llm_request_cost_USD_sum[1m])) by (provider) * 60",
79
- "legendFormat": "{{ provider }}"
182
+ "expr": "sum(rate(gen_ai_client_request_cost_USD_sum{gen_ai_provider_name=~\"$provider\", gen_ai_request_model=~\"$model\"}[1m])) by (gen_ai_provider_name) * 60",
183
+ "legendFormat": "{{ gen_ai_provider_name }}",
184
+ "refId": "A"
80
185
  }
81
186
  ],
82
187
  "fieldConfig": {
@@ -88,13 +193,14 @@
88
193
  }
89
194
  },
90
195
  {
91
- "title": "Total tokens consumed",
196
+ "title": "Total Tokens",
92
197
  "type": "stat",
93
- "gridPos": { "h": 4, "w": 8, "x": 0, "y": 16 },
198
+ "gridPos": { "h": 4, "w": 8, "x": 0, "y": 20 },
94
199
  "datasource": { "type": "prometheus", "uid": "prometheus" },
95
200
  "targets": [
96
201
  {
97
- "expr": "sum(llm_tokens_total)"
202
+ "expr": "sum(gen_ai_client_token_usage_total{gen_ai_provider_name=~\"$provider\", gen_ai_request_model=~\"$model\"})",
203
+ "refId": "A"
98
204
  }
99
205
  ],
100
206
  "fieldConfig": {
@@ -112,13 +218,14 @@
112
218
  }
113
219
  },
114
220
  {
115
- "title": "Total requests",
221
+ "title": "Total Requests",
116
222
  "type": "stat",
117
- "gridPos": { "h": 4, "w": 8, "x": 8, "y": 16 },
223
+ "gridPos": { "h": 4, "w": 8, "x": 8, "y": 20 },
118
224
  "datasource": { "type": "prometheus", "uid": "prometheus" },
119
225
  "targets": [
120
226
  {
121
- "expr": "sum(llm_requests_total)"
227
+ "expr": "sum(gen_ai_client_requests_total{gen_ai_provider_name=~\"$provider\", gen_ai_request_model=~\"$model\"})",
228
+ "refId": "A"
122
229
  }
123
230
  ],
124
231
  "fieldConfig": {
@@ -136,13 +243,14 @@
136
243
  }
137
244
  },
138
245
  {
139
- "title": "Total errors",
246
+ "title": "Total Errors",
140
247
  "type": "stat",
141
- "gridPos": { "h": 4, "w": 8, "x": 16, "y": 16 },
248
+ "gridPos": { "h": 4, "w": 8, "x": 16, "y": 20 },
142
249
  "datasource": { "type": "prometheus", "uid": "prometheus" },
143
250
  "targets": [
144
251
  {
145
- "expr": "sum(llm_errors_total)"
252
+ "expr": "sum(gen_ai_client_errors_total{gen_ai_provider_name=~\"$provider\", gen_ai_request_model=~\"$model\"})",
253
+ "refId": "A"
146
254
  }
147
255
  ],
148
256
  "fieldConfig": {
@@ -163,11 +271,34 @@
163
271
  "refresh": "5s",
164
272
  "schemaVersion": 39,
165
273
  "tags": ["llm", "observability", "toad-eye"],
166
- "templating": { "list": [] },
274
+ "templating": {
275
+ "list": [
276
+ {
277
+ "name": "provider",
278
+ "type": "query",
279
+ "datasource": { "type": "prometheus", "uid": "prometheus" },
280
+ "query": "label_values(gen_ai_client_requests_total, gen_ai_provider_name)",
281
+ "includeAll": true,
282
+ "allValue": ".*",
283
+ "current": { "text": "All", "value": "$__all" },
284
+ "multi": true
285
+ },
286
+ {
287
+ "name": "model",
288
+ "type": "query",
289
+ "datasource": { "type": "prometheus", "uid": "prometheus" },
290
+ "query": "label_values(gen_ai_client_requests_total{gen_ai_provider_name=~\"$provider\"}, gen_ai_request_model)",
291
+ "includeAll": true,
292
+ "allValue": ".*",
293
+ "current": { "text": "All", "value": "$__all" },
294
+ "multi": true
295
+ }
296
+ ]
297
+ },
167
298
  "time": { "from": "now-15m", "to": "now" },
168
299
  "timepicker": {},
169
300
  "timezone": "browser",
170
- "title": "toad-eye: LLM observability",
171
- "uid": "toad-eye-llm-overview",
172
- "version": 2
301
+ "title": "toad-eye: Overview",
302
+ "uid": "toad-eye-overview",
303
+ "version": 1
173
304
  }
@@ -0,0 +1,143 @@
1
+ {
2
+ "annotations": { "list": [] },
3
+ "editable": true,
4
+ "fiscalYearStartMonth": 0,
5
+ "graphTooltip": 1,
6
+ "id": null,
7
+ "links": [],
8
+ "panels": [
9
+ {
10
+ "title": "Latency by Model (p95)",
11
+ "type": "timeseries",
12
+ "gridPos": { "h": 8, "w": 12, "x": 0, "y": 0 },
13
+ "datasource": { "type": "prometheus", "uid": "prometheus" },
14
+ "targets": [
15
+ {
16
+ "expr": "histogram_quantile(0.95, sum(rate(gen_ai_client_operation_duration_milliseconds_bucket{gen_ai_provider_name=~\"$provider\", gen_ai_request_model=~\"$model\"}[5m])) by (le, gen_ai_request_model))",
17
+ "legendFormat": "p95 {{ gen_ai_request_model }}",
18
+ "refId": "A"
19
+ }
20
+ ],
21
+ "fieldConfig": {
22
+ "defaults": {
23
+ "unit": "ms",
24
+ "custom": { "drawStyle": "line", "fillOpacity": 15, "lineWidth": 2 }
25
+ },
26
+ "overrides": []
27
+ }
28
+ },
29
+ {
30
+ "title": "Cost by Model (avg per request)",
31
+ "type": "timeseries",
32
+ "gridPos": { "h": 8, "w": 12, "x": 12, "y": 0 },
33
+ "datasource": { "type": "prometheus", "uid": "prometheus" },
34
+ "targets": [
35
+ {
36
+ "expr": "sum(rate(gen_ai_client_request_cost_USD_sum{gen_ai_provider_name=~\"$provider\", gen_ai_request_model=~\"$model\"}[5m])) by (gen_ai_request_model) / sum(rate(gen_ai_client_request_cost_USD_count{gen_ai_provider_name=~\"$provider\", gen_ai_request_model=~\"$model\"}[5m])) by (gen_ai_request_model)",
37
+ "legendFormat": "{{ gen_ai_request_model }}",
38
+ "refId": "A"
39
+ }
40
+ ],
41
+ "fieldConfig": {
42
+ "defaults": {
43
+ "unit": "currencyUSD",
44
+ "custom": { "drawStyle": "line", "fillOpacity": 15, "lineWidth": 2 }
45
+ },
46
+ "overrides": []
47
+ }
48
+ },
49
+ {
50
+ "title": "Error Rate by Model (%)",
51
+ "type": "timeseries",
52
+ "gridPos": { "h": 8, "w": 12, "x": 0, "y": 8 },
53
+ "datasource": { "type": "prometheus", "uid": "prometheus" },
54
+ "targets": [
55
+ {
56
+ "expr": "sum(rate(gen_ai_client_errors_total{gen_ai_provider_name=~\"$provider\", gen_ai_request_model=~\"$model\"}[5m])) by (gen_ai_request_model) / sum(rate(gen_ai_client_requests_total{gen_ai_provider_name=~\"$provider\", gen_ai_request_model=~\"$model\"}[5m])) by (gen_ai_request_model) * 100",
57
+ "legendFormat": "{{ gen_ai_request_model }}",
58
+ "refId": "A"
59
+ }
60
+ ],
61
+ "fieldConfig": {
62
+ "defaults": {
63
+ "unit": "percent",
64
+ "custom": { "drawStyle": "line", "fillOpacity": 15, "lineWidth": 2 }
65
+ },
66
+ "overrides": []
67
+ }
68
+ },
69
+ {
70
+ "title": "Throughput by Model (req/min)",
71
+ "type": "timeseries",
72
+ "gridPos": { "h": 8, "w": 12, "x": 12, "y": 8 },
73
+ "datasource": { "type": "prometheus", "uid": "prometheus" },
74
+ "targets": [
75
+ {
76
+ "expr": "sum(rate(gen_ai_client_requests_total{gen_ai_provider_name=~\"$provider\", gen_ai_request_model=~\"$model\"}[1m])) by (gen_ai_request_model) * 60",
77
+ "legendFormat": "{{ gen_ai_request_model }}",
78
+ "refId": "A"
79
+ }
80
+ ],
81
+ "fieldConfig": {
82
+ "defaults": {
83
+ "unit": "reqpm",
84
+ "custom": { "drawStyle": "line", "fillOpacity": 15, "lineWidth": 2 }
85
+ },
86
+ "overrides": []
87
+ }
88
+ },
89
+ {
90
+ "title": "Tokens per Request by Model",
91
+ "type": "timeseries",
92
+ "gridPos": { "h": 8, "w": 24, "x": 0, "y": 16 },
93
+ "datasource": { "type": "prometheus", "uid": "prometheus" },
94
+ "targets": [
95
+ {
96
+ "expr": "sum(rate(gen_ai_client_token_usage_total{gen_ai_provider_name=~\"$provider\", gen_ai_request_model=~\"$model\"}[5m])) by (gen_ai_request_model) / sum(rate(gen_ai_client_requests_total{gen_ai_provider_name=~\"$provider\", gen_ai_request_model=~\"$model\"}[5m])) by (gen_ai_request_model)",
97
+ "legendFormat": "{{ gen_ai_request_model }}",
98
+ "refId": "A"
99
+ }
100
+ ],
101
+ "fieldConfig": {
102
+ "defaults": {
103
+ "unit": "short",
104
+ "custom": { "drawStyle": "line", "fillOpacity": 15, "lineWidth": 2 }
105
+ },
106
+ "overrides": []
107
+ }
108
+ }
109
+ ],
110
+ "refresh": "5s",
111
+ "schemaVersion": 39,
112
+ "tags": ["llm", "observability", "toad-eye"],
113
+ "templating": {
114
+ "list": [
115
+ {
116
+ "name": "provider",
117
+ "type": "query",
118
+ "datasource": { "type": "prometheus", "uid": "prometheus" },
119
+ "query": "label_values(gen_ai_client_requests_total, gen_ai_provider_name)",
120
+ "includeAll": true,
121
+ "allValue": ".*",
122
+ "current": { "text": "All", "value": "$__all" },
123
+ "multi": true
124
+ },
125
+ {
126
+ "name": "model",
127
+ "type": "query",
128
+ "datasource": { "type": "prometheus", "uid": "prometheus" },
129
+ "query": "label_values(gen_ai_client_requests_total{gen_ai_provider_name=~\"$provider\"}, gen_ai_request_model)",
130
+ "includeAll": true,
131
+ "allValue": ".*",
132
+ "current": { "text": "All", "value": "$__all" },
133
+ "multi": true
134
+ }
135
+ ]
136
+ },
137
+ "time": { "from": "now-15m", "to": "now" },
138
+ "timepicker": {},
139
+ "timezone": "browser",
140
+ "title": "toad-eye: Model Comparison",
141
+ "uid": "toad-eye-comparison",
142
+ "version": 1
143
+ }