rails-profiler 0.19.0 → 0.19.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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 713e1b01bcd916191e3ae2b89124f4637eeb95d7b9837d350d2ee76a575a2f14
|
|
4
|
+
data.tar.gz: 9f1becf53b9b39145a4ebdf81981793aeb5f0494cce1e6872facdcf11c0a597a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 298e772fd273b734126c095e57186e36d7f6fbaf26c7bb7db9899d02a38431231e4ecbde42f0b1a103deac26c29f48a596a065b5dd93f16a900b24d66e69a280
|
|
7
|
+
data.tar.gz: 78f23d51a52d0467e3acf9d912cbcbeebec03cf245632d88c7306d00d7c00645dda2be0a6208f3e58f4c815ea3a9efe0cb4e6783a3c6c4be44b784fd72e35f37
|
|
@@ -989,6 +989,7 @@
|
|
|
989
989
|
const body = await res.json().catch(() => ({}));
|
|
990
990
|
throw new Error(body.error ?? `Request failed (${res.status})`);
|
|
991
991
|
}
|
|
992
|
+
return res.json();
|
|
992
993
|
}
|
|
993
994
|
async function resetEnvVar(key) {
|
|
994
995
|
const res = await fetch(`/_profiler/api/env_vars/reset?key=${encodeURIComponent(key)}`, {
|
|
@@ -1005,7 +1006,7 @@
|
|
|
1005
1006
|
if (!res.ok) throw new Error(`Request failed (${res.status})`);
|
|
1006
1007
|
}
|
|
1007
1008
|
function EnvTab({ envData, readOnly: forceReadOnly = false }) {
|
|
1008
|
-
const initial =
|
|
1009
|
+
const [initial, setInitial] = d2(() => ({ ...envData?.variables ?? {} }));
|
|
1009
1010
|
const [variables, setVariables] = d2(initial);
|
|
1010
1011
|
const [overrides, setOverrides] = d2(envData?.overrides ?? {});
|
|
1011
1012
|
const [total, setTotal] = d2(envData?.total ?? 0);
|
|
@@ -1070,6 +1071,7 @@
|
|
|
1070
1071
|
setTotal(data.total);
|
|
1071
1072
|
setOverrides(data.overrides ?? {});
|
|
1072
1073
|
showFlash("success", `Refreshed \u2014 ${data.total} variables`);
|
|
1074
|
+
return data;
|
|
1073
1075
|
} catch (e3) {
|
|
1074
1076
|
showFlash("error", e3.message ?? "Failed to refresh");
|
|
1075
1077
|
} finally {
|
|
@@ -1116,11 +1118,25 @@
|
|
|
1116
1118
|
};
|
|
1117
1119
|
const saveEdit = async () => {
|
|
1118
1120
|
if (!editingKey) return;
|
|
1121
|
+
const key = editingKey;
|
|
1122
|
+
if (editValue === variables[key]) {
|
|
1123
|
+
setEditingKey(null);
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1119
1126
|
setSaving(true);
|
|
1120
1127
|
try {
|
|
1121
|
-
await patchEnvVar(
|
|
1122
|
-
setVariables((prev) => ({ ...prev, [
|
|
1123
|
-
|
|
1128
|
+
const data = await patchEnvVar(key, editValue);
|
|
1129
|
+
setVariables((prev) => ({ ...prev, [key]: editValue }));
|
|
1130
|
+
setOverrides((prev) => {
|
|
1131
|
+
const n2 = { ...prev };
|
|
1132
|
+
if (data.override) {
|
|
1133
|
+
n2[key] = data.override;
|
|
1134
|
+
} else {
|
|
1135
|
+
delete n2[key];
|
|
1136
|
+
}
|
|
1137
|
+
return n2;
|
|
1138
|
+
});
|
|
1139
|
+
showFlash("success", `${key} updated`);
|
|
1124
1140
|
setEditingKey(null);
|
|
1125
1141
|
} catch (e3) {
|
|
1126
1142
|
showFlash("error", e3.message ?? "Failed to update");
|
|
@@ -1131,12 +1147,21 @@
|
|
|
1131
1147
|
const deleteVar = async (key) => {
|
|
1132
1148
|
setSaving(true);
|
|
1133
1149
|
try {
|
|
1134
|
-
await patchEnvVar(key, null);
|
|
1150
|
+
const data = await patchEnvVar(key, null);
|
|
1135
1151
|
setVariables((prev) => {
|
|
1136
1152
|
const n2 = { ...prev };
|
|
1137
1153
|
delete n2[key];
|
|
1138
1154
|
return n2;
|
|
1139
1155
|
});
|
|
1156
|
+
setOverrides((prev) => {
|
|
1157
|
+
const n2 = { ...prev };
|
|
1158
|
+
if (data.override) {
|
|
1159
|
+
n2[key] = data.override;
|
|
1160
|
+
} else {
|
|
1161
|
+
delete n2[key];
|
|
1162
|
+
}
|
|
1163
|
+
return n2;
|
|
1164
|
+
});
|
|
1140
1165
|
setUnmaskedKeys((prev) => {
|
|
1141
1166
|
const n2 = new Set(prev);
|
|
1142
1167
|
n2.delete(key);
|
|
@@ -1154,8 +1179,17 @@
|
|
|
1154
1179
|
const next = /^(true|yes)$/i.test(current) ? "false" : "true";
|
|
1155
1180
|
setSaving(true);
|
|
1156
1181
|
try {
|
|
1157
|
-
await patchEnvVar(key, next);
|
|
1182
|
+
const data = await patchEnvVar(key, next);
|
|
1158
1183
|
setVariables((prev) => ({ ...prev, [key]: next }));
|
|
1184
|
+
setOverrides((prev) => {
|
|
1185
|
+
const n2 = { ...prev };
|
|
1186
|
+
if (data.override) {
|
|
1187
|
+
n2[key] = data.override;
|
|
1188
|
+
} else {
|
|
1189
|
+
delete n2[key];
|
|
1190
|
+
}
|
|
1191
|
+
return n2;
|
|
1192
|
+
});
|
|
1159
1193
|
} catch (e3) {
|
|
1160
1194
|
showFlash("error", e3.message ?? "Failed to update");
|
|
1161
1195
|
} finally {
|
|
@@ -1167,8 +1201,17 @@
|
|
|
1167
1201
|
if (!key) return;
|
|
1168
1202
|
setSaving(true);
|
|
1169
1203
|
try {
|
|
1170
|
-
await patchEnvVar(key, newValue);
|
|
1204
|
+
const data = await patchEnvVar(key, newValue);
|
|
1171
1205
|
setVariables((prev) => ({ ...prev, [key]: newValue }));
|
|
1206
|
+
setOverrides((prev) => {
|
|
1207
|
+
const n2 = { ...prev };
|
|
1208
|
+
if (data.override) {
|
|
1209
|
+
n2[key] = data.override;
|
|
1210
|
+
} else {
|
|
1211
|
+
delete n2[key];
|
|
1212
|
+
}
|
|
1213
|
+
return n2;
|
|
1214
|
+
});
|
|
1172
1215
|
setNewKey("");
|
|
1173
1216
|
setNewValue("");
|
|
1174
1217
|
showFlash("success", `${key} added`);
|
|
@@ -1191,7 +1234,7 @@
|
|
|
1191
1234
|
delete n2[key];
|
|
1192
1235
|
return n2;
|
|
1193
1236
|
});
|
|
1194
|
-
|
|
1237
|
+
const updater = (prev) => {
|
|
1195
1238
|
const n2 = { ...prev };
|
|
1196
1239
|
if (data.value === null) {
|
|
1197
1240
|
delete n2[key];
|
|
@@ -1199,7 +1242,9 @@
|
|
|
1199
1242
|
n2[key] = data.value;
|
|
1200
1243
|
}
|
|
1201
1244
|
return n2;
|
|
1202
|
-
}
|
|
1245
|
+
};
|
|
1246
|
+
setVariables(updater);
|
|
1247
|
+
setInitial(updater);
|
|
1203
1248
|
showFlash("success", `${key} reset to original`);
|
|
1204
1249
|
} catch (e3) {
|
|
1205
1250
|
showFlash("error", e3.message ?? "Failed to reset");
|
|
@@ -1212,7 +1257,8 @@
|
|
|
1212
1257
|
try {
|
|
1213
1258
|
await resetAllEnvVars();
|
|
1214
1259
|
setOverrides({});
|
|
1215
|
-
await refresh();
|
|
1260
|
+
const data = await refresh();
|
|
1261
|
+
if (data) setInitial(data.variables);
|
|
1216
1262
|
showFlash("success", "All overrides reset");
|
|
1217
1263
|
} catch (e3) {
|
|
1218
1264
|
showFlash("error", e3.message ?? "Failed to reset all");
|
|
@@ -1449,10 +1495,6 @@
|
|
|
1449
1495
|
override.value === "__profiler_deleted__" ? "(deleted)" : override.value,
|
|
1450
1496
|
" \xB7 original: ",
|
|
1451
1497
|
override.original ?? "(unset)"
|
|
1452
|
-
] }),
|
|
1453
|
-
!override && wasModified && /* @__PURE__ */ u3("div", { style: "font-size:10px;color:#f59e0b;margin-top:2px;font-family:monospace;", children: [
|
|
1454
|
-
"was: ",
|
|
1455
|
-
initial[key]
|
|
1456
1498
|
] })
|
|
1457
1499
|
] }) : /* @__PURE__ */ u3(k, { children: [
|
|
1458
1500
|
/* @__PURE__ */ u3("div", { class: "profiler-flex", style: "align-items:center;gap:4px;", children: [
|
|
@@ -1461,7 +1503,9 @@
|
|
|
1461
1503
|
"span",
|
|
1462
1504
|
{
|
|
1463
1505
|
class: "profiler-text--xs profiler-text--mono",
|
|
1464
|
-
|
|
1506
|
+
onClick: () => !readOnly && !isEditing && startEdit(key),
|
|
1507
|
+
title: !readOnly ? "Click to edit" : void 0,
|
|
1508
|
+
style: `word-break:break-all;flex:1;${!readOnly ? "cursor:pointer;" : ""}`,
|
|
1465
1509
|
children: unmasked ? isQuoted(value) ? /* @__PURE__ */ u3(k, { children: [
|
|
1466
1510
|
/* @__PURE__ */ u3("span", { style: "color:var(--profiler-text-muted);opacity:0.5;", children: '"' }),
|
|
1467
1511
|
value,
|
|
@@ -1493,28 +1537,24 @@
|
|
|
1493
1537
|
override.value === "__profiler_deleted__" ? "(deleted)" : unmasked ? override.value : "\u2022".repeat(Math.min((override.value ?? "").length, 20)),
|
|
1494
1538
|
" \xB7 original: ",
|
|
1495
1539
|
override.original == null ? "(unset)" : unmasked ? override.original : "\u2022".repeat(Math.min(override.original.length, 20))
|
|
1496
|
-
] }),
|
|
1497
|
-
!override && wasModified && /* @__PURE__ */ u3("div", { style: "font-size:10px;color:#f59e0b;margin-top:2px;font-family:monospace;", children: [
|
|
1498
|
-
"was: ",
|
|
1499
|
-
unmasked ? isQuoted(initial[key]) ? `"${initial[key]}"` : initial[key] : "\u2022".repeat(Math.min(initial[key].length, 20))
|
|
1500
1540
|
] })
|
|
1501
1541
|
] }) }),
|
|
1502
1542
|
!readOnly && /* @__PURE__ */ u3("td", { style: "text-align:right;white-space:nowrap;", children: isEditing ? /* @__PURE__ */ u3(k, { children: [
|
|
1503
1543
|
/* @__PURE__ */ u3("button", { onClick: saveEdit, disabled: saving, title: "Save", style: "background:none;border:none;cursor:pointer;color:var(--profiler-success,#22c55e);font-size:14px;padding:0 4px;", children: "\u2713" }),
|
|
1504
1544
|
/* @__PURE__ */ u3("button", { onClick: cancelEdit, disabled: saving, title: "Cancel", style: "background:none;border:none;cursor:pointer;color:var(--profiler-text-muted);font-size:14px;padding:0 4px;", children: "\u2717" })
|
|
1505
1545
|
] }) : /* @__PURE__ */ u3(k, { children: [
|
|
1506
|
-
/* @__PURE__ */ u3("button", { onClick: () => startEdit(key), disabled: saving, style: "background:none;border:none;cursor:pointer;color:var(--profiler-accent);font-size:
|
|
1546
|
+
/* @__PURE__ */ u3("button", { onClick: () => startEdit(key), disabled: saving, title: "Edit", style: "background:none;border:none;cursor:pointer;color:var(--profiler-accent);font-size:14px;padding:0 4px;", children: "\u270E" }),
|
|
1507
1547
|
override && /* @__PURE__ */ u3(
|
|
1508
1548
|
"button",
|
|
1509
1549
|
{
|
|
1510
1550
|
onClick: () => resetVar(key),
|
|
1511
1551
|
disabled: saving,
|
|
1512
1552
|
title: `Reset to original: ${override.original ?? "(unset)"}`,
|
|
1513
|
-
style: "background:none;border:none;cursor:pointer;color:var(--profiler-warning,#f59e0b);font-size:
|
|
1514
|
-
children: "\u21A9
|
|
1553
|
+
style: "background:none;border:none;cursor:pointer;color:var(--profiler-warning,#f59e0b);font-size:14px;padding:0 4px;",
|
|
1554
|
+
children: "\u21A9"
|
|
1515
1555
|
}
|
|
1516
1556
|
),
|
|
1517
|
-
/* @__PURE__ */ u3("button", { onClick: () => deleteVar(key), disabled: saving, style: "background:none;border:none;cursor:pointer;color:var(--profiler-error,#ef4444);font-size:
|
|
1557
|
+
/* @__PURE__ */ u3("button", { onClick: () => deleteVar(key), disabled: saving, title: "Delete", style: "background:none;border:none;cursor:pointer;color:var(--profiler-error,#ef4444);font-size:14px;padding:0 4px;", children: "\u2715" })
|
|
1518
1558
|
] }) })
|
|
1519
1559
|
] }, key);
|
|
1520
1560
|
})
|
|
@@ -22,13 +22,18 @@ module Profiler
|
|
|
22
22
|
value = params[:value]
|
|
23
23
|
|
|
24
24
|
if value.nil? || value.to_s.empty?
|
|
25
|
-
ENV.delete(key)
|
|
26
25
|
Profiler.env_override_store.delete(key)
|
|
27
|
-
|
|
26
|
+
ENV.delete(key)
|
|
27
|
+
render json: { key: key, value: nil, deleted: true, override: Profiler.env_override_store.all_overrides[key] }
|
|
28
28
|
else
|
|
29
|
+
current_original = Profiler.env_override_store.all_overrides.dig(key, "original")
|
|
30
|
+
if current_original == value.to_s
|
|
31
|
+
Profiler.env_override_store.reset(key)
|
|
32
|
+
else
|
|
33
|
+
Profiler.env_override_store.set(key, value.to_s)
|
|
34
|
+
end
|
|
29
35
|
ENV[key] = value.to_s
|
|
30
|
-
Profiler.env_override_store.
|
|
31
|
-
render json: { key: key, value: ENV[key] }
|
|
36
|
+
render json: { key: key, value: ENV[key], override: Profiler.env_override_store.all_overrides[key] }
|
|
32
37
|
end
|
|
33
38
|
end
|
|
34
39
|
|
|
@@ -14,6 +14,11 @@ module Profiler
|
|
|
14
14
|
def call(env)
|
|
15
15
|
return @app.call(env) unless should_profile?(env)
|
|
16
16
|
|
|
17
|
+
status = nil
|
|
18
|
+
headers = nil
|
|
19
|
+
body = nil
|
|
20
|
+
collectors = nil
|
|
21
|
+
|
|
17
22
|
profile = Models::Profile.new(build_request(env))
|
|
18
23
|
Profiler::CurrentContext.token = profile.token
|
|
19
24
|
|
|
@@ -23,14 +28,12 @@ module Profiler
|
|
|
23
28
|
# Store profile in env for collectors
|
|
24
29
|
env["profiler.profile"] = profile
|
|
25
30
|
|
|
26
|
-
# Create and subscribe collectors
|
|
27
31
|
collectors = create_collectors(profile)
|
|
28
32
|
env["profiler.collectors"] = collectors
|
|
29
33
|
|
|
30
34
|
# Measure memory before
|
|
31
35
|
memory_before = current_memory if Profiler.configuration.track_memory
|
|
32
36
|
|
|
33
|
-
# Process request
|
|
34
37
|
status, headers, body = @app.call(env)
|
|
35
38
|
|
|
36
39
|
# Measure memory after
|
|
@@ -39,14 +42,11 @@ module Profiler
|
|
|
39
42
|
profile.memory = memory_after - memory_before
|
|
40
43
|
end
|
|
41
44
|
|
|
42
|
-
# Collect and buffer response body (avoids double-reading by ToolbarInjector)
|
|
43
45
|
body_content = collect_body(body)
|
|
44
46
|
body = [body_content]
|
|
45
47
|
|
|
46
|
-
# Finish profile
|
|
47
48
|
profile.finish(status, headers)
|
|
48
49
|
|
|
49
|
-
# Store request and response bodies
|
|
50
50
|
profile.set_bodies(
|
|
51
51
|
request_body: req_body_raw,
|
|
52
52
|
response_body: body_content,
|
|
@@ -54,7 +54,6 @@ module Profiler
|
|
|
54
54
|
resp_content_type: (headers["content-type"] || headers["Content-Type"]).to_s
|
|
55
55
|
)
|
|
56
56
|
|
|
57
|
-
# Collect data from all collectors
|
|
58
57
|
collectors.each do |collector|
|
|
59
58
|
begin
|
|
60
59
|
collector.collect if collector.respond_to?(:collect)
|
|
@@ -64,14 +63,11 @@ module Profiler
|
|
|
64
63
|
end
|
|
65
64
|
end
|
|
66
65
|
|
|
67
|
-
# Store profile
|
|
68
66
|
Profiler.storage.save(profile.token, profile)
|
|
69
67
|
Profiler::CurrentContext.clear
|
|
70
68
|
|
|
71
|
-
# Add profiler token header
|
|
72
69
|
headers["X-Profiler-Token"] = profile.token
|
|
73
70
|
|
|
74
|
-
# Inject toolbar if HTML response
|
|
75
71
|
if html_response?(headers)
|
|
76
72
|
nonce = env['action_dispatch.content_security_policy_nonce']
|
|
77
73
|
body = ToolbarInjector.new(body, profile.token, nonce).inject
|
|
@@ -80,7 +76,9 @@ module Profiler
|
|
|
80
76
|
[status, headers, body]
|
|
81
77
|
rescue => e
|
|
82
78
|
warn "Profiler error: #{e.message}\n#{e.backtrace.join("\n")}"
|
|
83
|
-
|
|
79
|
+
collectors&.each { |c| c.unsubscribe if c.respond_to?(:unsubscribe) }
|
|
80
|
+
Profiler::CurrentContext.clear
|
|
81
|
+
status ? [status, headers, body || []] : @app.call(env)
|
|
84
82
|
end
|
|
85
83
|
|
|
86
84
|
private
|
|
@@ -19,6 +19,9 @@ module Profiler
|
|
|
19
19
|
|
|
20
20
|
@db = SQLite3::Database.new(db_path.to_s)
|
|
21
21
|
@db.results_as_hash = true
|
|
22
|
+
@db.busy_timeout = 5000
|
|
23
|
+
@db.execute("PRAGMA journal_mode=WAL")
|
|
24
|
+
@db.execute("PRAGMA synchronous=NORMAL")
|
|
22
25
|
|
|
23
26
|
@blob_store = BlobStore.new(blob_path.to_s)
|
|
24
27
|
|
data/lib/profiler/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails-profiler
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.19.
|
|
4
|
+
version: 0.19.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sébastien Duplessy
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-04-
|
|
11
|
+
date: 2026-04-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|