Class: RailsErrorDashboard::Queries::PlatformComparison

Inherits:
Object
  • Object
show all
Defined in:
lib/rails_error_dashboard/queries/platform_comparison.rb

Overview

Query object for comparing error metrics across platforms

Provides analytics comparing iOS vs Android vs API vs Web platforms:

  • Error rates and trends

  • Severity distribution

  • Resolution times

  • Top errors per platform

  • Platform stability scores

  • Cross-platform errors

Examples:

comparison = PlatformComparison.new(days: 7)
comparison.error_rate_by_platform
# => { "ios" => 150, "android" => 200, "api" => 50, "web" => 100 }

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(days: 7, application_id: nil) ⇒ PlatformComparison

Returns a new instance of PlatformComparison.

Parameters:

  • days (Integer) (defaults to: 7)

    Number of days to analyze (default: 7)

  • application_id (Integer, nil) (defaults to: nil)

    Optional application ID to filter by



24
25
26
27
28
# File 'lib/rails_error_dashboard/queries/platform_comparison.rb', line 24

def initialize(days: 7, application_id: nil)
  @days = days
  @application_id = application_id
  @start_date = days.days.ago
end

Instance Attribute Details

#application_idObject (readonly)

Returns the value of attribute application_id.



20
21
22
# File 'lib/rails_error_dashboard/queries/platform_comparison.rb', line 20

def application_id
  @application_id
end

#daysObject (readonly)

Returns the value of attribute days.



20
21
22
# File 'lib/rails_error_dashboard/queries/platform_comparison.rb', line 20

def days
  @days
end

Instance Method Details

#cross_platform_errorsArray<Hash>

Find errors that occur across multiple platforms

Returns:

  • (Array<Hash>)

    Errors with their platforms



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/rails_error_dashboard/queries/platform_comparison.rb', line 146

def cross_platform_errors
  # Get error types that appear on 2+ platforms
  error_types_with_platforms = base_scope
    .where("occurred_at >= ?", @start_date)
    .group(:error_type, :platform)
    .select(:error_type, :platform)
    .having("COUNT(*) > 0")
    .pluck(:error_type, :platform)

  # Group by error_type to find those on multiple platforms
  errors_by_type = error_types_with_platforms.group_by { |error_type, _| error_type }

  errors_by_type
    .select { |_, platforms| platforms.map(&:last).uniq.count > 1 }
    .map do |error_type, platform_pairs|
      platforms = platform_pairs.map(&:last).uniq
      total_count = base_scope
        .where(error_type: error_type, platform: platforms)
        .where("occurred_at >= ?", @start_date)
        .sum(:occurrence_count)

      {
        error_type: error_type,
        platforms: platforms.sort,
        total_occurrences: total_count,
        platform_breakdown: platforms.each_with_object({}) do |platform, breakdown|
          breakdown[platform] = base_scope
            .where(error_type: error_type, platform: platform)
            .where("occurred_at >= ?", @start_date)
            .sum(:occurrence_count)
        end
      }
    end
    .sort_by { |error| -error[:total_occurrences] }
end

#daily_trend_by_platformHash

Get daily error trend by platform

Returns:

  • (Hash)

    Platform => { date => count }



184
185
186
187
188
189
190
191
192
193
194
# File 'lib/rails_error_dashboard/queries/platform_comparison.rb', line 184

def daily_trend_by_platform
  platforms = base_scope.distinct.pluck(:platform).compact

  platforms.each_with_object({}) do |platform, result|
    result[platform] = base_scope
      .where(platform: platform)
      .where("occurred_at >= ?", @start_date)
      .group_by_day(:occurred_at, range: @start_date..Time.current)
      .count
  end
end

#error_rate_by_platformHash

Get error count by platform for the time period

Returns:

  • (Hash)

    Platform name => error count



44
45
46
47
48
49
# File 'lib/rails_error_dashboard/queries/platform_comparison.rb', line 44

def error_rate_by_platform
  base_scope
    .where("occurred_at >= ?", @start_date)
    .group(:platform)
    .count
end

#platform_health_summaryHash

Get platform health summary

Returns:

  • (Hash)

    Platform => health metrics



198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/rails_error_dashboard/queries/platform_comparison.rb', line 198

