statsrb 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/statsrb/statsrb.c +64 -11
- data/test/test_statsrb.rb +89 -0
- metadata +10 -6
data/ext/statsrb/statsrb.c
CHANGED
@@ -3,6 +3,52 @@
|
|
3
3
|
#include <string.h>
|
4
4
|
#include <stdlib.h>
|
5
5
|
|
6
|
+
/**
|
7
|
+
* Retrieves internal data based on specified filters.
|
8
|
+
* @param namespace [String]
|
9
|
+
* @param limit [Number]
|
10
|
+
* @param start_time [Number]
|
11
|
+
* @param end_time [Number]
|
12
|
+
* @return [Array] An array of data hashes.
|
13
|
+
*/
|
14
|
+
static VALUE statsrb_get(VALUE self, VALUE query_ns, VALUE query_limit, VALUE query_start, VALUE query_end) {
|
15
|
+
VALUE statsrb_data = rb_iv_get(self, "@data");
|
16
|
+
VALUE statsrb_event = rb_hash_new();
|
17
|
+
int data_length = RARRAY_LEN(statsrb_data);
|
18
|
+
int i = 0;
|
19
|
+
int count = 0;
|
20
|
+
int tmp_ts;
|
21
|
+
|
22
|
+
VALUE filtered_data = rb_ary_new();
|
23
|
+
VALUE tmp_ns;
|
24
|
+
|
25
|
+
// @data hash key symbols.
|
26
|
+
VALUE statsrb_key_ts = rb_iv_get(self, "@key_ts");
|
27
|
+
VALUE statsrb_key_ns = rb_iv_get(self, "@key_ns");
|
28
|
+
VALUE statsrb_key_v = rb_iv_get(self, "@key_v");
|
29
|
+
|
30
|
+
// Convert into an int that ruby understands.
|
31
|
+
int limit = NUM2INT(query_limit);
|
32
|
+
int qstart = NUM2INT(query_start);
|
33
|
+
int qend = NUM2INT(query_end);
|
34
|
+
|
35
|
+
for (i = 0; i < data_length; i++) {
|
36
|
+
tmp_ts = NUM2INT(rb_hash_aref(rb_ary_entry(statsrb_data, i), statsrb_key_ts));
|
37
|
+
tmp_ns = rb_hash_aref(rb_ary_entry(statsrb_data, i), statsrb_key_ns);
|
38
|
+
if (rb_str_equal(query_ns, tmp_ns)
|
39
|
+
&& (qstart == 0 || tmp_ts >= qstart)
|
40
|
+
&& (qend == 0 || tmp_ts <= qend)) {
|
41
|
+
rb_hash_aset(statsrb_event, statsrb_key_ts, rb_hash_aref(rb_ary_entry(statsrb_data, i), statsrb_key_ts));
|
42
|
+
rb_hash_aset(statsrb_event, statsrb_key_ns, rb_hash_aref(rb_ary_entry(statsrb_data, i), statsrb_key_ns));
|
43
|
+
rb_hash_aset(statsrb_event, statsrb_key_v, rb_hash_aref(rb_ary_entry(statsrb_data, i), statsrb_key_v));
|
44
|
+
rb_ary_push(filtered_data, statsrb_event);
|
45
|
+
count++;
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
return filtered_data;
|
50
|
+
}
|
51
|
+
|
6
52
|
/**
|
7
53
|
* Locates data from a specified file and loads into @data.
|
8
54
|
* @param filepath [String]
|
@@ -12,7 +58,7 @@
|
|
12
58
|
* @param end_time [Number]
|
13
59
|
* @return [Statsrb] A reference to the object.
|
14
60
|
*/
|
15
|
-
static VALUE
|
61
|
+
static VALUE statsrb_read(VALUE self, VALUE logfile, VALUE query_ns, VALUE query_limit, VALUE query_start, VALUE query_end) {
|
16
62
|
FILE * file;
|
17
63
|
int line_size = 256;
|
18
64
|
char *line = (char *) malloc(line_size);
|
@@ -39,13 +85,13 @@ static VALUE statsrb_query(VALUE self, VALUE logfile, VALUE query_ns, VALUE quer
|
|
39
85
|
file = fopen(filepath, "r");
|
40
86
|
if (file == NULL) {
|
41
87
|
fprintf(stderr, "File error: could not open file %s for reading.", filepath);
|
42
|
-
return;
|
88
|
+
return self;
|
43
89
|
}
|
44
90
|
|
45
91
|
int count = 0;
|
46
92
|
|
47
93
|
while (NULL != fgets(line, line_size, file) && count < limit) {
|
48
|
-
// strstr doesn't work with newline chars.
|
94
|
+
// strstr doesn't work with newline chars.
|
49
95
|
size_t len = strlen(line) - 1;
|
50
96
|
if (line[len] == '\n');
|
51
97
|
line[len] = '\0';
|
@@ -66,7 +112,7 @@ static VALUE statsrb_query(VALUE self, VALUE logfile, VALUE query_ns, VALUE quer
|
|
66
112
|
VALUE statsrb_str_ns = rb_str_new2(strtok(NULL, "\t"));
|
67
113
|
//strtok(NULL, "\t");
|
68
114
|
int statsrb_v = atoi(strtok(NULL, "\0"));
|
69
|
-
|
115
|
+
|
70
116
|
// @TODO this should really query the namespace exactly instead of just relying on strstr.
|
71
117
|
//if (rb_str_cmp(query_ns, statsrb_str_empty) == 0 || rb_str_cmp(query_ns, statsrb_str_ns) == 0) {
|
72
118
|
if (statsrb_ts && (statsrb_v || statsrb_v == 0)) {
|
@@ -155,7 +201,7 @@ static VALUE statsrb_write(VALUE self, VALUE logfile, VALUE mode) {
|
|
155
201
|
int line_size = 256;
|
156
202
|
int tmp_ts, tmp_v;
|
157
203
|
const char *tmp_ns = (char *) malloc(line_size);
|
158
|
-
|
204
|
+
|
159
205
|
// @data hash key symbols.
|
160
206
|
VALUE statsrb_key_ts = rb_iv_get(self, "@key_ts");
|
161
207
|
VALUE statsrb_key_ns = rb_iv_get(self, "@key_ns");
|
@@ -164,7 +210,7 @@ static VALUE statsrb_write(VALUE self, VALUE logfile, VALUE mode) {
|
|
164
210
|
file = fopen(filepath, filemode);
|
165
211
|
if (file==NULL) {
|
166
212
|
fprintf(stderr, "File error: could not open file %s mode %s.", filepath, filemode);
|
167
|
-
return;
|
213
|
+
return self;
|
168
214
|
}
|
169
215
|
|
170
216
|
// Iterate through the data array, writing the data as we go.
|
@@ -222,7 +268,12 @@ static VALUE statsrb_split_write(VALUE self, VALUE logdir, VALUE mode) {
|
|
222
268
|
//fputs (RSTRING_PTR(rb_obj_as_string(INT2NUM(RARRAY_LEN(tmp_data)))),stderr);
|
223
269
|
rb_iv_set(tmp, "@data", tmp_data);
|
224
270
|
|
225
|
-
//
|
271
|
+
// If there is no trailing slash on the log dir, add one.
|
272
|
+
const char *filepath = RSTRING_PTR(logdir);
|
273
|
+
size_t len = strlen(filepath);
|
274
|
+
if (filepath[len - 1] != '/') {
|
275
|
+
logdir = rb_str_plus(logdir, rb_str_new2("/"));
|
276
|
+
}
|
226
277
|
statsrb_write(tmp, rb_str_plus(logdir, rb_ary_entry(ns_list, i)), mode);
|
227
278
|
}
|
228
279
|
|
@@ -393,7 +444,7 @@ static VALUE statsrb_rack_call(VALUE self, VALUE env) {
|
|
393
444
|
VALUE tmp = rb_obj_dup(self);
|
394
445
|
VALUE tmp_data = rb_ary_new();
|
395
446
|
rb_iv_set(tmp, "@data", tmp_data);
|
396
|
-
|
447
|
+
statsrb_read(tmp, rb_str_plus(rb_iv_get(self, "@split_file_dir"), statsrb_ns), statsrb_ns, INT2NUM(query_limit), INT2NUM(query_start), INT2NUM(query_end));
|
397
448
|
statsrb_sort(tmp);
|
398
449
|
|
399
450
|
int i, data_length = RARRAY_LEN(tmp_data);
|
@@ -408,7 +459,7 @@ static VALUE statsrb_rack_call(VALUE self, VALUE env) {
|
|
408
459
|
rb_ary_push(body, rb_str_new(",", 1));
|
409
460
|
}
|
410
461
|
rb_ary_push(body, rb_str_new("\n", 1));
|
411
|
-
}
|
462
|
+
}
|
412
463
|
rb_ary_resize(tmp_data, 0);
|
413
464
|
}
|
414
465
|
rb_ary_push(body, rb_str_new("]}", 2));
|
@@ -454,7 +505,7 @@ static VALUE statsrb_push(VALUE self, VALUE timestamp, VALUE namespace, VALUE va
|
|
454
505
|
|
455
506
|
return self;
|
456
507
|
}
|
457
|
-
|
508
|
+
|
458
509
|
/**
|
459
510
|
* Class constructor, sets up an instance variable.
|
460
511
|
*/
|
@@ -485,7 +536,9 @@ void Init_statsrb(void) {
|
|
485
536
|
|
486
537
|
// Instance methods and properties.
|
487
538
|
rb_define_method(klass, "initialize", statsrb_constructor, 0);
|
488
|
-
rb_define_method(klass, "query",
|
539
|
+
rb_define_method(klass, "query", statsrb_read, 5);
|
540
|
+
rb_define_method(klass, "read", statsrb_read, 5);
|
541
|
+
rb_define_method(klass, "get", statsrb_get, 4);
|
489
542
|
rb_define_method(klass, "sort", statsrb_sort, 0);
|
490
543
|
rb_define_method(klass, "write", statsrb_write, 2);
|
491
544
|
rb_define_method(klass, "split_write", statsrb_split_write, 2);
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'statsrb'
|
3
|
+
|
4
|
+
class TestStatsrb < MiniTest::Test
|
5
|
+
|
6
|
+
attr_accessor :tmpfile
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@s = Statsrb.new
|
10
|
+
@tmpfile = "/tmp/test.statsrb"
|
11
|
+
end
|
12
|
+
|
13
|
+
def teardown
|
14
|
+
File.delete @tmpfile unless !File.exists? @tmpfile
|
15
|
+
end
|
16
|
+
|
17
|
+
# Provides test data.
|
18
|
+
def get_data
|
19
|
+
[[123, "test1", 33],
|
20
|
+
[321, "test1", 34],
|
21
|
+
[222, "test1", 35],
|
22
|
+
[111, "test2", 36],
|
23
|
+
[432, "test2", 37]]
|
24
|
+
end
|
25
|
+
|
26
|
+
# Stores the data in the current object.
|
27
|
+
def push_data
|
28
|
+
get_data.each do |value|
|
29
|
+
@s.push value[0], value[1], value[2]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Writes the data to a temp file.
|
34
|
+
def write_data
|
35
|
+
@s.write @tmpfile, "w+"
|
36
|
+
end
|
37
|
+
|
38
|
+
# Tests that the data was indeed pushed.
|
39
|
+
def test_push_data
|
40
|
+
push_data
|
41
|
+
assert_equal @s.data.length, get_data.length
|
42
|
+
end
|
43
|
+
|
44
|
+
# Tests that we can filter the in-memory data.
|
45
|
+
def test_get_data
|
46
|
+
push_data
|
47
|
+
t = @s.get "test2", 100, 0, 0
|
48
|
+
assert_equal(t.length, 2);
|
49
|
+
end
|
50
|
+
|
51
|
+
# Tests that we can sort the data.
|
52
|
+
def test_sort_data
|
53
|
+
current = 0
|
54
|
+
push_data
|
55
|
+
@s.sort
|
56
|
+
@s.data.each do |value|
|
57
|
+
assert value[:ts] > current
|
58
|
+
current = value[:ts]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Tests that we can write the data to a file.
|
63
|
+
def test_write_data
|
64
|
+
push_data
|
65
|
+
write_data
|
66
|
+
data = get_data
|
67
|
+
file_data = File.read(@tmpfile).split "\n"
|
68
|
+
|
69
|
+
assert_equal file_data.length, data.length
|
70
|
+
count = 0
|
71
|
+
file_data.each do |value|
|
72
|
+
parts = value.split "\t"
|
73
|
+
assert_equal parts[0], data[count][0].to_s
|
74
|
+
assert_equal parts[1], data[count][1].to_s
|
75
|
+
assert_equal parts[2], data[count][2].to_s
|
76
|
+
count = count + 1
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Tests that we can read data from a file.
|
81
|
+
def test_read_data
|
82
|
+
push_data
|
83
|
+
write_data
|
84
|
+
@s.read @tmpfile, "test1", 100, 0, 0
|
85
|
+
assert_equal @s.data.length, 3
|
86
|
+
@s.read @tmpfile, "test2", 100, 0, 0
|
87
|
+
assert_equal @s.data.length, 2
|
88
|
+
end
|
89
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: statsrb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,7 +11,8 @@ bindir: bin
|
|
11
11
|
cert_chain: []
|
12
12
|
date: 2013-06-08 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
|
-
description: A
|
14
|
+
description: A Ruby time series stats repository using flat file storage, providing
|
15
|
+
a Ruby API as well as a Rack compatible REST API.
|
15
16
|
email: email@kevinhankens.com
|
16
17
|
executables: []
|
17
18
|
extensions:
|
@@ -21,9 +22,11 @@ files:
|
|
21
22
|
- lib/statsrb.rb
|
22
23
|
- ext/statsrb/statsrb.c
|
23
24
|
- ext/statsrb/extconf.rb
|
25
|
+
- test/test_statsrb.rb
|
24
26
|
homepage: https://github.com/kevinhankens/statsrb
|
25
|
-
licenses:
|
26
|
-
|
27
|
+
licenses:
|
28
|
+
- ! "MIT\t"
|
29
|
+
post_install_message: ! 'Please view documentation at: https://github.com/kevinhankens/statsrb'
|
27
30
|
rdoc_options: []
|
28
31
|
require_paths:
|
29
32
|
- lib
|
@@ -44,6 +47,7 @@ rubyforge_project:
|
|
44
47
|
rubygems_version: 1.8.25
|
45
48
|
signing_key:
|
46
49
|
specification_version: 3
|
47
|
-
summary:
|
48
|
-
test_files:
|
50
|
+
summary: A Ruby time series stats repository.
|
51
|
+
test_files:
|
52
|
+
- test/test_statsrb.rb
|
49
53
|
has_rdoc:
|