cronitor 4.1.0 → 5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d91bccffc3a53dfe487e4740c00aa83b47fe31c4347a1bdc93e017bbb3467751
4
- data.tar.gz: 5730c8a4742bab773c1e3582fa4f00298890171e91ef96b83fda8e0a6ebd6470
3
+ metadata.gz: 1c33ade0ff17f4941318a1483b1255556d2b5d7b3c89c41fa70ffb9d6bc05a4b
4
+ data.tar.gz: 2e2c69fe75cf72f65964d59994a3dce7e58266449bd21be76428b4c1f32d354a
5
5
  SHA512:
6
- metadata.gz: '054173538e57d465de2cc25786a42ccdb80c2be0532f0526634153de3fd7c46f428cdeaded4dd84e6169a9aa5717439bab0b1b4cc9672b56b93543ae58183ae3'
7
- data.tar.gz: 311901851f90644a7d0c46eeed1b2bd821880816090799d1601008e29fa19a4cad2199905f317a9a08225296d579ba054bc87456dadf19fe427f3487c0ac42ce
6
+ metadata.gz: 98a47cd2ded8d3661ea8527b4dfd4b457b6b6d92ed101fac6f58e5d43eb791564b7f074dbfed5019036f9b1a01ed3f6f0687d8bbd90c5c19f3a7cf21cbe5d5d0
7
+ data.tar.gz: f69e2de58e9cfa009e4255c6613e5338d68babdac5bd3848e9b1aea8ee4e6411694750b4e933dadaa447a0033b51f4ef120801e5305f704785c7bfedb4ce79ee
data/.rubocop.yml CHANGED
@@ -12,6 +12,9 @@ AllCops:
12
12
  TargetRubyVersion: 2.5
13
13
  Exclude:
14
14
  - 'spec/cronitor_spec.rb'
15
+
16
+ RequireMFA:
17
+ Enabled: false
15
18
 
16
19
  Metrics/AbcSize:
17
20
  Enabled: false
data/README.md CHANGED
@@ -8,13 +8,12 @@
8
8
 
9
9
  In this guide:
10
10
 
