mercy 1.3.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +13 -0
  3. data/.gitignore +1 -0
  4. data/LICENSE +1 -1
  5. data/README.md +12 -10
  6. data/docker-compose.yml +18 -0
  7. data/lib/arstotzka/type_cast_ext.rb +15 -0
  8. data/lib/mercy.rb +15 -0
  9. data/lib/mercy/class_methods.rb +17 -0
  10. data/lib/mercy/concern.rb +8 -0
  11. data/lib/{bidu → mercy}/period_parser.rb +1 -1
  12. data/lib/mercy/report.rb +42 -0
  13. data/lib/mercy/report/active_record.rb +26 -0
  14. data/lib/mercy/report/error.rb +60 -0
  15. data/lib/{bidu/mercy → mercy}/report/multiple.rb +1 -1
  16. data/lib/mercy/report/range.rb +48 -0
  17. data/lib/mercy/report_builder.rb +22 -0
  18. data/lib/mercy/report_config.rb +35 -0
  19. data/lib/mercy/status.rb +25 -0
  20. data/lib/mercy/status_builder.rb +33 -0
  21. data/lib/mercy/version.rb +3 -0
  22. data/mercy.gemspec +9 -10
  23. data/mercy.jpg +0 -0
  24. data/spec/lib/arstotzka/type_cast_spec.rb +67 -0
  25. data/spec/lib/{bidu → mercy}/period_parser_spec.rb +3 -9
  26. data/spec/lib/{bidu/mercy → mercy}/report/error_spec.rb +1 -1
  27. data/spec/lib/{bidu/mercy → mercy}/report/multiple_spec.rb +7 -7
  28. data/spec/lib/{bidu/mercy → mercy}/report/range_spec.rb +2 -2
  29. data/spec/lib/{bidu/mercy → mercy}/report/report_config_spec.rb +5 -5
  30. data/spec/lib/{bidu/mercy → mercy}/report_builder_spec.rb +3 -3
  31. data/spec/lib/{bidu/mercy → mercy}/report_spec.rb +5 -5
  32. data/spec/lib/{bidu/mercy → mercy}/status_builder_spec.rb +2 -2
  33. data/spec/lib/{bidu/mercy → mercy}/status_spec.rb +4 -4
  34. data/spec/spec_helper.rb +2 -6
  35. data/spec/support/report/dummy.rb +5 -7
  36. data/spec/support/shared_examples/time_parser.rb +7 -0
  37. metadata +49 -61
  38. data/Gemfile.lock +0 -88
  39. data/circle.yml +0 -16
  40. data/lib/bidu.rb +0 -3
  41. data/lib/bidu/mercy.rb +0 -18
  42. data/lib/bidu/mercy/class_methods.rb +0 -19
  43. data/lib/bidu/mercy/concern.rb +0 -10
  44. data/lib/bidu/mercy/report.rb +0 -44
  45. data/lib/bidu/mercy/report/active_record.rb +0 -28
  46. data/lib/bidu/mercy/report/error.rb +0 -62
  47. data/lib/bidu/mercy/report/range.rb +0 -54
  48. data/lib/bidu/mercy/report_builder.rb +0 -24
  49. data/lib/bidu/mercy/report_config.rb +0 -37
  50. data/lib/bidu/mercy/status.rb +0 -27
  51. data/lib/bidu/mercy/status_builder.rb +0 -35
  52. data/lib/bidu/mercy/version.rb +0 -5
  53. data/lib/json_parser/type_cast_ext.rb +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 68a29e5f4fa044fa73b32f12b346d4cceed9e412
4
- data.tar.gz: daf14a5ee6e905a90fef1f07f0bfeed96ef7e88f
3
+ metadata.gz: ea2e29aaca202d99f4b6d0d8ea3a9515b0ee8c80
4
+ data.tar.gz: 8b1bfb1ac1ab08640814ded69b186c6b1664c6d0
5
5
  SHA512:
