rails_pulse 0.2.4 → 0.2.5.pre.pre.3
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/README.md +269 -12
- data/Rakefile +142 -8
- data/app/assets/stylesheets/rails_pulse/components/table.css +16 -1
- data/app/assets/stylesheets/rails_pulse/components/tags.css +7 -2
- data/app/assets/stylesheets/rails_pulse/components/utilities.css +3 -0
- data/app/controllers/concerns/chart_table_concern.rb +2 -1
- data/app/controllers/rails_pulse/application_controller.rb +11 -1
- data/app/controllers/rails_pulse/assets_controller.rb +18 -2
- data/app/controllers/rails_pulse/job_runs_controller.rb +37 -0
- data/app/controllers/rails_pulse/jobs_controller.rb +80 -0
- data/app/controllers/rails_pulse/operations_controller.rb +43 -31
- data/app/controllers/rails_pulse/queries_controller.rb +1 -1
- data/app/controllers/rails_pulse/requests_controller.rb +3 -9
- data/app/controllers/rails_pulse/routes_controller.rb +1 -1
- data/app/controllers/rails_pulse/tags_controller.rb +31 -5
- data/app/helpers/rails_pulse/application_helper.rb +32 -1
- data/app/helpers/rails_pulse/breadcrumbs_helper.rb +15 -1
- data/app/helpers/rails_pulse/status_helper.rb +16 -0
- data/app/helpers/rails_pulse/tags_helper.rb +39 -1
- data/app/javascript/rails_pulse/controllers/chart_controller.js +112 -8
- data/app/models/concerns/rails_pulse/taggable.rb +25 -2
- data/app/models/rails_pulse/charts/operations_chart.rb +33 -0
- data/app/models/rails_pulse/dashboard/charts/p95_response_time.rb +1 -2
- data/app/models/rails_pulse/dashboard/tables/slow_routes.rb +1 -1
- data/app/models/rails_pulse/job.rb +85 -0
- data/app/models/rails_pulse/job_run.rb +76 -0
- data/app/models/rails_pulse/jobs/cards/average_duration.rb +85 -0
- data/app/models/rails_pulse/jobs/cards/base.rb +70 -0
- data/app/models/rails_pulse/jobs/cards/failure_rate.rb +85 -0
- data/app/models/rails_pulse/jobs/cards/total_jobs.rb +74 -0
- data/app/models/rails_pulse/jobs/cards/total_runs.rb +48 -0
- data/app/models/rails_pulse/operation.rb +16 -3
- data/app/models/rails_pulse/queries/cards/average_query_times.rb +3 -3
- data/app/models/rails_pulse/queries/cards/execution_rate.rb +1 -1
- data/app/models/rails_pulse/queries/cards/percentile_query_times.rb +1 -1
- data/app/models/rails_pulse/queries/tables/index.rb +2 -1
- data/app/models/rails_pulse/query.rb +10 -1
- data/app/models/rails_pulse/routes/cards/average_response_times.rb +3 -2
- data/app/models/rails_pulse/routes/cards/error_rate_per_route.rb +1 -1
- data/app/models/rails_pulse/routes/cards/percentile_response_times.rb +1 -1
- data/app/models/rails_pulse/routes/cards/request_count_totals.rb +1 -1
- data/app/models/rails_pulse/routes/tables/index.rb +2 -1
- data/app/models/rails_pulse/summary.rb +10 -3
- data/app/services/rails_pulse/summary_service.rb +46 -0
- data/app/views/layouts/rails_pulse/_menu_items.html.erb +7 -0
- data/app/views/layouts/rails_pulse/application.html.erb +23 -0
- data/app/views/rails_pulse/components/_active_filters.html.erb +7 -6
- data/app/views/rails_pulse/components/_page_header.html.erb +8 -7
- data/app/views/rails_pulse/components/_table.html.erb +7 -4
- data/app/views/rails_pulse/dashboard/index.html.erb +1 -1
- data/app/views/rails_pulse/job_runs/_operations.html.erb +78 -0
- data/app/views/rails_pulse/job_runs/index.html.erb +3 -0
- data/app/views/rails_pulse/job_runs/show.html.erb +51 -0
- data/app/views/rails_pulse/jobs/_job_runs_table.html.erb +35 -0
- data/app/views/rails_pulse/jobs/_table.html.erb +43 -0
- data/app/views/rails_pulse/jobs/index.html.erb +34 -0
- data/app/views/rails_pulse/jobs/show.html.erb +49 -0
- data/app/views/rails_pulse/operations/_operation_analysis_application.html.erb +29 -27
- data/app/views/rails_pulse/operations/_operation_analysis_view.html.erb +11 -9
- data/app/views/rails_pulse/operations/show.html.erb +10 -8
- data/app/views/rails_pulse/queries/_table.html.erb +3 -3
- data/app/views/rails_pulse/requests/_table.html.erb +6 -6
- data/app/views/rails_pulse/routes/_table.html.erb +3 -3
- data/app/views/rails_pulse/routes/show.html.erb +1 -1
- data/app/views/rails_pulse/tags/_tag_manager.html.erb +7 -14
- data/config/brakeman.ignore +213 -0
- data/config/brakeman.yml +68 -0
- data/config/initializers/rails_pulse.rb +52 -0
- data/config/routes.rb +6 -0
- data/db/rails_pulse_migrate/20250113000000_add_jobs_to_rails_pulse.rb +95 -0
- data/db/rails_pulse_migrate/20250122000000_add_query_fingerprinting.rb +150 -0
- data/db/rails_pulse_migrate/20250202000000_add_index_to_request_uuid.rb +14 -0
- data/db/rails_pulse_schema.rb +186 -103
- data/lib/generators/rails_pulse/templates/db/rails_pulse_schema.rb +186 -103
- data/lib/generators/rails_pulse/templates/migrations/install_rails_pulse_tables.rb +30 -1
- data/lib/generators/rails_pulse/templates/rails_pulse.rb +31 -0
- data/lib/rails_pulse/active_job_extensions.rb +13 -0
- data/lib/rails_pulse/adapters/delayed_job_plugin.rb +25 -0
- data/lib/rails_pulse/adapters/sidekiq_middleware.rb +41 -0
- data/lib/rails_pulse/cleanup_service.rb +65 -0
- data/lib/rails_pulse/configuration.rb +80 -7
- data/lib/rails_pulse/engine.rb +34 -3
- data/lib/rails_pulse/extensions/active_record.rb +82 -0
- data/lib/rails_pulse/job_run_collector.rb +172 -0
- data/lib/rails_pulse/middleware/request_collector.rb +20 -43
- data/lib/rails_pulse/subscribers/operation_subscriber.rb +11 -5
- data/lib/rails_pulse/tracker.rb +82 -0
- data/lib/rails_pulse/version.rb +1 -1
- data/lib/rails_pulse.rb +2 -0
- data/lib/rails_pulse_server.ru +107 -0
- data/lib/tasks/rails_pulse_benchmark.rake +382 -0
- data/public/rails-pulse-assets/rails-pulse-icons.js +3 -2
- data/public/rails-pulse-assets/rails-pulse-icons.js.map +1 -1
- data/public/rails-pulse-assets/rails-pulse.css +1 -1
- data/public/rails-pulse-assets/rails-pulse.css.map +1 -1
- data/public/rails-pulse-assets/rails-pulse.js +1 -1
- data/public/rails-pulse-assets/rails-pulse.js.map +3 -3
- metadata +37 -9
- data/app/models/rails_pulse/requests/charts/operations_chart.rb +0 -35
- data/db/migrate/20250930105043_install_rails_pulse_tables.rb +0 -23
data/db/rails_pulse_schema.rb
CHANGED
|
@@ -3,128 +3,211 @@
|
|
|
3
3
|
# Load with: rails db:schema:load:rails_pulse or db:prepare
|
|
4
4
|
|
|
5
5
|
RailsPulse::Schema = lambda do |connection|
|
|
6
|
+
adapter = connection.adapter_name.downcase
|
|
6
7
|
# Skip if all tables already exist to prevent conflicts
|
|
7
|
-
required_tables = [ :rails_pulse_routes, :rails_pulse_queries, :rails_pulse_requests, :rails_pulse_operations, :rails_pulse_summaries ]
|
|
8
|
+
required_tables = [ :rails_pulse_routes, :rails_pulse_queries, :rails_pulse_requests, :rails_pulse_operations, :rails_pulse_jobs, :rails_pulse_job_runs, :rails_pulse_summaries ]
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
# Check which tables already exist
|
|
11
|
+
existing_tables = required_tables.select { |table| connection.table_exists?(table) }
|
|
12
|
+
missing_tables = required_tables - existing_tables
|
|
13
|
+
|
|
14
|
+
# Always log for transparency (not just in CI)
|
|
15
|
+
if existing_tables.any?
|
|
16
|
+
puts "[RailsPulse::Schema] Existing tables detected: #{existing_tables.join(', ')}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
if missing_tables.any?
|
|
20
|
+
puts "[RailsPulse::Schema] Creating missing tables: #{missing_tables.join(', ')}"
|
|
14
21
|
end
|
|
15
22
|
|
|
16
|
-
|
|
23
|
+
# If all tables exist, skip creation entirely
|
|
24
|
+
if missing_tables.empty?
|
|
25
|
+
puts "[RailsPulse::Schema] All Rails Pulse tables already exist. Skipping schema load."
|
|
26
|
+
return
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
unless connection.table_exists?(:rails_pulse_routes)
|
|
30
|
+
connection.create_table :rails_pulse_routes do |t|
|
|
31
|
+
t.string :method, null: false, comment: "HTTP method (e.g., GET, POST)"
|
|
32
|
+
t.string :path, null: false, comment: "Request path (e.g., /posts/index)"
|
|
33
|
+
t.text :tags, comment: "JSON array of tags for filtering and categorization"
|
|
34
|
+
t.timestamps
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
connection.add_index :rails_pulse_routes, [ :method, :path ], unique: true, name: "index_rails_pulse_routes_on_method_and_path"
|
|
38
|
+
end
|
|
17
39
|
|
|
18
|
-
connection.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
40
|
+
unless connection.table_exists?(:rails_pulse_queries)
|
|
41
|
+
connection.create_table :rails_pulse_queries do |t|
|
|
42
|
+
t.string :hashed_sql, limit: 32, null: false, comment: "MD5 hash of normalized SQL for fast lookups and uniqueness"
|
|
43
|
+
t.text :normalized_sql, null: false, comment: "Full normalized SQL query string (e.g., SELECT * FROM users WHERE id = ?)"
|
|
44
|
+
t.datetime :analyzed_at, comment: "When query analysis was last performed"
|
|
45
|
+
t.text :explain_plan, comment: "EXPLAIN output from actual SQL execution"
|
|
46
|
+
t.text :issues, comment: "JSON array of detected performance issues"
|
|
47
|
+
t.text :metadata, comment: "JSON object containing query complexity metrics"
|
|
48
|
+
t.text :query_stats, comment: "JSON object with query characteristics analysis"
|
|
49
|
+
t.text :backtrace_analysis, comment: "JSON object with call chain and N+1 detection"
|
|
50
|
+
t.text :index_recommendations, comment: "JSON array of database index recommendations"
|
|
51
|
+
t.text :n_plus_one_analysis, comment: "JSON object with enhanced N+1 query detection results"
|
|
52
|
+
t.text :suggestions, comment: "JSON array of optimization recommendations"
|
|
53
|
+
t.text :tags, comment: "JSON array of tags for filtering and categorization"
|
|
54
|
+
t.timestamps
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
connection.add_index :rails_pulse_queries, :hashed_sql, unique: true, name: "index_rails_pulse_queries_on_hashed_sql"
|
|
23
58
|
end
|
|
24
59
|
|
|
25
|
-
connection.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
60
|
+
unless connection.table_exists?(:rails_pulse_requests)
|
|
61
|
+
connection.create_table :rails_pulse_requests do |t|
|
|
62
|
+
t.references :route, null: false, foreign_key: { to_table: :rails_pulse_routes }, comment: "Link to the route"
|
|
63
|
+
t.decimal :duration, precision: 15, scale: 6, null: false, comment: "Total request duration in milliseconds"
|
|
64
|
+
t.integer :status, null: false, comment: "HTTP status code (e.g., 200, 500)"
|
|
65
|
+
t.boolean :is_error, null: false, default: false, comment: "True if status >= 500"
|
|
66
|
+
t.string :request_uuid, null: false, comment: "Unique identifier for the request (e.g., UUID)"
|
|
67
|
+
t.string :controller_action, comment: "Controller and action handling the request (e.g., PostsController#show)"
|
|
68
|
+
t.timestamp :occurred_at, null: false, comment: "When the request started"
|
|
69
|
+
t.text :tags, comment: "JSON array of tags for filtering and categorization"
|
|
70
|
+
t.timestamps
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
connection.add_index :rails_pulse_requests, :occurred_at, name: "index_rails_pulse_requests_on_occurred_at"
|
|
74
|
+
connection.add_index :rails_pulse_requests, :request_uuid, unique: true, name: "index_rails_pulse_requests_on_request_uuid"
|
|
75
|
+
connection.add_index :rails_pulse_requests, [ :route_id, :occurred_at ], name: "index_rails_pulse_requests_on_route_id_and_occurred_at"
|
|
40
76
|
end
|
|
41
77
|
|
|
42
|
-
connection.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
78
|
+
unless connection.table_exists?(:rails_pulse_jobs)
|
|
79
|
+
connection.create_table :rails_pulse_jobs do |t|
|
|
80
|
+
t.string :name, null: false, comment: "Job class name"
|
|
81
|
+
t.string :queue_name, comment: "Default queue"
|
|
82
|
+
t.text :description, comment: "Optional description"
|
|
83
|
+
t.integer :runs_count, null: false, default: 0, comment: "Cache of total runs"
|
|
84
|
+
t.integer :failures_count, null: false, default: 0, comment: "Cache of failed runs"
|
|
85
|
+
t.integer :retries_count, null: false, default: 0, comment: "Cache of retried runs"
|
|
86
|
+
t.decimal :avg_duration, precision: 15, scale: 6, comment: "Average duration in milliseconds"
|
|
87
|
+
t.text :tags, comment: "JSON array of tags"
|
|
88
|
+
t.timestamps
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
connection.add_index :rails_pulse_jobs, :name, unique: true, name: "index_rails_pulse_jobs_on_name"
|
|
92
|
+
connection.add_index :rails_pulse_jobs, :queue_name, name: "index_rails_pulse_jobs_on_queue"
|
|
93
|
+
connection.add_index :rails_pulse_jobs, :runs_count, name: "index_rails_pulse_jobs_on_runs_count"
|
|
54
94
|
end
|
|
55
95
|
|
|
56
|
-
connection.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
96
|
+
unless connection.table_exists?(:rails_pulse_job_runs)
|
|
97
|
+
connection.create_table :rails_pulse_job_runs do |t|
|
|
98
|
+
t.references :job, null: false, foreign_key: { to_table: :rails_pulse_jobs }, comment: "Link to job definition"
|
|
99
|
+
t.string :run_id, null: false, comment: "Adapter specific run id"
|
|
100
|
+
t.decimal :duration, precision: 15, scale: 6, comment: "Execution duration in milliseconds"
|
|
101
|
+
t.string :status, null: false, comment: "Execution status"
|
|
102
|
+
t.string :error_class, comment: "Error class name"
|
|
103
|
+
t.text :error_message, comment: "Error message"
|
|
104
|
+
t.integer :attempts, null: false, default: 0, comment: "Retry attempts"
|
|
105
|
+
t.timestamp :occurred_at, null: false, comment: "When the job started"
|
|
106
|
+
t.timestamp :enqueued_at, comment: "When the job was enqueued"
|
|
107
|
+
t.text :arguments, comment: "Serialized arguments"
|
|
108
|
+
t.string :adapter, comment: "Queue adapter"
|
|
109
|
+
t.text :tags, comment: "Execution tags"
|
|
110
|
+
t.timestamps
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
connection.add_index :rails_pulse_job_runs, :run_id, unique: true, name: "index_rails_pulse_job_runs_on_run_id"
|
|
114
|
+
connection.add_index :rails_pulse_job_runs, [ :job_id, :occurred_at ], name: "index_rails_pulse_job_runs_on_job_and_occurred"
|
|
115
|
+
connection.add_index :rails_pulse_job_runs, :occurred_at, name: "index_rails_pulse_job_runs_on_occurred_at"
|
|
116
|
+
connection.add_index :rails_pulse_job_runs, :status, name: "index_rails_pulse_job_runs_on_status"
|
|
117
|
+
connection.add_index :rails_pulse_job_runs, [ :job_id, :status ], name: "index_rails_pulse_job_runs_on_job_and_status"
|
|
70
118
|
end
|
|
71
119
|
|
|
72
|
-
connection.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
t.float :total_duration, comment: "Total duration in milliseconds"
|
|
98
|
-
t.float :stddev_duration, comment: "Standard deviation of duration"
|
|
99
|
-
|
|
100
|
-
# Request/Route specific metrics
|
|
101
|
-
t.integer :error_count, default: 0, comment: "Number of error responses (5xx)"
|
|
102
|
-
t.integer :success_count, default: 0, comment: "Number of successful responses"
|
|
103
|
-
t.integer :status_2xx, default: 0, comment: "Number of 2xx responses"
|
|
104
|
-
t.integer :status_3xx, default: 0, comment: "Number of 3xx responses"
|
|
105
|
-
t.integer :status_4xx, default: 0, comment: "Number of 4xx responses"
|
|
106
|
-
t.integer :status_5xx, default: 0, comment: "Number of 5xx responses"
|
|
107
|
-
|
|
108
|
-
t.timestamps
|
|
120
|
+
unless connection.table_exists?(:rails_pulse_operations)
|
|
121
|
+
connection.create_table :rails_pulse_operations do |t|
|
|
122
|
+
t.references :request, null: true, foreign_key: { to_table: :rails_pulse_requests }, comment: "Link to the request"
|
|
123
|
+
t.references :job_run, null: true, foreign_key: { to_table: :rails_pulse_job_runs }, comment: "Link to a background job execution"
|
|
124
|
+
t.references :query, foreign_key: { to_table: :rails_pulse_queries }, index: true, comment: "Link to the normalized SQL query"
|
|
125
|
+
t.string :operation_type, null: false, comment: "Type of operation (e.g., database, view, gem_call)"
|
|
126
|
+
t.string :label, null: false, comment: "Descriptive name (e.g., SELECT FROM users WHERE id = 1, render layout)"
|
|
127
|
+
t.decimal :duration, precision: 15, scale: 6, null: false, comment: "Operation duration in milliseconds"
|
|
128
|
+
t.string :codebase_location, comment: "File and line number (e.g., app/models/user.rb:25)"
|
|
129
|
+
t.float :start_time, null: false, default: 0.0, comment: "Operation start time in milliseconds"
|
|
130
|
+
t.timestamp :occurred_at, null: false, comment: "When the request started"
|
|
131
|
+
t.timestamps
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
connection.add_index :rails_pulse_operations, :operation_type, name: "index_rails_pulse_operations_on_operation_type"
|
|
135
|
+
connection.add_index :rails_pulse_operations, :occurred_at, name: "index_rails_pulse_operations_on_occurred_at"
|
|
136
|
+
connection.add_index :rails_pulse_operations, [ :query_id, :occurred_at ], name: "index_rails_pulse_operations_on_query_and_time"
|
|
137
|
+
connection.add_index :rails_pulse_operations, [ :query_id, :duration, :occurred_at ], name: "index_rails_pulse_operations_query_performance"
|
|
138
|
+
connection.add_index :rails_pulse_operations, [ :occurred_at, :duration, :operation_type ], name: "index_rails_pulse_operations_on_time_duration_type"
|
|
139
|
+
|
|
140
|
+
if adapter.include?("postgres") || adapter.include?("mysql")
|
|
141
|
+
connection.add_check_constraint :rails_pulse_operations,
|
|
142
|
+
"(request_id IS NOT NULL OR job_run_id IS NOT NULL)",
|
|
143
|
+
name: "rails_pulse_operations_request_or_job_run"
|
|
144
|
+
end
|
|
109
145
|
end
|
|
110
146
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
147
|
+
unless connection.table_exists?(:rails_pulse_summaries)
|
|
148
|
+
connection.create_table :rails_pulse_summaries do |t|
|
|
149
|
+
# Time fields
|
|
150
|
+
t.datetime :period_start, null: false, comment: "Start of the aggregation period"
|
|
151
|
+
t.datetime :period_end, null: false, comment: "End of the aggregation period"
|
|
152
|
+
t.string :period_type, null: false, comment: "Aggregation period type: hour, day, week, month"
|
|
153
|
+
|
|
154
|
+
# Polymorphic association to handle both routes and queries
|
|
155
|
+
t.references :summarizable, polymorphic: true, null: false, index: true, comment: "Link to Route or Query"
|
|
156
|
+
# This creates summarizable_type (e.g., 'RailsPulse::Route', 'RailsPulse::Query')
|
|
157
|
+
# and summarizable_id (route_id or query_id)
|
|
158
|
+
|
|
159
|
+
# Universal metrics
|
|
160
|
+
t.integer :count, default: 0, null: false, comment: "Total number of requests/operations"
|
|
161
|
+
t.float :avg_duration, comment: "Average duration in milliseconds"
|
|
162
|
+
t.float :min_duration, comment: "Minimum duration in milliseconds"
|
|
163
|
+
t.float :max_duration, comment: "Maximum duration in milliseconds"
|
|
164
|
+
t.float :p50_duration, comment: "50th percentile duration"
|
|
165
|
+
t.float :p95_duration, comment: "95th percentile duration"
|
|
166
|
+
t.float :p99_duration, comment: "99th percentile duration"
|
|
167
|
+
t.float :total_duration, comment: "Total duration in milliseconds"
|
|
168
|
+
t.float :stddev_duration, comment: "Standard deviation of duration"
|
|
169
|
+
|
|
170
|
+
# Request/Route specific metrics
|
|
171
|
+
t.integer :error_count, default: 0, comment: "Number of error responses (5xx)"
|
|
172
|
+
t.integer :success_count, default: 0, comment: "Number of successful responses"
|
|
173
|
+
t.integer :status_2xx, default: 0, comment: "Number of 2xx responses"
|
|
174
|
+
t.integer :status_3xx, default: 0, comment: "Number of 3xx responses"
|
|
175
|
+
t.integer :status_4xx, default: 0, comment: "Number of 4xx responses"
|
|
176
|
+
t.integer :status_5xx, default: 0, comment: "Number of 5xx responses"
|
|
177
|
+
|
|
178
|
+
t.timestamps
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# Unique constraint and indexes for summaries
|
|
182
|
+
connection.add_index :rails_pulse_summaries, [ :summarizable_type, :summarizable_id, :period_type, :period_start ],
|
|
183
|
+
unique: true,
|
|
184
|
+
name: "idx_pulse_summaries_unique"
|
|
185
|
+
connection.add_index :rails_pulse_summaries, [ :period_type, :period_start ], name: "index_rails_pulse_summaries_on_period"
|
|
186
|
+
connection.add_index :rails_pulse_summaries, :created_at, name: "index_rails_pulse_summaries_on_created_at"
|
|
187
|
+
end
|
|
117
188
|
|
|
118
189
|
# Add indexes to existing tables for efficient aggregation
|
|
119
|
-
connection.
|
|
120
|
-
|
|
190
|
+
unless connection.index_exists?(:rails_pulse_requests, [ :created_at, :route_id ], name: "idx_requests_for_aggregation")
|
|
191
|
+
connection.add_index :rails_pulse_requests, [ :created_at, :route_id ], name: "idx_requests_for_aggregation"
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
unless connection.index_exists?(:rails_pulse_requests, :created_at, name: "idx_requests_created_at")
|
|
195
|
+
connection.add_index :rails_pulse_requests, :created_at, name: "idx_requests_created_at"
|
|
196
|
+
end
|
|
121
197
|
|
|
122
|
-
connection.
|
|
123
|
-
|
|
198
|
+
unless connection.index_exists?(:rails_pulse_operations, [ :created_at, :query_id ], name: "idx_operations_for_aggregation")
|
|
199
|
+
connection.add_index :rails_pulse_operations, [ :created_at, :query_id ], name: "idx_operations_for_aggregation"
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
unless connection.index_exists?(:rails_pulse_operations, :created_at, name: "idx_operations_created_at")
|
|
203
|
+
connection.add_index :rails_pulse_operations, :created_at, name: "idx_operations_created_at"
|
|
204
|
+
end
|
|
124
205
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
206
|
+
# Log successful creation
|
|
207
|
+
created_tables = required_tables.select { |table| connection.table_exists?(table) }
|
|
208
|
+
newly_created = created_tables - existing_tables
|
|
209
|
+
if newly_created.any?
|
|
210
|
+
puts "[RailsPulse::Schema] Successfully created tables: #{newly_created.join(', ')}"
|
|
128
211
|
end
|
|
129
212
|
end
|
|
130
213
|
|