11
- - [Installation](##Installation)
12
- - [Monitoring Background Jobs](##monitoring-background-jobs)
13
- - [Sending Telemetry Events](##sending-telemetry-events)
14
- - [Configuring Monitors](##configuring-monitors)
15
- - [Package Configuration & Env Vars](##package-configuration)
16
- - [Command Line Usage](##command-line-usage)
17
- - [Contributing](##contributing)
11
+ - [Installation](#Installation)
12
+ - [Monitoring Background Jobs](#monitoring-background-jobs)
13
+ - [Sending Telemetry Events](#sending-telemetry-events)
14
+ - [Configuring Monitors](#configuring-monitors)
15
+ - [Package Configuration & Env Vars](#package-configuration)
16
+ - [Contributing](#contributing)
18
17
 
19
18
  ## Installation
20
19
 
@@ -70,7 +69,7 @@ a deployment or build process. For details on all of the attributes that can be
70
69
  require 'cronitor'
71
70
  Cronitor.api_key = 'api_key_123'
72
71
 
73
- # read config file and set credentials (if included).
72
+ # read config file.
74
73
  Cronitor.read_config('./cronitor.yaml')
75
74
 
76
75
  # sync config file's monitors to Cronitor.
@@ -79,9 +78,12 @@ Cronitor.apply_config
79
78
  # send config file's monitors to Cronitor to validate correctness.
80
79
  # monitors will not be saved.
81
80
  Cronitor.validate_config
81
+
82
+ # generate a new config file from the Cronitor API.
83
+ Cronitor.generate_config
82
84
  ```
83
85
 
84
- The `cronitor.yaml` file includes three top level keys `jobs`, `checks`, `events`. You can configure monitors under each key by defining [monitors](https://cronitor.io/docs/monitor-api#attributes).
86
+ The `cronitor.yaml` file includes three top level keys `jobs`, `checks`, `heartbeats`. You can configure monitors under each key by defining [monitors](https://cronitor.io/docs/monitor-api#attributes).
85
87
 
86
88
  ```yaml
87
89
  jobs:
@@ -179,6 +181,11 @@ require 'cronitor'
179
181
  Cronitor.api_key = 'apiKey123'
180
182
  Cronitor.api_version = '2020-10-01'
181
183
  Cronitor.environment = 'cluster_1_prod'
184
+
185
+ Cronitor.timeout = 20 # defaults to 10 can also be set with ENV['CRONITOR_TIMEOUT']
186
+ Cronitor.logger = nil # defaults to Logger.new($stdout)
187
+ # faster timeout for potentially more time sensitive call
188
+ Cronitor.ping_timeout = 10 # defaults to 5 can also be set with ENV['CRONITOR_PING_TIMEOUT']
182
189
  ```
183
190
 
184
191
  ## Contributing
@@ -1,33 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cronitor
4
- TYPE_JOB = 'job'
5
- TYPE_HEARTBEAT = 'heartbeat'
6
- TYPE_CHECK = 'check'
7
- MONITOR_TYPES = [TYPE_JOB, TYPE_HEARTBEAT, TYPE_CHECK].freeze
8
- YAML_KEYS = %w[
9
- api_key
10
- api_version
11
- environment
12
- ] + MONITOR_TYPES.map { |t| "#{t}s" }
4
+ MONITOR_TYPES = [
5
+ TYPE_JOB = 'job',
6
+ TYPE_HEARTBEAT = 'heartbeat',
7
+ TYPE_CHECK = 'check'
8
+ ].freeze
9
+ YAML_KEYS = MONITOR_TYPES.map { |t| "#{t}s" }
13
10
 
14
11
  class << self
15
- attr_accessor :api_key, :api_version, :environment, :logger, :config, :_headers
12
+ attr_accessor :api_key, :api_version, :environment, :logger, :config, :timeout, :ping_timeout
16
13
 
17
14
  def configure(&block)
18
15
  block.call(self)
19
16
  end
20
17
  end
21
18
 
22
- self.api_key = ENV['CRONITOR_API_KEY']
23
- self.api_version = ENV['CRONITOR_API_VERSION']
24
- self.environment = ENV['CRONITOR_ENVIRONMENT']
25
- self.config = ENV['CRONITOR_CONFIG']
19
+ self.api_key = ENV.fetch('CRONITOR_API_KEY', nil)
20
+ self.api_version = ENV.fetch('CRONITOR_API_VERSION', nil)
21
+ self.environment = ENV.fetch('CRONITOR_ENVIRONMENT', nil)
22
+ self.timeout = ENV.fetch('CRONITOR_TIMEOUT', nil) || 10
23
+ self.ping_timeout = ENV.fetch('CRONITOR_PING_TIMEOUT', nil) || 5
24
+ self.config = ENV.fetch('CRONITOR_CONFIG', nil)
26
25
  self.logger = Logger.new($stdout)
27
26
  logger.level = Logger::INFO
28
- self._headers = {
29
- 'Content-Type': 'application/json',
30
- 'User-Agent': 'cronitor-ruby',
31
- 'Cronitor-Version': Cronitor.api_version
32
- }
33
27
  end
@@ -6,56 +6,89 @@ module Cronitor
6
6
 
7
7
  PING_RETRY_THRESHOLD = 5
8
8
 
9
+ module Formats
10
+ ALL = [
11
+ JSON = 'json',
12
+ YAML = 'yaml'
13
+ ].freeze
14
+ end
15
+
16
+ module Headers
17
+ JSON = {
18
+ 'Content-Type': 'application/json',
19
+ 'User-Agent': "cronitor-ruby-#{Cronitor::VERSION}",
20
+ 'Cronitor-Version': Cronitor.api_version
21
+ }.freeze
22
+ YAML = JSON.merge({
23
+ 'Content-Type': 'application/yaml'
24
+ })
25
+ end
26
+
9
27
  def self.put(opts = {})
10
28
  rollback = opts[:rollback] || false
11
29
  opts.delete(:rollback)
12
30
 
13
31
  monitors = opts[:monitors] || [opts]
14
32
 
33
+ if opts[:format] == Cronitor::Monitor::Formats::YAML
34
+ url = "#{Cronitor.monitor_api_url}.yaml"
35
+ monitors['rollback'] = true if rollback
36
+ body = YAML.dump(monitors)
37
+ headers = Cronitor::Monitor::Headers::YAML
38
+ else
39
+ url = Cronitor.monitor_api_url
40
+ body = {
41
+ monitors: monitors,
42
+ rollback: rollback
43
+ }.to_json
44
+ headers = Cronitor::Monitor::Headers::JSON
45
+ end
46
+
15
47
  resp = HTTParty.put(
16
- Cronitor.monitor_api_url,
48
+ url,
17
49
  basic_auth: {
18
50
  username: Cronitor.api_key,
19
51
  password: ''
20
52
  },
21
- body: {
22
- monitors: monitors,
23
- rollback: rollback
24
- }.to_json,
25
- headers: Cronitor._headers,
26
- timeout: 10
53
+ body: body,
54
+ headers: headers,
55
+ timeout: opts[:timeout] || Cronitor.timeout
27
56
  )
28
57
 
29
58
  case resp.code
30
59
  when 200
31
- out = []
32
- data = JSON.parse(resp.body)
33
-
34
- (data['monitors'] || []).each do |md|
35
- m = Monitor.new(md['key'])
36
- m.data = Cronitor.symbolize_keys(md)
37
- out << m
60
+ if opts[:format] == Cronitor::Monitor::Formats::YAML
61
+ YAML.safe_load(resp.body)
62
+ else
63
+ out = []
64
+ data = JSON.parse(resp.body)
65
+
66
+ (data['monitors'] || []).each do |md|
67
+ m = Monitor.new(md['key'])
68
+ m.data = Cronitor.symbolize_keys(md)
69
+ out << m
70
+ end
71
+ out.length == 1 ? out[0] : out
38
72
  end
39
- out.length == 1 ? out[0] : out
40
73
  when 400
41
74
  raise ValidationError.new(resp.body)
42
75
  else
43
- raise Error.new("Error connecting to Cronitor: #{resp.code}")
76
+ raise Error.new("Error connecting to Cronitor: #{resp.code}\n #{resp.body}")
44
77
  end
45
78
  end
46
79
 
47
80
  def self.delete(key)
48
81
  resp = HTTParty.delete(
49
82
  "#{Cronitor.monitor_api_url}/#{key}",
50
- timeout: 10,
83
+ timeout: Cronitor.timeout,
51
84
  basic_auth: {
52
85
  username: Cronitor.api_key,
53
86
  password: ''
54
87
  },
55
- headers: Cronitor._headers
88
+ headers: Cronitor::Monitor::Headers::JSON
56
89
  )
57
90
  if resp.code != 204
58
- Cronitor.logger.error("Error deleting monitor: #{key}")
91
+ Cronitor.logger&.error("Error deleting monitor: #{key}")
59
92
  return false
60
93
  end
61
94
  true
@@ -81,7 +114,7 @@ module Cronitor
81
114
  def ping(params = {})
82
115
  retry_count = params[:retry_count] || 0
83
116
  if api_key.nil?
84
- Cronitor.logger.error('No API key detected. Set Cronitor.api_key or initialize Monitor with an api_key:')
117
+ Cronitor.logger&.error('No API key detected. Set Cronitor.api_key or initialize Monitor with an api_key:')
85
118
  return false
86
119
  end
87
120
 
@@ -92,8 +125,8 @@ module Cronitor
92
125
  response = HTTParty.get(
93
126
  ping_url,
94
127
  query: clean_params(params),
95
- timeout: 5,
96
- headers: Cronitor._headers,
128
+ timeout: Cronitor.ping_timeout,
129
+ headers: Cronitor::Monitor::Headers::JSON,
97
130
  query_string_normalizer: lambda do |query|
98
131
  query.compact!
99
132
  metrics = query[:metric]
@@ -106,18 +139,18 @@ module Cronitor
106
139
  )
107
140
 
108
141
  if response.code != 200
109
- Cronitor.logger.error("Cronitor Telemetry Error: #{response.code}")
142
+ Cronitor.logger&.error("Cronitor Telemetry Error: #{response.code}")
110
143
  return false
111
144
  end
112
145
  true
113
146
  rescue StandardError => e
114
147
  # rescue instances of StandardError i.e. Timeout::Error, SocketError, etc
115
- Cronitor.logger.error("Cronitor Telemetry Error: #{e}")
148
+ Cronitor.logger&.error("Cronitor Telemetry Error: #{e}")
116
149
  return false if retry_count >= Monitor::PING_RETRY_THRESHOLD
117
150
 
118
151
  # apply a backoff before sending the next ping
119
152
  sleep(retry_count * 1.5 * rand)
120
- ping(params.merge(retry_count: params[:retry_count] + 1))
153
+ ping(params.merge(retry_count: retry_count + 1))
121
154
  end
122
155
  end
123
156
 
@@ -131,8 +164,8 @@ module Cronitor
131
164
 
132
165
  resp = HTTParty.get(
133
166
  pause_url,
134
- timeout: 5,
135
- headers: Cronitor._headers,
167
+ timeout: Cronitor.timeout,
168
+ headers: Cronitor::Monitor::Headers::JSON,
136
169
  basic_auth: {
137
170
  username: api_key,
138
171
  password: ''
@@ -162,13 +195,13 @@ module Cronitor
162
195
 
163
196
  def fetch
164
197
  unless api_key
165
- Cronitor.logger.error(
198
+ Cronitor.logger&.error(
166
199
  'No API key detected. Set Cronitor.api_key or initialize Monitor with the api_key kwarg'
167
200
  )
168
201
  return
169
202
  end
170
203
 
171
- HTTParty.get(monitor_api_url, timeout: 10, headers: Cronitor._headers, format: :json)
204
+ HTTParty.get(monitor_api_url, timeout: Cronitor.timeout, headers: Cronitor::Monitor::Headers::JSON, format: :json)
172
205
  end
173
206
 
174
207
  def clean_params(params)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cronitor
4
- VERSION = '4.1.0'
4
+ VERSION = '5.0.0'
5
5
  end
data/lib/cronitor.rb CHANGED
@@ -13,7 +13,7 @@ require 'cronitor/version'
13
13
  require 'cronitor/monitor'
14
14
 
15
15
  module Cronitor
16
- def self.read_config(path = nil, output: false)
16
+ def self.read_config(path = nil)
17
17
  Cronitor.config = path || Cronitor.config
18
18
  unless Cronitor.config
19
19
  raise ConfigurationError.new(
@@ -26,39 +26,23 @@ module Cronitor
26
26
  conf.each do |k, _v|
27
27
  raise ConfigurationError.new("Invalid configuration variable: #{k}") unless Cronitor::YAML_KEYS.include?(k)
28
28
  end
29
-
30
- Cronitor.api_key = conf[:api_key] if conf[:api_key]
31
- Cronitor.api_version = conf[:api_version] if conf[:api_version]
32
- Cronitor.environment = conf[:environment] if conf[:environment]
33
-
34
- return unless output
35
-
36
- monitors = []
37
- Cronitor::MONITOR_TYPES.each do |t|
38
- plural_t = "#{t}s"
39
- to_parse = conf[t] || conf[plural_t] || nil
40
- next unless to_parse
41
-
42
- unless to_parse.is_a?(Hash)
43
- raise ConfigurationError.new('A Hash with keys corresponding to monitor keys is expected.')
44
- end
45
-
46
- to_parse.each do |key, m|
47
- m['key'] = key
48
- m['type'] = t
49
- monitors << m
50
- end
51
- end
52
- conf['monitors'] = monitors
53
29
  conf
54
30
  end
55
31
 
56
32
  def self.apply_config(rollback: false)
57
- conf = read_config(output: true)
58
- monitors = Monitor.put(monitors: conf.fetch('monitors', []), rollback: rollback)
59
- puts("#{monitors.length} monitors #{rollback ? 'validated' : 'synced to Cronitor'}.")
33
+ conf = read_config
34
+ # allow a significantly longer timeout on requests that are sending full yaml config. min 30 seconds.
35
+ timeout = Cronitor.timeout < 30 ? 30 : Cronitor.timeout
36
+ monitors = Monitor.put(monitors: conf, format: Cronitor::Monitor::Formats::YAML, rollback: rollback,
37
+ timeout: timeout)
38
+ count = 0
39
+ # step through the different monitor types and count up all the returned configurations
40
+ Cronitor::YAML_KEYS.each do |k|
41
+ count += (monitors[k]&.count || 0)
42
+ end
43
+ puts("#{count} monitors #{rollback ? 'validated' : 'synced to Cronitor'}.")
60
44
  rescue ValidationError => e
61
- Cronitor.logger.error(e)
45
+ Cronitor.logger&.error(e)
62
46
  end
63
47
 
64
48
  def self.validate_config
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cronitor
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.0
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Byrnes
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2021-05-20 00:00:00.000000000 Z
12
+ date: 2022-05-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: httparty