6
- metadata.gz: 125286d85808a19342179001573365be133f7e88a0a2b847ca3b18a5d5627d41dd78061d1aa82cd82c1c1aa4484fa20f0d2716640fce8672e88a561a45c3f354
7
- data.tar.gz: 8d67fde38e51096f1fb47f3fa272159658088a152bfadb7ad77d5b6e5a89d98cf9a85f2be2cd232a07e7d7632cbbcb173533b3a21a8bb51d6e57f2e4534fd923
6
+ metadata.gz: 60d0ff4fe15a81f17e59f203a7839f68d1fe82fa2ae178f7a1785e626eb0c12c9e030b3cfb6bd97b882090f8b8bca48e99beaf0f4e184938ee07e45d01811e1c
7
+ data.tar.gz: a3c670ed0b56a98f534ba6c62af5df0c9ae32c302243db676d3b5f8cbaec013b3d01c4ac1eaa0436f160d0d5de05fe2f242f297d8807fc685c9f610512c0d67b
@@ -0,0 +1,13 @@
1
+ version: 2
2
+ jobs:
3
+ build:
4
+ docker:
5
+ - image: circleci/ruby:2.4.1
6
+ steps:
7
+ - checkout
8
+ - run: curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
9
+ - run: chmod +x ./cc-test-reporter
10
+ - run: ./cc-test-reporter before-build
11
+ - run: bundle install
12
+ - run: bundle exec rspec
13
+ - run: ./cc-test-reporter after-build --exit-code $?
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  coverage
2
2
  pkg
3
+ Gemfile.lock
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015 Bidu Corretora
3
+ Copyright (c) 2017 Favini
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,19 +1,21 @@
1
- Bidu House
1
+ Mercy
2
2
  ==========
3
3
 
