simple_events_redis 0.0.2
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 +15 -0
- data/README.md +41 -0
- data/lib/events.rb +348 -0
- metadata +46 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MzRlMWU0MjUxNGIxYmFiZTBiN2YzMDYyZjdkN2Q1NTA3ZDdhYzFlOQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NzFlOGMwOWVhNWZkMDdmNWFkNDA1MDJhOTYxMjAxYWI5MDViZGM1ZA==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
YzQ0ZjgyZGE0NGVhZWQwYjgxZjBjMmFiOThlYTFiZjZjZTVlZWFlZGRjOGRi
|
10
|
+
MzdjMzUwOGRkYTI5NzZiMTVjMTNmMjIyMTkwZjE5ZWRlNDk2ODVmN2IzYjM4
|
11
|
+
ZDZhYjI2NmE0MTczYjBiOWM5YTRkMDZlNWJiZmM5NjA0MGRlYzA=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YjdjOTBhNWRmMDNlZTQ0OTViMGNlOTQzMDViMzZkZDU5ODk4ODVkNmYyMzkx
|
14
|
+
ZjU0ODNiNDU1N2E5MDA0ODk4NGM3OWYyODliNWExYzM2M2VlMTVmMDk2NmNi
|
15
|
+
ZTA1MTdjNTI2NmMzOGNiNjNhYmJkYWI5MTk2MmRlODVhNzRhMTA=
|
data/README.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# Simple tracking of custom events
|
2
|
+
|
3
|
+
|
4
|
+
Library to store custom data in lists by days in Redis.
|
5
|
+
Old data is automatically removed.
|
6
|
+
Useful for debugging and tracking different events in application.
|
7
|
+
|
8
|
+
|
9
|
+
## Overview
|
10
|
+
Data is stored in Redis in lists with names:
|
11
|
+
<<YOUR_SITE_NAME>> : lists : <list_name> : <day> - Redis list
|
12
|
+
|
13
|
+
for example,
|
14
|
+
|
15
|
+
mysite:lists:mylist:20130407 - list for day April 04, 2013
|
16
|
+
|
17
|
+
|
18
|
+
## Installation
|
19
|
+
|
20
|
+
It uses gem 'redis' and relies on $redis global variable to access Redis server.
|
21
|
+
|
22
|
+
in Rails application:
|
23
|
+
|
24
|
+
gem 'redis'
|
25
|
+
gem 'lists_by_days_redis'
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
Setup:
|
30
|
+
|
31
|
+
initializer:
|
32
|
+
|
33
|
+
ListsByDaysRedis::List::SITE_NAME = 'mysite'
|
34
|
+
ListsByDaysRedis::List::EXPIRE_DAYS = 7
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
## Add new item to list
|
39
|
+
|
40
|
+
|
41
|
+
|
data/lib/events.rb
ADDED
@@ -0,0 +1,348 @@
|
|
1
|
+
module SimpleEventsRedis
|
2
|
+
|
3
|
+
require 'redis'
|
4
|
+
|
5
|
+
class Events
|
6
|
+
# static data
|
7
|
+
#PROCESSES = ['effects']
|
8
|
+
SITE_NAME = ''
|
9
|
+
|
10
|
+
EXPIRE_DAYS = 7
|
11
|
+
|
12
|
+
|
13
|
+
@@redis = nil
|
14
|
+
|
15
|
+
# redis object to access Redis server
|
16
|
+
def self.redis
|
17
|
+
return @@redis unless @redis.nil?
|
18
|
+
|
19
|
+
# init by global object
|
20
|
+
unless $redis.nil?
|
21
|
+
@@redis = $redis
|
22
|
+
return @@redis
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
# default
|
27
|
+
@@redis = Redis.new(:host => 'localhost', :port => 6379)
|
28
|
+
|
29
|
+
@@redis
|
30
|
+
end
|
31
|
+
|
32
|
+
# methods for any log_type add_<<ANY_LOG_TYPE>>
|
33
|
+
def self.method_missing(method_name, *args, &block)
|
34
|
+
if method_name.to_s =~ /^log_(.+)$/
|
35
|
+
self.log($1, *args)
|
36
|
+
else
|
37
|
+
super
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
# logging
|
43
|
+
|
44
|
+
def self.log(log_name, data={})
|
45
|
+
t = Time.now.utc.to_i
|
46
|
+
rkey = self.redis_key_log log_name
|
47
|
+
|
48
|
+
#
|
49
|
+
hash = {:created=>t}
|
50
|
+
if data.is_a?(Hash)
|
51
|
+
data.each_pair { |k,v| hash["#{k}"] = v }
|
52
|
+
elsif data.is_a?(String)
|
53
|
+
hash["msg"] = data
|
54
|
+
else
|
55
|
+
hash["msg"] = "#{data.inspect}"
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
require 'json'
|
60
|
+
s = JSON.generate(hash)
|
61
|
+
|
62
|
+
redis.rpush rkey, s
|
63
|
+
redis.expireat rkey, t+EXPIRE_DAYS*24*60*60
|
64
|
+
|
65
|
+
return true
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
def self.log_event(log_name, event_name, msg, data={})
|
70
|
+
data['event'] = event_name
|
71
|
+
data['msg'] = msg
|
72
|
+
return self.log log_name, data
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
def self.debug(event_name, msg, data={})
|
77
|
+
data['event'] = event_name
|
78
|
+
data['msg'] = msg
|
79
|
+
return self.log 'debug', data
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
|
84
|
+
def self.get_logs(log_name, n_days_back=-1, filter={})
|
85
|
+
all_keys = redis.keys(self.redis_key_log_prefix + "#{log_name}:" +'*')
|
86
|
+
|
87
|
+
return [] if all_keys.nil?
|
88
|
+
|
89
|
+
require 'json'
|
90
|
+
|
91
|
+
tnow = Time.now.utc.to_i
|
92
|
+
rows = []
|
93
|
+
all_keys.each do |rkey|
|
94
|
+
day = self.parse_date rkey
|
95
|
+
|
96
|
+
# if cannot parse key
|
97
|
+
next if day.nil?
|
98
|
+
|
99
|
+
# if not too old day
|
100
|
+
if n_days_back>0
|
101
|
+
next if tnow - day.to_i > n_days_back * (60*60*24)
|
102
|
+
end
|
103
|
+
|
104
|
+
# get all items from the list
|
105
|
+
values = redis.lrange rkey, 0, 100000
|
106
|
+
|
107
|
+
values.each do |v|
|
108
|
+
#r = Marshal.load v
|
109
|
+
r = JSON.parse(v)
|
110
|
+
|
111
|
+
# filter
|
112
|
+
is_good = true
|
113
|
+
|
114
|
+
unless filter.nil? && filter.is_a?(Hash)
|
115
|
+
filter.each_pair do |field_name, field_value|
|
116
|
+
if r[field_name].nil?
|
117
|
+
is_good = false
|
118
|
+
break
|
119
|
+
end
|
120
|
+
if r[field_name] != field_value
|
121
|
+
is_good = false
|
122
|
+
break
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# add to result
|
128
|
+
if is_good
|
129
|
+
rows << r
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
rows
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
|
140
|
+
|
141
|
+
|
142
|
+
# status
|
143
|
+
def self.status_set(event_name)
|
144
|
+
redis.hset self.redis_key_status, event_name, Time.now.utc.to_i
|
145
|
+
|
146
|
+
return true
|
147
|
+
end
|
148
|
+
|
149
|
+
def self.get_status(event_name, v_def=nil)
|
150
|
+
v = redis.hget self.redis_key_status, event_name
|
151
|
+
v ||= v_def
|
152
|
+
v
|
153
|
+
end
|
154
|
+
|
155
|
+
def self.get_statuses(pattern='*')
|
156
|
+
# event_names like 'name*'
|
157
|
+
|
158
|
+
rows = []
|
159
|
+
|
160
|
+
all_values = redis.hgetall self.redis_key_status
|
161
|
+
|
162
|
+
all_values.each do |event, v|
|
163
|
+
rows << {:site=>SITE_NAME, :event=>event, :v=>v}
|
164
|
+
end
|
165
|
+
|
166
|
+
rows
|
167
|
+
end
|
168
|
+
|
169
|
+
|
170
|
+
|
171
|
+
# counters
|
172
|
+
|
173
|
+
def self.stat_add(event_name, n=1)
|
174
|
+
redis.hincrby self.redis_key_stat, event_name, n
|
175
|
+
|
176
|
+
return true
|
177
|
+
end
|
178
|
+
|
179
|
+
def self.stat_add_perf(event_name, duration_secs, n=1)
|
180
|
+
redis.hincrby self.redis_key_stat, event_name+'_time', (duration_secs*1000).floor
|
181
|
+
redis.hincrby self.redis_key_stat, event_name+'_n', 1
|
182
|
+
|
183
|
+
return 1
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
def self.get_stats(n_days_back=1)
|
188
|
+
rows = []
|
189
|
+
|
190
|
+
self.stat_walk(n_days_back, 0) do |key, day|
|
191
|
+
all_values = redis.hgetall key
|
192
|
+
|
193
|
+
all_values.each do |event, v|
|
194
|
+
rows << {:site=>SITE_NAME, :created=>day.to_i, :event=>event, :amount=>v.to_i}
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
rows
|
199
|
+
end
|
200
|
+
|
201
|
+
|
202
|
+
|
203
|
+
|
204
|
+
# helper methods
|
205
|
+
|
206
|
+
def self.redis_key_prefix
|
207
|
+
"#{SITE_NAME=='' ? '' : SITE_NAME+':'}"
|
208
|
+
end
|
209
|
+
|
210
|
+
def self.key_day(d=nil)
|
211
|
+
d ||= DateTime.now.new_offset(0)
|
212
|
+
|
213
|
+
d.strftime("%Y%m%d")
|
214
|
+
end
|
215
|
+
|
216
|
+
|
217
|
+
# redis keys for log
|
218
|
+
def self.redis_key_log_prefix
|
219
|
+
self.redis_key_prefix + "log:"
|
220
|
+
end
|
221
|
+
|
222
|
+
def self.redis_key_log(name)
|
223
|
+
self.redis_key_log_prefix + "#{name}:" + self.key_day
|
224
|
+
end
|
225
|
+
|
226
|
+
|
227
|
+
# redis keys for status
|
228
|
+
|
229
|
+
def self.redis_key_status
|
230
|
+
self.redis_key_prefix + 'status'
|
231
|
+
end
|
232
|
+
|
233
|
+
|
234
|
+
# redis keys for stat
|
235
|
+
|
236
|
+
def self.redis_key_stat_prefix
|
237
|
+
self.redis_key_prefix + 'stat:'
|
238
|
+
end
|
239
|
+
|
240
|
+
def self.redis_key_stat
|
241
|
+
self.redis_key_stat_prefix + self.key_day
|
242
|
+
end
|
243
|
+
|
244
|
+
|
245
|
+
#
|
246
|
+
def self.parse_date(s)
|
247
|
+
# parse key
|
248
|
+
mm = s.scan(/(\d\d\d\d)(\d\d)(\d\d)$/i)
|
249
|
+
|
250
|
+
return nil if mm.nil? || mm[0].nil?
|
251
|
+
|
252
|
+
y, m, d = mm[0].map{|v| v.to_i}
|
253
|
+
|
254
|
+
Time.utc(y,m,d)
|
255
|
+
end
|
256
|
+
|
257
|
+
|
258
|
+
|
259
|
+
# clear data
|
260
|
+
|
261
|
+
def self.clear_logs_all
|
262
|
+
keys = redis.keys self.redis_key_log_prefix + '*'
|
263
|
+
return if keys.empty?
|
264
|
+
redis.del keys
|
265
|
+
end
|
266
|
+
|
267
|
+
def self.clear_logs(name)
|
268
|
+
keys = redis.keys self.redis_key_log_prefix+"#{name}:*"
|
269
|
+
return if keys.empty?
|
270
|
+
redis.del keys
|
271
|
+
end
|
272
|
+
|
273
|
+
# TODO:
|
274
|
+
def self.clear_logs_old(name)
|
275
|
+
|
276
|
+
end
|
277
|
+
|
278
|
+
|
279
|
+
# clear status
|
280
|
+
|
281
|
+
def self.clear_status_all
|
282
|
+
rkey = self.redis_key_status
|
283
|
+
|
284
|
+
redis.del rkey
|
285
|
+
end
|
286
|
+
|
287
|
+
|
288
|
+
|
289
|
+
# clear stats
|
290
|
+
|
291
|
+
def self.clear_stats_all
|
292
|
+
keys = redis.keys self.redis_key_stat_prefix+"*"
|
293
|
+
return if keys.empty?
|
294
|
+
redis.del keys
|
295
|
+
end
|
296
|
+
|
297
|
+
|
298
|
+
# clear data older than n_days_back
|
299
|
+
def self.clear_stats_old(n_days_back=1)
|
300
|
+
rows = []
|
301
|
+
|
302
|
+
# all days older than N days
|
303
|
+
self.stat_walk(-1, n_days_back) do |key, day|
|
304
|
+
redis.del key
|
305
|
+
end
|
306
|
+
|
307
|
+
rows
|
308
|
+
end
|
309
|
+
|
310
|
+
|
311
|
+
def self.stat_walk(n_days_back_from, n_days_back_to)
|
312
|
+
|
313
|
+
tnow = Time.now.utc_to_i
|
314
|
+
|
315
|
+
key_prefix = self.redis_key_stat_prefix
|
316
|
+
keys = redis.keys key_prefix + "*"
|
317
|
+
|
318
|
+
keys.each do |key|
|
319
|
+
# parse key
|
320
|
+
mm = key.scan(/#{key_prefix}:(\d+)$/i)
|
321
|
+
|
322
|
+
next if mm.nil? || mm[0].nil?
|
323
|
+
|
324
|
+
day = self.parse_date(mm[0][0])
|
325
|
+
|
326
|
+
next if day.nil?
|
327
|
+
|
328
|
+
# too old
|
329
|
+
if n_days_back_from>=0
|
330
|
+
next if tnow - day.to_i > n_days_back_from * (60*60*24)
|
331
|
+
end
|
332
|
+
|
333
|
+
# too fresh
|
334
|
+
if n_days_back_to>=0
|
335
|
+
next if tnow - day.to_i < n_days_back_to * (60*60*24)
|
336
|
+
end
|
337
|
+
|
338
|
+
# do the work
|
339
|
+
yield(key, day)
|
340
|
+
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
end
|
345
|
+
|
346
|
+
|
347
|
+
end
|
348
|
+
|
metadata
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: simple_events_redis
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- ! 'Max Ivak '
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-04-09 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: ''
|
14
|
+
email:
|
15
|
+
- maxivak@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/events.rb
|
21
|
+
- README.md
|
22
|
+
homepage: https://github.com/maxivak/simple_events_redis/
|
23
|
+
licenses: []
|
24
|
+
metadata: {}
|
25
|
+
post_install_message:
|
26
|
+
rdoc_options: []
|
27
|
+
require_paths:
|
28
|
+
- lib
|
29
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
requirements: []
|
40
|
+
rubyforge_project:
|
41
|
+
rubygems_version: 2.0.3
|
42
|
+
signing_key:
|
43
|
+
specification_version: 4
|
44
|
+
summary: ! 'Library to track events: counters of events, logging, state monitoring.
|
45
|
+
Data is stored in Redis'
|
46
|
+
test_files: []
|