kennel 2.8.2 → 2.10.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 +4 -4
- data/lib/kennel/api.rb +15 -15
- data/lib/kennel/models/monitor.rb +29 -2
- data/lib/kennel/models/project.rb +8 -1
- data/lib/kennel/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9213ac86e78dd85ff280d2048bd20fe3d074c3d6218cc45021b8c11eee7c720c
|
|
4
|
+
data.tar.gz: b2506ab43bb450a0496db0985ffa990b378ad591fa7be2a1c8db32223863680e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 73331755a7074cd0eeb95c92901cb8bf477380672a553cd7ef4722ec4cb6ea6f2fd56634eef442fb4a59de961d102c7b8b0f5b39788d006c24d960573eb27500
|
|
7
|
+
data.tar.gz: fa9ee34a57cce815f63eba43208daac2232cd04456f1200adc4181e6a381407b93962d52cbc5f9b27398caa863c8ab371758f5c216613b0218f8b9e958de6bc5
|
data/lib/kennel/api.rb
CHANGED
|
@@ -5,8 +5,6 @@ module Kennel
|
|
|
5
5
|
class Api
|
|
6
6
|
CACHE_FILE = ENV.fetch("KENNEL_API_CACHE_FILE", "tmp/cache/details")
|
|
7
7
|
|
|
8
|
-
RateLimitParams = Data.define(:limit, :period, :remaining, :reset, :name)
|
|
9
|
-
|
|
10
8
|
def self.with_tracking(api_resource, reply)
|
|
11
9
|
klass = Models::Record.api_resource_map[api_resource]
|
|
12
10
|
return reply unless klass # do not blow up on unknown models
|
|
@@ -125,20 +123,8 @@ module Kennel
|
|
|
125
123
|
end
|
|
126
124
|
end
|
|
127
125
|
|
|
128
|
-
rate_limit = RateLimitParams.new(
|
|
129
|
-
limit: response.headers["x-ratelimit-limit"],
|
|
130
|
-
period: response.headers["x-ratelimit-period"],
|
|
131
|
-
remaining: response.headers["x-ratelimit-remaining"],
|
|
132
|
-
reset: response.headers["x-ratelimit-reset"],
|
|
133
|
-
name: response.headers["x-ratelimit-name"]
|
|
134
|
-
)
|
|
135
|
-
|
|
136
126
|
if response.status == 429
|
|
137
|
-
|
|
138
|
-
message += " (#{rate_limit.limit} requests per #{rate_limit.period} seconds)"
|
|
139
|
-
message += "; sleeping #{rate_limit.reset} seconds before trying again"
|
|
140
|
-
Kennel.err.puts message
|
|
141
|
-
sleep rate_limit.reset.to_f
|
|
127
|
+
sleep_until_rate_limit_resets(response)
|
|
142
128
|
redo
|
|
143
129
|
end
|
|
144
130
|
|
|
@@ -161,6 +147,20 @@ module Kennel
|
|
|
161
147
|
end
|
|
162
148
|
end
|
|
163
149
|
|
|
150
|
+
def sleep_until_rate_limit_resets(response)
|
|
151
|
+
limit = response.headers["x-ratelimit-limit"]
|
|
152
|
+
period = response.headers["x-ratelimit-period"]
|
|
153
|
+
reset = response.headers["x-ratelimit-reset"]
|
|
154
|
+
name = response.headers["x-ratelimit-name"]
|
|
155
|
+
|
|
156
|
+
message = "Datadog rate limit #{name.inspect} hit"
|
|
157
|
+
message += " (#{limit} requests per #{period} seconds)"
|
|
158
|
+
message += "; sleeping #{reset} seconds before trying again"
|
|
159
|
+
|
|
160
|
+
Kennel.err.puts message
|
|
161
|
+
sleep reset.to_f
|
|
162
|
+
end
|
|
163
|
+
|
|
164
164
|
# allow caching all requests to speedup/benchmark logic that includes repeated requests
|
|
165
165
|
def with_cache(enabled, key)
|
|
166
166
|
return yield unless enabled
|
|
@@ -32,6 +32,12 @@ module Kennel
|
|
|
32
32
|
DEFAULT_ESCALATION_MESSAGE = ["", nil].freeze
|
|
33
33
|
ALLOWED_PRIORITY_CLASSES = [NilClass, Integer].freeze
|
|
34
34
|
SKIP_NOTIFY_NO_DATA_TYPES = ["event alert", "event-v2 alert", "log alert"].freeze
|
|
35
|
+
MINUTES_PER_UNIT = {
|
|
36
|
+
"m" => 1,
|
|
37
|
+
"h" => 60,
|
|
38
|
+
"d" => 60 * 24,
|
|
39
|
+
"w" => 60 * 24 * 7
|
|
40
|
+
}.freeze
|
|
35
41
|
|
|
36
42
|
settings(
|
|
37
43
|
:query, :name, :message, :escalation_message, :critical, :type, :renotify_interval, :warning, :timeout_h, :evaluation_delay,
|
|
@@ -49,13 +55,11 @@ module Kennel
|
|
|
49
55
|
# datadog UI sets this to false by default, but true is safer
|
|
50
56
|
# except for log alerts which will always have "no error" gaps and should default to false
|
|
51
57
|
notify_no_data: -> { !SKIP_NOTIFY_NO_DATA_TYPES.include?(type) },
|
|
52
|
-
no_data_timeframe: -> { 60 },
|
|
53
58
|
notify_audit: -> { MONITOR_OPTION_DEFAULTS.fetch(:notify_audit) },
|
|
54
59
|
new_host_delay: -> { MONITOR_OPTION_DEFAULTS.fetch(:new_host_delay) },
|
|
55
60
|
new_group_delay: -> { nil },
|
|
56
61
|
group_retention_duration: -> { MONITOR_OPTION_DEFAULTS.fetch(:group_retention_duration) },
|
|
57
62
|
tags: -> { @project.tags },
|
|
58
|
-
timeout_h: -> { MONITOR_OPTION_DEFAULTS.fetch(:timeout_h) },
|
|
59
63
|
evaluation_delay: -> { MONITOR_OPTION_DEFAULTS.fetch(:evaluation_delay) },
|
|
60
64
|
critical_recovery: -> { nil },
|
|
61
65
|
warning_recovery: -> { nil },
|
|
@@ -187,6 +191,24 @@ module Kennel
|
|
|
187
191
|
"cannot update type from #{actual_type} to #{type}"
|
|
188
192
|
end
|
|
189
193
|
|
|
194
|
+
# deprecated this setting is no longer returned by dd for new monitors
|
|
195
|
+
# datadog UI warns when setting no data timeframe to less than 2x the query window
|
|
196
|
+
# limited to 24h because `no_data_timeframe must not exceed group retention` and max group retention is 24h
|
|
197
|
+
def no_data_timeframe
|
|
198
|
+
default = 60
|
|
199
|
+
if type == "query alert" && (minutes = query_window_minutes)
|
|
200
|
+
(minutes * 2).clamp(default, 24 * 60)
|
|
201
|
+
else
|
|
202
|
+
default
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# validate that monitors that alert on no data resolve in external services by using timeout_h, so it sends a
|
|
207
|
+
# notification when the no data group is removed from the monitor, which datadog does automatically after 24h
|
|
208
|
+
def timeout_h
|
|
209
|
+
notify_no_data && on_missing_data != "resolve" ? 24 : MONITOR_OPTION_DEFAULTS.fetch(:timeout_h)
|
|
210
|
+
end
|
|
211
|
+
|
|
190
212
|
def self.api_resource
|
|
191
213
|
"monitor"
|
|
192
214
|
end
|
|
@@ -372,6 +394,11 @@ module Kennel
|
|
|
372
394
|
else # do nothing
|
|
373
395
|
end
|
|
374
396
|
end
|
|
397
|
+
|
|
398
|
+
def query_window_minutes
|
|
399
|
+
return unless (match = query.match(/^\s*\w+\(last_(?<count>\d+)(?<unit>[mhdw])\):/))
|
|
400
|
+
Integer(match["count"]) * MINUTES_PER_UNIT.fetch(match["unit"])
|
|
401
|
+
end
|
|
375
402
|
end
|
|
376
403
|
end
|
|
377
404
|
end
|
|
@@ -11,7 +11,7 @@ module Kennel
|
|
|
11
11
|
def self.file_location
|
|
12
12
|
return @file_location if defined?(@file_location)
|
|
13
13
|
if (location = instance_methods(false).first)
|
|
14
|
-
@file_location = instance_method(location).source_location.first
|
|
14
|
+
@file_location = force_relative_path(instance_method(location).source_location.first)
|
|
15
15
|
else
|
|
16
16
|
@file_location = nil
|
|
17
17
|
end
|
|
@@ -29,6 +29,13 @@ module Kennel
|
|
|
29
29
|
|
|
30
30
|
private
|
|
31
31
|
|
|
32
|
+
private_class_method def self.force_relative_path(path)
|
|
33
|
+
return path unless File.absolute_path?(path)
|
|
34
|
+
path.dup.sub!("#{Bundler.root}/", "") ||
|
|
35
|
+
path.dup.sub!("#{Dir.pwd}/", "") ||
|
|
36
|
+
raise("Unable to make path #{path} relative with bundler root #{Bundler.root} or pwd #{Dir.pwd}")
|
|
37
|
+
end
|
|
38
|
+
|
|
32
39
|
# hook for users to add custom filtering via `prepend`
|
|
33
40
|
def filter_parts(parts)
|
|
34
41
|
parts
|
data/lib/kennel/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kennel
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.10.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michael Grosser
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-01-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: diff-lcs
|