statsrb 0.1.3 → 0.1.4
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.
- 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:
|