routes_alerts 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3af83f1b06855dd7430a019b27ed602e73198df30946387c9cd4872b7e53e31e
4
+ data.tar.gz: d638319a534fc7e17dd9efc9b9db6d21340ac4a7538448db25bf8e7176f6dd4b
5
+ SHA512:
6
+ metadata.gz: 2cc5fe7a72e69f74ccebf5c5f352377937088616ccd02486af085ccf72c82f2b3d3ef3b7395cae3573c65fc83801b4c90e976751293588d347b4d0d757335e22
7
+ data.tar.gz: 99d8ca7e90ee2a3a84f7674f6e0b4f4e0a732f6f4be236e91c6273f41ce9727153e7ea1bc7169e64e6fa5ddbedb5f83c9faeb458089006961c47c02d1f22518f
@@ -0,0 +1,54 @@
1
+ require 'aws-sdk-cloudwatchlogs'
2
+ require_relative "./metrics.rb"
3
+ require_relative "./route_info.rb"
4
+
5
+ module RoutesAlerts
6
+ class Configuration
7
+ DEFAULT_ALARM_PERIOD = 300
8
+ DEFAULT_NUMBER_OF_DATAPOINTS = 2
9
+ DEFAULT_MAX_DURATION = 100.0
10
+ DEFAULT_MIN_COUNT = 1
11
+ DEFAULT_SUCCESS_RATE = 99.0
12
+
13
+ attr_accessor :routes,
14
+ :default_alarm_period,
15
+ :default_number_of_datapoints,
16
+ :default_max_duration,
17
+ :default_min_count,
18
+ :default_success_rate,
19
+ :default_metrics,
20
+ :default_log_group_name,
21
+ :default_namespace,
22
+ :cloudwatch_logs,
23
+ :default_actions
24
+
25
+ def initialize
26
+ @cloudwatch_logs = Aws::CloudWatchLogs::Client.new(region: "us-west-2")
27
+ @default_alarm_period = DEFAULT_ALARM_PERIOD
28
+ @default_number_of_datapoints = DEFAULT_NUMBER_OF_DATAPOINTS
29
+ @default_max_duration = DEFAULT_MAX_DURATION
30
+ @default_min_count = DEFAULT_MIN_COUNT
31
+ @default_success_rate = DEFAULT_SUCCESS_RATE
32
+ @default_metrics = RoutesAlerts::Metrics::DEFAULT_METRICS
33
+ @routes = []
34
+ @default_actions = []
35
+ end
36
+
37
+ def add_route(path:, method:, max_duration:, min_count:, success_rate:, alarm_period:, number_of_datapoints:, metrics:, namespace:, log_group_name:, actions:)
38
+ route_info = RoutesAlerts::RouteInfo.new(
39
+ path: path.to_s,
40
+ method: method.to_s.upcase,
41
+ max_duration: (max_duration || default_max_duration).to_f,
42
+ min_count: (min_count || default_min_count).to_i,
43
+ success_rate: (success_rate || default_success_rate).to_f,
44
+ alarm_period: (alarm_period || default_alarm_period).to_i,
45
+ number_of_datapoints: (number_of_datapoints || default_number_of_datapoints).to_i,
46
+ log_group_name: (log_group_name || default_log_group_name),
47
+ namespace: (namespace || default_namespace),
48
+ actions: (actions || default_actions),
49
+ metrics: (metrics || default_metrics)
50
+ )
51
+ self.routes << route_info
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,37 @@
1
+ class RoutesAlerts::Base
2
+ attr_reader :route_info, :config
3
+
4
+ def initialize(config, route_info)
5
+ @config = config
6
+ @route_info = route_info
7
+ end
8
+
9
+ def metric_params
10
+ raise NotImplementedError, "Subclasses must implement the metric_params method"
11
+ end
12
+
13
+ def alarm_params
14
+ raise NotImplementedError, "Subclasses must implement the alarm_params method"
15
+ end
16
+
17
+ def create!
18
+ config.cloudwatch_logs.put_metric_filter(metric_params)
19
+ config.cloudwatch_logs.put_metric_alarm(alarm_params)
20
+ end
21
+
22
+ def log_group_name
23
+ route_info.log_group_name
24
+ end
25
+
26
+ def namespace
27
+ route_info.namespace
28
+ end
29
+
30
+ def route_name
31
+ "#{route_info.method}-#{route_info.path.gsub("/", "_").gsub("{", "").gsub("}", "")}"
32
+ end
33
+
34
+ def actions
35
+ route_info.actions.any? ? route_info.actions : nil
36
+ end
37
+ end
@@ -0,0 +1,44 @@
1
+ require_relative "./base.rb"
2
+
3
+ class RoutesAlerts::Count < RoutesAlerts::Base
4
+ def filter_pattern
5
+ "{ $.path = \"#{route_info.path}\" && $.method = \"#{route_info.method}\" }"
6
+ end
7
+
8
+ def metric_params
9
+ {
10
+ log_group_name: log_group_name,
11
+ filter_name: "#{RoutesAlerts::Metrics::COUNT_METRIC_NAME}-#{route_name}",
12
+ filter_pattern: filter_pattern,
13
+ metric_transformations: [
14
+ {
15
+ metric_name: "#{RoutesAlerts::Metrics::COUNT_METRIC_NAME}-#{route_name}",
16
+ metric_namespace: namespace,
17
+ metric_value: "1",
18
+ default_value: 0,
19
+ unit: "Count",
20
+ },
21
+ ]
22
+ }
23
+ end
24
+
25
+ def alarm_params
26
+ {
27
+ alarm_name: "Alarm-#{RoutesAlerts::Metrics::COUNT_METRIC_NAME}-#{route_name}",
28
+ actions_enabled: !!actions&.any?,
29
+ ok_actions: actions,
30
+ alarm_actions: actions,
31
+ metric_name: "#{RoutesAlerts::Metrics::COUNT_METRIC_NAME}-#{route_name}",
32
+ namespace: namespace,
33
+ statistic: "Sum",
34
+ dimensions: [],
35
+ period: route_info.alarm_period,
36
+ unit: "Count",
37
+ evaluation_periods: route_info.number_of_datapoints,
38
+ datapoints_to_alarm: route_info.number_of_datapoints,
39
+ threshold: route_info.min_count,
40
+ comparison_operator: "LessThanOrEqualToThreshold",
41
+ treat_missing_data: "notBreaching",
42
+ }
43
+ end
44
+ end
@@ -0,0 +1,44 @@
1
+ require_relative "./base.rb"
2
+
3
+ class RoutesAlerts::Duration < RoutesAlerts::Base
4
+ def filter_pattern
5
+ "{ $.path = \"#{route_info.path}\" && $.method = \"#{route_info.method}\" && EXISTS($.duration) }"
6
+ end
7
+
8
+ def metric_params
9
+ {
10
+ log_group_name: log_group_name,
11
+ filter_name: "#{RoutesAlerts::Metrics::DURATION_METRIC_NAME}-#{route_name}",
12
+ filter_pattern: filter_pattern,
13
+ metric_transformations: [
14
+ {
15
+ metric_name: "#{RoutesAlerts::Metrics::DURATION_METRIC_NAME}-#{route_name}",
16
+ metric_namespace: namespace,
17
+ metric_value: "$.duration",
18
+ default_value: 0,
19
+ unit: "Milliseconds",
20
+ },
21
+ ]
22
+ }
23
+ end
24
+
25
+ def alarm_params
26
+ {
27
+ alarm_name: "Alarm-#{RoutesAlerts::Metrics::DURATION_METRIC_NAME}-#{route_name}",
28
+ actions_enabled: !!actions&.any?,
29
+ ok_actions: actions,
30
+ alarm_actions: actions,
31
+ metric_name: "#{RoutesAlerts::Metrics::DURATION_METRIC_NAME}-#{route_name}",
32
+ namespace: namespace,
33
+ statistic: "Average",
34
+ dimensions: [],
35
+ period: route_info.alarm_period,
36
+ unit: "Milliseconds",
37
+ evaluation_periods: route_info.number_of_datapoints,
38
+ datapoints_to_alarm: route_info.number_of_datapoints,
39
+ threshold: route_info.max_duration,
40
+ comparison_operator: "GreaterThanThreshold",
41
+ treat_missing_data: "notBreaching",
42
+ }
43
+ end
44
+ end
@@ -0,0 +1,44 @@
1
+ require_relative "./base.rb"
2
+
3
+ class RoutesAlerts::SuccessRate < RoutesAlerts::Base
4
+ def filter_pattern
5
+ "{ $.path = \"#{route_info.path}\" && $.method = \"#{route_info.method}\" && $.status >= 200 && $.status < 300 }"
6
+ end
7
+
8
+ def metric_params
9
+ {
10
+ log_group_name: log_group_name,
11
+ filter_name: "#{RoutesAlerts::Metrics::SUCCESS_METRIC_NAME}-#{route_name}",
12
+ filter_pattern: filter_pattern,
13
+ metric_transformations: [
14
+ {
15
+ metric_name: "#{RoutesAlerts::Metrics::SUCCESS_METRIC_NAME}-#{route_name}",
16
+ metric_namespace: namespace,
17
+ metric_value: "1",
18
+ default_value: 0,
19
+ unit: "Percent",
20
+ },
21
+ ]
22
+ }
23
+ end
24
+
25
+ def alarm_params
26
+ {
27
+ alarm_name: "Alarm-#{RoutesAlerts::Metrics::SUCCESS_METRIC_NAME}-#{route_name}",
28
+ actions_enabled: !!actions&.any?,
29
+ ok_actions: actions,
30
+ alarm_actions: actions,
31
+ metric_name: "#{RoutesAlerts::Metrics::SUCCESS_METRIC_NAME}-#{route_name}",
32
+ namespace: namespace,
33
+ statistic: "Average",
34
+ dimensions: [],
35
+ period: route_info.alarm_period,
36
+ unit: "Percent",
37
+ evaluation_periods: route_info.number_of_datapoints,
38
+ datapoints_to_alarm: route_info.number_of_datapoints,
39
+ threshold: route_info.success_rate,
40
+ comparison_operator: "LessThanThreshold",
41
+ treat_missing_data: "breaching",
42
+ }
43
+ end
44
+ end
@@ -0,0 +1,37 @@
1
+ require_relative "./metrics/base.rb"
2
+ require_relative "./metrics/count.rb"
3
+ require_relative "./metrics/duration.rb"
4
+ require_relative "./metrics/success_rate.rb"
5
+
6
+ class RoutesAlerts::Metrics
7
+ COUNT_METRIC_NAME = "Count"
8
+ DURATION_METRIC_NAME = "Duration"
9
+ SUCCESS_METRIC_NAME = "SuccessRate"
10
+
11
+ DEFAULT_METRICS = [
12
+ COUNT_METRIC_NAME,
13
+ DURATION_METRIC_NAME,
14
+ SUCCESS_METRIC_NAME
15
+ ]
16
+
17
+ attr_reader :config
18
+
19
+ def initialize(config)
20
+ @config = config
21
+ end
22
+
23
+ def create_metrics!(route_info)
24
+ route_info.metrics.each do |metric|
25
+ case metric
26
+ when COUNT_METRIC_NAME
27
+ RoutesAlerts::Count.new(config, route_info).create!
28
+ when DURATION_METRIC_NAME
29
+ RoutesAlerts::Duration.new(config, route_info).create!
30
+ when SUCCESS_METRIC_NAME
31
+ RoutesAlerts::SuccessRate.new(config, route_info).create!
32
+ else
33
+ raise "Unknown metric type: #{metric}"
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,20 @@
1
+
2
+ class RoutesAlerts::RouteInfo
3
+ attr_reader :path, :method, :max_duration, :min_count, :success_rate,
4
+ :alarm_period, :number_of_datapoints, :metrics, :namespace,
5
+ :log_group_name, :actions
6
+
7
+ def initialize(path:, method:, max_duration:, min_count:, success_rate:, alarm_period:, number_of_datapoints:, metrics:, namespace:, log_group_name:, actions:)
8
+ @path = path.to_s
9
+ @method = method.to_s.upcase
10
+ @max_duration = max_duration.to_f
11
+ @min_count = min_count.to_i
12
+ @success_rate = success_rate.to_f
13
+ @alarm_period = alarm_period.to_i
14
+ @number_of_datapoints = number_of_datapoints.to_i
15
+ @metrics = metrics
16
+ @namespace = namespace.to_s
17
+ @log_group_name = log_group_name.to_s
18
+ @actions = actions || []
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ module RoutesAlerts
2
+ require_relative "./routes_alerts/configuration.rb"
3
+ require_relative "./routes_alerts/metrics.rb"
4
+
5
+ class << self
6
+ attr_accessor :configuration
7
+ end
8
+
9
+ def self.configure
10
+ self.configuration ||= RoutesAlerts::Configuration.new
11
+ yield(configuration)
12
+ end
13
+
14
+ def self.create_metrics!
15
+ configuration.routes.each do |route|
16
+ RoutesAlerts::Metrics.new(configuration).create_metrics!(route)
17
+ end
18
+ end
19
+ end
metadata ADDED
@@ -0,0 +1,48 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: routes_alerts
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - ''
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: Allows you to create metrics (for reporting, dashboards) and alerts for
13
+ request time, count and response code based on your routes.
14
+ email: jarrett.baugh@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/routes_alerts.rb
20
+ - lib/routes_alerts/configuration.rb
21
+ - lib/routes_alerts/metrics.rb
22
+ - lib/routes_alerts/metrics/base.rb
23
+ - lib/routes_alerts/metrics/count.rb
24
+ - lib/routes_alerts/metrics/duration.rb
25
+ - lib/routes_alerts/metrics/success_rate.rb
26
+ - lib/routes_alerts/route_info.rb
27
+ homepage: https://rubygems.org/gems/routes_alerts
28
+ licenses:
29
+ - MIT
30
+ metadata: {}
31
+ rdoc_options: []
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ required_rubygems_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ requirements: []
45
+ rubygems_version: 3.6.7
46
+ specification_version: 4
47
+ summary: Create AWS alerts/metrics for routes
48
+ test_files: []