Class: RailsErrorDashboard::Services::BaselineCalculator
- Inherits:
-
Object
- Object
- RailsErrorDashboard::Services::BaselineCalculator
- Defined in:
- lib/rails_error_dashboard/services/baseline_calculator.rb
Overview
Calculates baseline statistics for error types
This service analyzes historical error data to calculate statistical baselines for different time periods (hourly, daily, weekly). These baselines enable anomaly detection by establishing “normal” error behavior.
Statistical methods used:
-
Mean and Standard Deviation
-
95th and 99th Percentiles
-
Outlier removal (> 3 std devs)
Constant Summary collapse
- HOURLY_LOOKBACK =
Lookback periods for baseline calculation
4.weeks
- DAILY_LOOKBACK =
12.weeks
- WEEKLY_LOOKBACK =
1.year
- OUTLIER_THRESHOLD =
Outlier threshold (standard deviations)
3
Class Method Summary collapse
- .calculate_all_baselines ⇒ Object
- .calculate_for_error_type(error_type, platform) ⇒ Object
-
.calculate_statistics(counts) ⇒ Object
Class-level pure algorithm: calculate statistics from counts.
-
.default_stats ⇒ Hash
Default statistics for empty datasets.
-
.percentile(sorted_array, pct) ⇒ Float
Calculate percentile value using linear interpolation.
-
.remove_outliers(counts) ⇒ Array<Integer>
Remove outliers from counts (values > 3 std devs from mean).
Instance Method Summary collapse
-
#calculate_all_baselines ⇒ Hash
Calculate baselines for all error types and platforms.
-
#calculate_for_error_type(error_type, platform) ⇒ Hash
Calculate baselines for a specific error type and platform.
-
#initialize ⇒ BaselineCalculator
constructor
A new instance of BaselineCalculator.
Constructor Details
#initialize ⇒ BaselineCalculator
Returns a new instance of BaselineCalculator.
36 37 38 |
# File 'lib/rails_error_dashboard/services/baseline_calculator.rb', line 36 def initialize @calculated_count = 0 end |
Class Method Details
.calculate_all_baselines ⇒ Object
28 29 30 |
# File 'lib/rails_error_dashboard/services/baseline_calculator.rb', line 28 def self.calculate_all_baselines new.calculate_all_baselines end |
.calculate_for_error_type(error_type, platform) ⇒ Object
32 33 34 |
# File 'lib/rails_error_dashboard/services/baseline_calculator.rb', line 32 def self.calculate_for_error_type(error_type, platform) new.calculate_for_error_type(error_type, platform) end |
.calculate_statistics(counts) ⇒ Object
Class-level pure algorithm: calculate statistics from counts
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/rails_error_dashboard/services/baseline_calculator.rb', line 168 def self.calculate_statistics(counts) return default_stats if counts.empty? # Remove outliers clean_counts = remove_outliers(counts) return default_stats if clean_counts.empty? mean = clean_counts.sum.to_f / clean_counts.size variance = clean_counts.map { |c| (c - mean)**2 }.sum / clean_counts.size std_dev = Math.sqrt(variance) sorted = clean_counts.sort percentile_95 = percentile(sorted, 95) percentile_99 = percentile(sorted, 99) { mean: mean.round(2), std_dev: std_dev.round(2), percentile_95: percentile_95.round(2), percentile_99: percentile_99.round(2) } end |
.default_stats ⇒ Hash
Default statistics for empty datasets
230 231 232 233 234 235 236 237 |
# File 'lib/rails_error_dashboard/services/baseline_calculator.rb', line 230 def self.default_stats { mean: 0.0, std_dev: 0.0, percentile_95: 0.0, percentile_99: 0.0 } end |
.percentile(sorted_array, pct) ⇒ Float
Calculate percentile value using linear interpolation
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/rails_error_dashboard/services/baseline_calculator.rb', line 209 def self.percentile(sorted_array, pct) return 0 if sorted_array.empty? return sorted_array.first if sorted_array.size == 1 rank = (pct / 100.0) * (sorted_array.size - 1) lower_index = rank.floor upper_index = rank.ceil if lower_index == upper_index sorted_array[lower_index].to_f else # Linear interpolation lower_value = sorted_array[lower_index] upper_value = sorted_array[upper_index] fraction = rank - lower_index lower_value + (upper_value - lower_value) * fraction end end |
.remove_outliers(counts) ⇒ Array<Integer>
Remove outliers from counts (values > 3 std devs from mean)
194 195 196 197 198 199 200 201 202 203 |
# File 'lib/rails_error_dashboard/services/baseline_calculator.rb', line 194 def self.remove_outliers(counts) return counts if counts.size < 3 mean = counts.sum.to_f / counts.size variance = counts.map { |c| (c - mean)**2 }.sum / counts.size std_dev = Math.sqrt(variance) # Remove values more than OUTLIER_THRESHOLD std devs from mean counts.select { |c| (c - mean).abs <= (OUTLIER_THRESHOLD * std_dev) } end |
Instance Method Details
#calculate_all_baselines ⇒ Hash
Calculate baselines for all error types and platforms
42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/rails_error_dashboard/services/baseline_calculator.rb', line 42 def calculate_all_baselines return { calculated: 0, message: "ErrorBaseline table not available" } unless can_calculate? # Get all unique combinations of error_type and platform combinations = ErrorLog.distinct.pluck(:error_type, :platform).compact combinations.each do |(error_type, platform)| calculate_for_error_type(error_type, platform) end { calculated: @calculated_count } end |
#calculate_for_error_type(error_type, platform) ⇒ Hash
Calculate baselines for a specific error type and platform
59 60 61 62 63 64 65 66 67 |
# File 'lib/rails_error_dashboard/services/baseline_calculator.rb', line 59 def calculate_for_error_type(error_type, platform) return {} unless can_calculate? { hourly: calculate_hourly_baseline(error_type, platform), daily: calculate_daily_baseline(error_type, platform), weekly: calculate_weekly_baseline(error_type, platform) } end |