rails_pulse 0.3.3 → 0.4.0.pre.2
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/CHANGELOG.md +299 -0
- data/README.md +44 -3
- data/app/assets/stylesheets/rails_pulse/application.css +21 -32
- data/app/assets/stylesheets/rails_pulse/components/backtrace.css +238 -0
- data/app/assets/stylesheets/rails_pulse/components/badge.css +32 -0
- data/app/assets/stylesheets/rails_pulse/components/button.css +2 -36
- data/app/assets/stylesheets/rails_pulse/components/card.css +8 -11
- data/app/assets/stylesheets/rails_pulse/components/chart.css +16 -3
- data/app/assets/stylesheets/rails_pulse/components/csp_safe_positioning.css +5 -39
- data/app/assets/stylesheets/rails_pulse/components/dashboard.css +0 -52
- data/app/assets/stylesheets/rails_pulse/components/deployments.css +39 -0
- data/app/assets/stylesheets/rails_pulse/components/dialog.css +0 -5
- data/app/assets/stylesheets/rails_pulse/components/input.css +0 -14
- data/app/assets/stylesheets/rails_pulse/components/layouts.css +0 -20
- data/app/assets/stylesheets/rails_pulse/components/menu.css +0 -16
- data/app/assets/stylesheets/rails_pulse/components/sidebar_menu.css +0 -16
- data/app/assets/stylesheets/rails_pulse/components/storage.css +187 -0
- data/app/assets/stylesheets/rails_pulse/components/tags.css +0 -14
- data/app/assets/stylesheets/rails_pulse/components/time_range_selector.css +5 -5
- data/app/assets/stylesheets/rails_pulse/components/utilities.css +0 -17
- data/app/controllers/concerns/chart_table_concern.rb +15 -3
- data/app/controllers/concerns/ransack_params_concern.rb +18 -0
- data/app/controllers/concerns/response_range_concern.rb +1 -1
- data/app/controllers/concerns/time_range_concern.rb +28 -14
- data/app/controllers/rails_pulse/application_controller.rb +104 -31
- data/app/controllers/rails_pulse/dashboard_controller.rb +9 -0
- data/app/controllers/rails_pulse/deployments_controller.rb +26 -5
- data/app/controllers/rails_pulse/exception_occurrences_controller.rb +19 -0
- data/app/controllers/rails_pulse/exceptions_controller.rb +119 -0
- data/app/controllers/rails_pulse/job_runs_controller.rb +1 -1
- data/app/controllers/rails_pulse/requests_controller.rb +1 -1
- data/app/controllers/rails_pulse/routes_controller.rb +7 -1
- data/app/controllers/rails_pulse/storage_controller.rb +7 -0
- data/app/controllers/rails_pulse/tags_controller.rb +2 -2
- data/app/helpers/rails_pulse/application_helper.rb +1 -0
- data/app/helpers/rails_pulse/backtrace_helper.rb +85 -0
- data/app/helpers/rails_pulse/breadcrumbs_helper.rb +4 -1
- data/app/helpers/rails_pulse/chart_helper.rb +0 -3
- data/app/helpers/rails_pulse/route_helper.rb +8 -16
- data/app/javascript/rails_pulse/application.js +29 -8
- data/app/javascript/rails_pulse/controllers/clipboard_controller.js +58 -0
- data/app/javascript/rails_pulse/controllers/index_controller.js +16 -10
- data/app/javascript/rails_pulse/controllers/pagination_controller.js +6 -2
- data/app/javascript/rails_pulse/controllers/popover_controller.js +4 -0
- data/app/models/concerns/rails_pulse/taggable.rb +11 -6
- data/app/models/rails_pulse/cards/base.rb +53 -0
- data/app/models/rails_pulse/dashboard/health_summary.rb +52 -0
- data/app/models/rails_pulse/dashboard/needs_attention.rb +73 -1
- data/app/models/rails_pulse/dashboard/storage_status.rb +490 -0
- data/app/models/rails_pulse/deployment.rb +47 -1
- data/app/models/rails_pulse/exception_group.rb +37 -0
- data/app/models/rails_pulse/exception_occurrence.rb +27 -0
- data/app/models/rails_pulse/exceptions/cards/exception_rate.rb +116 -0
- data/app/models/rails_pulse/exceptions/cards/open_groups.rb +49 -0
- data/app/models/rails_pulse/exceptions/cards/total_occurrences.rb +62 -0
- data/app/models/rails_pulse/exceptions/charts/occurrence_volume.rb +56 -0
- data/app/models/rails_pulse/exceptions/raw_data.rb +216 -0
- data/app/models/rails_pulse/jobs/cards/p95_duration.rb +8 -2
- data/app/models/rails_pulse/operation.rb +13 -4
- data/app/models/rails_pulse/queries/cards/percentile_query_times.rb +8 -3
- data/app/models/rails_pulse/request.rb +5 -1
- data/app/models/rails_pulse/route.rb +71 -21
- data/app/models/rails_pulse/routes/cards/error_rates.rb +6 -3
- data/app/models/rails_pulse/routes/cards/percentile_response_times.rb +8 -3
- data/app/models/rails_pulse/routes/tables/index.rb +8 -6
- data/app/models/rails_pulse/summary.rb +21 -10
- data/app/models/rails_pulse/tables/base.rb +4 -2
- data/app/services/rails_pulse/analysis/explain_plan_analyzer.rb +47 -12
- data/app/services/rails_pulse/exception_capture_service.rb +228 -0
- data/app/services/rails_pulse/exception_message_sanitizer.rb +152 -0
- data/app/services/rails_pulse/operations/change_point.rb +144 -0
- data/app/services/rails_pulse/operations/compare.rb +92 -0
- data/app/services/rails_pulse/operations/comparison.rb +126 -0
- data/app/services/rails_pulse/operations/metric.rb +63 -0
- data/app/services/rails_pulse/operations/series.rb +84 -0
- data/app/services/rails_pulse/operations/subject.rb +77 -0
- data/app/services/rails_pulse/route_controller_action_backfiller.rb +110 -0
- data/app/services/rails_pulse/route_merger.rb +99 -0
- data/app/services/rails_pulse/route_migrator.rb +139 -0
- data/app/services/rails_pulse/route_path_normalizer.rb +79 -0
- data/app/services/rails_pulse/route_recognizer.rb +47 -0
- data/app/services/rails_pulse/summary_service.rb +45 -0
- data/app/services/rails_pulse/tag_filter_service.rb +5 -3
- data/app/views/layouts/rails_pulse/_menu_items.html.erb +7 -0
- data/app/views/layouts/rails_pulse/_onboarding_banner.html.erb +8 -0
- data/app/views/layouts/rails_pulse/_setup_screen.html.erb +5 -5
- data/app/views/layouts/rails_pulse/application.html.erb +4 -4
- data/app/views/rails_pulse/components/_empty_state.html.erb +1 -1
- data/app/views/rails_pulse/components/_panel.html.erb +16 -6
- data/app/views/rails_pulse/components/_raw_data.html.erb +34 -0
- data/app/views/rails_pulse/dashboard/_chart_panel.html.erb +6 -8
- data/app/views/rails_pulse/dashboard/_deployments_panel.html.erb +64 -0
- data/app/views/rails_pulse/dashboard/_health_badge.html.erb +21 -10
- data/app/views/rails_pulse/dashboard/_storage_panel.html.erb +67 -0
- data/app/views/rails_pulse/dashboard/index.html.erb +22 -1
- data/app/views/rails_pulse/deployments/_status_badge.html.erb +5 -0
- data/app/views/rails_pulse/deployments/_table.html.erb +29 -0
- data/app/views/rails_pulse/deployments/index.html.erb +15 -0
- data/app/views/rails_pulse/deployments/show.html.erb +62 -0
- data/app/views/rails_pulse/exception_occurrences/show.html.erb +45 -0
- data/app/views/rails_pulse/exceptions/_backtrace.html.erb +33 -0
- data/app/views/rails_pulse/exceptions/_metric_cards.html.erb +6 -0
- data/app/views/rails_pulse/exceptions/_occurrences_table.html.erb +23 -0
- data/app/views/rails_pulse/exceptions/_status_badge.html.erb +6 -0
- data/app/views/rails_pulse/exceptions/_table.html.erb +33 -0
- data/app/views/rails_pulse/exceptions/index.html.erb +66 -0
- data/app/views/rails_pulse/exceptions/show.html.erb +52 -0
- data/app/views/rails_pulse/queries/_raw_data.html.erb +1 -23
- data/app/views/rails_pulse/requests/_table.html.erb +1 -1
- data/app/views/rails_pulse/routes/_requests_table.html.erb +5 -0
- data/app/views/rails_pulse/routes/_table.html.erb +22 -8
- data/app/views/rails_pulse/routes/index.html.erb +5 -1
- data/app/views/rails_pulse/routes/show.html.erb +5 -0
- data/app/views/rails_pulse/storage/show.html.erb +123 -0
- data/config/routes.rb +13 -4
- data/db/rails_pulse_migrate/20260506000001_create_rails_pulse_exceptions.rb +50 -0
- data/db/rails_pulse_migrate/20260507000001_add_actual_query_to_operations.rb +10 -5
- data/db/rails_pulse_migrate/20260610000001_add_controller_action_to_rails_pulse_routes.rb +8 -0
- data/db/rails_pulse_migrate/20260610000002_change_rails_pulse_routes_to_multi_verb_model.rb +185 -0
- data/db/rails_pulse_migrate/20260610000003_add_null_action_unique_index_to_routes.rb +32 -0
- data/db/rails_pulse_migrate/20260823000001_add_location_to_exception_groups.rb +12 -0
- data/db/rails_pulse_schema.rb +54 -6
- data/lib/generators/rails_pulse/base_methods.rb +2 -0
- data/lib/generators/rails_pulse/install_generator.rb +5 -0
- data/lib/generators/rails_pulse/schema_parser.rb +22 -2
- data/lib/generators/rails_pulse/templates/db/rails_pulse_schema.rb +54 -6
- data/lib/generators/rails_pulse/templates/migrations/upgrade_rails_pulse_tables.rb +1 -1
- data/lib/generators/rails_pulse/templates/rails_pulse.rb +157 -16
- data/lib/generators/rails_pulse/upgrade_generator.rb +166 -38
- data/lib/rails_pulse/cleanup_service.rb +110 -15
- data/lib/rails_pulse/configuration.rb +125 -6
- data/lib/rails_pulse/engine.rb +32 -17
- data/lib/rails_pulse/installers/config_updater.rb +202 -0
- data/lib/rails_pulse/job_run_collector.rb +43 -16
- data/lib/rails_pulse/middleware/asset_server.rb +11 -0
- data/lib/rails_pulse/middleware/request_collector.rb +9 -4
- data/lib/rails_pulse/packaged_assets.rb +147 -0
- data/lib/rails_pulse/route_indexes.rb +66 -0
- data/lib/rails_pulse/subscribers/exception_subscriber.rb +36 -0
- data/lib/rails_pulse/tracker.rb +29 -10
- data/lib/rails_pulse/version.rb +1 -1
- data/lib/rails_pulse.rb +1 -0
- data/lib/rails_pulse_server.ru +16 -47
- data/lib/tasks/rails_pulse.rake +83 -4
- data/lib/tasks/rails_pulse_assets.rake +15 -0
- data/lib/tasks/rails_pulse_tasks.rake +29 -0
- data/public/rails-pulse-assets/rails-pulse-icons.js +6 -2
- data/public/rails-pulse-assets/rails-pulse.css +1 -1
- data/public/rails-pulse-assets/rails-pulse.js +18 -117
- metadata +78 -37
- data/Rakefile +0 -554
- data/app/javascript/rails_pulse/controllers/form_controller.js +0 -39
- data/app/javascript/rails_pulse/controllers/period_selector_controller.js +0 -19
- data/app/javascript/rails_pulse/controllers/timezone_controller.js +0 -89
- data/app/javascript/rails_pulse/theme.js +0 -416
- data/config/brakeman.ignore +0 -190
- data/config/brakeman.yml +0 -68
- data/config/initializers/rails_pulse.rb +0 -287
- data/public/rails-pulse-assets/csp-test.js +0 -120
- data/public/rails-pulse-assets/rails-pulse-icons.js.map +0 -13
- data/public/rails-pulse-assets/rails-pulse.css.map +0 -1
- data/public/rails-pulse-assets/rails-pulse.js.map +0 -7
- data/vendor/assets/javascripts/rails-pulse-icons.js +0 -93
- data/vendor/assets/javascripts/rails-pulse-icons.js.map +0 -13
- data/vendor/assets/javascripts/rails-pulse.js +0 -157
- data/vendor/assets/javascripts/rails-pulse.js.map +0 -7
- data/vendor/assets/stylesheets/rails-pulse.css +0 -1
- data/vendor/assets/stylesheets/rails-pulse.css.map +0 -1
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
RailsPulse.configure do |config|
|
|
2
|
-
# ====================================================================================================
|
|
3
|
-
# GLOBAL CONFIGURATION
|
|
4
|
-
# ====================================================================================================
|
|
5
|
-
|
|
6
|
-
# Enable or disable Rails Pulse
|
|
7
|
-
config.enabled = true
|
|
8
|
-
|
|
9
|
-
# ====================================================================================================
|
|
10
|
-
# THRESHOLDS
|
|
11
|
-
# ====================================================================================================
|
|
12
|
-
# These thresholds are used to determine if a route, request, or query is slow, very slow, or critical.
|
|
13
|
-
# Values are in milliseconds (ms). Adjust these based on your application's performance requirements.
|
|
14
|
-
|
|
15
|
-
# Thresholds for an individual route
|
|
16
|
-
config.route_thresholds = {
|
|
17
|
-
slow: 500,
|
|
18
|
-
very_slow: 1500,
|
|
19
|
-
critical: 3000
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
# Thresholds for an individual request
|
|
23
|
-
config.request_thresholds = {
|
|
24
|
-
slow: 700,
|
|
25
|
-
very_slow: 2000,
|
|
26
|
-
critical: 4000
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
# Thresholds for an individual database query
|
|
30
|
-
config.query_thresholds = {
|
|
31
|
-
slow: 100,
|
|
32
|
-
very_slow: 500,
|
|
33
|
-
critical: 1000
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
# ====================================================================================================
|
|
37
|
-
# SERVICE LEVEL OBJECTIVES (SLO)
|
|
38
|
-
# ====================================================================================================
|
|
39
|
-
# Define Service Level Objectives to visualize performance targets on the dashboard.
|
|
40
|
-
# These SLOs appear as dashed threshold lines on the performance charts, color-matched
|
|
41
|
-
# to their percentile series (green for P95, blue for P99).
|
|
42
|
-
#
|
|
43
|
-
# SLO Configuration:
|
|
44
|
-
# :percentile - Must be 95 or 99 (binds to the matching chart series)
|
|
45
|
-
# :threshold - Maximum acceptable response time in milliseconds
|
|
46
|
-
|
|
47
|
-
# SLO for HTTP request response times (shown on Response Time Percentiles chart)
|
|
48
|
-
# config.service_level_objectives = [
|
|
49
|
-
# { percentile: 95, threshold: 200 },
|
|
50
|
-
# { percentile: 99, threshold: 500 }
|
|
51
|
-
# ]
|
|
52
|
-
|
|
53
|
-
# SLO for database query execution times (shown on Query Performance chart)
|
|
54
|
-
# Query SLOs should typically be 5-10x stricter than request SLOs
|
|
55
|
-
# config.query_service_level_objectives = [
|
|
56
|
-
# { percentile: 95, threshold: 50 },
|
|
57
|
-
# { percentile: 99, threshold: 100 }
|
|
58
|
-
# ]
|
|
59
|
-
|
|
60
|
-
# ====================================================================================================
|
|
61
|
-
# FILTERING
|
|
62
|
-
# ====================================================================================================
|
|
63
|
-
|
|
64
|
-
# Asset Tracking Configuration
|
|
65
|
-
# By default, Rails Pulse ignores asset requests (images, CSS, JS files) to focus on application performance.
|
|
66
|
-
# Set track_assets to true if you want to monitor asset delivery performance.
|
|
67
|
-
config.track_assets = false
|
|
68
|
-
|
|
69
|
-
# Custom asset patterns to ignore (in addition to the built-in defaults)
|
|
70
|
-
# Only applies when track_assets is false. Add patterns for app-specific asset paths.
|
|
71
|
-
config.custom_asset_patterns = [
|
|
72
|
-
# Example: ignore specific asset directories
|
|
73
|
-
# %r{^/uploads/},
|
|
74
|
-
# %r{^/media/},
|
|
75
|
-
# "/special-assets/"
|
|
76
|
-
]
|
|
77
|
-
|
|
78
|
-
# Rails Pulse Mount Path (optional)
|
|
79
|
-
# If Rails Pulse is mounted at a custom path, specify it here to prevent
|
|
80
|
-
# Rails Pulse from tracking its own requests. Leave as nil for default '/rails_pulse'.
|
|
81
|
-
# Examples:
|
|
82
|
-
# config.mount_path = "/admin/monitoring"
|
|
83
|
-
config.mount_path = nil
|
|
84
|
-
|
|
85
|
-
# Manual route filtering
|
|
86
|
-
# Specify additional routes, requests, or queries to ignore from performance tracking.
|
|
87
|
-
# Each array can include strings (exact matches) or regular expressions.
|
|
88
|
-
#
|
|
89
|
-
# Examples:
|
|
90
|
-
# config.ignored_routes = ["/health_check", %r{^/admin}]
|
|
91
|
-
# config.ignored_requests = ["GET /status", %r{POST /api/v1/.*}]
|
|
92
|
-
# config.ignored_queries = ["SELECT 1", %r{FROM \"schema_migrations\"}]
|
|
93
|
-
|
|
94
|
-
config.ignored_routes = []
|
|
95
|
-
config.ignored_requests = []
|
|
96
|
-
config.ignored_queries = []
|
|
97
|
-
|
|
98
|
-
# ====================================================================================================
|
|
99
|
-
# TAGGING
|
|
100
|
-
# ====================================================================================================
|
|
101
|
-
# Define custom tags for categorizing routes, requests, and queries.
|
|
102
|
-
# You can add any custom tags you want for filtering and organization.
|
|
103
|
-
#
|
|
104
|
-
# Tag names should be in present tense and describe the current state or category.
|
|
105
|
-
# Examples of good tag names:
|
|
106
|
-
# - "critical" (for high-priority endpoints)
|
|
107
|
-
# - "experimental" (for routes under development)
|
|
108
|
-
# - "deprecated" (for routes being phased out)
|
|
109
|
-
# - "external" (for third-party API calls)
|
|
110
|
-
# - "background" (for async job-related operations)
|
|
111
|
-
# - "admin" (for administrative routes)
|
|
112
|
-
# - "public" (for public-facing routes)
|
|
113
|
-
#
|
|
114
|
-
# Example configuration:
|
|
115
|
-
# config.tags = ["ignored", "critical", "experimental", "deprecated", "external", "admin"]
|
|
116
|
-
|
|
117
|
-
config.tags = [ "ignored", "critical", "experimental" ]
|
|
118
|
-
|
|
119
|
-
# ====================================================================================================
|
|
120
|
-
# BACKGROUND JOBS
|
|
121
|
-
# ====================================================================================================
|
|
122
|
-
# Configure background job monitoring and tracking.
|
|
123
|
-
# When enabled, Rails Pulse will track job executions, durations, failures, and retries.
|
|
124
|
-
# Supports ActiveJob, Sidekiq, and Delayed Job.
|
|
125
|
-
|
|
126
|
-
# Enable or disable background job tracking
|
|
127
|
-
config.track_jobs = false
|
|
128
|
-
|
|
129
|
-
# Thresholds for job execution times (in milliseconds)
|
|
130
|
-
config.job_thresholds = {
|
|
131
|
-
slow: 5_000, # 5 seconds
|
|
132
|
-
very_slow: 30_000, # 30 seconds
|
|
133
|
-
critical: 60_000 # 1 minute
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
# Job classes to ignore from tracking (by class name)
|
|
137
|
-
# Examples:
|
|
138
|
-
# config.ignored_jobs = ["ActionMailer::MailDeliveryJob", "MyApp::HealthCheckJob"]
|
|
139
|
-
config.ignored_jobs = []
|
|
140
|
-
|
|
141
|
-
# Queue names to ignore from tracking
|
|
142
|
-
# Examples:
|
|
143
|
-
# config.ignored_queues = ["low_priority", "mailers"]
|
|
144
|
-
config.ignored_queues = []
|
|
145
|
-
|
|
146
|
-
# Capture job arguments for debugging (may contain sensitive data)
|
|
147
|
-
# Set to false in production to avoid storing potentially sensitive information
|
|
148
|
-
config.capture_job_arguments = true
|
|
149
|
-
|
|
150
|
-
# ====================================================================================================
|
|
151
|
-
# DATABASE CONFIGURATION
|
|
152
|
-
# ====================================================================================================
|
|
153
|
-
# Configure Rails Pulse to use a separate database for performance monitoring data.
|
|
154
|
-
# This is optional but recommended for production applications to isolate performance
|
|
155
|
-
# data from your main application database.
|
|
156
|
-
#
|
|
157
|
-
# Uncomment and configure one of the following patterns:
|
|
158
|
-
|
|
159
|
-
# Option 1: Separate single database for Rails Pulse
|
|
160
|
-
# config.connects_to = {
|
|
161
|
-
# database: { writing: :rails_pulse, reading: :rails_pulse }
|
|
162
|
-
# }
|
|
163
|
-
|
|
164
|
-
# Option 2: Primary/replica configuration for Rails Pulse
|
|
165
|
-
# config.connects_to = {
|
|
166
|
-
# database: { writing: :rails_pulse_primary, reading: :rails_pulse_replica }
|
|
167
|
-
# }
|
|
168
|
-
|
|
169
|
-
# Don't forget to add the database configuration to config/database.yml:
|
|
170
|
-
#
|
|
171
|
-
# production:
|
|
172
|
-
# # ... your main database config ...
|
|
173
|
-
# rails_pulse:
|
|
174
|
-
# adapter: postgresql # or mysql2, sqlite3
|
|
175
|
-
# database: myapp_rails_pulse_production
|
|
176
|
-
# username: rails_pulse_user
|
|
177
|
-
# password: <%= Rails.application.credentials.dig(:rails_pulse, :database_password) %>
|
|
178
|
-
# host: localhost
|
|
179
|
-
# pool: 5
|
|
180
|
-
|
|
181
|
-
# ====================================================================================================
|
|
182
|
-
# AUTHENTICATION
|
|
183
|
-
# ====================================================================================================
|
|
184
|
-
# Configure authentication to secure access to the Rails Pulse dashboard.
|
|
185
|
-
# Authentication is ENABLED BY DEFAULT in production environments for security.
|
|
186
|
-
#
|
|
187
|
-
# If no authentication method is configured, Rails Pulse will use HTTP Basic Auth
|
|
188
|
-
# with credentials from RAILS_PULSE_USERNAME (default: 'admin') and RAILS_PULSE_PASSWORD
|
|
189
|
-
# environment variables. Set RAILS_PULSE_PASSWORD to enable this fallback.
|
|
190
|
-
#
|
|
191
|
-
# Uncomment and configure one of the following patterns based on your authentication system:
|
|
192
|
-
|
|
193
|
-
# Enable/disable authentication (enabled by default in production)
|
|
194
|
-
# config.authentication_enabled = Rails.env.production?
|
|
195
|
-
|
|
196
|
-
# Where to redirect unauthorized users
|
|
197
|
-
# config.authentication_redirect_path = "/"
|
|
198
|
-
|
|
199
|
-
# Custom authentication method - choose one of the examples below:
|
|
200
|
-
|
|
201
|
-
# Example 1: Devise with admin role check
|
|
202
|
-
# config.authentication_method = proc {
|
|
203
|
-
# unless user_signed_in? && current_user.admin?
|
|
204
|
-
# redirect_to main_app.root_path, alert: "Access denied"
|
|
205
|
-
# end
|
|
206
|
-
# }
|
|
207
|
-
|
|
208
|
-
# Example 2: Custom session-based authentication
|
|
209
|
-
# config.authentication_method = proc {
|
|
210
|
-
# unless session[:user_id] && User.find_by(id: session[:user_id])&.admin?
|
|
211
|
-
# redirect_to main_app.login_path, alert: "Please log in as an admin"
|
|
212
|
-
# end
|
|
213
|
-
# }
|
|
214
|
-
|
|
215
|
-
# Example 3: Warden authentication
|
|
216
|
-
# config.authentication_method = proc {
|
|
217
|
-
# warden.authenticate!(:scope => :admin)
|
|
218
|
-
# }
|
|
219
|
-
|
|
220
|
-
# Example 4: Basic HTTP authentication
|
|
221
|
-
# config.authentication_method = proc {
|
|
222
|
-
# authenticate_or_request_with_http_basic do |username, password|
|
|
223
|
-
# username == ENV['RAILS_PULSE_USERNAME'] && password == ENV['RAILS_PULSE_PASSWORD']
|
|
224
|
-
# end
|
|
225
|
-
# }
|
|
226
|
-
|
|
227
|
-
# Example 5: Custom authorization check
|
|
228
|
-
# config.authentication_method = proc {
|
|
229
|
-
# current_user = User.find_by(id: session[:user_id])
|
|
230
|
-
# unless current_user&.can_access_rails_pulse?
|
|
231
|
-
# render plain: "Forbidden", status: :forbidden
|
|
232
|
-
# end
|
|
233
|
-
# }
|
|
234
|
-
|
|
235
|
-
# ====================================================================================================
|
|
236
|
-
# DEPLOYMENT TRACKING
|
|
237
|
-
# ====================================================================================================
|
|
238
|
-
# Record deployments to display vertical marker lines on performance charts, making it easy
|
|
239
|
-
# to correlate performance changes with specific releases.
|
|
240
|
-
#
|
|
241
|
-
# API token for the POST /rails_pulse/deployments endpoint.
|
|
242
|
-
# When set, requests must include an `X-Rails-Pulse-Token` header matching this value.
|
|
243
|
-
# When nil, the endpoint falls back to the standard dashboard authentication.
|
|
244
|
-
#
|
|
245
|
-
# Set this in your CI/CD pipeline and store the value in credentials or an environment variable:
|
|
246
|
-
# config.deployment_api_token = Rails.application.credentials.dig(:rails_pulse, :deployment_api_token)
|
|
247
|
-
# config.deployment_api_token = ENV["RAILS_PULSE_DEPLOYMENT_TOKEN"]
|
|
248
|
-
#
|
|
249
|
-
# Record a deployment from your CI/CD pipeline:
|
|
250
|
-
# curl -X POST https://yourapp.com/rails_pulse/deployments \
|
|
251
|
-
# -H "X-Rails-Pulse-Token: $RAILS_PULSE_DEPLOYMENT_TOKEN" \
|
|
252
|
-
# -H "Content-Type: application/json" \
|
|
253
|
-
# -d '{"deployment": {"revision": "abc1234", "metadata": {"environment": "production"}}}'
|
|
254
|
-
#
|
|
255
|
-
# Or use the rake task for simple shell-based deploys:
|
|
256
|
-
# rake rails_pulse:record_deployment[abc1234]
|
|
257
|
-
|
|
258
|
-
# config.deployment_api_token = ENV["RAILS_PULSE_DEPLOYMENT_TOKEN"]
|
|
259
|
-
|
|
260
|
-
# ====================================================================================================
|
|
261
|
-
# DATA CLEANUP
|
|
262
|
-
# ====================================================================================================
|
|
263
|
-
# Configure automatic cleanup of old performance data to manage database size.
|
|
264
|
-
# Rails Pulse provides two cleanup mechanisms that work together:
|
|
265
|
-
#
|
|
266
|
-
# 1. Time-based cleanup: Delete records older than the retention period
|
|
267
|
-
# 2. Count-based cleanup: Keep only the specified number of records per table
|
|
268
|
-
#
|
|
269
|
-
# Cleanup order respects foreign key constraints:
|
|
270
|
-
# operations → requests → queries/routes
|
|
271
|
-
|
|
272
|
-
# Enable or disable automatic data cleanup
|
|
273
|
-
config.archiving_enabled = true
|
|
274
|
-
|
|
275
|
-
# Time-based retention - delete records older than this period
|
|
276
|
-
config.full_retention_period = 2.weeks
|
|
277
|
-
|
|
278
|
-
# Count-based retention - maximum records to keep per table
|
|
279
|
-
# After time-based cleanup, if tables still exceed these limits,
|
|
280
|
-
# the oldest remaining records will be deleted to stay under the limit
|
|
281
|
-
config.max_table_records = {
|
|
282
|
-
rails_pulse_requests: 10000, # HTTP requests (moderate volume)
|
|
283
|
-
rails_pulse_operations: 50000, # Operations within requests (high volume)
|
|
284
|
-
rails_pulse_routes: 1000, # Unique routes (low volume)
|
|
285
|
-
rails_pulse_queries: 500 # Normalized SQL queries (low volume)
|
|
286
|
-
}
|
|
287
|
-
end
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
// CSP Test functionality
|
|
2
|
-
// Tests asset loading and AJAX requests under strict Content Security Policy
|
|
3
|
-
|
|
4
|
-
document.addEventListener('DOMContentLoaded', function() {
|
|
5
|
-
// Check asset loading status
|
|
6
|
-
checkAssetLoadingStatus();
|
|
7
|
-
|
|
8
|
-
// Setup AJAX button
|
|
9
|
-
setupAjaxButton();
|
|
10
|
-
|
|
11
|
-
// Check for CSP violations
|
|
12
|
-
checkCspViolations();
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
function checkAssetLoadingStatus() {
|
|
16
|
-
const cssStatus = document.getElementById('css-status');
|
|
17
|
-
const jsStatus = document.getElementById('js-status');
|
|
18
|
-
const iconsStatus = document.getElementById('icons-status');
|
|
19
|
-
const stimulusStatus = document.getElementById('stimulus-status');
|
|
20
|
-
|
|
21
|
-
// Check if CSS is loaded by testing if styles are applied
|
|
22
|
-
if (cssStatus) {
|
|
23
|
-
const testElement = document.querySelector('.card');
|
|
24
|
-
if (testElement && getComputedStyle(testElement).backgroundColor !== 'rgba(0, 0, 0, 0)') {
|
|
25
|
-
cssStatus.textContent = 'Loaded';
|
|
26
|
-
cssStatus.className = 'badge badge--success';
|
|
27
|
-
} else {
|
|
28
|
-
cssStatus.textContent = 'Failed';
|
|
29
|
-
cssStatus.className = 'badge badge--error';
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Check if JS is loaded (this script proves it)
|
|
34
|
-
if (jsStatus) {
|
|
35
|
-
jsStatus.textContent = 'Loaded';
|
|
36
|
-
jsStatus.className = 'badge badge--success';
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Check if icons script is loaded
|
|
40
|
-
if (iconsStatus) {
|
|
41
|
-
if (typeof window.RailsPulseIcons !== 'undefined') {
|
|
42
|
-
iconsStatus.textContent = 'Loaded';
|
|
43
|
-
iconsStatus.className = 'badge badge--success';
|
|
44
|
-
} else {
|
|
45
|
-
iconsStatus.textContent = 'Failed';
|
|
46
|
-
iconsStatus.className = 'badge badge--error';
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Check if Stimulus is active
|
|
51
|
-
if (stimulusStatus) {
|
|
52
|
-
if (window.Stimulus && typeof window.Stimulus.getControllerForElementAndIdentifier === 'function') {
|
|
53
|
-
stimulusStatus.textContent = 'Active';
|
|
54
|
-
stimulusStatus.className = 'badge badge--success';
|
|
55
|
-
} else {
|
|
56
|
-
stimulusStatus.textContent = 'Inactive';
|
|
57
|
-
stimulusStatus.className = 'badge badge--error';
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function setupAjaxButton() {
|
|
63
|
-
const ajaxButton = document.getElementById('ajax-test-btn');
|
|
64
|
-
const ajaxResult = document.getElementById('ajax-result');
|
|
65
|
-
|
|
66
|
-
if (ajaxButton && ajaxResult) {
|
|
67
|
-
ajaxButton.addEventListener('click', function() {
|
|
68
|
-
// Update UI to show loading state
|
|
69
|
-
ajaxButton.disabled = true;
|
|
70
|
-
ajaxButton.textContent = 'Loading...';
|
|
71
|
-
ajaxResult.innerHTML = '<span class="text-subtle">Making AJAX request...</span>';
|
|
72
|
-
|
|
73
|
-
// Make AJAX request to the JSON endpoint
|
|
74
|
-
fetch('/rails_pulse/csp_test.json', {
|
|
75
|
-
method: 'GET',
|
|
76
|
-
headers: {
|
|
77
|
-
'Accept': 'application/json',
|
|
78
|
-
'Content-Type': 'application/json'
|
|
79
|
-
},
|
|
80
|
-
credentials: 'same-origin'
|
|
81
|
-
})
|
|
82
|
-
.then(response => {
|
|
83
|
-
if (!response.ok) {
|
|
84
|
-
throw new Error('Network response was not ok');
|
|
85
|
-
}
|
|
86
|
-
return response.json();
|
|
87
|
-
})
|
|
88
|
-
.then(data => {
|
|
89
|
-
// Success - display the success message
|
|
90
|
-
ajaxResult.innerHTML = '<span class="text-success">AJAX request completed successfully</span>';
|
|
91
|
-
ajaxButton.textContent = 'Test AJAX Loading';
|
|
92
|
-
ajaxButton.disabled = false;
|
|
93
|
-
})
|
|
94
|
-
.catch(error => {
|
|
95
|
-
// Error handling
|
|
96
|
-
console.error('AJAX request failed:', error);
|
|
97
|
-
ajaxResult.innerHTML = '<span class="text-error">AJAX request failed: ' + error.message + '</span>';
|
|
98
|
-
ajaxButton.textContent = 'Test AJAX Loading';
|
|
99
|
-
ajaxButton.disabled = false;
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function checkCspViolations() {
|
|
106
|
-
const violationCount = document.getElementById('violation-count');
|
|
107
|
-
|
|
108
|
-
if (violationCount) {
|
|
109
|
-
// Start with 0 violations and mark as success immediately
|
|
110
|
-
let violations = 0;
|
|
111
|
-
violationCount.className = 'badge badge--success';
|
|
112
|
-
|
|
113
|
-
// Listen for CSP violations
|
|
114
|
-
document.addEventListener('securitypolicyviolation', function() {
|
|
115
|
-
violations++;
|
|
116
|
-
violationCount.textContent = violations.toString();
|
|
117
|
-
violationCount.className = 'badge badge--error';
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"file": "rails-pulse-icons.js",
|
|
4
|
-
"sourceRoot": "",
|
|
5
|
-
"sources": [
|
|
6
|
-
"rails-pulse-icons.js"
|
|
7
|
-
],
|
|
8
|
-
"names": [],
|
|
9
|
-
"mappings": "",
|
|
10
|
-
"sourcesContent": [
|
|
11
|
-
"// Rails Pulse Icons Bundle - Auto-generated\n// Contains 37 SVG icons for Rails Pulse\n\n(function() {\n 'use strict';\n\n // Icon data\n const icons = {\n \"menu\": \"<path d=\\\"M4 5h16\\\" /><path d=\\\"M4 12h16\\\" /><path d=\\\"M4 19h16\\\" />\",\n \"sun\": \"<circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"4\\\" /><path d=\\\"M12 2v2\\\" /><path d=\\\"M12 20v2\\\" /><path d=\\\"m4.93 4.93 1.41 1.41\\\" /><path d=\\\"m17.66 17.66 1.41 1.41\\\" /><path d=\\\"M2 12h2\\\" /><path d=\\\"M20 12h2\\\" /><path d=\\\"m6.34 17.66-1.41 1.41\\\" /><path d=\\\"m19.07 4.93-1.41 1.41\\\" />\",\n \"moon\": \"<path d=\\\"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401\\\" />\",\n \"chevron-right\": \"<path d=\\\"m9 18 6-6-6-6\\\" />\",\n \"chevron-left\": \"<path d=\\\"m15 18-6-6 6-6\\\" />\",\n \"chevron-down\": \"<path d=\\\"m6 9 6 6 6-6\\\" />\",\n \"chevron-up\": \"<path d=\\\"m18 15-6-6-6 6\\\" />\",\n \"chevrons-left\": \"<path d=\\\"m11 17-5-5 5-5\\\" /><path d=\\\"m18 17-5-5 5-5\\\" />\",\n \"chevrons-right\": \"<path d=\\\"m6 17 5-5-5-5\\\" /><path d=\\\"m13 17 5-5-5-5\\\" />\",\n \"loader-circle\": \"<path d=\\\"M12 2v4\\\" /><path d=\\\"m16.2 7.8 2.9-2.9\\\" /><path d=\\\"M18 12h4\\\" /><path d=\\\"m16.2 16.2 2.9 2.9\\\" /><path d=\\\"M12 18v4\\\" /><path d=\\\"m4.9 19.1 2.9-2.9\\\" /><path d=\\\"M2 12h4\\\" /><path d=\\\"m4.9 4.9 2.9 2.9\\\" />\",\n \"search\": \"<path d=\\\"m21 21-4.34-4.34\\\" /><circle cx=\\\"11\\\" cy=\\\"11\\\" r=\\\"8\\\" />\",\n \"list-filter\": \"<path d=\\\"M2 5h20\\\" /><path d=\\\"M6 12h12\\\" /><path d=\\\"M9 19h6\\\" />\",\n \"list-filter-plus\": \"<path d=\\\"M12 5H2\\\" /><path d=\\\"M6 12h12\\\" /><path d=\\\"M9 19h6\\\" /><path d=\\\"M16 5h6\\\" /><path d=\\\"M19 8V2\\\" />\",\n \"x\": \"<path d=\\\"M18 6 6 18\\\" /><path d=\\\"m6 6 12 12\\\" />\",\n \"x-circle\": \"<circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"10\\\" /><path d=\\\"m15 9-6 6\\\" /><path d=\\\"m9 9 6 6\\\" />\",\n \"check\": \"<path d=\\\"M20 6 9 17l-5-5\\\" />\",\n \"alert-circle\": \"<circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"10\\\" /><line x1=\\\"12\\\" x2=\\\"12\\\" y1=\\\"8\\\" y2=\\\"12\\\" /><line x1=\\\"12\\\" x2=\\\"12.01\\\" y1=\\\"16\\\" y2=\\\"16\\\" />\",\n \"alert-triangle\": \"<path d=\\\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\\\" /><path d=\\\"M12 9v4\\\" /><path d=\\\"M12 17h.01\\\" />\",\n \"info\": \"<circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"10\\\" /><path d=\\\"M12 16v-4\\\" /><path d=\\\"M12 8h.01\\\" />\",\n \"external-link\": \"<path d=\\\"M15 3h6v6\\\" /><path d=\\\"M10 14 21 3\\\" /><path d=\\\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\\\" />\",\n \"download\": \"<path d=\\\"M12 15V3\\\" /><path d=\\\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\\\" /><path d=\\\"m7 10 5 5 5-5\\\" />\",\n \"refresh-cw\": \"<path d=\\\"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8\\\" /><path d=\\\"M21 3v5h-5\\\" /><path d=\\\"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16\\\" /><path d=\\\"M8 16H3v5\\\" />\",\n \"clock\": \"<path d=\\\"M12 6v6l4 2\\\" /><circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"10\\\" />\",\n \"database\": \"<ellipse cx=\\\"12\\\" cy=\\\"5\\\" rx=\\\"9\\\" ry=\\\"3\\\" /><path d=\\\"M3 5V19A9 3 0 0 0 21 19V5\\\" /><path d=\\\"M3 12A9 3 0 0 0 21 12\\\" />\",\n \"server\": \"<rect width=\\\"20\\\" height=\\\"8\\\" x=\\\"2\\\" y=\\\"2\\\" rx=\\\"2\\\" ry=\\\"2\\\" /><rect width=\\\"20\\\" height=\\\"8\\\" x=\\\"2\\\" y=\\\"14\\\" rx=\\\"2\\\" ry=\\\"2\\\" /><line x1=\\\"6\\\" x2=\\\"6.01\\\" y1=\\\"6\\\" y2=\\\"6\\\" /><line x1=\\\"6\\\" x2=\\\"6.01\\\" y1=\\\"18\\\" y2=\\\"18\\\" />\",\n \"activity\": \"<path d=\\\"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2\\\" />\",\n \"layout-dashboard\": \"<rect width=\\\"7\\\" height=\\\"9\\\" x=\\\"3\\\" y=\\\"3\\\" rx=\\\"1\\\" /><rect width=\\\"7\\\" height=\\\"5\\\" x=\\\"14\\\" y=\\\"3\\\" rx=\\\"1\\\" /><rect width=\\\"7\\\" height=\\\"9\\\" x=\\\"14\\\" y=\\\"12\\\" rx=\\\"1\\\" /><rect width=\\\"7\\\" height=\\\"5\\\" x=\\\"3\\\" y=\\\"16\\\" rx=\\\"1\\\" />\",\n \"audio-lines\": \"<path d=\\\"M2 10v3\\\" /><path d=\\\"M6 6v11\\\" /><path d=\\\"M10 3v18\\\" /><path d=\\\"M14 8v7\\\" /><path d=\\\"M18 5v13\\\" /><path d=\\\"M22 10v3\\\" />\",\n \"message-circle-question\": \"<path d=\\\"M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719\\\" /><path d=\\\"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3\\\" /><path d=\\\"M12 17h.01\\\" />\",\n \"route\": \"<circle cx=\\\"6\\\" cy=\\\"19\\\" r=\\\"3\\\" /><path d=\\\"M9 19h8.5a3.5 3.5 0 0 0 0-7h-11a3.5 3.5 0 0 1 0-7H15\\\" /><circle cx=\\\"18\\\" cy=\\\"5\\\" r=\\\"3\\\" />\",\n \"trending-up\": \"<path d=\\\"M16 7h6v6\\\" /><path d=\\\"m22 7-8.5 8.5-5-5L2 17\\\" />\",\n \"trending-down\": \"<path d=\\\"M16 17h6v-6\\\" /><path d=\\\"m22 17-8.5-8.5-5 5L2 7\\\" />\",\n \"move-right\": \"<path d=\\\"M18 8L22 12L18 16\\\" /><path d=\\\"M2 12H22\\\" />\",\n \"eye\": \"<path d=\\\"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0\\\" /><circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"3\\\" />\",\n \"zap\": \"<path d=\\\"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z\\\" />\",\n \"shield-check\": \"<path d=\\\"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z\\\" /><path d=\\\"m9 12 2 2 4-4\\\" />\",\n \"bell\": \"<path d=\\\"M10.268 21a2 2 0 0 0 3.464 0\\\" /><path d=\\\"M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326\\\" />\"\n};\n\n // Global icon registry\n window.RailsPulseIcons = {\n icons: icons,\n\n // Get icon SVG content\n get: function(name) {\n return icons[name] || null;\n },\n\n // Check if icon exists\n has: function(name) {\n return name in icons;\n },\n\n // Get all icon names\n list: function() {\n return Object.keys(icons);\n },\n\n // Render icon to element (CSP-safe)\n render: function(name, element, options = {}) {\n const svgContent = this.get(name);\n if (!svgContent || !element) return false;\n\n // Create SVG element\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttribute('width', options.width || '24');\n svg.setAttribute('height', options.height || '24');\n svg.setAttribute('viewBox', '0 0 24 24');\n svg.setAttribute('fill', 'none');\n svg.setAttribute('stroke', 'currentColor');\n svg.setAttribute('stroke-width', '2');\n svg.setAttribute('stroke-linecap', 'round');\n svg.setAttribute('stroke-linejoin', 'round');\n\n // Add icon content\n svg.innerHTML = svgContent;\n\n // Replace element content\n element.innerHTML = '';\n element.appendChild(svg);\n\n return true;\n }\n };\n})();\n"
|
|
12
|
-
]
|
|
13
|
-
}
|