railwatch 0.6.0 → 0.7.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 +4 -4
- data/AGENTS.md +42 -26
- data/CHANGELOG.md +41 -0
- data/README.md +40 -29
- data/app/frontend/components/app-content.tsx +26 -0
- data/app/frontend/components/app-logo-icon.tsx +23 -0
- data/app/frontend/components/app-logo.tsx +14 -0
- data/app/frontend/components/app-shell.tsx +38 -0
- data/app/frontend/components/app-sidebar-header.tsx +54 -0
- data/app/frontend/components/app-sidebar.tsx +94 -0
- data/app/frontend/components/app-wordmark.tsx +29 -0
- data/app/frontend/components/breadcrumbs.tsx +46 -0
- data/app/frontend/components/icon.tsx +16 -0
- data/app/frontend/components/input-error.tsx +18 -0
- data/app/frontend/components/nav-footer.tsx +46 -0
- data/app/frontend/components/nav-main.tsx +41 -0
- data/app/frontend/components/nav-user.tsx +50 -0
- data/app/frontend/components/railwatch/chart-hover.tsx +34 -0
- data/app/frontend/components/railwatch/chart-panel.tsx +170 -0
- data/app/frontend/components/railwatch/code.tsx +28 -0
- data/app/frontend/components/railwatch/command-palette.tsx +132 -0
- data/app/frontend/components/railwatch/copy-block.tsx +52 -0
- data/app/frontend/components/railwatch/copy-id.tsx +49 -0
- data/app/frontend/components/railwatch/cursor-load-more.tsx +39 -0
- data/app/frontend/components/railwatch/data-table.tsx +195 -0
- data/app/frontend/components/railwatch/digit-roll.tsx +312 -0
- data/app/frontend/components/railwatch/empty-state.tsx +159 -0
- data/app/frontend/components/railwatch/env-nav.tsx +130 -0
- data/app/frontend/components/railwatch/env-switcher.tsx +145 -0
- data/app/frontend/components/railwatch/filter-bar.tsx +153 -0
- data/app/frontend/components/railwatch/flamegraph.tsx +324 -0
- data/app/frontend/components/railwatch/frames.tsx +295 -0
- data/app/frontend/components/railwatch/json-viewer.tsx +159 -0
- data/app/frontend/components/railwatch/live-dot.tsx +78 -0
- data/app/frontend/components/railwatch/live-toggle.tsx +76 -0
- data/app/frontend/components/railwatch/metric-chart.tsx +112 -0
- data/app/frontend/components/railwatch/mobile-page-switcher.tsx +89 -0
- data/app/frontend/components/railwatch/onboarding.tsx +91 -0
- data/app/frontend/components/railwatch/origin-identity.tsx +84 -0
- data/app/frontend/components/railwatch/page-header.tsx +42 -0
- data/app/frontend/components/railwatch/percentile-picker.tsx +18 -0
- data/app/frontend/components/railwatch/relative-time.tsx +18 -0
- data/app/frontend/components/railwatch/saved-views.tsx +232 -0
- data/app/frontend/components/railwatch/segmented.tsx +64 -0
- data/app/frontend/components/railwatch/series-chart.tsx +400 -0
- data/app/frontend/components/railwatch/shortcuts-dialog.tsx +89 -0
- data/app/frontend/components/railwatch/signal-toast.tsx +121 -0
- data/app/frontend/components/railwatch/sort-header.tsx +37 -0
- data/app/frontend/components/railwatch/source-link.tsx +57 -0
- data/app/frontend/components/railwatch/sparkline-cell.tsx +14 -0
- data/app/frontend/components/railwatch/sql-block.tsx +116 -0
- data/app/frontend/components/railwatch/stat.tsx +173 -0
- data/app/frontend/components/railwatch/status-badge.tsx +79 -0
- data/app/frontend/components/railwatch/step-picker.tsx +57 -0
- data/app/frontend/components/railwatch/timeline.tsx +405 -0
- data/app/frontend/components/railwatch/utilisation-bar.tsx +44 -0
- data/app/frontend/components/railwatch/window-picker.tsx +147 -0
- data/app/frontend/components/ui/avatar.tsx +51 -0
- data/app/frontend/components/ui/badge.tsx +46 -0
- data/app/frontend/components/ui/breadcrumb.tsx +109 -0
- data/app/frontend/components/ui/button.tsx +60 -0
- data/app/frontend/components/ui/card.tsx +92 -0
- data/app/frontend/components/ui/chart.tsx +374 -0
- data/app/frontend/components/ui/checkbox.tsx +32 -0
- data/app/frontend/components/ui/collapsible.tsx +31 -0
- data/app/frontend/components/ui/command.tsx +182 -0
- data/app/frontend/components/ui/dialog.tsx +158 -0
- data/app/frontend/components/ui/dropdown-menu.tsx +255 -0
- data/app/frontend/components/ui/hover-card.tsx +42 -0
- data/app/frontend/components/ui/input.tsx +21 -0
- data/app/frontend/components/ui/label.tsx +24 -0
- data/app/frontend/components/ui/popover.tsx +87 -0
- data/app/frontend/components/ui/select.tsx +185 -0
- data/app/frontend/components/ui/separator.tsx +28 -0
- data/app/frontend/components/ui/sheet.tsx +137 -0
- data/app/frontend/components/ui/sidebar.tsx +726 -0
- data/app/frontend/components/ui/skeleton.tsx +13 -0
- data/app/frontend/components/ui/sonner.tsx +41 -0
- data/app/frontend/components/ui/table.tsx +114 -0
- data/app/frontend/components/ui/tabs.tsx +91 -0
- data/app/frontend/components/ui/textarea.tsx +18 -0
- data/app/frontend/components/ui/tooltip.tsx +61 -0
- data/app/frontend/components/user-info.tsx +32 -0
- data/app/frontend/components/user-menu-content.tsx +94 -0
- data/app/frontend/entrypoints/application.css +244 -0
- data/app/frontend/entrypoints/inertia.tsx +95 -0
- data/app/frontend/fonts/CommitMono-Bold.woff2 +0 -0
- data/app/frontend/fonts/CommitMono-Regular.woff2 +0 -0
- data/app/frontend/fonts/Roboto-Black.woff2 +0 -0
- data/app/frontend/fonts/Roboto-Bold.woff2 +0 -0
- data/app/frontend/fonts/Roboto-Medium.woff2 +0 -0
- data/app/frontend/fonts/Roboto-Regular.woff2 +0 -0
- data/app/frontend/hooks/use-appearance.tsx +67 -0
- data/app/frontend/hooks/use-clipboard.ts +32 -0
- data/app/frontend/hooks/use-flash.tsx +23 -0
- data/app/frontend/hooks/use-hotkeys.ts +63 -0
- data/app/frontend/hooks/use-initials.tsx +15 -0
- data/app/frontend/hooks/use-live.ts +179 -0
- data/app/frontend/hooks/use-mobile-navigation.ts +8 -0
- data/app/frontend/hooks/use-mobile.ts +21 -0
- data/app/frontend/hooks/use-percentile.ts +24 -0
- data/app/frontend/hooks/use-reduced-motion.ts +25 -0
- data/app/frontend/hooks/use-row-nav.ts +106 -0
- data/app/frontend/hooks/use-step.ts +27 -0
- data/app/frontend/hooks/use-ticker.ts +12 -0
- data/app/frontend/hooks/use-window.ts +58 -0
- data/app/frontend/layouts/app/app-sidebar-layout.tsx +107 -0
- data/app/frontend/layouts/app-layout.tsx +21 -0
- data/app/frontend/layouts/env-layout.tsx +53 -0
- data/app/frontend/layouts/persistent-layout.tsx +18 -0
- data/app/frontend/lib/cable.ts +10 -0
- data/app/frontend/lib/env-pages.ts +236 -0
- data/app/frontend/lib/execution-path.ts +55 -0
- data/app/frontend/lib/explain.ts +50 -0
- data/app/frontend/lib/filter.ts +25 -0
- data/app/frontend/lib/flamegraph.ts +155 -0
- data/app/frontend/lib/format.ts +71 -0
- data/app/frontend/lib/keyboard.ts +18 -0
- data/app/frontend/lib/source-link.ts +217 -0
- data/app/frontend/lib/utils.ts +6 -0
- data/app/frontend/pages/alerts/index.tsx +171 -0
- data/app/frontend/pages/broadcasts/index.tsx +171 -0
- data/app/frontend/pages/cache_events/index.tsx +127 -0
- data/app/frontend/pages/commands/index.tsx +143 -0
- data/app/frontend/pages/deploys/index.tsx +94 -0
- data/app/frontend/pages/deploys/show.tsx +309 -0
- data/app/frontend/pages/deprecations/index.tsx +176 -0
- data/app/frontend/pages/exceptions/index.tsx +271 -0
- data/app/frontend/pages/executions/show.tsx +821 -0
- data/app/frontend/pages/issues/index.tsx +399 -0
- data/app/frontend/pages/issues/show.tsx +1367 -0
- data/app/frontend/pages/jobs/index.tsx +381 -0
- data/app/frontend/pages/jobs/klass.tsx +215 -0
- data/app/frontend/pages/llm_calls/index.tsx +664 -0
- data/app/frontend/pages/logs/index.tsx +303 -0
- data/app/frontend/pages/mails/index.tsx +218 -0
- data/app/frontend/pages/notifications/index.tsx +161 -0
- data/app/frontend/pages/outgoing_requests/index.tsx +309 -0
- data/app/frontend/pages/overview/show.tsx +333 -0
- data/app/frontend/pages/people/index.tsx +102 -0
- data/app/frontend/pages/people/show.tsx +149 -0
- data/app/frontend/pages/processes/index.tsx +335 -0
- data/app/frontend/pages/profiles/index.tsx +110 -0
- data/app/frontend/pages/profiles/show.tsx +105 -0
- data/app/frontend/pages/queries/index.tsx +492 -0
- data/app/frontend/pages/queries/show.tsx +276 -0
- data/app/frontend/pages/releases/index.tsx +190 -0
- data/app/frontend/pages/releases/release-health.tsx +68 -0
- data/app/frontend/pages/releases/release-path.ts +25 -0
- data/app/frontend/pages/releases/show.tsx +262 -0
- data/app/frontend/pages/requests/index.tsx +235 -0
- data/app/frontend/pages/requests/route.tsx +159 -0
- data/app/frontend/pages/scheduled_tasks/index.tsx +220 -0
- data/app/frontend/pages/spans/index.tsx +229 -0
- data/app/frontend/pages/spans/show.tsx +220 -0
- data/app/frontend/pages/storage_ops/index.tsx +150 -0
- data/app/frontend/pages/tenants/index.tsx +236 -0
- data/app/frontend/pages/tenants/show.tsx +477 -0
- data/app/frontend/pages/tenants/tenant-path.ts +26 -0
- data/app/frontend/pages/thresholds/index.tsx +414 -0
- data/app/frontend/pages/traces/show.tsx +208 -0
- data/app/frontend/pages/transactions/index.tsx +220 -0
- data/app/frontend/pages/view_renders/index.tsx +241 -0
- data/app/frontend/pages/visits/index.tsx +321 -0
- data/app/frontend/public/icon.png +0 -0
- data/app/frontend/public/icon.svg +5 -0
- data/app/frontend/routes/index.d.ts +2136 -0
- data/app/frontend/routes/index.js +2112 -0
- data/app/frontend/types/globals.d.ts +9 -0
- data/app/frontend/types/index.ts +288 -0
- data/app/frontend/types/vite-env.d.ts +9 -0
- data/app/jobs/railwatch/rollup_job.rb +3 -1
- data/app/models/railwatch/ingest/rollup_absorber.rb +1 -1
- data/docs/ai-and-mcp.md +9 -3
- data/docs/configuration.md +68 -27
- data/docs/embedded.md +76 -43
- data/docs/faq.md +22 -10
- data/docs/getting-started.md +116 -41
- data/docs/records.md +13 -10
- data/docs/replacing-nightwatch.md +16 -14
- data/docs/replacing-sentry.md +19 -10
- data/docs/security.md +24 -3
- data/docs/self-hosting.md +9 -1
- data/docs/testing.md +14 -4
- data/docs/troubleshooting.md +62 -23
- data/lib/generators/railwatch/install/install_generator.rb +5 -4
- data/lib/generators/railwatch/install/templates/initializer.rb.tt +2 -2
- data/lib/railwatch/version.rb +1 -1
- data/lib/railwatch.rb +8 -3
- data/llms.txt +21 -18
- data/public/railwatch/assets/app-layout-LvxN9xSS.js +41 -0
- data/public/railwatch/assets/application-Cc5v_Vk9.css +1 -0
- data/public/railwatch/assets/{arrow-up-EmePsTKP.js → arrow-up-DG01k9AL.js} +1 -1
- data/public/railwatch/assets/{braces-iZ7MEfYP.js → braces-C3w7pfxS.js} +1 -1
- data/public/railwatch/assets/{card-DqdEEKcJ.js → card-Dpwlr0uY.js} +1 -1
- data/public/railwatch/assets/{chart-C4k7Ub9W.js → chart-DJHv3R7W.js} +1 -1
- data/public/railwatch/assets/{chart-hover-2yZG3w2u.js → chart-hover-CEH-DtXO.js} +1 -1
- data/public/railwatch/assets/{chart-panel-CONkZcn9.js → chart-panel-CUdIzJvk.js} +1 -1
- data/public/railwatch/assets/code-BRZprwun.js +1 -0
- data/public/railwatch/assets/copy-id-CwhGGiwF.js +1 -0
- data/public/railwatch/assets/cursor-load-more-uF1_955Q.js +1 -0
- data/public/railwatch/assets/data-table-DYi-N0hm.js +1 -0
- data/public/railwatch/assets/env-layout-HdcOaPPX.js +1 -0
- data/public/railwatch/assets/{execution-path-DWovhgLi.js → execution-path-CElXXFO_.js} +1 -1
- data/public/railwatch/assets/filter-bar-DEv0G_34.js +1 -0
- data/public/railwatch/assets/{flamegraph-BNbNIuKT.js → flamegraph-SKD9yxW9.js} +2 -2
- data/public/railwatch/assets/frames-CUpyJQDy.js +1 -0
- data/public/railwatch/assets/index-2W-ppwap.js +1 -0
- data/public/railwatch/assets/index-74ocuU5d.js +1 -0
- data/public/railwatch/assets/{index-Zkt4W_CM.js → index-B8NA62Lz.js} +2 -2
- data/public/railwatch/assets/index-BBCEkLqp.js +1 -0
- data/public/railwatch/assets/index-BDcglJzX.js +1 -0
- data/public/railwatch/assets/index-B_KFb9LS.js +1 -0
- data/public/railwatch/assets/index-BqK_VKom.js +1 -0
- data/public/railwatch/assets/index-BxCXBHP2.js +1 -0
- data/public/railwatch/assets/index-C1jc1OoH.js +1 -0
- data/public/railwatch/assets/index-C7zREldp.js +1 -0
- data/public/railwatch/assets/index-CEetm4oC.js +1 -0
- data/public/railwatch/assets/index-CIaZkokF.js +1 -0
- data/public/railwatch/assets/index-CNH85TZp.js +1 -0
- data/public/railwatch/assets/index-Ce4SB5AB.js +1 -0
- data/public/railwatch/assets/index-CiRMSYMn.js +1 -0
- data/public/railwatch/assets/index-CjxXgOs-.js +1 -0
- data/public/railwatch/assets/index-ClL-PYEV.js +1 -0
- data/public/railwatch/assets/index-CteZ6fop.js +1 -0
- data/public/railwatch/assets/index-CvqfEExO.js +1 -0
- data/public/railwatch/assets/index-CxTLT-Qh.js +1 -0
- data/public/railwatch/assets/index-DJd3OUSd.js +1 -0
- data/public/railwatch/assets/index-DPD-rLp6.js +1 -0
- data/public/railwatch/assets/index-DYK_dps4.js +1 -0
- data/public/railwatch/assets/index-DrayARrI.js +1 -0
- data/public/railwatch/assets/index-HRXGir-0.js +1 -0
- data/public/railwatch/assets/index-UJOUALr_.js +1 -0
- data/public/railwatch/assets/index-d-3J7gQ5.js +1 -0
- data/public/railwatch/assets/index-oQrvBpOm.js +1 -0
- data/public/railwatch/assets/inertia-FoqYZAk8.js +97 -0
- data/public/railwatch/assets/json-viewer-CxqMojEm.js +1 -0
- data/public/railwatch/assets/klass-DEF-Vat5.js +1 -0
- data/public/railwatch/assets/origin-identity-Y6gvfQVR.js +1 -0
- data/public/railwatch/assets/{percentile-picker-BxIVblBw.js → percentile-picker-E2aUdLxx.js} +1 -1
- data/public/railwatch/assets/relative-time-DcJbkKlN.js +1 -0
- data/public/railwatch/assets/{release-health-Cb1tMOOO.js → release-health-C8WSCDKD.js} +1 -1
- data/public/railwatch/assets/route-qO5vX1p-.js +1 -0
- data/public/railwatch/assets/{segmented-C4oWE73o.js → segmented-BWee8uc9.js} +1 -1
- data/public/railwatch/assets/select-G7rNBzv0.js +1 -0
- data/public/railwatch/assets/series-chart-C5nXIUc5.js +1 -0
- data/public/railwatch/assets/show-BEWisLQw.js +1 -0
- data/public/railwatch/assets/show-BEa9PGu1.js +2 -0
- data/public/railwatch/assets/{show-gtwKsTsl.js → show-BiT_Aloc.js} +3 -3
- data/public/railwatch/assets/show-BpCO49d3.js +1 -0
- data/public/railwatch/assets/show-CH7yxt7R.js +1 -0
- data/public/railwatch/assets/show-CTO8Lvd2.js +1 -0
- data/public/railwatch/assets/show-DnYsDMUt.js +2 -0
- data/public/railwatch/assets/show-DyzHM527.js +1 -0
- data/public/railwatch/assets/show-Nfpxs8su.js +1 -0
- data/public/railwatch/assets/show-ddjUMo9G.js +1 -0
- data/public/railwatch/assets/show-ksjbSzDH.js +1 -0
- data/public/railwatch/assets/{sort-header-CPM6fhXv.js → sort-header-uOq5VlrB.js} +1 -1
- data/public/railwatch/assets/{sparkline-cell-CXCxXPWt.js → sparkline-cell-DgGij0cu.js} +1 -1
- data/public/railwatch/assets/stat-BTzNKTm2.js +1 -0
- data/public/railwatch/assets/status-badge-BDkOXa-C.js +1 -0
- data/public/railwatch/assets/{tenant-path-C4aM_cO0.js → tenant-path-DU0ezKSU.js} +1 -1
- data/public/railwatch/assets/{use-clipboard-C1ApSwzA.js → use-clipboard-DoENmlWY.js} +1 -1
- data/public/railwatch/assets/{use-live-DWwLg1Nj.js → use-live-CE_fN5_6.js} +1 -1
- data/public/railwatch/manifest.json +612 -1591
- metadata +242 -117
- data/public/railwatch/assets/app-layout-2xAKndVD.js +0 -1
- data/public/railwatch/assets/app-wordmark-Bt6XqURo.js +0 -1
- data/public/railwatch/assets/appearance-DyCfeh9o.js +0 -1
- data/public/railwatch/assets/application-B7h1MIhi.css +0 -1
- data/public/railwatch/assets/auth-layout-BuwogWMZ.js +0 -1
- data/public/railwatch/assets/badge-Dv7I-ebP.js +0 -1
- data/public/railwatch/assets/checkbox-DKbThbxr.js +0 -1
- data/public/railwatch/assets/code-CYahYQHZ.js +0 -1
- data/public/railwatch/assets/copy-DaQMJWoT.js +0 -1
- data/public/railwatch/assets/copy-block-CbJum9s8.js +0 -1
- data/public/railwatch/assets/copy-id-JmvLfkmx.js +0 -1
- data/public/railwatch/assets/cursor-load-more-C1ylbqqL.js +0 -1
- data/public/railwatch/assets/data-table-CVKR2wkq.js +0 -1
- data/public/railwatch/assets/edit-BXF5oNYA.js +0 -1
- data/public/railwatch/assets/edit-BwSEVrTG.js +0 -8
- data/public/railwatch/assets/edit-D5BRDwLT.js +0 -1
- data/public/railwatch/assets/empty-state-Bn48Gplm.js +0 -1
- data/public/railwatch/assets/env-layout-CKLL8Ds7.js +0 -1
- data/public/railwatch/assets/filter-bar-xcbJC93z.js +0 -1
- data/public/railwatch/assets/frames-Bk39xfJG.js +0 -1
- data/public/railwatch/assets/google-sign-in-button-B5as2ps1.js +0 -1
- data/public/railwatch/assets/index-Atp1FTgX.js +0 -1
- data/public/railwatch/assets/index-B-FXAo1w.js +0 -1
- data/public/railwatch/assets/index-B0xgzHuN.js +0 -1
- data/public/railwatch/assets/index-BDVShWMs.js +0 -1
- data/public/railwatch/assets/index-BRvRkfob.js +0 -1
- data/public/railwatch/assets/index-BVWapDeB.js +0 -1
- data/public/railwatch/assets/index-Bd4YpOIO.js +0 -1
- data/public/railwatch/assets/index-BeQw69GM.js +0 -1
- data/public/railwatch/assets/index-BfitxVBv.js +0 -1
- data/public/railwatch/assets/index-C-EwH4lO.js +0 -1
- data/public/railwatch/assets/index-C8JIdb3_.js +0 -1
- data/public/railwatch/assets/index-CBFCtJAR.js +0 -1
- data/public/railwatch/assets/index-CDXlITyG.js +0 -1
- data/public/railwatch/assets/index-COd9lT84.js +0 -1
- data/public/railwatch/assets/index-C_hQmVTP.js +0 -1
- data/public/railwatch/assets/index-CcennT28.js +0 -1
- data/public/railwatch/assets/index-CiaeS-n7.js +0 -1
- data/public/railwatch/assets/index-CrA7jBTK.js +0 -1
- data/public/railwatch/assets/index-D0mKj3Hg.js +0 -1
- data/public/railwatch/assets/index-DV5MdmpY.js +0 -1
- data/public/railwatch/assets/index-DaE-1xhx.js +0 -1
- data/public/railwatch/assets/index-DdVg9LKX.js +0 -1
- data/public/railwatch/assets/index-DeLtMWou.js +0 -1
- data/public/railwatch/assets/index-DiQ4mqT_.js +0 -1
- data/public/railwatch/assets/index-LKgpCzoR.js +0 -1
- data/public/railwatch/assets/index-S0NVaLj9.js +0 -1
- data/public/railwatch/assets/index-Vj93BTR5.js +0 -1
- data/public/railwatch/assets/index-XjXcV-EO.js +0 -1
- data/public/railwatch/assets/index-aPCZX-pW.js +0 -1
- data/public/railwatch/assets/index-cTzBycCg.js +0 -1
- data/public/railwatch/assets/index-dpG-19ZN.js +0 -1
- data/public/railwatch/assets/index-gCvuyG1l.js +0 -1
- data/public/railwatch/assets/index-o1xqGvLo.js +0 -1
- data/public/railwatch/assets/index-w_skgMmK.js +0 -1
- data/public/railwatch/assets/inertia-CqnzqPVD.js +0 -97
- data/public/railwatch/assets/input-error-ByT28UdP.js +0 -1
- data/public/railwatch/assets/json-viewer-Bnu9RsJL.js +0 -1
- data/public/railwatch/assets/klass-nLiBV-Az.js +0 -1
- data/public/railwatch/assets/label-1nSzpSB6.js +0 -1
- data/public/railwatch/assets/layout-D7lE1Doo.js +0 -1
- data/public/railwatch/assets/live-dot-UdzOfzJb.js +0 -41
- data/public/railwatch/assets/nav-BRCgp2w3.js +0 -1
- data/public/railwatch/assets/new-C60G72DR.js +0 -1
- data/public/railwatch/assets/new-COyDKOOb.js +0 -1
- data/public/railwatch/assets/new-Cd9zPNJ8.js +0 -1
- data/public/railwatch/assets/new-DMJGKjmH.js +0 -1
- data/public/railwatch/assets/new-Omvf-c9s.js +0 -1
- data/public/railwatch/assets/new-vjRzERL3.js +0 -1
- data/public/railwatch/assets/onboarding-gUjJQc-6.js +0 -1
- data/public/railwatch/assets/origin-identity-M1YUPYS0.js +0 -1
- data/public/railwatch/assets/relative-time-DQ4kjowZ.js +0 -1
- data/public/railwatch/assets/route-BJkoEm7r.js +0 -1
- data/public/railwatch/assets/select-ocdQJdQo.js +0 -1
- data/public/railwatch/assets/separator-Ct2UcZ2x.js +0 -1
- data/public/railwatch/assets/series-chart-D6upsrSn.js +0 -1
- data/public/railwatch/assets/show-B4bwI9x2.js +0 -2
- data/public/railwatch/assets/show-BAjfddEn.js +0 -6
- data/public/railwatch/assets/show-BLJOyLb_.js +0 -1
- data/public/railwatch/assets/show-BoVyMQS6.js +0 -1
- data/public/railwatch/assets/show-Bsu1rvnK.js +0 -1
- data/public/railwatch/assets/show-C6OiJ6Hr.js +0 -1
- data/public/railwatch/assets/show-C8TkpEgm.js +0 -1
- data/public/railwatch/assets/show-CBFBiBY2.js +0 -1
- data/public/railwatch/assets/show-CEhPVMMT.js +0 -1
- data/public/railwatch/assets/show-CV-lG2b6.js +0 -2
- data/public/railwatch/assets/show-CX_pab9S.js +0 -2
- data/public/railwatch/assets/show-D6lgzL6n.js +0 -1
- data/public/railwatch/assets/show-DDVsv-uS.js +0 -1
- data/public/railwatch/assets/show-Dwiq-8hA.js +0 -1
- data/public/railwatch/assets/show-eKazflRI.js +0 -1
- data/public/railwatch/assets/show-yEOrk6Pt.js +0 -1
- data/public/railwatch/assets/stat-BNEfE8X1.js +0 -1
- data/public/railwatch/assets/status-badge-D0aylrM5.js +0 -1
- data/public/railwatch/assets/text-link-CP4lqUi6.js +0 -1
- data/public/railwatch/assets/textarea-DzJo2ds4.js +0 -1
- data/public/railwatch/assets/timeline-BNcJ9PMc.js +0 -1
- data/public/railwatch/assets/transition-BX2M1iaq.js +0 -5
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import type { LucideIcon } from "lucide-react"
|
|
2
|
+
|
|
3
|
+
export interface Auth {
|
|
4
|
+
user: User
|
|
5
|
+
session: Pick<Session, "id" | "recently_authenticated">
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface BreadcrumbItem {
|
|
9
|
+
title: string
|
|
10
|
+
href: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface NavItem {
|
|
14
|
+
title: string
|
|
15
|
+
href: string
|
|
16
|
+
icon?: LucideIcon | null
|
|
17
|
+
isActive?: boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface FlashData {
|
|
21
|
+
alert?: string
|
|
22
|
+
warning?: string
|
|
23
|
+
notice?: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface AccountSummary {
|
|
27
|
+
id: number
|
|
28
|
+
name: string
|
|
29
|
+
slug: string
|
|
30
|
+
plan: string
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface EnvironmentSummary {
|
|
34
|
+
id: number
|
|
35
|
+
name: string
|
|
36
|
+
slug: string
|
|
37
|
+
last_seen_at: string | null
|
|
38
|
+
paused: boolean
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ApplicationSummary {
|
|
42
|
+
id: number
|
|
43
|
+
name: string
|
|
44
|
+
slug: string
|
|
45
|
+
issue_prefix: string
|
|
46
|
+
environments: EnvironmentSummary[]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface EnvironmentContext {
|
|
50
|
+
id: number
|
|
51
|
+
name: string
|
|
52
|
+
slug: string
|
|
53
|
+
application_id: number
|
|
54
|
+
application_name: string
|
|
55
|
+
issue_prefix: string
|
|
56
|
+
last_seen_at: string | null
|
|
57
|
+
paused: boolean
|
|
58
|
+
token_prefix: string
|
|
59
|
+
repository_url: string | null
|
|
60
|
+
default_branch: string
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type Window = "1h" | "6h" | "24h" | "7d" | "30d" | "custom"
|
|
64
|
+
|
|
65
|
+
// Chart bucket width; the server offers the subset that fits the window.
|
|
66
|
+
export type Step = "1m" | "5m" | "15m" | "1h" | "6h" | "1d"
|
|
67
|
+
|
|
68
|
+
export interface WindowRange {
|
|
69
|
+
from: string
|
|
70
|
+
to: string
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export type TelemetryTimeParams =
|
|
74
|
+
| { window: Exclude<Window, "custom">; from?: never; to?: never }
|
|
75
|
+
| { window?: never; from: string; to: string }
|
|
76
|
+
|
|
77
|
+
export interface CursorMeta {
|
|
78
|
+
limit: number
|
|
79
|
+
next_cursor: string | null
|
|
80
|
+
has_more: boolean
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface SharedProps {
|
|
84
|
+
auth: Auth
|
|
85
|
+
account: AccountSummary | null
|
|
86
|
+
accounts: { id: number; name: string }[]
|
|
87
|
+
applications: ApplicationSummary[]
|
|
88
|
+
environment?: EnvironmentContext
|
|
89
|
+
telemetry_freshness?: {
|
|
90
|
+
received_at: string | null
|
|
91
|
+
aggregated_at?: string | null
|
|
92
|
+
processing_lag_seconds: number | null
|
|
93
|
+
}
|
|
94
|
+
window?: Window
|
|
95
|
+
range?: WindowRange
|
|
96
|
+
step?: Step
|
|
97
|
+
steps?: Step[]
|
|
98
|
+
flash: FlashData
|
|
99
|
+
google_oauth: boolean
|
|
100
|
+
embedded?: boolean
|
|
101
|
+
saved_views?: SavedView[]
|
|
102
|
+
[key: string]: unknown
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface User {
|
|
106
|
+
id: number
|
|
107
|
+
name: string
|
|
108
|
+
email: string
|
|
109
|
+
provider: string | null
|
|
110
|
+
avatar?: string
|
|
111
|
+
verified: boolean
|
|
112
|
+
editor: string
|
|
113
|
+
editor_root: string | null
|
|
114
|
+
created_at: string
|
|
115
|
+
updated_at: string
|
|
116
|
+
[key: string]: unknown
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface Session {
|
|
120
|
+
id: string
|
|
121
|
+
user_agent: string
|
|
122
|
+
ip_address: string
|
|
123
|
+
created_at: string
|
|
124
|
+
recently_authenticated: boolean
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Telemetry shapes shared by pages
|
|
128
|
+
|
|
129
|
+
export type Percentile = "p50" | "p95" | "p99"
|
|
130
|
+
|
|
131
|
+
// One chart bucket. Durations are null where nothing ran, so a latency
|
|
132
|
+
// line breaks over a quiet bucket instead of dropping to zero.
|
|
133
|
+
export interface SeriesPoint {
|
|
134
|
+
t: string
|
|
135
|
+
count: number
|
|
136
|
+
errors: number
|
|
137
|
+
client_errors: number
|
|
138
|
+
avg: number | null
|
|
139
|
+
p50: number | null
|
|
140
|
+
p95: number | null
|
|
141
|
+
p99: number | null
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface GroupRow {
|
|
145
|
+
group_hash: string
|
|
146
|
+
name: string
|
|
147
|
+
count: number
|
|
148
|
+
errors: number
|
|
149
|
+
client_errors: number
|
|
150
|
+
avg: number
|
|
151
|
+
p50: number
|
|
152
|
+
p95: number
|
|
153
|
+
p99: number
|
|
154
|
+
max: number
|
|
155
|
+
sparkline: number[]
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface Summary {
|
|
159
|
+
count: number
|
|
160
|
+
errors: number
|
|
161
|
+
client_errors: number
|
|
162
|
+
avg: number
|
|
163
|
+
p50: number
|
|
164
|
+
p95: number
|
|
165
|
+
p99: number
|
|
166
|
+
max: number
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export interface SummaryWithDelta {
|
|
170
|
+
current: Summary
|
|
171
|
+
previous: Summary
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Release health: crash-free rates are null, not 0, when there were no
|
|
175
|
+
// sessions (or no users) to divide by.
|
|
176
|
+
export interface ReleaseHealthSummary {
|
|
177
|
+
sessions: number
|
|
178
|
+
users: number
|
|
179
|
+
crash_free_sessions: number | null
|
|
180
|
+
crash_free_users: number | null
|
|
181
|
+
errored: number | null
|
|
182
|
+
avg_duration_ms: number | null
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export interface SessionStatusPoint {
|
|
186
|
+
t: string
|
|
187
|
+
sessions: number
|
|
188
|
+
ok: number
|
|
189
|
+
errored: number
|
|
190
|
+
crashed: number
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export interface DeployMarker {
|
|
194
|
+
deploy: string
|
|
195
|
+
ref: string
|
|
196
|
+
at: string
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export interface IssueRow {
|
|
200
|
+
id: number
|
|
201
|
+
key: string
|
|
202
|
+
title: string
|
|
203
|
+
kind: "exception" | "performance"
|
|
204
|
+
status: "open" | "resolved" | "ignored" | "merged"
|
|
205
|
+
priority: "low" | "normal" | "high" | "urgent"
|
|
206
|
+
culprit?: string | null
|
|
207
|
+
occurrences: number
|
|
208
|
+
affected_users: number
|
|
209
|
+
first_seen_at?: string
|
|
210
|
+
last_seen_at: string
|
|
211
|
+
assignee?: { id: number; name: string } | null
|
|
212
|
+
fingerprint_source?: string | null
|
|
213
|
+
source?: string | null
|
|
214
|
+
application?: { id: number; name: string }
|
|
215
|
+
environment?: { id: number; name: string }
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export interface ExecutionRow {
|
|
219
|
+
execution_id: string
|
|
220
|
+
name: string
|
|
221
|
+
kind?: string
|
|
222
|
+
status?: number | null
|
|
223
|
+
outcome?: string | null
|
|
224
|
+
duration: number
|
|
225
|
+
occurred_at: string
|
|
226
|
+
user_ref?: string | null
|
|
227
|
+
tenant?: string | null
|
|
228
|
+
exception_preview?: string | null
|
|
229
|
+
inertia_component?: string | null
|
|
230
|
+
queries?: number
|
|
231
|
+
deploy?: string | null
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export interface Frame {
|
|
235
|
+
file: string
|
|
236
|
+
line: number
|
|
237
|
+
function: string
|
|
238
|
+
in_app: boolean
|
|
239
|
+
code?: Record<string, string>
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export interface ExceptionDetail {
|
|
243
|
+
id: number
|
|
244
|
+
class_name: string
|
|
245
|
+
message: string
|
|
246
|
+
handled: boolean
|
|
247
|
+
severity?: string
|
|
248
|
+
source?: string
|
|
249
|
+
file?: string | null
|
|
250
|
+
line?: number | null
|
|
251
|
+
frames: Frame[]
|
|
252
|
+
cause?: { class: string; message: string } | null
|
|
253
|
+
locals?: Record<string, string> | null
|
|
254
|
+
context?: string | null
|
|
255
|
+
occurred_at?: string
|
|
256
|
+
execution_id?: string | null
|
|
257
|
+
execution_source?: string | null
|
|
258
|
+
execution_preview?: string | null
|
|
259
|
+
deploy?: string | null
|
|
260
|
+
group_hash?: string
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export interface TimelineEntry {
|
|
264
|
+
type: string
|
|
265
|
+
id: number
|
|
266
|
+
offset: number
|
|
267
|
+
duration: number | null
|
|
268
|
+
label: string
|
|
269
|
+
stage: string | null
|
|
270
|
+
sql?: string | null
|
|
271
|
+
source?: string | null
|
|
272
|
+
detail?: Record<string, string | number | boolean | null>
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// A named filter on one environment page, shared through every env page's
|
|
276
|
+
// props. `url` is built server-side from the page's route helper.
|
|
277
|
+
export interface SavedView {
|
|
278
|
+
id: number
|
|
279
|
+
name: string
|
|
280
|
+
page: string
|
|
281
|
+
query: string | null
|
|
282
|
+
window: string | null
|
|
283
|
+
params: Record<string, string>
|
|
284
|
+
pinned: boolean
|
|
285
|
+
shared: boolean
|
|
286
|
+
mine: boolean
|
|
287
|
+
url: string
|
|
288
|
+
}
|
|
@@ -118,7 +118,9 @@ module Railwatch
|
|
|
118
118
|
cache_read_tokens: group.sum { |r| r.cache_read_tokens.to_i }, cache_write_tokens: group.sum { |r| r.cache_write_tokens.to_i },
|
|
119
119
|
cost_nanos: group.sum { |r| r.cost_nanos.to_i },
|
|
120
120
|
priced: group.count { |r| r.cost_nanos },
|
|
121
|
-
|
|
121
|
+
# A call that failed before the provider answered used no tokens,
|
|
122
|
+
# so there is nothing to price; only an answered call can be unpriced.
|
|
123
|
+
unpriced: group.count { |r| r.cost_nanos.nil? && r.status != "failed" },
|
|
122
124
|
# A cut-off answer is not an error and will never show in the error
|
|
123
125
|
# rate, so it needs counting on its own or it stays invisible.
|
|
124
126
|
truncated: group.count { |r| r.finish_reason == "max_tokens" },
|
|
@@ -160,7 +160,7 @@ module Railwatch
|
|
|
160
160
|
extra["cache_write_tokens"] += row[:cache_write_tokens].to_i
|
|
161
161
|
extra["cost_nanos"] += row[:cost_nanos].to_i
|
|
162
162
|
extra["priced"] += 1 if row[:cost_nanos]
|
|
163
|
-
extra["unpriced"] += 1 if row[:cost_nanos].nil?
|
|
163
|
+
extra["unpriced"] += 1 if row[:cost_nanos].nil? && row[:status] != "failed"
|
|
164
164
|
extra["truncated"] += 1 if row[:finish_reason] == "max_tokens"
|
|
165
165
|
extra["with_attachments"] += 1 if row[:attachments].to_i.positive?
|
|
166
166
|
end
|
data/docs/ai-and-mcp.md
CHANGED
|
@@ -9,6 +9,10 @@ crash-free rates per release. It can also write — resolve an issue, set a
|
|
|
9
9
|
priority, leave a comment — and every write is signed with your user and the
|
|
10
10
|
agent's name in the issue's activity feed.
|
|
11
11
|
|
|
12
|
+
MCP is a Railwatch Cloud feature. The embedded dashboard at `/railwatch`
|
|
13
|
+
does not serve it; an embedded install gets it by
|
|
14
|
+
[exporting to the cloud](embedded.md#three-ways-to-run-it).
|
|
15
|
+
|
|
12
16
|
The endpoint is `<your ingest host>/mcp`. For the hosted platform that's
|
|
13
17
|
`https://railwatch.rebulk.com/mcp`; if you self-host, it is your own host (see
|
|
14
18
|
[`self-hosting.md`](self-hosting.md)). The gem knows which one you're on:
|
|
@@ -145,9 +149,9 @@ durations are milliseconds.** Every `window` argument takes `1h`, `6h`,
|
|
|
145
149
|
|
|
146
150
|
| Tool | Arguments | Returns |
|
|
147
151
|
|---|---|---|
|
|
148
|
-
| `list_applications` | — | applications, their account, and their environments. Start here — everything else takes the `application_slug` and `environment` this returns. |
|
|
152
|
+
| `list_applications` | — | applications, their account, and their environments. Start here — everything else takes the `application_slug` and `environment` this returns (plus `account_slug`/`application_id` when two accounts share a slug). |
|
|
149
153
|
| `list_issues` | `application_slug?`, `environment?`, `status?` (`open`/`resolved`/`ignored`, default `open`), `limit?` | issues with key, title, kind, status, priority, occurrence and affected-user counts, culprit, first/last seen. |
|
|
150
|
-
| `get_issue` | `key` | one issue
|
|
154
|
+
| `get_issue` | `key` or `issue_id` | one issue. For an exception, the sample and latest occurrences with stored stack frames, cause, locals, parsed context, browser breadcrumbs, and the execution it happened inside. For a performance or anomaly issue, the metric, limit or baseline, representative records, trend, and deploy comparison. |
|
|
151
155
|
| `update_issue` | `key`, `status?`, `priority?`, `assignee_email?`, `agent?` | the updated issue. Writes an activity entry attributed to your user and `agent`. |
|
|
152
156
|
| `add_comment` | `key`, `body`, `agent?` | the created comment, attributed the same way. |
|
|
153
157
|
| `list_slow_routes` | `application_slug`, `environment`, `window?` | the 20 slowest routes by p95, each with `group_hash`, count, errors, `p95_ms`. |
|
|
@@ -157,6 +161,7 @@ durations are milliseconds.** Every `window` argument takes `1h`, `6h`,
|
|
|
157
161
|
| `explain_query` | `application_slug`, `environment`, `group_hash`, `window?` | the stored query plan for a query group, with the SQL and the sample's duration. `explain` is null unless the app sets `RAILWATCH_CAPTURE_QUERY_EXPLAIN`. `sql` is the normalized shape unless the app also sets `RAILWATCH_CAPTURE_SQL_VALUES`. |
|
|
158
162
|
| `get_profile` | `application_slug`, `environment`, `profile_id?`, `execution_id?`, `limit?` | the hottest frames of a stack profile — self and total samples, each with a percentage. |
|
|
159
163
|
| `search_logs` | `application_slug`, `environment`, `q`, `level?`, `limit?` | matching log lines, each with the `execution_id` to expand with `get_execution`. |
|
|
164
|
+
| `search_telemetry` | `application_slug`, `environment`, `resource` (`jobs`/`exceptions`/`logs`/`queries`), `q?`, `window?`, `cursor?`, `limit?` | raw rows of that resource with cursor pagination (`meta.next_cursor`, `meta.has_more`). `q` takes `after:`, `before:`, `user:`, `tenant:`, `deploy:`, plus per-resource keys such as `class:`, `queue:`, `level:`. |
|
|
160
165
|
| `list_tenants` | `application_slug`, `environment`, `window?`, `q?` | your app's own tenants (whatever it passes to `Railwatch.context(tenant:)`) with request, error, job, exception, and user counts. |
|
|
161
166
|
| `recent_deploys` | `application_slug`, `environment` | the 20 most recent deploys with ref, name, time, and link. |
|
|
162
167
|
| `release_health` | `application_slug`, `environment`, `window?` | crash-free session rate, crash-free user rate, and adoption per release. |
|
|
@@ -220,7 +225,8 @@ Copy either into your own app's repo to give its agent the same context.
|
|
|
220
225
|
|
|
221
226
|
## See also
|
|
222
227
|
|
|
223
|
-
- [`getting-started.md`](getting-started.md) — install, token,
|
|
228
|
+
- [`getting-started.md`](getting-started.md) — install, the cloud token,
|
|
229
|
+
first request.
|
|
224
230
|
- [`self-hosting.md`](self-hosting.md) — pointing the gem, and this endpoint,
|
|
225
231
|
at your own platform.
|
|
226
232
|
- [`troubleshooting.md`](troubleshooting.md) — when something isn't
|
data/docs/configuration.md
CHANGED
|
@@ -2,18 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
Everything below lives on `Railwatch::Configuration`, in
|
|
4
4
|
`lib/railwatch/configuration.rb`. Set it via
|
|
5
|
-
`Railwatch.configure { |c| ... }` in `config/initializers/railwatch.rb
|
|
6
|
-
|
|
7
|
-
`
|
|
8
|
-
|
|
9
|
-
initializer always win over the env var.
|
|
5
|
+
`Railwatch.configure { |c| ... }` in `config/initializers/railwatch.rb`,
|
|
6
|
+
which `bin/rails generate railwatch:install` creates. Most settings have a
|
|
7
|
+
`RAILWATCH_*` env var default; the tables below show which. Explicit
|
|
8
|
+
values set in the initializer always win over the env var.
|
|
10
9
|
|
|
11
10
|
## Core
|
|
12
11
|
|
|
13
12
|
| Attribute | Env var | Default | Meaning |
|
|
14
13
|
|---|---|---|---|
|
|
15
|
-
| `enabled` | `RAILWATCH_ENABLED` | `true` | Master switch. `Railwatch.enabled?` is also `false` whenever `token` is blank, so setting only `RAILWATCH_TOKEN` is enough to turn
|
|
16
|
-
| `token` | `RAILWATCH_TOKEN` | nil | Bearer token for `/ingest`. Required. |
|
|
14
|
+
| `enabled` | `RAILWATCH_ENABLED` | `true` | Master switch. With `transport = :http`, `Railwatch.enabled?` is also `false` whenever `token` is blank, so setting only `RAILWATCH_TOKEN` is enough to turn a cloud install on. An embedded install needs no token. |
|
|
15
|
+
| `token` | `RAILWATCH_TOKEN` | nil | Bearer token for `/ingest`. Required with `transport = :http` and for [export](#export-to-railwatch-cloud). |
|
|
17
16
|
| `ingest_url` | `RAILWATCH_INGEST_URL` | `https://railwatch.rebulk.com` | Platform base URL. Point at a self-hosted instance to override. |
|
|
18
17
|
| `allow_http` | `RAILWATCH_ALLOW_HTTP` | `false` | Permit a non-loopback plain HTTP ingest URL. HTTPS is required by default; `localhost`, `127.0.0.1`, and `::1` remain available for local self-hosted development. |
|
|
19
18
|
| `deploy` | `RAILWATCH_DEPLOY` | auto-detected (order below), then nil | Version tag stamped on every record and used by `railwatch:deploy`. Full 40-character SHAs are shortened to 12 characters. |
|
|
@@ -26,7 +25,8 @@ initializer always win over the env var.
|
|
|
26
25
|
| `beacon_rate_limit` | `RAILWATCH_BEACON_RATE_LIMIT` | `120` | Beacon POSTs accepted per client IP per minute before `POST /railwatch/beacon` answers 429. The beacon is unauthenticated and keeps every browser error it is sent, so this is what stops a script from spending the app's event quota. Counted in the app's cache store; `0` turns it off. |
|
|
27
26
|
|
|
28
27
|
`Railwatch.enabled?` delegates to `config.enabled?`, which is `@enabled &&
|
|
29
|
-
token.present
|
|
28
|
+
(local? || token.present?)`. There is no separate "is configured" check
|
|
29
|
+
elsewhere.
|
|
30
30
|
|
|
31
31
|
Deploy detection stops at the first value found: `RAILWATCH_DEPLOY`,
|
|
32
32
|
`KAMAL_VERSION`, `GIT_REV`, `GIT_SHA`, `SOURCE_VERSION`,
|
|
@@ -569,7 +569,7 @@ Rake tasks and Solid Queue jobs are never interactive.
|
|
|
569
569
|
|
|
570
570
|
| Attribute | Env var | Default | Meaning |
|
|
571
571
|
|---|---|---|---|
|
|
572
|
-
| `capture_exception_source` | `RAILWATCH_CAPTURE_EXCEPTION_SOURCE_CODE` | `true` |
|
|
572
|
+
| `capture_exception_source` | `RAILWATCH_CAPTURE_EXCEPTION_SOURCE_CODE` | `true` | Record source snippet lines surrounding each in-application exception frame (sent to Railwatch Cloud when the install reports there or exports). This is on by default for crash context; disable it when source disclosure is outside the application's telemetry policy. |
|
|
573
573
|
| `capture_exception_locals` | `RAILWATCH_CAPTURE_EXCEPTION_LOCALS` | `false` | Snapshot the raising frame's local variables (up to 25, values truncated to 200 chars, run through the same filter as request params) onto each exception, like Sentry's locals panel. Installs a `TracePoint(:raise)`; opt in per environment. |
|
|
574
574
|
| `capture_request_payload` | `RAILWATCH_CAPTURE_REQUEST_PAYLOAD` | `false` | Capture (redacted) request params — only for a request that raised, never otherwise. |
|
|
575
575
|
| `capture_job_arguments` | `RAILWATCH_CAPTURE_JOB_ARGUMENTS` | `false` | Add the job's real arguments (`job.serialize["arguments"]`) to each `job_attempt`/`scheduled_task` record, capped at 8 KiB of JSON. Hash arguments run through the same filter as request params. Off by default because job arguments routinely carry PII; `arguments_preview` (argument *shapes* only) is always on regardless. |
|
|
@@ -884,7 +884,7 @@ ignore block's building blocks, and are nestable.
|
|
|
884
884
|
## Embedded mode
|
|
885
885
|
|
|
886
886
|
```ruby
|
|
887
|
-
c.transport = :local # RAILWATCH_TRANSPORT; default "http"
|
|
887
|
+
c.transport = :local # RAILWATCH_TRANSPORT; runtime default "http", but the installer writes :local
|
|
888
888
|
c.issue_prefix = "SHOP" # RAILWATCH_ISSUE_PREFIX; default from the app name
|
|
889
889
|
c.repository_url = "..." # RAILWATCH_REPOSITORY_URL
|
|
890
890
|
c.retention_days = 7 # RAILWATCH_RETENTION_DAYS
|
|
@@ -892,8 +892,9 @@ c.http_basic_auth_enabled = true # RAILWATCH_HTTP_BASIC_AUTH_ENABLED; on, a
|
|
|
892
892
|
c.http_basic_auth_user = "ops" # RAILWATCH_HTTP_BASIC_AUTH_USER, or credentials railwatch.http_basic_auth_user
|
|
893
893
|
c.http_basic_auth_password = "..." # RAILWATCH_HTTP_BASIC_AUTH_PASSWORD, or credentials railwatch.http_basic_auth_password
|
|
894
894
|
c.base_controller_class = "AdminController" # RAILWATCH_BASE_CONTROLLER_CLASS; default ActionController::Base
|
|
895
|
-
c.dashboard_open = false # RAILWATCH_DASHBOARD_OPEN; public on purpose
|
|
895
|
+
c.dashboard_open = false # RAILWATCH_DASHBOARD_OPEN; default false, true makes it public on purpose
|
|
896
896
|
c.dashboard_user = ->(request) { { id:, name:, email: } or nil }
|
|
897
|
+
c.writer_socket = "tmp/sockets/railwatch-writer.sock" # RAILWATCH_WRITER_SOCKET
|
|
897
898
|
```
|
|
898
899
|
|
|
899
900
|
With `transport = :local` the reporter writes each batch into the app's
|
|
@@ -905,25 +906,48 @@ railwatch:authentication:configure` has written credentials; a host with
|
|
|
905
906
|
its own admin auth turns Basic off and sets `base_controller_class` or a
|
|
906
907
|
routes constraint. Full walkthrough: [Embedded mode](embedded.md).
|
|
907
908
|
|
|
909
|
+
### Export to Railwatch Cloud
|
|
910
|
+
|
|
911
|
+
An embedded install can also mirror every record to Railwatch Cloud.
|
|
912
|
+
Off unless `export_enabled` is set; a configured token alone sends
|
|
913
|
+
nothing. Only meaningful with `transport = :local`.
|
|
914
|
+
|
|
915
|
+
| Attribute | Env var | Default | Meaning |
|
|
916
|
+
|---|---|---|---|
|
|
917
|
+
| `export_enabled` | `RAILWATCH_EXPORT_ENABLED` | `false` | Mirror every record to the cloud as well as storing it locally. |
|
|
918
|
+
| `export_token` | `RAILWATCH_EXPORT_TOKEN` | `token` | Cloud environment token to send with. |
|
|
919
|
+
| `export_url` | `RAILWATCH_EXPORT_URL` | `{ingest_url}/ingest` | Where to send. |
|
|
920
|
+
| `export_max_bytes` | `RAILWATCH_EXPORT_MAX_BYTES` | `268435456` (256 MiB) | Queue ceiling in bytes. At capacity new work is refused and counted, not swapped for old. |
|
|
921
|
+
| `export_max_deliveries` | `RAILWATCH_EXPORT_MAX_DELIVERIES` | `100000` | Queue ceiling in deliveries. |
|
|
922
|
+
| `export_max_age` | `RAILWATCH_EXPORT_MAX_AGE_SECONDS` | `86400` | How long a queued delivery is kept. At most seven days, past which the receiver no longer recognises it. |
|
|
923
|
+
|
|
924
|
+
`railwatch:doctor` fails when export is enabled and cannot work, and
|
|
925
|
+
`railwatch:export:status` shows the queue. See
|
|
926
|
+
[Embedded mode](embedded.md#three-ways-to-run-it).
|
|
927
|
+
|
|
908
928
|
## Rake tasks
|
|
909
929
|
|
|
910
930
|
Ship with the gem via Rails::Engine's default `lib/tasks` convention, in
|
|
911
931
|
`lib/tasks/railwatch_tasks.rake`:
|
|
912
932
|
|
|
913
|
-
- **`railwatch:status`**
|
|
914
|
-
|
|
915
|
-
fails.
|
|
916
|
-
- **`railwatch:doctor`** prints a ✓/✗ checklist of the whole install
|
|
917
|
-
|
|
933
|
+
- **`railwatch:status`** embedded: prints that telemetry is stored in the
|
|
934
|
+
app. Cloud: pings `{ingest_url}/ingest/ping` with the configured token,
|
|
935
|
+
and aborts if `RAILWATCH_TOKEN` is unset or the ping fails.
|
|
936
|
+
- **`railwatch:doctor`** prints a ✓/✗ checklist of the whole install.
|
|
937
|
+
Embedded, it checks both databases and their migrations, telemetry
|
|
938
|
+
disk mode, the maintenance clock, the writer process, dashboard access,
|
|
939
|
+
and export when enabled. Cloud, it checks the token, where the token is
|
|
940
|
+
stored, the ingest URL and its transport security, and
|
|
941
|
+
`GET /ingest/ping`. Then, either way: `Railwatch::Middleware::Request`
|
|
918
942
|
in the middleware stack, the mounted engine's beacon route,
|
|
919
|
-
`config.deploy` and its
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
server, timestamp, performer, destination, service, commits}` to
|
|
943
|
+
`config.deploy` and its source, sample rates, ignored record types, the
|
|
944
|
+
Kamal `post-deploy` hook, the browser client and whether an entrypoint
|
|
945
|
+
calls it, the profiler backend, and the test matchers. It exits
|
|
946
|
+
non-zero only on the lines marked fatal in
|
|
947
|
+
[Troubleshooting](troubleshooting.md).
|
|
948
|
+
- **`railwatch:deploy[ref,name,url]`** embedded: writes the deploy marker
|
|
949
|
+
to the app's `railwatch` database. Cloud: POSTs `{deploy, ref, name,
|
|
950
|
+
url, server, timestamp, performer, destination, service, commits}` to
|
|
927
951
|
`{ingest_url}/ingest/deploys`. `deploy` comes from `config.deploy`. It
|
|
928
952
|
aborts if that's unset. `ref` defaults to `git rev-parse HEAD` when not
|
|
929
953
|
passed. `performer`/`destination`/`service` come from `KAMAL_PERFORMER`,
|
|
@@ -931,13 +955,30 @@ Ship with the gem via Rails::Engine's default `lib/tasks` convention, in
|
|
|
931
955
|
`{sha, author, message, at}` objects, newest first, from `git log`. It
|
|
932
956
|
is empty inside an app container, which has no `.git`. That is why the
|
|
933
957
|
hook below posts from the deployer instead.
|
|
958
|
+
- **`railwatch:authentication:configure`** writes the embedded
|
|
959
|
+
dashboard's HTTP Basic credentials to the current environment's Rails
|
|
960
|
+
credentials.
|
|
961
|
+
- **`railwatch:export:status`**, **`railwatch:export:rebind`**,
|
|
962
|
+
**`railwatch:export:discard`** show the export queue, clear a
|
|
963
|
+
credential block (abandoning work queued under the old token), and
|
|
964
|
+
abandon everything queued.
|
|
965
|
+
- **`railwatch:vacuum:status`** and **`railwatch:vacuum`** report and
|
|
966
|
+
reclaim the telemetry database's disk
|
|
967
|
+
([Embedded mode](embedded.md#giving-the-disk-back)).
|
|
968
|
+
- **`railwatch:token`** and **`railwatch:mcp`** print where to create a
|
|
969
|
+
cloud ingest token and paste-ready MCP client configuration.
|
|
970
|
+
- **`railwatch:sourcemaps[directory,delete]`** uploads browser source
|
|
971
|
+
maps ([Source maps](source-maps.md)).
|
|
934
972
|
|
|
935
973
|
## Kamal integration
|
|
936
974
|
|
|
937
975
|
`bin/rails generate railwatch:install` writes `.kamal/hooks/post-deploy`,
|
|
938
|
-
but only if `config/deploy.yml` already exists.
|
|
939
|
-
`
|
|
940
|
-
|
|
976
|
+
but only if `config/deploy.yml` already exists. With
|
|
977
|
+
`RAILWATCH_TRANSPORT=local` in the deployer's environment it runs
|
|
978
|
+
`bin/rails railwatch:deploy[$KAMAL_VERSION]` in the primary container,
|
|
979
|
+
which records the marker in the embedded database, and stops. Otherwise
|
|
980
|
+
it no-ops when `RAILWATCH_TOKEN` isn't set. It never fails a deploy.
|
|
981
|
+
Every network call ends in `|| true`.
|
|
941
982
|
|
|
942
983
|
The hook runs on the **deployer machine**, not in a container, which is
|
|
943
984
|
the whole point. That's where the git history lives and where Kamal
|