4
- [![Code Climate](https://codeclimate.com/github/darthjee/house/badges/gpa.svg)](https://codeclimate.com/github/darthjee/house)
5
- [![Test Coverage](https://codeclimate.com/github/darthjee/house/badges/coverage.svg)](https://codeclimate.com/github/darthjee/house/coverage)
6
- [![Issue Count](https://codeclimate.com/github/darthjee/house/badges/issue_count.svg)](https://codeclimate.com/github/darthjee/house)
4
+ ![mercy](https://raw.githubusercontent.com/darthjee/mercy/master/mercy.jpg)
5
+
6
+ [![Code Climate](https://codeclimate.com/github/darthjee/mercy/badges/gpa.svg)](https://codeclimate.com/github/darthjee/mercy)
7
+ [![Test Coverage](https://codeclimate.com/github/darthjee/mercy/badges/coverage.svg)](https://codeclimate.com/github/darthjee/mercy/coverage)
8
+ [![Issue Count](https://codeclimate.com/github/darthjee/mercy/badges/issue_count.svg)](https://codeclimate.com/github/darthjee/mercy)
7
9
 
8
10
  This gem tries to make server monitoring easier and more reliable by adding an easly configurable
9
11
  report and making it avaliable in a controller
10
12
 
11
13
  Getting started
12
14
  ---------------
13
- 1. Add House to your `Gemfile` and `bundle install`:
15
+ 1. Add Mercy to your `Gemfile` and `bundle install`:
14
16
 
15
17
  ```ruby
16
- gem 'bidu-house'
18
+ gem 'mercy'
17
19
  ```
18
20
 
19
21
 
@@ -22,12 +24,12 @@ with error and render the report
22
24
 
23
25
  ```ruby
24
26
  class HealthCheckController < ApplicationController
25
- include Bidu::House
27
+ include Mercy
26
28
 
27
29
  status_report :failures, clazz: Document
28
30
  status_report :failures, clazz: Schedules, on: :schedules
29
31
  status_report :delays, clazz: Schedules, scope: :late, on: :schedules
30
- status_report :'documents.count', clazz: Document, scope: :active, type: House::Range, minimum: 100
32
+ status_report :'documents.count', clazz: Document, scope: :active, type: Mercy::Range, minimum: 100
31
33
  status_report :'documents.errors', clazz: Document, scope: :'active.with_error', type: :range, maximum: 1000
32
34
 
33
35
  def status
@@ -57,14 +59,14 @@ with error and render the report
57
59
 
58
60
  Remembering that each report may have its onw parameters
59
61
 
60
- - ```House::Error```
62
+ - ```Mercy::Error```
61
63
  - scope: scope to be fetched when trying to find objects with error (default: :with_error)
62
64
  - external_key: column to be exposed as id for the objects with error
63
65
  - threshold: default report threshold (default: 0.02)
64
66
  - base_scope: scope to be universal sample
65
67
  - uniq: when the output ids should not be repeated
66
68
  - limit: limit of ids to be outputed
67
- - ```House::Range```
69
+ - ```Mercy::Range```
68
70
  - scope: scope of the query to be counted
69
71
  - maximum: max value accepted in the range
70
72
  - minimum: minimum value accepted in the range
@@ -0,0 +1,18 @@
1
+ version: '2'
2
+ services:
3
+ base: &base
4
+ image: ruby:2.4.0
5
+ working_dir: /home/app/mercy
6
+ volumes:
7
+ - .:/home/app/mercy
8
+ - mercy_gems_2_4_0:/usr/local/bundle
9
+
10
+ #################### CONTAINERS ####################
11
+
12
+ mercy:
13
+ <<: *base
14
+ container_name: mercy
15
+ command: /bin/bash -c 'bundle install && bundle exec rspec'
16
+
17
+ volumes:
18
+ mercy_gems_2_4_0:
@@ -0,0 +1,15 @@
1
+ module Arstotzka
2
+ module TypeCast
3
+ def to_period(value)
4
+ Mercy::PeriodParser.parse(value)
5
+ end
6
+
7
+ def to_infinity_float(value)
8
+ return value if value.is_a?(Numeric)
9
+ return -Float::INFINITY if value.match(/-inf/)
10
+ return Float::INFINITY if value.match(/inf/)
11
+
12
+ value.to_f
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'darthjee/active_ext'
2
+ require 'darthjee/core_ext'
3
+ require 'mercy/period_parser'
4
+ require 'arstotzka'
5
+ require 'arstotzka/type_cast_ext'
6
+
7
+ module Mercy
8
+ require 'mercy/concern'
9
+ require 'mercy/report_config'
10
+ require 'mercy/report'
11
+ require 'mercy/status'
12
+ require 'mercy/report_builder'
13
+ require 'mercy/status_builder'
14
+ require 'mercy/class_methods'
15
+ end
@@ -0,0 +1,17 @@
1
+ module Mercy
2
+ module ClassMethods
3
+
4
+ def status_report(*attr_names)
5
+ id = attr_names.first
6
+ options = {
7
+ id: id
8
+ }.merge(attr_names.extract_options!)
9
+
10
+ self.status_builder.add_report_config(id, options)
11
+ end
12
+
13
+ def status_builder
14
+ @status_builder ||= Mercy::StatusBuilder.new
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,8 @@
1
+ module Mercy
2
+ extend ActiveSupport::Concern
3
+
4
+ def render_status(key = :default)
5
+ status = self.class.status_builder.build(key, params)
6
+ render json: status.as_json.stringify_keys.to_deep_hash, status: status.status
7
+ end
8
+ end
@@ -1,4 +1,4 @@
1
- module Bidu
1
+ module Mercy
2
2
  class PeriodParser
3
3
  class << self
4
4
  def parse(period)
@@ -0,0 +1,42 @@
1
+ module Mercy
2
+ class Report
3
+ include Arstotzka
4
+ require 'mercy/report/active_record'
5
+ require 'mercy/report/error'
6
+ require 'mercy/report/range'
7
+ require 'mercy/report/multiple'
8
+ ALLOWED_PARAMETERS = []
9
+ DEFAULT_OPTION = {}
10
+
11
+ attr_reader :json
12
+
13
+ expose :id, case: :snake
14
+
15
+ def initialize(options = {})
16
+ @json = default_option.merge(options)
17
+ end
18
+
19
+ def status
20
+ @status ||= error? ? :error : :ok
21
+ end
22
+
23
+ def error?
24
+ raise 'Not implemented yet'
25
+ end
26
+
27
+ def as_json
28
+ { status: status }
29
+ end
30
+
31
+ private
32
+
33
+ def default_option
34
+ self.class.default_options
35
+ end
36
+
37
+ def self.default_options
38
+ return {} if self == Report
39
+ self.superclass.default_options.merge(self::DEFAULT_OPTION)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,26 @@
1
+ module Mercy
2
+ class Report::ActiveRecord < Report
3
+ expose :period, type: :period
4
+ expose :clazz, :base_scope, case: :snake
5
+
6
+ private
7
+
8
+ def fetch_scoped(base, scope)
9
+ if (scope.is_a?(Symbol))
10
+ scope.to_s.split('.').inject(base) do |entries, method|
11
+ entries.public_send(method)
12
+ end
13
+ else
14
+ base.where(scope)
15
+ end
16
+ end
17
+
18
+ def last_entries
19
+ @last_entries ||= base.where('updated_at >= ?', period.seconds.ago)
20
+ end
21
+
22
+ def base
23
+ fetch_scoped(clazz, base_scope)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,60 @@
1
+ module Mercy
2
+ class Report
3
+ class Error < Report::ActiveRecord
4
+ ALLOWED_PARAMETERS=[:period, :threshold]
5
+ DEFAULT_OPTION = {
6
+ external_key: :id,
7
+ threshold: 0.02,
8
+ period: 1.day,
9
+ scope: :with_error,
10
+ base_scope: :all,
11
+ uniq: false
12
+ }
13
+
14
+ expose :threshold, type: :float
15
+ expose :scope, :external_key, :uniq, :limit, case: :snake
16
+
17
+ def initialize(options)
18
+ super(self.class::DEFAULT_OPTION.merge(options))
19
+ end
20
+
21
+ def percentage
22
+ @percentage ||= fetch_percentage
23
+ end
24
+
25
+ def scoped
26
+ @scoped ||= fetch_scoped(last_entries, scope)
27
+ end
28
+
29
+ def error?
30
+ @error ||= percentage > threshold
31
+ end
32
+
33
+ def as_json
34
+ {
35
+ ids: ids,
36
+ percentage: percentage,
37
+ status: status
38
+ }
39
+ end
40
+
41
+ private
42
+
43
+ def ids
44
+ relation = scoped
45
+ relation = relation.distinct if uniq
46
+ relation = relation.limit(limit) if limit
47
+
48
+ relation.pluck(external_key)
49
+ end
50
+
51
+ def fetch_percentage
52
+ if (scope.is_a?(Symbol))
53
+ last_entries.percentage(*(scope.to_s.split('.').map(&:to_sym)))
54
+ else
55
+ last_entries.percentage(scope)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -1,4 +1,4 @@
1
- module Bidu::Mercy::Report::Multiple
1
+ module Mercy::Report::Multiple
2
2
  def as_json
3
3
  {
4
4
  status: status
@@ -0,0 +1,48 @@
1
+ module Mercy
2
+ class Report
3
+ class Range < Report::ActiveRecord
4
+ ALLOWED_PARAMETERS=[:period, :maximum, :minimum]
5
+ DEFAULT_OPTION = {
6
+ period: 1.day,
7
+ scope: :all,
8
+ }
9
+
10
+ expose :scope
11
+ expose :maximum, type: :infinity_float, default: 'inf'
12
+ expose :minimum, type: :infinity_float, default: '-inf'
13
+
14
+ def initialize(options)
15
+ super(DEFAULT_OPTION.merge(options))
16
+ end
17
+
18
+ def scoped
19
+ @scoped ||= fetch_scoped(last_entries, scope)
20
+ end
21
+
22
+ def error?
23
+ @error ||= !count_in_range?
24
+ end
25
+
26
+ def as_json
27
+ {
28
+ status: status,
29
+ count: count
30
+ }
31
+ end
32
+
33
+ def count
34
+ scoped.count
35
+ end
36
+
37
+ private
38
+
39
+ def range
40
+ (minimum..maximum)
41
+ end
42
+
43
+ def count_in_range?
44
+ return range.include?(count)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,22 @@
1
+ module Mercy
2
+ class ReportBuilder
3
+ def build(key, parameters = {})
4
+ config = config_for(key)
5
+ config.build(parameters)
6
+ end
7
+
8
+ def add_config(key, config)
9
+ configs[key] = Mercy::ReportConfig.new(config)
10
+ end
11
+
12
+ private
13
+
14
+ def config_for(key)
15
+ configs[key]
16
+ end
17
+
18
+ def configs
19
+ @configs ||= {}
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,35 @@
1
+ module Mercy
2
+ class ReportConfig
3
+ attr_accessor :config
4
+
5
+ delegate :[], :[]=, :merge, to: :config
6
+
7
+ def initialize(config)
8
+ @config = config
9
+ end
10
+
11
+ def build(parameters)
12
+ params = slice_parameters(parameters)
13
+ report_class.new(config.merge(params))
14
+ end
15
+
16
+ private
17
+
18
+ def type
19
+ self[:type] ||= :error
20
+ end
21
+
22
+ def report_class
23
+ return type if type.is_a?(Class)
24
+ @report_class ||= Mercy::Report.const_get(type.to_s.camelize)
25
+ end
26
+
27
+ def slice_parameters(parameters)
28
+ parameters.slice(*allowed_parameters)
29
+ end
30
+
31
+ def allowed_parameters
32
+ report_class::ALLOWED_PARAMETERS
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,25 @@
1
+ module Mercy
2
+ class Status
3
+ attr_reader :reports
4
+
5
+ def initialize(reports)
6
+ @reports = reports
7
+ end
8
+
9
+ def status
10
+ reports.any? { |r| r.error? } ? :error : :ok
11
+ end
12
+
13
+ def as_json
14
+ {
15
+ status: status
16
+ }.merge(reports_jsons)
17
+ end
18
+
19
+ private
20
+
21
+ def reports_jsons
22
+ reports.map(&:as_json).as_hash(reports.map(&:id))
23
+ end
24
+ end
25
+ end