def platform_health_summary
  platforms = base_scope.distinct.pluck(:platform).compact
  error_rates = error_rate_by_platform
  stability_scores = platform_stability_scores

  platforms.each_with_object({}) do |platform, result|
    total_errors = error_rates[platform] || 0

    # Count critical errors by checking severity method
    critical_errors = base_scope
      .where(platform: platform)
      .where("occurred_at >= ?", @start_date)
      .select { |error| error.severity == :critical }
      .count

    unresolved_errors = base_scope
      .where(platform: platform, resolved_at: nil)
      .where("occurred_at >= ?", @start_date)
      .count

    resolved_errors = base_scope
      .where(platform: platform)
      .where.not(resolved_at: nil)
      .where("occurred_at >= ?", @start_date)
      .count

    resolution_rate = total_errors.positive? ? ((resolved_errors.to_f / total_errors) * 100).round(1) : 0.0

    # Calculate error velocity (increasing or decreasing)
    first_half = base_scope
      .where(platform: platform)
      .where("occurred_at >= ? AND occurred_at < ?", @start_date, @start_date + (@days / 2.0).days)
      .count

    second_half = base_scope
      .where(platform: platform)
      .where("occurred_at >= ?", @start_date + (@days / 2.0).days)
      .count

    velocity = first_half.positive? ? (((second_half - first_half).to_f / first_half) * 100).round(1) : 0.0

    result[platform] = {
      total_errors: total_errors,
      critical_errors: critical_errors,
      unresolved_errors: unresolved_errors,
      resolution_rate: resolution_rate,
      stability_score: stability_scores[platform] || 0,
      error_velocity: velocity, # Positive = increasing, negative = decreasing
      health_status: determine_health_status(stability_scores[platform] || 0, velocity)
    }
  end
end

#platform_stability_scoresHash

Calculate platform stability score (0-100) Higher score = more stable (fewer errors, faster resolution)

Returns:

  • (Hash)

    Platform => stability score



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/rails_error_dashboard/queries/platform_comparison.rb', line 121

def platform_stability_scores
  platforms = base_scope.distinct.pluck(:platform).compact
  error_rates = error_rate_by_platform
  resolution_times = resolution_time_by_platform

  # Find max values for normalization
  max_errors = error_rates.values.max || 1
  max_resolution_time = resolution_times.values.compact.max || 1

  platforms.each_with_object({}) do |platform, result|
    error_count = error_rates[platform] || 0
    avg_resolution = resolution_times[platform] || 0

    # Normalize to 0-1 scale (inverted - lower is better)
    error_score = 1.0 - (error_count.to_f / max_errors)
    resolution_score = avg_resolution.positive? ? 1.0 - (avg_resolution / max_resolution_time) : 1.0

    # Weight: 70% error count, 30% resolution time
    # Convert to 0-100 scale
    result[platform] = ((error_score * 0.7 + resolution_score * 0.3) * 100).round(1)
  end
end

#resolution_time_by_platformHash

Get average resolution time by platform

Returns:

  • (Hash)

    Platform => average hours to resolve



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/rails_error_dashboard/queries/platform_comparison.rb', line 73

def resolution_time_by_platform
  platforms = base_scope.distinct.pluck(:platform).compact

  platforms.each_with_object({}) do |platform, result|
    resolved_errors = base_scope
      .where(platform: platform)
      .where.not(resolved_at: nil)
      .where("occurred_at >= ?", @start_date)

    if resolved_errors.any?
      total_hours = resolved_errors.sum do |error|
        ((error.resolved_at - error.occurred_at) / 3600.0).round(2)
      end
      result[platform] = (total_hours / resolved_errors.count).round(2)
    else
      result[platform] = nil
    end
  end
end

#severity_distribution_by_platformHash

Get severity distribution by platform

Returns:

  • (Hash)

    Platform => { severity => count }



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/rails_error_dashboard/queries/platform_comparison.rb', line 53

def severity_distribution_by_platform
  platforms = base_scope.distinct.pluck(:platform).compact

  platforms.each_with_object({}) do |platform, result|
    errors = base_scope
      .where(platform: platform)
      .where("occurred_at >= ?", @start_date)

    # Calculate severity in Ruby since it's a method, not a column
    severity_counts = Hash.new(0)
    errors.each do |error|
      severity_counts[error.severity] += 1
    end

    result[platform] = severity_counts
  end
end

#top_errors_by_platformHash

Get top 10 errors for each platform

Returns:

  • (Hash)

    Platform => Array of error hashes



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/rails_error_dashboard/queries/platform_comparison.rb', line 95

def top_errors_by_platform
  platforms = base_scope.distinct.pluck(:platform).compact

  platforms.each_with_object({}) do |platform, result|
    result[platform] = base_scope
      .where(platform: platform)
      .where("occurred_at >= ?", @start_date)
      .select(:id, :error_type, :message, :occurrence_count, :occurred_at)
      .order(occurrence_count: :desc)
      .limit(10)
      .map do |error|
        {
          id: error.id,
          error_type: error.error_type,
          message: error.message&.truncate(100),
          severity: error.severity, # Calls the method
          occurrence_count: error.occurrence_count,
          occurred_at: error.occurred_at
        }
      end
  end
end