logster 1.1.1 → 1.2.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/README.md +4 -0
- data/lib/logster/configuration.rb +1 -1
- data/lib/logster/redis_store.rb +42 -24
- data/lib/logster/version.rb +1 -1
- data/test/logster/test_redis_rate_limiter.rb +13 -8
- data/test/logster/test_redis_store.rb +52 -10
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 97266a5b02f788e8537daaf28e0adff771a3bf6b
|
4
|
+
data.tar.gz: f43b618a847f9e98f54ecb9e469a29e0354a6947
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 22657415d4f4173ed2a1850e43a146d81db3c53e33d6009f99069fbe81671fb65d88809fc79a963b06744a17e288364706d1ef63127bcacb3076cc9be789e28d
|
7
|
+
data.tar.gz: 7e57a8c7862c3375948e2a097b89c1c1d3f023e33a32c928196371e3c7ef4c02b90df6828790d12fafb49c21acccf5b7810abe32220f4030e012ed463a271081
|
data/README.md
CHANGED
@@ -97,6 +97,10 @@ Logster UI is built using [Ember.js](http://emberjs.com/)
|
|
97
97
|
|
98
98
|
# CHANGELOG
|
99
99
|
|
100
|
+
- 2015-03-18: Version 1.2.0
|
101
|
+
- Fix: Move Redis configuration into RedisStore.
|
102
|
+
- Feature: Allow `RedisStore#redis_prefix` to either be a String or a Proc.
|
103
|
+
|
100
104
|
- 2015-02-11: Version 1.1.1
|
101
105
|
- Feature: Error rate can now be tracked in one minute and one hour buckets.
|
102
106
|
|
data/lib/logster/redis_store.rb
CHANGED
@@ -4,20 +4,15 @@ require 'logster/base_store'
|
|
4
4
|
module Logster
|
5
5
|
class RedisRateLimiter
|
6
6
|
BUCKETS = 6
|
7
|
+
PREFIX = "__LOGSTER__RATE_LIMIT".freeze
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
def initialize(redis, severities, limit, duration, callback = nil)
|
11
|
-
@redis = use_raw_connection? ? Logster.config.redis_raw_connection : redis
|
9
|
+
def initialize(redis, severities, limit, duration, redis_prefix = nil, callback = nil)
|
12
10
|
@severities = severities
|
13
11
|
@limit = limit
|
14
12
|
@duration = duration
|
15
13
|
@callback = callback
|
16
|
-
|
17
|
-
|
18
|
-
# Triggers callback when log levels of :debug, :info and :warn occurs 20 times within 30 secs
|
19
|
-
@key = "#{key_prefix}#{@severities.join("")}:#{@limit}:#{@duration}"
|
20
|
-
@callback_key = "#{@key}:callback_triggered"
|
14
|
+
@redis_prefix = redis_prefix
|
15
|
+
@redis = redis
|
21
16
|
@bucket_range = @duration / BUCKETS
|
22
17
|
end
|
23
18
|
|
@@ -25,7 +20,7 @@ module Logster
|
|
25
20
|
return unless @severities.include?(severity)
|
26
21
|
time = Time.now.to_i
|
27
22
|
num = bucket_number(time)
|
28
|
-
redis_key = "#{
|
23
|
+
redis_key = "#{key}:#{num}"
|
29
24
|
|
30
25
|
current_rate = @redis.eval <<-LUA
|
31
26
|
local bucket_number = #{num}
|
@@ -48,20 +43,32 @@ module Logster
|
|
48
43
|
return (retrieve_rate() + bucket_count)
|
49
44
|
LUA
|
50
45
|
|
51
|
-
if !@redis.get(
|
46
|
+
if !@redis.get(callback_key) && (current_rate >= @limit)
|
52
47
|
@callback.call(current_rate) if @callback
|
53
|
-
@redis.set(
|
48
|
+
@redis.set(callback_key, 1)
|
54
49
|
end
|
55
50
|
|
56
51
|
current_rate
|
57
52
|
end
|
58
53
|
|
54
|
+
def key
|
55
|
+
# "_LOGSTER_RATE_LIMIT:012:20:30"
|
56
|
+
# Triggers callback when log levels of :debug, :info and :warn occurs 20 times within 30 secs
|
57
|
+
"#{key_prefix}:#{@severities.join("")}:#{@limit}:#{@duration}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def callback_key
|
61
|
+
"#{@key}:callback_triggered"
|
62
|
+
end
|
63
|
+
|
59
64
|
private
|
60
65
|
|
61
66
|
def key_prefix
|
62
|
-
|
63
|
-
|
64
|
-
|
67
|
+
if @redis_prefix
|
68
|
+
"#{@redis_prefix.call}:#{PREFIX}"
|
69
|
+
else
|
70
|
+
PREFIX
|
71
|
+
end
|
65
72
|
end
|
66
73
|
|
67
74
|
def mget_keys(bucket_num)
|
@@ -78,15 +85,12 @@ module Logster
|
|
78
85
|
def bucket_expiry(time)
|
79
86
|
@duration - ((time % @duration) % @bucket_range)
|
80
87
|
end
|
81
|
-
|
82
|
-
def use_raw_connection?
|
83
|
-
Logster.config.redis_prefix && Logster.config.redis_raw_connection
|
84
|
-
end
|
85
88
|
end
|
86
89
|
|
87
90
|
class RedisStore < BaseStore
|
88
91
|
|
89
|
-
attr_accessor :redis, :max_backlog
|
92
|
+
attr_accessor :redis, :max_backlog, :redis_raw_connection
|
93
|
+
attr_writer :redis_prefix
|
90
94
|
|
91
95
|
def initialize(redis = nil)
|
92
96
|
super()
|
@@ -269,10 +273,16 @@ module Logster
|
|
269
273
|
register_rate_limit(severities, limit, 3600, block)
|
270
274
|
end
|
271
275
|
|
276
|
+
def redis_prefix
|
277
|
+
return 'default'.freeze if !@redis_prefix
|
278
|
+
@prefix_is_proc ||= @redis_prefix.respond_to?(:call)
|
279
|
+
@prefix_is_proc ? @redis_prefix.call : @redis_prefix
|
280
|
+
end
|
281
|
+
|
272
282
|
protected
|
273
283
|
|
274
284
|
def rate_limits
|
275
|
-
@rate_limits ||=
|
285
|
+
@rate_limits ||= {}
|
276
286
|
end
|
277
287
|
|
278
288
|
def clear_solved(count = nil)
|
@@ -395,7 +405,9 @@ module Logster
|
|
395
405
|
end
|
396
406
|
|
397
407
|
def check_rate_limits(severity)
|
398
|
-
|
408
|
+
rate_limits_to_check = rate_limits[self.redis_prefix]
|
409
|
+
return if !rate_limits_to_check
|
410
|
+
rate_limits_to_check.each { |rate_limit| rate_limit.check(severity) }
|
399
411
|
end
|
400
412
|
|
401
413
|
def solved_key
|
@@ -422,8 +434,14 @@ module Logster
|
|
422
434
|
|
423
435
|
def register_rate_limit(severities, limit, duration, callback)
|
424
436
|
severities = [severities] unless severities.is_a?(Array)
|
425
|
-
|
426
|
-
|
437
|
+
redis = (@redis_raw_connection && @redis_prefix) ? @redis_raw_connection : @redis
|
438
|
+
|
439
|
+
rate_limiter = RedisRateLimiter.new(
|
440
|
+
redis, severities, limit, duration, Proc.new { redis_prefix }, callback
|
441
|
+
)
|
442
|
+
|
443
|
+
rate_limits[self.redis_prefix] ||= []
|
444
|
+
rate_limits[self.redis_prefix] << rate_limiter
|
427
445
|
rate_limiter
|
428
446
|
end
|
429
447
|
end
|
data/lib/logster/version.rb
CHANGED
@@ -17,7 +17,7 @@ class TestRedisRateLimiter < Minitest::Test
|
|
17
17
|
called = 0
|
18
18
|
|
19
19
|
@rate_limiter = Logster::RedisRateLimiter.new(
|
20
|
-
@redis, [Logger::WARN], 8, 60, Proc.new { called += 1 }
|
20
|
+
@redis, [Logger::WARN], 8, 60, nil, Proc.new { called += 1 }
|
21
21
|
)
|
22
22
|
|
23
23
|
assert_equal(1, @rate_limiter.check(Logger::WARN))
|
@@ -82,7 +82,7 @@ class TestRedisRateLimiter < Minitest::Test
|
|
82
82
|
called = 0
|
83
83
|
|
84
84
|
@rate_limiter = Logster::RedisRateLimiter.new(
|
85
|
-
@redis, [Logger::WARN, Logger::ERROR], 4, 60, Proc.new { called += 1 }
|
85
|
+
@redis, [Logger::WARN, Logger::ERROR], 4, 60, nil, Proc.new { called += 1 }
|
86
86
|
)
|
87
87
|
|
88
88
|
assert_equal(1, @rate_limiter.check(Logger::WARN))
|
@@ -138,14 +138,19 @@ class TestRedisRateLimiter < Minitest::Test
|
|
138
138
|
def test_raw_connection
|
139
139
|
time = Time.new(2015, 1, 1, 1, 1)
|
140
140
|
Timecop.freeze(time)
|
141
|
-
Logster.
|
142
|
-
Logster.config.redis_raw_connection = @redis
|
143
|
-
|
144
|
-
@rate_limiter = Logster::RedisRateLimiter.new(nil, [Logger::WARN], 1, 60)
|
141
|
+
@rate_limiter = Logster::RedisRateLimiter.new(@redis, [Logger::WARN], 1, 60, Proc.new { "lobster" })
|
145
142
|
|
146
143
|
assert_equal(1, @rate_limiter.check(Logger::WARN))
|
147
|
-
assert_includes(key, "lobster")
|
148
144
|
assert_redis_key(60, 0)
|
145
|
+
|
146
|
+
array = ['lobster1', 'lobster2']
|
147
|
+
|
148
|
+
@rate_limiter = Logster::RedisRateLimiter.new(
|
149
|
+
@redis, [Logger::WARN], 1, 60, Proc.new { array.delete_at(0) }
|
150
|
+
)
|
151
|
+
|
152
|
+
assert_includes(key, "lobster1")
|
153
|
+
assert_includes(key, "lobster2")
|
149
154
|
end
|
150
155
|
|
151
156
|
private
|
@@ -172,7 +177,7 @@ class TestRedisRateLimiter < Minitest::Test
|
|
172
177
|
|
173
178
|
def assert_redis_key(expected_ttl, expected_bucket_number)
|
174
179
|
redis_key = "#{key}:#{expected_bucket_number}"
|
175
|
-
assert(@redis.get(redis_key))
|
180
|
+
assert(@redis.get(redis_key), "the right bucket should be created")
|
176
181
|
assert_equal(expected_ttl, @redis.ttl(redis_key))
|
177
182
|
end
|
178
183
|
end
|
@@ -326,19 +326,61 @@ class TestRedisStore < Minitest::Test
|
|
326
326
|
assert_equal(orig, env)
|
327
327
|
end
|
328
328
|
|
329
|
-
|
330
|
-
|
331
|
-
|
329
|
+
def test_rate_limits
|
330
|
+
%w{minute hour}.each do |duration|
|
331
|
+
begin
|
332
|
+
called = false
|
333
|
+
|
334
|
+
assert_instance_of(
|
335
|
+
Logster::RedisRateLimiter,
|
336
|
+
@store.public_send("register_rate_limit_per_#{duration}", Logger::WARN, 0) do
|
337
|
+
called = true
|
338
|
+
end
|
339
|
+
)
|
340
|
+
|
341
|
+
@store.report(Logger::WARN, "test", "test")
|
342
|
+
assert called
|
343
|
+
ensure
|
344
|
+
reset_redis
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
def test_rate_limits_with_prefix
|
350
|
+
begin
|
351
|
+
time = Time.now
|
352
|
+
Timecop.freeze(time)
|
353
|
+
current_namespace = 'first'
|
354
|
+
@store.redis_prefix = Proc.new { current_namespace }
|
355
|
+
|
356
|
+
called_first = 0
|
357
|
+
called_second = 0
|
332
358
|
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
called = true
|
337
|
-
end
|
338
|
-
)
|
359
|
+
@store.register_rate_limit_per_minute(Logger::WARN, 0) { called_first += 1 }
|
360
|
+
@store.report(Logger::WARN, "test", "test")
|
361
|
+
assert_equal(1, called_first)
|
339
362
|
|
363
|
+
current_namespace = 'second'
|
364
|
+
@store.register_rate_limit_per_minute(Logger::WARN, 0) { called_second += 1 }
|
340
365
|
@store.report(Logger::WARN, "test", "test")
|
341
|
-
|
366
|
+
assert_equal(1, called_first)
|
367
|
+
assert_equal(1, called_second)
|
368
|
+
|
369
|
+
Timecop.freeze(time + 10) do
|
370
|
+
current_namespace = 'first'
|
371
|
+
@store.report(Logger::WARN, "test", "test")
|
372
|
+
|
373
|
+
assert_equal(2, called_first)
|
374
|
+
assert_equal(1, called_second)
|
375
|
+
end
|
376
|
+
ensure
|
377
|
+
reset_redis
|
342
378
|
end
|
343
379
|
end
|
380
|
+
|
381
|
+
private
|
382
|
+
|
383
|
+
def reset_redis
|
384
|
+
@store.redis.flushall
|
385
|
+
end
|
344
386
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logster
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- UI for viewing logs in Rack
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-03-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|