railwatch 0.9.4 → 1.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.
- checksums.yaml +4 -4
- data/AGENTS.md +37 -33
- data/CHANGELOG.md +50 -0
- data/README.md +51 -60
- data/config/routes.rb +0 -59
- data/docs/ai-and-mcp.md +9 -8
- data/docs/configuration.md +35 -66
- data/docs/faq.md +17 -25
- data/docs/getting-started.md +105 -117
- data/docs/replacing-nightwatch.md +8 -7
- data/docs/replacing-sentry.md +12 -16
- data/docs/security.md +14 -20
- data/docs/self-hosting.md +24 -22
- data/docs/testing.md +6 -14
- data/docs/troubleshooting.md +12 -46
- data/lib/generators/railwatch/install/install_generator.rb +12 -240
- data/lib/generators/railwatch/install/templates/initializer.rb.tt +10 -40
- data/lib/generators/railwatch/install/templates/post-deploy +0 -7
- data/lib/railwatch/authentication.rb +6 -5
- data/lib/railwatch/configuration.rb +21 -151
- data/lib/railwatch/engine.rb +9 -118
- data/lib/railwatch/patches.rb +0 -11
- data/lib/railwatch/reporter.rb +3 -19
- data/lib/railwatch/subscribers/process_info.rb +1 -2
- data/lib/railwatch/version.rb +1 -1
- data/lib/railwatch.rb +4 -62
- data/lib/tasks/railwatch_tasks.rake +3 -325
- data/llms.txt +23 -25
- metadata +3 -453
- data/app/channels/railwatch/environment_channel.rb +0 -62
- data/app/controllers/concerns/railwatch/telemetry_identity.rb +0 -25
- data/app/controllers/railwatch/alerts_controller.rb +0 -48
- data/app/controllers/railwatch/anomaly_rules_controller.rb +0 -31
- data/app/controllers/railwatch/attachments_controller.rb +0 -22
- data/app/controllers/railwatch/broadcasts_controller.rb +0 -15
- data/app/controllers/railwatch/cache_events_controller.rb +0 -30
- data/app/controllers/railwatch/commands_controller.rb +0 -16
- data/app/controllers/railwatch/comments_controller.rb +0 -11
- data/app/controllers/railwatch/dashboard_controller.rb +0 -70
- data/app/controllers/railwatch/deploys_controller.rb +0 -34
- data/app/controllers/railwatch/deprecations_controller.rb +0 -54
- data/app/controllers/railwatch/environment_scoped.rb +0 -81
- data/app/controllers/railwatch/exceptions_controller.rb +0 -52
- data/app/controllers/railwatch/executions_controller.rb +0 -13
- data/app/controllers/railwatch/issues_controller.rb +0 -258
- data/app/controllers/railwatch/jobs_controller.rb +0 -63
- data/app/controllers/railwatch/llm_calls_controller.rb +0 -124
- data/app/controllers/railwatch/logs_controller.rb +0 -40
- data/app/controllers/railwatch/mails_controller.rb +0 -19
- data/app/controllers/railwatch/notifications_controller.rb +0 -11
- data/app/controllers/railwatch/outgoing_requests_controller.rb +0 -19
- data/app/controllers/railwatch/overview_controller.rb +0 -38
- data/app/controllers/railwatch/people_controller.rb +0 -25
- data/app/controllers/railwatch/processes_controller.rb +0 -33
- data/app/controllers/railwatch/profiles_controller.rb +0 -65
- data/app/controllers/railwatch/queries_controller.rb +0 -59
- data/app/controllers/railwatch/releases_controller.rb +0 -75
- data/app/controllers/railwatch/requests_controller.rb +0 -37
- data/app/controllers/railwatch/saved_views_controller.rb +0 -53
- data/app/controllers/railwatch/scheduled_tasks_controller.rb +0 -45
- data/app/controllers/railwatch/spans_controller.rb +0 -47
- data/app/controllers/railwatch/storage_ops_controller.rb +0 -15
- data/app/controllers/railwatch/tenants_controller.rb +0 -44
- data/app/controllers/railwatch/thresholds_controller.rb +0 -47
- data/app/controllers/railwatch/traces_controller.rb +0 -72
- data/app/controllers/railwatch/transactions_controller.rb +0 -21
- data/app/controllers/railwatch/view_renders_controller.rb +0 -28
- data/app/controllers/railwatch/visits_controller.rb +0 -53
- data/app/frontend/components/app-content.tsx +0 -26
- data/app/frontend/components/app-logo-icon.tsx +0 -23
- data/app/frontend/components/app-logo.tsx +0 -14
- data/app/frontend/components/app-shell.tsx +0 -38
- data/app/frontend/components/app-sidebar-header.tsx +0 -54
- data/app/frontend/components/app-sidebar.tsx +0 -94
- data/app/frontend/components/app-wordmark.tsx +0 -29
- data/app/frontend/components/breadcrumbs.tsx +0 -46
- data/app/frontend/components/icon.tsx +0 -16
- data/app/frontend/components/input-error.tsx +0 -18
- data/app/frontend/components/nav-footer.tsx +0 -46
- data/app/frontend/components/nav-main.tsx +0 -41
- data/app/frontend/components/nav-user.tsx +0 -50
- data/app/frontend/components/railwatch/chart-hover.tsx +0 -34
- data/app/frontend/components/railwatch/chart-panel.tsx +0 -170
- data/app/frontend/components/railwatch/code.tsx +0 -28
- data/app/frontend/components/railwatch/command-palette.tsx +0 -132
- data/app/frontend/components/railwatch/copy-block.tsx +0 -52
- data/app/frontend/components/railwatch/copy-id.tsx +0 -49
- data/app/frontend/components/railwatch/cursor-load-more.tsx +0 -39
- data/app/frontend/components/railwatch/data-table.tsx +0 -195
- data/app/frontend/components/railwatch/digit-roll.tsx +0 -312
- data/app/frontend/components/railwatch/empty-state.tsx +0 -159
- data/app/frontend/components/railwatch/env-nav.tsx +0 -130
- data/app/frontend/components/railwatch/env-switcher.tsx +0 -145
- data/app/frontend/components/railwatch/filter-bar.tsx +0 -153
- data/app/frontend/components/railwatch/flamegraph.tsx +0 -324
- data/app/frontend/components/railwatch/frames.tsx +0 -295
- data/app/frontend/components/railwatch/json-viewer.tsx +0 -159
- data/app/frontend/components/railwatch/live-dot.tsx +0 -78
- data/app/frontend/components/railwatch/live-toggle.tsx +0 -76
- data/app/frontend/components/railwatch/metric-chart.tsx +0 -112
- data/app/frontend/components/railwatch/mobile-page-switcher.tsx +0 -89
- data/app/frontend/components/railwatch/onboarding.tsx +0 -91
- data/app/frontend/components/railwatch/origin-identity.tsx +0 -84
- data/app/frontend/components/railwatch/page-header.tsx +0 -42
- data/app/frontend/components/railwatch/percentile-picker.tsx +0 -18
- data/app/frontend/components/railwatch/relative-time.tsx +0 -18
- data/app/frontend/components/railwatch/saved-views.tsx +0 -232
- data/app/frontend/components/railwatch/segmented.tsx +0 -64
- data/app/frontend/components/railwatch/series-chart.tsx +0 -400
- data/app/frontend/components/railwatch/shortcuts-dialog.tsx +0 -89
- data/app/frontend/components/railwatch/signal-toast.tsx +0 -121
- data/app/frontend/components/railwatch/sort-header.tsx +0 -37
- data/app/frontend/components/railwatch/source-link.tsx +0 -57
- data/app/frontend/components/railwatch/sparkline-cell.tsx +0 -14
- data/app/frontend/components/railwatch/sql-block.tsx +0 -116
- data/app/frontend/components/railwatch/stat.tsx +0 -185
- data/app/frontend/components/railwatch/status-badge.tsx +0 -79
- data/app/frontend/components/railwatch/step-picker.tsx +0 -57
- data/app/frontend/components/railwatch/timeline.tsx +0 -405
- data/app/frontend/components/railwatch/utilisation-bar.tsx +0 -44
- data/app/frontend/components/railwatch/window-picker.tsx +0 -147
- data/app/frontend/components/ui/avatar.tsx +0 -51
- data/app/frontend/components/ui/badge.tsx +0 -46
- data/app/frontend/components/ui/breadcrumb.tsx +0 -109
- data/app/frontend/components/ui/button.tsx +0 -60
- data/app/frontend/components/ui/card.tsx +0 -92
- data/app/frontend/components/ui/chart.tsx +0 -374
- data/app/frontend/components/ui/checkbox.tsx +0 -32
- data/app/frontend/components/ui/collapsible.tsx +0 -31
- data/app/frontend/components/ui/command.tsx +0 -182
- data/app/frontend/components/ui/dialog.tsx +0 -158
- data/app/frontend/components/ui/dropdown-menu.tsx +0 -255
- data/app/frontend/components/ui/hover-card.tsx +0 -42
- data/app/frontend/components/ui/input.tsx +0 -21
- data/app/frontend/components/ui/label.tsx +0 -24
- data/app/frontend/components/ui/popover.tsx +0 -87
- data/app/frontend/components/ui/select.tsx +0 -185
- data/app/frontend/components/ui/separator.tsx +0 -28
- data/app/frontend/components/ui/sheet.tsx +0 -137
- data/app/frontend/components/ui/sidebar.tsx +0 -726
- data/app/frontend/components/ui/skeleton.tsx +0 -13
- data/app/frontend/components/ui/sonner.tsx +0 -41
- data/app/frontend/components/ui/table.tsx +0 -114
- data/app/frontend/components/ui/tabs.tsx +0 -91
- data/app/frontend/components/ui/textarea.tsx +0 -18
- data/app/frontend/components/ui/tooltip.tsx +0 -61
- data/app/frontend/components/user-info.tsx +0 -32
- data/app/frontend/components/user-menu-content.tsx +0 -94
- data/app/frontend/entrypoints/application.css +0 -244
- data/app/frontend/entrypoints/inertia.tsx +0 -92
- 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 +0 -67
- data/app/frontend/hooks/use-clipboard.ts +0 -32
- data/app/frontend/hooks/use-flash.tsx +0 -23
- data/app/frontend/hooks/use-hotkeys.ts +0 -63
- data/app/frontend/hooks/use-initials.tsx +0 -15
- data/app/frontend/hooks/use-live.ts +0 -205
- data/app/frontend/hooks/use-mobile-navigation.ts +0 -8
- data/app/frontend/hooks/use-mobile.ts +0 -21
- data/app/frontend/hooks/use-percentile.ts +0 -24
- data/app/frontend/hooks/use-reduced-motion.ts +0 -25
- data/app/frontend/hooks/use-row-nav.ts +0 -106
- data/app/frontend/hooks/use-step.ts +0 -27
- data/app/frontend/hooks/use-ticker.ts +0 -12
- data/app/frontend/hooks/use-window.ts +0 -58
- data/app/frontend/layouts/app/app-sidebar-layout.tsx +0 -107
- data/app/frontend/layouts/app-layout.tsx +0 -21
- data/app/frontend/layouts/env-layout.tsx +0 -53
- data/app/frontend/layouts/persistent-layout.tsx +0 -18
- data/app/frontend/lib/cable.ts +0 -10
- data/app/frontend/lib/env-pages.ts +0 -236
- data/app/frontend/lib/execution-path.ts +0 -55
- data/app/frontend/lib/explain.ts +0 -50
- data/app/frontend/lib/filter.ts +0 -25
- data/app/frontend/lib/flamegraph.ts +0 -155
- data/app/frontend/lib/format.ts +0 -71
- data/app/frontend/lib/keyboard.ts +0 -18
- data/app/frontend/lib/mount.ts +0 -23
- data/app/frontend/lib/source-link.ts +0 -217
- data/app/frontend/lib/utils.ts +0 -6
- data/app/frontend/pages/alerts/index.tsx +0 -171
- data/app/frontend/pages/broadcasts/index.tsx +0 -171
- data/app/frontend/pages/cache_events/index.tsx +0 -127
- data/app/frontend/pages/commands/index.tsx +0 -143
- data/app/frontend/pages/deploys/index.tsx +0 -94
- data/app/frontend/pages/deploys/show.tsx +0 -309
- data/app/frontend/pages/deprecations/index.tsx +0 -176
- data/app/frontend/pages/exceptions/index.tsx +0 -271
- data/app/frontend/pages/executions/show.tsx +0 -821
- data/app/frontend/pages/issues/index.tsx +0 -399
- data/app/frontend/pages/issues/show.tsx +0 -1367
- data/app/frontend/pages/jobs/index.tsx +0 -381
- data/app/frontend/pages/jobs/klass.tsx +0 -215
- data/app/frontend/pages/llm_calls/index.tsx +0 -664
- data/app/frontend/pages/logs/index.tsx +0 -303
- data/app/frontend/pages/mails/index.tsx +0 -218
- data/app/frontend/pages/notifications/index.tsx +0 -161
- data/app/frontend/pages/outgoing_requests/index.tsx +0 -309
- data/app/frontend/pages/overview/show.tsx +0 -333
- data/app/frontend/pages/people/index.tsx +0 -102
- data/app/frontend/pages/people/show.tsx +0 -149
- data/app/frontend/pages/processes/index.tsx +0 -335
- data/app/frontend/pages/profiles/index.tsx +0 -110
- data/app/frontend/pages/profiles/show.tsx +0 -105
- data/app/frontend/pages/queries/index.tsx +0 -492
- data/app/frontend/pages/queries/show.tsx +0 -276
- data/app/frontend/pages/releases/index.tsx +0 -190
- data/app/frontend/pages/releases/release-health.tsx +0 -68
- data/app/frontend/pages/releases/release-path.ts +0 -25
- data/app/frontend/pages/releases/show.tsx +0 -262
- data/app/frontend/pages/requests/index.tsx +0 -235
- data/app/frontend/pages/requests/route.tsx +0 -159
- data/app/frontend/pages/scheduled_tasks/index.tsx +0 -220
- data/app/frontend/pages/spans/index.tsx +0 -229
- data/app/frontend/pages/spans/show.tsx +0 -220
- data/app/frontend/pages/storage_ops/index.tsx +0 -150
- data/app/frontend/pages/tenants/index.tsx +0 -236
- data/app/frontend/pages/tenants/show.tsx +0 -477
- data/app/frontend/pages/tenants/tenant-path.ts +0 -26
- data/app/frontend/pages/thresholds/index.tsx +0 -414
- data/app/frontend/pages/traces/show.tsx +0 -208
- data/app/frontend/pages/transactions/index.tsx +0 -220
- data/app/frontend/pages/view_renders/index.tsx +0 -241
- data/app/frontend/pages/visits/index.tsx +0 -321
- data/app/frontend/public/icon.png +0 -0
- data/app/frontend/public/icon.svg +0 -5
- data/app/frontend/routes/index.d.ts +0 -2136
- data/app/frontend/routes/index.js +0 -2112
- data/app/frontend/types/globals.d.ts +0 -9
- data/app/frontend/types/index.ts +0 -288
- data/app/frontend/types/vite-env.d.ts +0 -9
- data/app/helpers/railwatch/assets_helper.rb +0 -52
- data/app/jobs/railwatch/anomaly_scan_job.rb +0 -11
- data/app/jobs/railwatch/application_job.rb +0 -7
- data/app/jobs/railwatch/auto_resolve_issues_job.rb +0 -19
- data/app/jobs/railwatch/check_scheduled_tasks_job.rb +0 -113
- data/app/jobs/railwatch/detect_anomalies_job.rb +0 -171
- data/app/jobs/railwatch/detect_performance_issues_job.rb +0 -95
- data/app/jobs/railwatch/group_exceptions_job.rb +0 -91
- data/app/jobs/railwatch/optimize_telemetry_job.rb +0 -23
- data/app/jobs/railwatch/performance_scan_job.rb +0 -11
- data/app/jobs/railwatch/prune_telemetry_job.rb +0 -129
- data/app/jobs/railwatch/release_health_rollup_job.rb +0 -64
- data/app/jobs/railwatch/rollup_catchup_job.rb +0 -21
- data/app/jobs/railwatch/rollup_job.rb +0 -132
- data/app/jobs/railwatch/scheduled_task_scan_job.rb +0 -11
- data/app/models/concerns/railwatch/detection_snapshotting.rb +0 -20
- data/app/models/railwatch/alert.rb +0 -229
- data/app/models/railwatch/alert_rule.rb +0 -121
- data/app/models/railwatch/anomaly_rule.rb +0 -51
- data/app/models/railwatch/application.rb +0 -44
- data/app/models/railwatch/application_record.rb +0 -33
- data/app/models/railwatch/comment.rb +0 -36
- data/app/models/railwatch/deploy.rb +0 -67
- data/app/models/railwatch/environment.rb +0 -68
- data/app/models/railwatch/execution_presenter.rb +0 -185
- data/app/models/railwatch/filter_query.rb +0 -184
- data/app/models/railwatch/followup_receipt.rb +0 -27
- data/app/models/railwatch/ingest/batch.rb +0 -355
- data/app/models/railwatch/ingest/mapper.rb +0 -585
- data/app/models/railwatch/ingest/payload.rb +0 -96
- data/app/models/railwatch/ingest/rollup_absorber.rb +0 -170
- data/app/models/railwatch/ingest/writer.rb +0 -137
- data/app/models/railwatch/issue.rb +0 -277
- data/app/models/railwatch/issue_activity.rb +0 -23
- data/app/models/railwatch/issue_detection_presenter.rb +0 -309
- data/app/models/railwatch/issue_detection_snapshot.rb +0 -77
- data/app/models/railwatch/maintenance_task.rb +0 -53
- data/app/models/railwatch/saved_view.rb +0 -63
- data/app/models/railwatch/telemetry/aggregations.rb +0 -251
- data/app/models/railwatch/telemetry/attachment.rb +0 -31
- data/app/models/railwatch/telemetry/bounded_gzip.rb +0 -101
- data/app/models/railwatch/telemetry/broadcast.rb +0 -13
- data/app/models/railwatch/telemetry/cache_event.rb +0 -16
- data/app/models/railwatch/telemetry/child.rb +0 -53
- data/app/models/railwatch/telemetry/cursor_page.rb +0 -99
- data/app/models/railwatch/telemetry/deprecation.rb +0 -13
- data/app/models/railwatch/telemetry/enqueued_job.rb +0 -13
- data/app/models/railwatch/telemetry/exception.rb +0 -28
- data/app/models/railwatch/telemetry/execution.rb +0 -152
- data/app/models/railwatch/telemetry/export_delivery.rb +0 -32
- data/app/models/railwatch/telemetry/export_destination.rb +0 -66
- data/app/models/railwatch/telemetry/health_sample.rb +0 -72
- data/app/models/railwatch/telemetry/ingest_batch.rb +0 -31
- data/app/models/railwatch/telemetry/llm_call.rb +0 -37
- data/app/models/railwatch/telemetry/log.rb +0 -91
- data/app/models/railwatch/telemetry/mail.rb +0 -13
- data/app/models/railwatch/telemetry/n_plus_one.rb +0 -92
- data/app/models/railwatch/telemetry/notification.rb +0 -13
- data/app/models/railwatch/telemetry/outgoing_request.rb +0 -13
- data/app/models/railwatch/telemetry/person.rb +0 -50
- data/app/models/railwatch/telemetry/process.rb +0 -10
- data/app/models/railwatch/telemetry/profile.rb +0 -37
- data/app/models/railwatch/telemetry/query.rb +0 -57
- data/app/models/railwatch/telemetry/query_shape.rb +0 -45
- data/app/models/railwatch/telemetry/release_health.rb +0 -69
- data/app/models/railwatch/telemetry/rollup.rb +0 -157
- data/app/models/railwatch/telemetry/session.rb +0 -24
- data/app/models/railwatch/telemetry/span.rb +0 -19
- data/app/models/railwatch/telemetry/storage_op.rb +0 -13
- data/app/models/railwatch/telemetry/tenant.rb +0 -240
- data/app/models/railwatch/telemetry/transaction.rb +0 -13
- data/app/models/railwatch/telemetry/view_render.rb +0 -13
- data/app/models/railwatch/telemetry/visit.rb +0 -24
- data/app/models/railwatch/telemetry_record.rb +0 -107
- data/app/models/railwatch/threshold.rb +0 -66
- data/app/models/railwatch/user.rb +0 -47
- data/app/models/railwatch/viewer.rb +0 -13
- data/app/models/railwatch/window.rb +0 -66
- data/app/views/layouts/railwatch/dashboard.html.erb +0 -25
- data/db/railwatch_migrate/20260916000000_create_railwatch_tables.rb +0 -151
- data/db/railwatch_migrate/20260917000000_create_railwatch_maintenance_tasks.rb +0 -18
- data/db/railwatch_migrate/20260917120000_create_railwatch_followup_receipts.rb +0 -20
- data/db/railwatch_migrate/20260918120000_widen_host_user_ids.rb +0 -71
- data/db/railwatch_telemetry_migrate/20260903000000_enable_incremental_vacuum.rb +0 -62
- data/db/railwatch_telemetry_migrate/20260903000001_create_telemetry.rb +0 -481
- data/db/railwatch_telemetry_migrate/20260903000002_rename_tenant_to_app_tenant.rb +0 -14
- data/db/railwatch_telemetry_migrate/20260903000003_add_statement_count_to_transactions.rb +0 -9
- data/db/railwatch_telemetry_migrate/20260903000004_add_role_and_channel.rb +0 -10
- data/db/railwatch_telemetry_migrate/20260903000005_add_locals_to_exceptions.rb +0 -9
- data/db/railwatch_telemetry_migrate/20260903000006_add_spans_health_vitals_and_fts.rb +0 -82
- data/db/railwatch_telemetry_migrate/20260903000007_rename_span_attributes_to_payload.rb +0 -10
- data/db/railwatch_telemetry_migrate/20260903000008_add_profiles_and_attachments.rb +0 -60
- data/db/railwatch_telemetry_migrate/20260903000009_add_truncated_to_attachments.rb +0 -9
- data/db/railwatch_telemetry_migrate/20260903000010_create_sessions_and_release_health.rb +0 -51
- data/db/railwatch_telemetry_migrate/20260903000011_add_fingerprint_to_exceptions.rb +0 -11
- data/db/railwatch_telemetry_migrate/20260904000012_add_failed_to_broadcasts.rb +0 -10
- data/db/railwatch_telemetry_migrate/20260904010000_add_filter_cursor_indexes.rb +0 -37
- data/db/railwatch_telemetry_migrate/20260904020000_add_n_plus_ones_execution_id_index.rb +0 -11
- data/db/railwatch_telemetry_migrate/20260904120000_create_query_shapes.rb +0 -15
- data/db/railwatch_telemetry_migrate/20260906120000_add_backpressure_factor_to_ingest_batches.rb +0 -9
- data/db/railwatch_telemetry_migrate/20260907000000_rename_lantern_version_on_processes.rb +0 -10
- data/db/railwatch_telemetry_migrate/20260913000000_rename_nightrail_version_on_processes.rb +0 -9
- data/db/railwatch_telemetry_migrate/20260914000000_drop_orphan_durable_ingest_tables.rb +0 -18
- data/db/railwatch_telemetry_migrate/20260914010000_drop_orphan_durable_ingest_columns.rb +0 -25
- data/db/railwatch_telemetry_migrate/20260915000000_create_llm_calls.rb +0 -55
- data/db/railwatch_telemetry_migrate/20260915120000_add_detail_to_llm_calls.rb +0 -21
- data/db/railwatch_telemetry_migrate/20260915200000_add_explained_index_to_queries.rb +0 -16
- data/db/railwatch_telemetry_migrate/20260915210000_add_slowest_index_to_queries.rb +0 -18
- data/db/railwatch_telemetry_migrate/20260917010000_add_batch_ledger_to_ingest_batches.rb +0 -16
- data/db/railwatch_telemetry_migrate/20260919000100_create_export_queue.rb +0 -146
- data/db/railwatch_telemetry_migrate/20260922000000_add_covering_indexes_for_dashboard_aggregates.rb +0 -34
- data/db/railwatch_telemetry_migrate/20260923000000_add_people_index.rb +0 -15
- data/db/railwatch_telemetry_migrate/20260925000000_add_tenant_summary_index.rb +0 -17
- data/db/railwatch_telemetry_migrate/20261008000000_add_in_transaction_to_outgoing_requests.rb +0 -10
- data/docs/embedded.md +0 -503
- data/lib/puma/plugin/railwatch.rb +0 -215
- data/lib/railwatch/dashboard_assets.rb +0 -45
- data/lib/railwatch/embedded.rb +0 -50
- data/lib/railwatch/export/client.rb +0 -124
- data/lib/railwatch/export/lease.rb +0 -56
- data/lib/railwatch/export/outbox.rb +0 -361
- data/lib/railwatch/export/policy.rb +0 -79
- data/lib/railwatch/export/sender.rb +0 -130
- data/lib/railwatch/ingest_request_body_limit.rb +0 -10
- data/lib/railwatch/maintenance.rb +0 -194
- data/lib/railwatch/patches/migration_busy_timeout.rb +0 -73
- data/lib/railwatch/transport/local.rb +0 -78
- data/lib/railwatch/transport/socket.rb +0 -183
- data/lib/railwatch/writer.rb +0 -370
- data/public/railwatch/assets/CommitMono-Bold-D6h61ieg.woff2 +0 -0
- data/public/railwatch/assets/CommitMono-Regular-zr8w7Obm.woff2 +0 -0
- data/public/railwatch/assets/Roboto-Black-auA4GeOK.woff2 +0 -0
- data/public/railwatch/assets/Roboto-Bold-CJLnO8j1.woff2 +0 -0
- data/public/railwatch/assets/Roboto-Medium-Cm2bwKpj.woff2 +0 -0
- data/public/railwatch/assets/Roboto-Regular-Chaq1-PV.woff2 +0 -0
- data/public/railwatch/assets/app-layout-by7G3sa1.js +0 -41
- data/public/railwatch/assets/application-Cc5v_Vk9.css +0 -1
- data/public/railwatch/assets/arrow-up-DCZ7emux.js +0 -1
- data/public/railwatch/assets/braces-CykT5_5u.js +0 -1
- data/public/railwatch/assets/card-C-PPSA0g.js +0 -1
- data/public/railwatch/assets/chart-Cov79YC5.js +0 -39
- data/public/railwatch/assets/chart-hover-DdK4E-2h.js +0 -1
- data/public/railwatch/assets/chart-panel-BPaYRXJB.js +0 -1
- data/public/railwatch/assets/code-BYjC4YZ_.js +0 -1
- data/public/railwatch/assets/copy-id-LPfoj9cC.js +0 -1
- data/public/railwatch/assets/cursor-load-more-DSdhgpGl.js +0 -1
- data/public/railwatch/assets/data-table-CQ_YRWQs.js +0 -1
- data/public/railwatch/assets/env-layout-CdMWbUkm.js +0 -1
- data/public/railwatch/assets/execution-path-7MYt-Qbn.js +0 -1
- data/public/railwatch/assets/filter-bar-CrzpQ_vD.js +0 -1
- data/public/railwatch/assets/flamegraph-BIFEdTAg.js +0 -2
- data/public/railwatch/assets/format-B9SDkrWj.js +0 -1
- data/public/railwatch/assets/frames-C5t-x4f0.js +0 -1
- data/public/railwatch/assets/index--NQ7us-L.js +0 -1
- data/public/railwatch/assets/index-2kgYe_99.js +0 -1
- data/public/railwatch/assets/index-4YEPHxtO.js +0 -1
- data/public/railwatch/assets/index-AOCC1GDJ.js +0 -1
- data/public/railwatch/assets/index-BEo-u0eO.js +0 -1
- data/public/railwatch/assets/index-BJ1V3w2N.js +0 -1
- data/public/railwatch/assets/index-BPoHsBKb.js +0 -1
- data/public/railwatch/assets/index-BZzyGUM3.js +0 -1
- data/public/railwatch/assets/index-BgVq7yKL.js +0 -1
- data/public/railwatch/assets/index-BqFGEZvW.js +0 -1
- data/public/railwatch/assets/index-ByuHJ1CH.js +0 -1
- data/public/railwatch/assets/index-C2j50AL2.js +0 -1
- data/public/railwatch/assets/index-CLEdTkvW.js +0 -1
- data/public/railwatch/assets/index-CWgq8qBu.js +0 -1
- data/public/railwatch/assets/index-CXQ7_oVj.js +0 -2
- data/public/railwatch/assets/index-CmyYrjS2.js +0 -1
- data/public/railwatch/assets/index-Cn9_HjDo.js +0 -1
- data/public/railwatch/assets/index-CsMAm9UK.js +0 -1
- data/public/railwatch/assets/index-D0Kk_oGY.js +0 -1
- data/public/railwatch/assets/index-DC9ZptJh.js +0 -1
- data/public/railwatch/assets/index-DNzg7jmV.js +0 -1
- data/public/railwatch/assets/index-DQ8uJO5f.js +0 -1
- data/public/railwatch/assets/index-Deq14BxB.js +0 -1
- data/public/railwatch/assets/index-IaV3Blzp.js +0 -1
- data/public/railwatch/assets/index-TYNWcJQs.js +0 -1
- data/public/railwatch/assets/index-WonH2fcZ.js +0 -1
- data/public/railwatch/assets/index-WxWUaH_d.js +0 -1
- data/public/railwatch/assets/index-mUNrl4ky.js +0 -1
- data/public/railwatch/assets/inertia-DfNRARuA.js +0 -97
- data/public/railwatch/assets/json-viewer-DMsF5glp.js +0 -1
- data/public/railwatch/assets/klass-CmHYk5rz.js +0 -1
- data/public/railwatch/assets/origin-identity-1R3bqa3R.js +0 -1
- data/public/railwatch/assets/percentile-picker-73z5PAps.js +0 -1
- data/public/railwatch/assets/relative-time-Dsc_cCdX.js +0 -1
- data/public/railwatch/assets/release-health-BV5OaOWd.js +0 -1
- data/public/railwatch/assets/route-CWh58C7K.js +0 -1
- data/public/railwatch/assets/segmented-DB4zh-Am.js +0 -1
- data/public/railwatch/assets/select-DBKjFlOX.js +0 -1
- data/public/railwatch/assets/series-chart-BaiDG795.js +0 -1
- data/public/railwatch/assets/show-B4ICCFGh.js +0 -1
- data/public/railwatch/assets/show-B5lOU9Gv.js +0 -1
- data/public/railwatch/assets/show-BYPB74t4.js +0 -2
- data/public/railwatch/assets/show-C7A0m2M8.js +0 -1
- data/public/railwatch/assets/show-DT5X1zqE.js +0 -1
- data/public/railwatch/assets/show-D_NBdXsn.js +0 -2
- data/public/railwatch/assets/show-DgPCnRg8.js +0 -1
- data/public/railwatch/assets/show-Yl69HF0x.js +0 -1
- data/public/railwatch/assets/show-_QxuUQCm.js +0 -3
- data/public/railwatch/assets/show-g__jnN36.js +0 -1
- data/public/railwatch/assets/show-l4ztfjl9.js +0 -1
- data/public/railwatch/assets/sort-header-BcG8ulEH.js +0 -1
- data/public/railwatch/assets/source-link-B2183i2-.js +0 -1
- data/public/railwatch/assets/sparkline-cell-B47ipscB.js +0 -1
- data/public/railwatch/assets/stat-DT2hhsqS.js +0 -1
- data/public/railwatch/assets/status-badge-CmbRKlY7.js +0 -1
- data/public/railwatch/assets/tenant-path-C4rNGauE.js +0 -1
- data/public/railwatch/assets/use-clipboard-oTNeP4ax.js +0 -1
- data/public/railwatch/assets/use-live-CLZZj245.js +0 -1
- data/public/railwatch/icon.png +0 -0
- data/public/railwatch/icon.svg +0 -5
- data/public/railwatch/manifest.json +0 -1245
- data/public/railwatch/rails-vite.json +0 -1
- /data/{app/frontend/lib → lib/generators/railwatch/install/templates}/railwatch.ts +0 -0
data/docs/faq.md
CHANGED
|
@@ -51,26 +51,25 @@ A second gate, `bench/no_db_writes.rb`, drives 200 requests and a job with
|
|
|
51
51
|
a `sql.active_record` subscriber watching for any `INSERT`/`UPDATE`/
|
|
52
52
|
`DELETE` issued from a frame inside `lib/railwatch`, and fails if it finds
|
|
53
53
|
one. **Railwatch never writes to your application's database.** Records
|
|
54
|
-
live in memory and are delivered by a background thread
|
|
55
|
-
|
|
54
|
+
live in memory and are delivered by a background thread over HTTP to the
|
|
55
|
+
Railwatch server, which owns its own storage. That
|
|
56
56
|
is not a nicety: instrumentation that takes a write lock is what turns a
|
|
57
57
|
single-writer SQLite app into a "database is locked" incident.
|
|
58
58
|
|
|
59
59
|
## Where does the data go, and how long is it kept?
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
hourly rollups back the charts. Nothing leaves the machine unless you
|
|
65
|
-
turn on export. See [Embedded mode](embedded.md).
|
|
61
|
+
One gzip-NDJSON POST to `{ingest_url}/ingest` per batch, to Railwatch
|
|
62
|
+
Cloud, a self-hosted railwatch-rs, or the server the `railwatch-server`
|
|
63
|
+
gem runs next to the app. The gem keeps nothing on disk itself.
|
|
66
64
|
|
|
67
|
-
Railwatch Cloud
|
|
68
|
-
batch. The platform stores each monitored environment's telemetry in its
|
|
65
|
+
Railwatch Cloud stores each monitored environment's telemetry in its
|
|
69
66
|
own database, prunes raw rows on a retention window, and keeps hourly
|
|
70
67
|
rollups for the charts. Retention there is set by the account's plan
|
|
71
|
-
tier, not by the gem — 7, 30, or 90 days depending on the plan. For
|
|
72
|
-
self-hosted
|
|
73
|
-
|
|
68
|
+
tier, not by the gem — 7, 30, or 90 days depending on the plan. For
|
|
69
|
+
railwatch-rs, self-hosted or through railwatch-server, retention and
|
|
70
|
+
backups are server settings
|
|
71
|
+
([railwatch-rs SELF-HOST.md](https://github.com/Rebulk/railwatch-rs/blob/main/docs/SELF-HOST.md),
|
|
72
|
+
[railwatch-server README](https://github.com/Rebulk/railwatch-server#readme)).
|
|
74
73
|
|
|
75
74
|
## What about PII?
|
|
76
75
|
|
|
@@ -125,15 +124,13 @@ Yes, on both sides, and it's the first-class target.
|
|
|
125
124
|
|
|
126
125
|
**In your app:** the gem does no I/O on the request path and never writes
|
|
127
126
|
to the app database, so there is no contention with SQLite's single
|
|
128
|
-
writer.
|
|
129
|
-
whatever the app runs on. SQL normalization is per adapter, so SQLite,
|
|
127
|
+
writer. SQL normalization is per adapter, so SQLite,
|
|
130
128
|
Postgres, MySQL, and Trilogy all group correctly.
|
|
131
129
|
|
|
132
|
-
**On the
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
runs unchanged on Postgres if that's what's configured.
|
|
130
|
+
**On the server:** telemetry is stored in SQLite per monitored
|
|
131
|
+
environment. That is what makes retention pruning, backup, and restore
|
|
132
|
+
per-environment operations rather than one enormous table, and it's why
|
|
133
|
+
log search gets FTS5 with snippet highlighting.
|
|
137
134
|
|
|
138
135
|
## One database per environment — what does that mean for me?
|
|
139
136
|
|
|
@@ -168,12 +165,7 @@ Two features are Solid Queue-specific, because they read its tables:
|
|
|
168
165
|
with `task_key`, `schedule`, and `drift`) and the queue depth and
|
|
169
166
|
oldest-job age on `health` records.
|
|
170
167
|
|
|
171
|
-
## What happens when the
|
|
172
|
-
|
|
173
|
-
This section is about the cloud transport. In embedded mode the
|
|
174
|
-
equivalent is the writer process being down, covered in
|
|
175
|
-
[Embedded mode](embedded.md#the-writer-process), and export keeps its
|
|
176
|
-
own durable queue.
|
|
168
|
+
## What happens when the server is unreachable?
|
|
177
169
|
|
|
178
170
|
Nothing, from your app's point of view. This is the property everything
|
|
179
171
|
else is built around: **delivery never raises into application code.**
|
data/docs/getting-started.md
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
# Getting started
|
|
2
2
|
|
|
3
|
-
Two commands on a Rails 8 app,
|
|
4
|
-
Everything below is the gem's own generator and rake tasks;
|
|
5
|
-
has to be wired by hand.
|
|
3
|
+
Two commands on a Rails 8 app, a token, and the app reports to
|
|
4
|
+
Railwatch. Everything below is the gem's own generator and rake tasks;
|
|
5
|
+
nothing else has to be wired by hand.
|
|
6
|
+
|
|
7
|
+
The `railwatch` gem is the agent: it instruments the app and sends what
|
|
8
|
+
it records over HTTPS to a Railwatch server. The server is one of:
|
|
9
|
+
|
|
10
|
+
- **Railwatch Cloud** at <https://railwatch.rebulk.com>, the default.
|
|
11
|
+
- **Your own [railwatch-rs](https://github.com/Rebulk/railwatch-rs)**,
|
|
12
|
+
one static binary that serves many apps
|
|
13
|
+
([Self-hosting](self-hosting.md)).
|
|
14
|
+
- **The [`railwatch-server`](https://github.com/Rebulk/railwatch-server)
|
|
15
|
+
gem**, which runs railwatch-rs next to Puma for this one app and serves
|
|
16
|
+
the dashboard at `/railwatch` ([below](#embedded-railwatch-server)).
|
|
6
17
|
|
|
7
18
|
## Install
|
|
8
19
|
|
|
@@ -14,89 +25,6 @@ bin/rails generate railwatch:install
|
|
|
14
25
|
The gem, its Ruby namespace, and its require path share one name:
|
|
15
26
|
`railwatch`, `Railwatch::*`, `require "railwatch"`.
|
|
16
27
|
|
|
17
|
-
With no flags the install is [embedded](embedded.md): telemetry stays in
|
|
18
|
-
two SQLite databases the app owns, Puma forks one writer process for
|
|
19
|
-
them (`plugin :railwatch` in `config/puma.rb`), and the dashboard is
|
|
20
|
-
served from the app. No token, no cloud, no job worker. The generator
|
|
21
|
-
creates and migrates both databases before it returns. On a PostgreSQL
|
|
22
|
-
or MySQL app without the `sqlite3` gem it adds the gem instead; run
|
|
23
|
-
`bundle install` and `bin/rails db:prepare` to finish.
|
|
24
|
-
|
|
25
|
-
Restart the app and open `/railwatch`. In development it is open; every
|
|
26
|
-
other environment answers 401 until you give it a password:
|
|
27
|
-
|
|
28
|
-
```sh
|
|
29
|
-
RAILS_ENV=production bin/rails railwatch:authentication:configure
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
[Embedded mode](embedded.md#authentication) covers using your own
|
|
33
|
-
admin authentication instead.
|
|
34
|
-
|
|
35
|
-
### What the generator writes
|
|
36
|
-
|
|
37
|
-
In every mode:
|
|
38
|
-
|
|
39
|
-
- `config/initializers/railwatch.rb`, with every option commented out at
|
|
40
|
-
its default (embedded: `c.transport = :local`).
|
|
41
|
-
- `mount Railwatch::Engine, at: "/railwatch"` in `config/routes.rb`: the
|
|
42
|
-
embedded dashboard and the beacon endpoint the browser client posts to.
|
|
43
|
-
- `.kamal/hooks/post-deploy` — only if `config/deploy.yml` already
|
|
44
|
-
exists.
|
|
45
|
-
- `app/frontend/lib/railwatch.ts` plus the `startRailwatch()` call in your
|
|
46
|
-
Inertia entrypoint — only if `app/frontend/` exists. If it can't find
|
|
47
|
-
an entrypoint it prints the two lines to add.
|
|
48
|
-
- `require "railwatch/rspec"` in `spec/rails_helper.rb`, or
|
|
49
|
-
`require "railwatch/minitest"` in `test/test_helper.rb`.
|
|
50
|
-
|
|
51
|
-
Embedded adds the two databases to `config/database.yml` and the Puma
|
|
52
|
-
plugin line; see [Embedded mode](embedded.md#your-applications-own-database).
|
|
53
|
-
|
|
54
|
-
### Check the wiring
|
|
55
|
-
|
|
56
|
-
```sh
|
|
57
|
-
bin/rails railwatch:doctor
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
With the app running, the embedded checklist starts like this:
|
|
61
|
-
|
|
62
|
-
```
|
|
63
|
-
✓ transport: local (telemetry stays in this app; dashboard at the engine mount)
|
|
64
|
-
✓ railwatch database: storage/development_railwatch.sqlite3
|
|
65
|
-
✓ railwatch_telemetry database: storage/development_railwatch_telemetry.sqlite3
|
|
66
|
-
✓ railwatch_telemetry migrations: up to date
|
|
67
|
-
✓ railwatch migrations: up to date
|
|
68
|
-
✓ telemetry disk: auto_vacuum=incremental; the nightly prune returns freed pages
|
|
69
|
-
✓ writer process: listening at /app/tmp/sockets/railwatch-writer.sock
|
|
70
|
-
✓ last write: 12 seconds ago
|
|
71
|
-
✓ dashboard access: open in development. Production stays closed until you run `RAILS_ENV=production bin/rails railwatch:authentication:configure`
|
|
72
|
-
✓ request middleware: Railwatch::Middleware::Request at position 0
|
|
73
|
-
✓ engine mounted: POST /railwatch/beacon -> railwatch/beacon#create
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
With the app stopped, `writer process` and `maintenance` are `✗`, and say
|
|
77
|
-
so. Every line and what to do about a `✗` is in
|
|
78
|
-
[`troubleshooting.md`](troubleshooting.md).
|
|
79
|
-
|
|
80
|
-
### Adding Railwatch Cloud
|
|
81
|
-
|
|
82
|
-
Railwatch Cloud delivers alerts to Slack, email, webhooks or Linear
|
|
83
|
-
(embedded mode only records them), serves the [MCP server](ai-and-mcp.md)
|
|
84
|
-
to your AI assistant, and puts many apps and servers in one place. An
|
|
85
|
-
embedded install can mirror every record to it and keep `/railwatch`:
|
|
86
|
-
set a token ([below](#where-the-token-comes-from)) and
|
|
87
|
-
`c.export_enabled = true`. See
|
|
88
|
-
[Embedded mode](embedded.md#three-ways-to-run-it).
|
|
89
|
-
|
|
90
|
-
## Railwatch Cloud instead
|
|
91
|
-
|
|
92
|
-
To send telemetry only to Railwatch Cloud, with no local databases, run
|
|
93
|
-
the same generator with `--cloud`:
|
|
94
|
-
|
|
95
|
-
```sh
|
|
96
|
-
bundle add railwatch
|
|
97
|
-
bin/rails generate railwatch:install --cloud
|
|
98
|
-
```
|
|
99
|
-
|
|
100
28
|
With the token already in hand, let the generator read it without placing the
|
|
101
29
|
secret in shell history or process arguments:
|
|
102
30
|
|
|
@@ -109,25 +37,34 @@ bin/rails generate railwatch:install \
|
|
|
109
37
|
|
|
110
38
|
- `--prompt-token` reads without echo. `--token-stdin` is available for a
|
|
111
39
|
secret-manager pipe; an already exported `RAILWATCH_TOKEN` is also detected.
|
|
112
|
-
- Any of `--prompt-token`, `--token-stdin`, `--url=` and `--kamal-secrets`
|
|
113
|
-
means the cloud, so none of them needs `--cloud` as well. An exported
|
|
114
|
-
`RAILWATCH_TOKEN` on its own does not: without one of these flags the
|
|
115
|
-
install is embedded.
|
|
116
40
|
- A token is written to `.env` only when Git confirms that `.env` is ignored.
|
|
117
41
|
A tracked or non-ignored dotenv file is refused; use Rails credentials, a
|
|
118
42
|
deployment secret manager, or add `.env` to `.gitignore` first. Token values
|
|
119
43
|
are never printed by the generator.
|
|
120
|
-
- `--url=` sets `RAILWATCH_INGEST_URL`, for a self-hosted
|
|
44
|
+
- `--url=` sets `RAILWATCH_INGEST_URL`, for a self-hosted server. Leave
|
|
121
45
|
it off to use the default, `https://railwatch.rebulk.com`.
|
|
122
46
|
- `--kamal-secrets` appends `RAILWATCH_TOKEN=$RAILWATCH_TOKEN` to
|
|
123
47
|
`.kamal/secrets` and adds `RAILWATCH_TOKEN` under `env: secret:` in
|
|
124
48
|
`config/deploy.yml`, which is the pair of edits Kamal needs to pass a
|
|
125
49
|
secret through to the containers.
|
|
50
|
+
- `--no-doctor` skips the `railwatch:doctor` run at the end.
|
|
126
51
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
52
|
+
### What the generator writes
|
|
53
|
+
|
|
54
|
+
- `config/initializers/railwatch.rb`, with every option commented out at
|
|
55
|
+
its default.
|
|
56
|
+
- `mount Railwatch::Engine, at: "/railwatch"` in `config/routes.rb`: the
|
|
57
|
+
beacon endpoint the browser client posts to (`POST /railwatch/beacon`).
|
|
58
|
+
- `.kamal/hooks/post-deploy` — only if `config/deploy.yml` already
|
|
59
|
+
exists.
|
|
60
|
+
- `app/frontend/lib/railwatch.ts` plus the `startRailwatch()` call in your
|
|
61
|
+
Inertia entrypoint — only if `app/frontend/` exists. If it can't find
|
|
62
|
+
an entrypoint it prints the two lines to add.
|
|
63
|
+
- `require "railwatch/rspec"` in `spec/rails_helper.rb`, or
|
|
64
|
+
`require "railwatch/minitest"` in `test/test_helper.rb`.
|
|
65
|
+
|
|
66
|
+
It finishes by running `railwatch:doctor`, so the install either ends in
|
|
67
|
+
a clean checklist or tells you what is still missing.
|
|
131
68
|
|
|
132
69
|
### Where the token comes from
|
|
133
70
|
|
|
@@ -135,18 +72,18 @@ In Railwatch Cloud, create an application, then an environment inside it
|
|
|
135
72
|
(`production`, `staging`, one token each). The token is shown once, on
|
|
136
73
|
the page you land on right after creating the environment — copy it
|
|
137
74
|
then. If you lose it, rotate it from the environment's settings and
|
|
138
|
-
update `RAILWATCH_TOKEN`.
|
|
75
|
+
update `RAILWATCH_TOKEN`. A self-hosted railwatch-rs creates tokens the
|
|
76
|
+
same way (or with `railwatch env create`; see its docs).
|
|
139
77
|
|
|
140
78
|
```sh
|
|
141
79
|
bin/rails railwatch:token # prints the URL to create/copy a token
|
|
142
80
|
```
|
|
143
81
|
|
|
144
|
-
A token looks like `rw_` followed by 40 characters.
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
subscribers and ships nothing.
|
|
82
|
+
A token looks like `rw_` followed by 40 characters. The gem is inert
|
|
83
|
+
without one: `Railwatch.enabled?` is `config.enabled && token.present?`,
|
|
84
|
+
so an app with no token installs no subscribers and ships nothing.
|
|
148
85
|
|
|
149
|
-
### Check the
|
|
86
|
+
### Check the wiring
|
|
150
87
|
|
|
151
88
|
```sh
|
|
152
89
|
bin/rails railwatch:doctor
|
|
@@ -169,11 +106,67 @@ It exits non-zero on three lines: `token` (missing), `token storage`
|
|
|
169
106
|
(a plaintext token in a tracked file), and `ingest reachable`. The rest
|
|
170
107
|
of the checklist is informational. Run it after the token is in place:
|
|
171
108
|
`ingest reachable` sends the token, so a missing or wrong token makes
|
|
172
|
-
the
|
|
109
|
+
the server answer 401 and that line is `✗` as well. Every line and what
|
|
110
|
+
to do about a `✗` is in [`troubleshooting.md`](troubleshooting.md).
|
|
173
111
|
|
|
174
112
|
`bin/rails railwatch:status` is the one-line version: it pings
|
|
175
113
|
`{ingest_url}/ingest/ping` and prints the ingest URL, deploy, and server.
|
|
176
114
|
|
|
115
|
+
## Embedded: railwatch-server
|
|
116
|
+
|
|
117
|
+
To keep telemetry inside the app instead, add the
|
|
118
|
+
[`railwatch-server`](https://github.com/Rebulk/railwatch-server) gem
|
|
119
|
+
next to this one. It bundles the railwatch-rs binary for your platform,
|
|
120
|
+
runs it as its own process beside Puma, and points this agent at it:
|
|
121
|
+
|
|
122
|
+
```ruby
|
|
123
|
+
# Gemfile
|
|
124
|
+
gem "railwatch"
|
|
125
|
+
gem "railwatch-server"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
```ruby
|
|
129
|
+
# config/puma.rb
|
|
130
|
+
plugin :railwatch_server
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
On first boot it provisions `storage/railwatch/<env>` and sets the
|
|
134
|
+
agent's token and ingest URL itself, so no `RAILWATCH_TOKEN` is needed.
|
|
135
|
+
When `RAILWATCH_TOKEN` is set, it leaves the agent alone and only serves
|
|
136
|
+
the dashboard. The dashboard at `/railwatch` is behind this gem's gate
|
|
137
|
+
settings: HTTP Basic, on and closed (401) until credentials exist, except
|
|
138
|
+
in development when none are configured:
|
|
139
|
+
|
|
140
|
+
```sh
|
|
141
|
+
RAILS_ENV=production bin/rails railwatch:authentication:configure
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
To use your own admin authentication instead, turn Basic off and name a
|
|
145
|
+
base controller ([Configuration](configuration.md#dashboard-gate-railwatch-server)).
|
|
146
|
+
Everything else about it (ports, data directory, email, backups) is in
|
|
147
|
+
the [railwatch-server README](https://github.com/Rebulk/railwatch-server#readme).
|
|
148
|
+
|
|
149
|
+
### Coming from 0.x embedded mode
|
|
150
|
+
|
|
151
|
+
Railwatch 0.x could keep telemetry in two SQLite databases of the app's
|
|
152
|
+
own, written by a Puma writer process, with the dashboard served from the
|
|
153
|
+
gem. 1.0 removes that mode. To move:
|
|
154
|
+
|
|
155
|
+
1. Remove `c.transport = :local` (or `RAILWATCH_TRANSPORT=local`) from
|
|
156
|
+
the initializer and environment.
|
|
157
|
+
2. Remove `plugin :railwatch` from `config/puma.rb`. Puma refuses to boot
|
|
158
|
+
with a plugin it cannot find.
|
|
159
|
+
3. Remove the `railwatch` and `railwatch_telemetry` entries from
|
|
160
|
+
`config/database.yml`.
|
|
161
|
+
4. Add `railwatch-server` as above, or point the app at Railwatch Cloud
|
|
162
|
+
or a self-hosted railwatch-rs.
|
|
163
|
+
|
|
164
|
+
The old files (`storage/<env>_railwatch.sqlite3`,
|
|
165
|
+
`storage/<env>_railwatch_telemetry.sqlite3`) are not migrated, and
|
|
166
|
+
railwatch-rs has no import for them: its `railwatch import-rails` reads a
|
|
167
|
+
Railwatch Cloud (Rails) install, not these files. History starts again
|
|
168
|
+
in the new server. Delete the files once you no longer want them.
|
|
169
|
+
|
|
177
170
|
## Make one request
|
|
178
171
|
|
|
179
172
|
```sh
|
|
@@ -183,8 +176,9 @@ curl http://localhost:3000/
|
|
|
183
176
|
|
|
184
177
|
Records are batched in-process and flushed every `flush_interval`
|
|
185
178
|
(2 seconds by default) or every 500 records, whichever comes first, so
|
|
186
|
-
the request shows up on the **Requests** page (
|
|
187
|
-
|
|
179
|
+
the request shows up on the **Requests** page (the environment in
|
|
180
|
+
Railwatch Cloud or your own server, or `/railwatch` with
|
|
181
|
+
railwatch-server) a couple of seconds after you make it —
|
|
188
182
|
with its queries, cache reads, view renders, and log lines already
|
|
189
183
|
attached to it.
|
|
190
184
|
|
|
@@ -266,14 +260,11 @@ up, on the account.
|
|
|
266
260
|
|
|
267
261
|
## Deploying
|
|
268
262
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
from the Kamal hook, set `RAILWATCH_TRANSPORT=local` in the deployer's
|
|
275
|
-
environment ([Embedded mode](embedded.md#deploys)). The token steps
|
|
276
|
-
below are for a cloud install or export.
|
|
263
|
+
With railwatch-server, the server's data lives under
|
|
264
|
+
`storage/railwatch/<env>`, which has to be on a volume that survives
|
|
265
|
+
deploys (the Rails 8 Kamal template mounts `storage/`); its README covers
|
|
266
|
+
deploys and two containers sharing a volume. The token steps below are
|
|
267
|
+
for Railwatch Cloud or a self-hosted server.
|
|
277
268
|
|
|
278
269
|
### Kamal
|
|
279
270
|
|
|
@@ -352,12 +343,9 @@ one — the deploy is still recorded.
|
|
|
352
343
|
`sentry-rails`.
|
|
353
344
|
- [`replacing-nightwatch.md`](replacing-nightwatch.md) — for people
|
|
354
345
|
coming from Laravel.
|
|
355
|
-
- [`embedded.md`](embedded.md) — authentication, the writer process,
|
|
356
|
-
maintenance, disk, and export to the cloud.
|
|
357
346
|
- [`self-hosting.md`](self-hosting.md) — pointing the gem at your own
|
|
358
|
-
|
|
347
|
+
railwatch-rs server.
|
|
359
348
|
- [`troubleshooting.md`](troubleshooting.md) — every `railwatch:doctor`
|
|
360
349
|
line and what a failure means.
|
|
361
350
|
- [`faq.md`](faq.md) — overhead, retention, PII, unreachable platform.
|
|
362
|
-
- [`ai-and-mcp.md`](ai-and-mcp.md) — asking an AI assistant what broke
|
|
363
|
-
(Railwatch Cloud).
|
|
351
|
+
- [`ai-and-mcp.md`](ai-and-mcp.md) — asking an AI assistant what broke.
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
Railwatch is the same product shape for Rails: one package instruments the
|
|
4
4
|
framework end to end, records are grouped under the execution that
|
|
5
5
|
produced them, and a dashboard turns them into routes, jobs, queries,
|
|
6
|
-
issues, and alerts.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
issues, and alerts. Railwatch Cloud is the hosted option; unlike
|
|
7
|
+
Nightwatch, the server can also be self-hosted
|
|
8
|
+
([railwatch-rs](self-hosting.md)) or run inside your app with the
|
|
9
|
+
[`railwatch-server`](getting-started.md#embedded-railwatch-server) gem.
|
|
10
|
+
If you know Nightwatch, you already know how to read Railwatch — this page maps the vocabulary and points out the three
|
|
10
11
|
places the Rails answer is genuinely different.
|
|
11
12
|
|
|
12
13
|
Railwatch is an independent product and is not affiliated with Laravel or
|
|
@@ -21,8 +22,8 @@ separate daemon POSTs them.
|
|
|
21
22
|
Puma and Solid Queue workers *are* long-lived, so Railwatch skips that
|
|
22
23
|
tier. A single reporter thread per process holds a bounded buffer
|
|
23
24
|
(16 MiB and 10,000 records by default, oldest dropped and counted) and
|
|
24
|
-
flushes batches every 2 seconds or every 500 records
|
|
25
|
-
|
|
25
|
+
flushes batches every 2 seconds or every 500 records, as gzip-NDJSON
|
|
26
|
+
POSTs to the Railwatch server.
|
|
26
27
|
There is no daemon to install, supervise, or forget to restart.
|
|
27
28
|
|
|
28
29
|
The thread is re-armed after `fork`, so clustered Puma workers and
|
|
@@ -184,7 +185,7 @@ every setting still has an env var — `NIGHTWATCH_*` becomes `RAILWATCH_*`.
|
|
|
184
185
|
| `nightwatch:agent` | Nothing — the reporter thread lives in the app process. |
|
|
185
186
|
| `nightwatch:status` | `bin/rails railwatch:status` |
|
|
186
187
|
| `nightwatch:deploy {deploy} --ref --name --url` | `bin/rails railwatch:deploy[ref,name,url]`, or the generated `.kamal/hooks/post-deploy` |
|
|
187
|
-
| — | `bin/rails railwatch:doctor`, which checks the whole install and exits non-zero if the
|
|
188
|
+
| — | `bin/rails railwatch:doctor`, which checks the whole install and exits non-zero if the token or the ingest host is wrong |
|
|
188
189
|
|
|
189
190
|
## The three things worth knowing about Rails
|
|
190
191
|
|
data/docs/replacing-sentry.md
CHANGED
|
@@ -8,10 +8,9 @@ depends on a conditional row.
|
|
|
8
8
|
|
|
9
9
|
Install Railwatch first ([`getting-started.md`](getting-started.md)); you
|
|
10
10
|
can run both for a day if you want to compare, since neither knows about
|
|
11
|
-
the other. The
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
from embedded.
|
|
11
|
+
the other. The token steps below apply to Railwatch Cloud and to a
|
|
12
|
+
self-hosted railwatch-rs; with the `railwatch-server` gem the token is
|
|
13
|
+
set for you.
|
|
15
14
|
|
|
16
15
|
## Decide whether Railwatch covers your workload
|
|
17
16
|
|
|
@@ -33,7 +32,7 @@ Railwatch does not claim those broader capabilities.
|
|
|
33
32
|
| Ruby profiling | Conditional | Requires `vernier` or `stackprof`; there is no profiler bundled into the SDK. |
|
|
34
33
|
| Browser monitoring | Partial | The optional Inertia client reports visits, Web Vitals, browser errors, and breadcrumbs. Session Replay, native/mobile SDKs, and Sentry's full browser/source-map workflow are outside the currently released Rails-server replacement. |
|
|
35
34
|
| Runtime compatibility | Narrow today | The currently proved pair is Ruby 3.4 + Rails 8.1. A maintained compatibility matrix and any safe lowering of requirements are tracked by [#26](https://github.com/Rebulk/railwatch/issues/26). |
|
|
36
|
-
| Managed integrations and operations | Partial | Railwatch Cloud
|
|
35
|
+
| Managed integrations and operations | Partial | Railwatch Cloud and railwatch-rs deliver alerts to email, Slack, webhooks and Linear. It does not promise Sentry's broader integration catalog. |
|
|
37
36
|
| SQL value privacy | Supported by default | Query records carry normalized SQL shapes without literal values, and Active Record binds are never sent. Raw SQL and query plans are separate opt-ins; either can contain values. |
|
|
38
37
|
|
|
39
38
|
For a Rails 8.1 application whose work enters through Rack and Active Job,
|
|
@@ -73,11 +72,10 @@ deploy config once the app boots without it.
|
|
|
73
72
|
`config/initializers/railwatch.rb` (written by the install generator) is
|
|
74
73
|
where every option from `Sentry.init` lands. The mapping:
|
|
75
74
|
|
|
76
|
-
- **`dsn:`**
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
switch: with it blank, Railwatch installs nothing.
|
|
75
|
+
- **`dsn:`** becomes `RAILWATCH_TOKEN`, one token per environment,
|
|
76
|
+
created in Railwatch Cloud or your own server. Self-hosting adds
|
|
77
|
+
`RAILWATCH_INGEST_URL`. The token is also the on/off switch: with it
|
|
78
|
+
blank, Railwatch installs nothing.
|
|
81
79
|
- **`environment:`** becomes `c.environment`, which defaults to
|
|
82
80
|
`Rails.env` — set it only to report under a different name.
|
|
83
81
|
- **`release:`** becomes `c.deploy`, which auto-detects the release from
|
|
@@ -116,9 +114,7 @@ where every option from `Sentry.init` lands. The mapping:
|
|
|
116
114
|
- **Rack `X-Request-Start` queue time** needs no setting: it is parsed
|
|
117
115
|
into `queue_time` on every `request` record.
|
|
118
116
|
|
|
119
|
-
A worked initializer
|
|
120
|
-
block turns into (an embedded install has `c.transport = :local` instead
|
|
121
|
-
of the token):
|
|
117
|
+
A worked initializer, roughly what a `Sentry.init` block turns into:
|
|
122
118
|
|
|
123
119
|
```ruby
|
|
124
120
|
# config/initializers/railwatch.rb
|
|
@@ -424,7 +420,7 @@ startRailwatch({
|
|
|
424
420
|
|---|---|
|
|
425
421
|
| `Sentry.init({ dsn })` | `startRailwatch()`. There is no DSN: the beacon posts to the app's own origin and the *server* decides whether to record it (`c.beacon_enabled`, and whether Railwatch is enabled). The gate you already have on whether `startRailwatch()` runs at all is the only gate. |
|
|
426
422
|
| `release` | Automatic. The record is stamped with `c.deploy`, the same release the server records carry, so a browser issue and a server issue from one deploy line up without a matching pair of settings to get wrong. |
|
|
427
|
-
| `environment` | Automatic — the
|
|
423
|
+
| `environment` | Automatic — the ingest token identifies the environment. |
|
|
428
424
|
| `ignoreErrors` | `startRailwatch({ ignoreErrors })`. Strings match anywhere in the message; regexes are tested against it. Both `ResizeObserver` messages are ignored by default. |
|
|
429
425
|
| `denyUrls` | `startRailwatch({ denyUrls })`, matched against the top stack frame's URL. `/extensions\//i`, `/^chrome:\/\//i`, and `/^moz-extension:\/\//i` are denied by default, **and** any frame from an origin that isn't the app's own is dropped — extensions, injected widgets, tag managers. |
|
|
430
426
|
| `Sentry.setUser` | Server-side. The beacon is a same-origin POST carrying the session cookie, so the server resolves the user the same way it does for a request (`Railwatch.user`) when `Current.user` or Warden is set by middleware; an app that authenticates in a `before_action` gives Railwatch the same lookup with `c.beacon_user { \|request\| ... }`. Nothing the browser sends names the user, so it cannot be forged. |
|
|
@@ -568,10 +564,10 @@ hook matching `rails runner …` previews, or `sentry_runner_noise.rb` under
|
|
|
568
564
|
| Inertia visit timing | Real browser page-visit duration, prop byte size, partial reloads, SSR time, and Core Web Vitals, from a client the generator installs. |
|
|
569
565
|
| Spec matchers as a CI gate | `have_railwatch_queries`, `have_railwatch_n_plus_one`, `have_railwatch_outgoing_requests` fail the pull request that regresses a hot path. |
|
|
570
566
|
| Zero app-DB writes | The gem holds records in memory and ships them from a background thread; a bench gate asserts no `INSERT`/`UPDATE`/`DELETE` ever originates in `lib/railwatch`. This is why it is safe on single-writer SQLite. |
|
|
571
|
-
| A dashboard inside the app | The
|
|
567
|
+
| A dashboard inside the app | The `railwatch-server` gem runs the server next to Puma and serves the whole dashboard at `/railwatch`, with no hosted service at all ([Getting started](getting-started.md#embedded-railwatch-server)). |
|
|
572
568
|
| One SQLite database per environment | Railwatch Cloud stores each monitored environment's telemetry in its own database file, which makes retention pruning, backup, and restore per-environment operations. |
|
|
573
569
|
| LLM calls | RubyLLM calls are recorded with tokens, cost, finish reason, tool calls and workflows, in the request or job that made them ([`records.md`](records.md#llm_call)). |
|
|
574
|
-
| An MCP server |
|
|
570
|
+
| An MCP server | AI assistants can ask what broke after the last deploy, list slow routes, read an execution's timeline, and search logs ([`ai-and-mcp.md`](ai-and-mcp.md)). |
|
|
575
571
|
|
|
576
572
|
## See also
|
|
577
573
|
|
data/docs/security.md
CHANGED
|
@@ -3,25 +3,20 @@
|
|
|
3
3
|
This review covers the open-source gem that runs in a customer's Rails
|
|
4
4
|
application. Railwatch Cloud is a separate service and is outside this review.
|
|
5
5
|
|
|
6
|
-
##
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
recorded
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
authorizes them. See [Embedded mode](embedded.md#authentication).
|
|
18
|
-
|
|
19
|
-
The writer socket that web workers hand batches to is created with a 0700
|
|
20
|
-
directory and a 0600 socket, so only the app's own user can connect.
|
|
6
|
+
## Dashboard gate (railwatch-server)
|
|
7
|
+
|
|
8
|
+
The gem serves no dashboard. With the separate `railwatch-server` gem
|
|
9
|
+
installed, a dashboard showing every query, log line and exception the app
|
|
10
|
+
recorded is proxied at `/railwatch`, and its gate is this gem's settings.
|
|
11
|
+
HTTP Basic authentication is on by default. With no credentials configured,
|
|
12
|
+
every dashboard request is 401 in every environment except development,
|
|
13
|
+
where it is open. Credentials, once set, apply in development too. An app
|
|
14
|
+
that turns Basic off gates the dashboard with its own `base_controller_class`,
|
|
15
|
+
which railwatch-server's proxy controller inherits from. See
|
|
16
|
+
[Configuration](configuration.md#dashboard-gate-railwatch-server).
|
|
21
17
|
|
|
22
18
|
## Transport
|
|
23
19
|
|
|
24
|
-
This applies to a cloud install and to export from an embedded install.
|
|
25
20
|
`Railwatch::Transport::Http` sends gzip NDJSON with `Net::HTTP`. HTTPS explicitly
|
|
26
21
|
sets OpenSSL's `VERIFY_PEER`; a spec pins that setting. The transport does not
|
|
27
22
|
implement redirect handling, so a redirect response is treated as a permanent
|
|
@@ -52,8 +47,7 @@ configuration and record specs:
|
|
|
52
47
|
filtered. `Locals.inspect_value` rescues an `inspect` implementation that
|
|
53
48
|
raises; this behavior is covered by an exception-record spec.
|
|
54
49
|
- `capture_exception_source` is true. Source lines surrounding in-application
|
|
55
|
-
backtrace frames are recorded
|
|
56
|
-
reports or exports there. Disable it if source context is outside the
|
|
50
|
+
backtrace frames are recorded and sent to the configured server. Disable it if source context is outside the
|
|
57
51
|
application's telemetry policy.
|
|
58
52
|
|
|
59
53
|
Log record messages are sent exactly as supplied to `Rails.logger`. Railwatch
|
|
@@ -107,8 +101,8 @@ application/deployment secret and must not be committed.
|
|
|
107
101
|
application-specific credentials and personal data.
|
|
108
102
|
- Keep secrets out of exception messages, log text, source files, tenant ids,
|
|
109
103
|
user resolvers, and custom context.
|
|
110
|
-
-
|
|
111
|
-
deploying; see [
|
|
104
|
+
- With railwatch-server, set dashboard credentials (or your own gate) before
|
|
105
|
+
deploying; see [Configuration](configuration.md#dashboard-gate-railwatch-server).
|
|
112
106
|
- Use HTTPS in production and keep TLS verification enabled.
|
|
113
107
|
- Put a request-body limit at the reverse proxy when the public beacon is
|
|
114
108
|
enabled, and choose a shared cache if rate limits must span processes.
|
data/docs/self-hosting.md
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
# Self-hosting
|
|
2
2
|
|
|
3
|
-
This page is for sending telemetry to a Railwatch
|
|
4
|
-
yourself
|
|
5
|
-
your app and needs none of it.
|
|
3
|
+
This page is for sending telemetry to a Railwatch server you run
|
|
4
|
+
yourself instead of Railwatch Cloud.
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
same.
|
|
6
|
+
The self-hosted server is [railwatch-rs](https://github.com/Rebulk/railwatch-rs)
|
|
7
|
+
(AGPL-3.0): one static binary on SQLite that serves many apps, with the
|
|
8
|
+
same dashboard, alerts, MCP server and JSON API as Railwatch Cloud. Its
|
|
9
|
+
install, configuration, backups and upgrades are documented in its
|
|
10
|
+
[SELF-HOST.md](https://github.com/Rebulk/railwatch-rs/blob/main/docs/SELF-HOST.md).
|
|
11
|
+
The gem doesn't care which server it talks to — point it at yours and
|
|
12
|
+
everything works the same.
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
For a single app, the [`railwatch-server`](https://github.com/Rebulk/railwatch-server)
|
|
15
|
+
gem runs that same server next to Puma and wires this gem to it, with no
|
|
16
|
+
host to set up; see [Getting started](getting-started.md#embedded-railwatch-server).
|
|
17
|
+
The rest of this page is for a server on its own host.
|
|
18
|
+
|
|
19
|
+
## Point the gem at your server
|
|
12
20
|
|
|
13
21
|
```ruby
|
|
14
22
|
# config/initializers/railwatch.rb
|
|
@@ -21,22 +29,22 @@ end
|
|
|
21
29
|
`ingest_url` defaults to `https://railwatch.rebulk.com`, so this is the one
|
|
22
30
|
setting a self-hosted install always needs; everything the gem sends —
|
|
23
31
|
records, ping, deploys — hangs off that host. Pass `--url=` to the
|
|
24
|
-
installer to have it written for you
|
|
32
|
+
installer to have it written for you:
|
|
25
33
|
|
|
26
34
|
```sh
|
|
27
35
|
bin/rails generate railwatch:install --url=https://telemetry.example.com
|
|
28
36
|
```
|
|
29
37
|
|
|
30
|
-
|
|
31
|
-
`
|
|
32
|
-
[export](embedded.md#three-ways-to-run-it) instead.
|
|
38
|
+
The railwatch-rs installer prints both values (`RAILWATCH_INGEST_URL`,
|
|
39
|
+
`RAILWATCH_TOKEN`) when it finishes.
|
|
33
40
|
|
|
34
41
|
## Getting a token
|
|
35
42
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
token
|
|
39
|
-
is
|
|
43
|
+
railwatch-rs prints the first environment's token once, at the end of
|
|
44
|
+
its install. Each further environment (`production`, `staging` — one
|
|
45
|
+
token each) gets its own, created from the dashboard or with
|
|
46
|
+
`sudo railwatch env create <name>`. A token is shown once; a lost one is
|
|
47
|
+
replaced, not recovered.
|
|
40
48
|
|
|
41
49
|
```sh
|
|
42
50
|
bin/rails railwatch:token # prints the URL to create/copy a token
|
|
@@ -55,14 +63,8 @@ so it works as a post-deploy smoke test.
|
|
|
55
63
|
|
|
56
64
|
## MCP
|
|
57
65
|
|
|
58
|
-
Your
|
|
66
|
+
Your server serves its own MCP endpoint at `<ingest host>/mcp` —
|
|
59
67
|
`https://telemetry.example.com/mcp` for the example above. It authenticates
|
|
60
68
|
with a per-user API token generated from Settings → Profile, the same
|
|
61
69
|
token the public JSON API at `/api/v1` uses. See
|
|
62
70
|
[`ai-and-mcp.md`](ai-and-mcp.md) for every client's configuration block.
|
|
63
|
-
|
|
64
|
-
## Running the platform
|
|
65
|
-
|
|
66
|
-
Railwatch Cloud's backend is not part of this gem repository. Licensed
|
|
67
|
-
self-hosted customers receive separate platform deployment, backup, retention,
|
|
68
|
-
quota, and restore documentation from Rebulk.
|