prometheus-client-mmap 0.7.0.beta34 → 0.7.0.beta35
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +18 -1
- data/ext/fast_mmaped_file/fast_mmaped_file.c +57 -24
- data/ext/fast_mmaped_file/mmap.h +2 -3
- data/lib/fast_mmaped_file.bundle +0 -0
- data/lib/prometheus/client/gauge.rb +4 -0
- data/lib/prometheus/client/helper/entry_parser.rb +14 -8
- data/lib/prometheus/client/helper/mmaped_file.rb +2 -5
- data/lib/prometheus/client/helper/plain_file.rb +1 -0
- data/lib/prometheus/client/mmaped_value.rb +50 -29
- data/lib/prometheus/client/simple_value.rb +1 -1
- data/lib/prometheus/client/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d8a992632af121ceb8b2b8049f293e69822afbce
|
4
|
+
data.tar.gz: 99c14fe2ced8279e6f02e9ca13fef3293bf55090
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 712cdf6271eb5660c4d13852be75a70a9aab6c736a9e8f77588e18ccb0ce82c22001e146273ee2ae4fa95270ea4bd3fe562541b5d25ed9e3bd49033724cc1dea
|
7
|
+
data.tar.gz: f49a4b52b8d5dcc2c629c52ab010dc979d8401c928632d51a0d82f211fadd9870503c9e4a7aa5cea5d6aab93fad76d6fa934eba76eb6f5d6b2072809be656444
|
data/README.md
CHANGED
@@ -10,7 +10,7 @@ through a HTTP interface. Intended to be used together with a
|
|
10
10
|
|
11
11
|
[![Gem Version][4]](http://badge.fury.io/rb/prometheus-client-mmap)
|
12
12
|
[![Build Status][3]](https://gitlab.com/gitlab-org/prometheus-client-mmap/commits/master)
|
13
|
-
[![Dependency Status][5]](https://gemnasium.com/prometheus/
|
13
|
+
[![Dependency Status][5]](https://gemnasium.com/prometheus/prometheus-client-mmap)
|
14
14
|
|
15
15
|
## Usage
|
16
16
|
|
@@ -185,6 +185,23 @@ To use it add this line to your `configure` block:
|
|
185
185
|
config.pid_provider = Prometheus::Client::Support::Unicorn.method(:worker_pid_provider)
|
186
186
|
```
|
187
187
|
|
188
|
+
## Tools
|
189
|
+
|
190
|
+
###`bin/parse`
|
191
|
+
|
192
|
+
This command can be used to parse metric files located on the filesystem just like a metric exporter would.
|
193
|
+
It outputs either `json` formatted raw data or digested data in prometheus `text` format.
|
194
|
+
|
195
|
+
#### Usage:
|
196
|
+
|
197
|
+
```bash
|
198
|
+
$ ./bin/parse -h
|
199
|
+
Usage: parse [options] files...
|
200
|
+
-t, --to-prometheus-text format output using Prometheus text formatter
|
201
|
+
-p, --profile enable profiling
|
202
|
+
-h, --help Show this message
|
203
|
+
```
|
204
|
+
|
188
205
|
## Tests
|
189
206
|
|
190
207
|
Install necessary development gems with `bundle install` and run tests with
|
@@ -12,33 +12,48 @@ VALUE MMAPED_FILE = Qnil;
|
|
12
12
|
#define START_POSITION 8
|
13
13
|
#define INITIAL_SIZE (2 * sizeof(int32_t))
|
14
14
|
|
15
|
-
|
15
|
+
int open_and_extend_file(mm_ipc *i_mm, size_t len) {
|
16
16
|
int fd;
|
17
|
-
|
18
|
-
rb_raise(rb_eArgError, "munmap failed");
|
19
|
-
}
|
17
|
+
|
20
18
|
if ((fd = open(i_mm->t->path, i_mm->t->smode)) == -1) {
|
21
19
|
rb_raise(rb_eArgError, "Can't open %s", i_mm->t->path);
|
22
20
|
}
|
23
21
|
|
24
|
-
if (len < i_mm->t->len) {
|
25
|
-
rb_raise(rb_eArgError, "Can't reduce the size of mmap");
|
26
|
-
}
|
27
|
-
|
28
22
|
if (lseek(fd, len - i_mm->t->len - 1, SEEK_END) == -1) {
|
23
|
+
close(fd);
|
29
24
|
rb_raise(rb_eIOError, "Can't lseek %lu", len - i_mm->t->len - 1);
|
30
25
|
}
|
26
|
+
|
31
27
|
if (write(fd, "\000", 1) != 1) {
|
28
|
+
close(fd);
|
32
29
|
rb_raise(rb_eIOError, "Can't extend %s", i_mm->t->path);
|
33
30
|
}
|
34
31
|
|
32
|
+
return fd;
|
33
|
+
}
|
34
|
+
|
35
|
+
void expand(mm_ipc *i_mm, size_t len) {
|
36
|
+
if (len < i_mm->t->len) {
|
37
|
+
rb_raise(rb_eArgError, "Can't reduce the size of mmap");
|
38
|
+
}
|
39
|
+
|
40
|
+
if (munmap(i_mm->t->addr, i_mm->t->len)) {
|
41
|
+
rb_raise(rb_eArgError, "munmap failed");
|
42
|
+
}
|
43
|
+
|
44
|
+
int fd = open_and_extend_file(i_mm, len);
|
45
|
+
|
35
46
|
i_mm->t->addr = mmap(0, len, i_mm->t->pmode, i_mm->t->vscope, fd, i_mm->t->offset);
|
36
|
-
close(fd);
|
37
47
|
|
38
48
|
if (i_mm->t->addr == MAP_FAILED) {
|
49
|
+
close(fd);
|
39
50
|
rb_raise(rb_eArgError, "mmap failed");
|
40
51
|
}
|
41
52
|
|
53
|
+
if (close(fd) == -1){
|
54
|
+
rb_raise(rb_eArgError, "Can't close %s", i_mm->t->path);
|
55
|
+
}
|
56
|
+
|
42
57
|
if ((i_mm->t->flag & MM_LOCK) && mlock(i_mm->t->addr, len) == -1) {
|
43
58
|
rb_raise(rb_eArgError, "mlock(%d)", errno);
|
44
59
|
}
|
@@ -46,8 +61,8 @@ void expand(mm_ipc *i_mm, size_t len){
|
|
46
61
|
i_mm->t->real = len;
|
47
62
|
}
|
48
63
|
|
49
|
-
inline uint32_t padding_length(uint32_t key_length){
|
50
|
-
return 8 - (
|
64
|
+
inline uint32_t padding_length(uint32_t key_length) {
|
65
|
+
return 8 - (sizeof(uint32_t) + key_length) % 8; // padding | 8 byte aligned
|
51
66
|
}
|
52
67
|
|
53
68
|
void save_entry(mm_ipc *i_mm, uint32_t offset, VALUE key, VALUE value){
|
@@ -68,9 +83,8 @@ void save_entry(mm_ipc *i_mm, uint32_t offset, VALUE key, VALUE value){
|
|
68
83
|
memcpy(pos, &val, sizeof(double));
|
69
84
|
}
|
70
85
|
|
71
|
-
inline uint32_t load_used(mm_ipc *i_mm){
|
72
|
-
uint32_t used =
|
73
|
-
memcpy(&used, (char *)i_mm->t->addr, sizeof(uint32_t));
|
86
|
+
inline uint32_t load_used(mm_ipc *i_mm) {
|
87
|
+
uint32_t used = *((uint32_t *)i_mm->t->addr);
|
74
88
|
|
75
89
|
if (used == 0){
|
76
90
|
used = START_POSITION;
|
@@ -78,8 +92,29 @@ inline uint32_t load_used(mm_ipc *i_mm){
|
|
78
92
|
return used;
|
79
93
|
}
|
80
94
|
|
81
|
-
inline void save_used(mm_ipc *i_mm, uint32_t used){
|
82
|
-
|
95
|
+
inline void save_used(mm_ipc *i_mm, uint32_t used) {
|
96
|
+
*((uint32_t *)i_mm->t->addr) = used;
|
97
|
+
}
|
98
|
+
|
99
|
+
VALUE method_load_used(VALUE self) {
|
100
|
+
mm_ipc *i_mm;
|
101
|
+
|
102
|
+
GET_MMAP(self, i_mm, MM_MODIFY);
|
103
|
+
return UINT2NUM(load_used(i_mm));
|
104
|
+
}
|
105
|
+
|
106
|
+
VALUE method_save_used(VALUE self, VALUE value) {
|
107
|
+
Check_Type(value, T_FIXNUM);
|
108
|
+
mm_ipc *i_mm;
|
109
|
+
|
110
|
+
GET_MMAP(self, i_mm, MM_MODIFY);
|
111
|
+
|
112
|
+
if (i_mm->t->len < INITIAL_SIZE) {
|
113
|
+
expand(i_mm, INITIAL_SIZE);
|
114
|
+
}
|
115
|
+
|
116
|
+
save_used(i_mm, NUM2UINT(value));
|
117
|
+
return value;
|
83
118
|
}
|
84
119
|
|
85
120
|
VALUE method_add_entry(VALUE self, VALUE positions, VALUE key, VALUE value) {
|
@@ -92,17 +127,13 @@ VALUE method_add_entry(VALUE self, VALUE positions, VALUE key, VALUE value) {
|
|
92
127
|
}
|
93
128
|
|
94
129
|
mm_ipc *i_mm;
|
95
|
-
|
96
|
-
|
97
|
-
if ((i_mm->t->len) < INITIAL_SIZE) {
|
98
|
-
expand(i_mm, INITIAL_SIZE);
|
99
|
-
}
|
130
|
+
GET_MMAP(self, i_mm, MM_MODIFY);
|
100
131
|
|
101
|
-
if (i_mm->t->flag & MM_FROZEN){
|
132
|
+
if (i_mm->t->flag & MM_FROZEN) {
|
102
133
|
rb_error_frozen("mmap");
|
103
134
|
}
|
104
135
|
|
105
|
-
if (RSTRING_LEN(key) > UINT32_MAX){
|
136
|
+
if (RSTRING_LEN(key) > UINT32_MAX) {
|
106
137
|
rb_raise(rb_eArgError, "string length gt %u", UINT32_MAX);
|
107
138
|
}
|
108
139
|
|
@@ -122,7 +153,7 @@ VALUE method_add_entry(VALUE self, VALUE positions, VALUE key, VALUE value) {
|
|
122
153
|
|
123
154
|
VALUE method_get_double(VALUE self, VALUE index) {
|
124
155
|
mm_ipc *i_mm;
|
125
|
-
|
156
|
+
GET_MMAP(self, i_mm, MM_MODIFY);
|
126
157
|
|
127
158
|
Check_Type(index, T_FIXNUM);
|
128
159
|
size_t idx = NUM2UINT(index);
|
@@ -140,5 +171,7 @@ VALUE method_get_double(VALUE self, VALUE index) {
|
|
140
171
|
void Init_fast_mmaped_file() {
|
141
172
|
MMAPED_FILE = rb_define_module("FastMmapedFile");
|
142
173
|
rb_define_method(MMAPED_FILE, "get_double", method_get_double, 1);
|
174
|
+
rb_define_method(MMAPED_FILE, "used", method_load_used, 0);
|
175
|
+
rb_define_method(MMAPED_FILE, "used=", method_save_used, 1);
|
143
176
|
rb_define_method(MMAPED_FILE, "add_entry", method_add_entry, 3);
|
144
177
|
}
|
data/ext/fast_mmaped_file/mmap.h
CHANGED
@@ -45,7 +45,7 @@ typedef struct {
|
|
45
45
|
} mm_ipc;
|
46
46
|
|
47
47
|
|
48
|
-
#define
|
48
|
+
#define GET_MMAP(obj, i_mm, t_modify) \
|
49
49
|
Data_Get_Struct(obj, mm_ipc, i_mm); \
|
50
50
|
if (!i_mm->t->path) { \
|
51
51
|
rb_raise(rb_eIOError, "unmapped file"); \
|
@@ -54,5 +54,4 @@ typedef struct {
|
|
54
54
|
rb_error_frozen("mmap"); \
|
55
55
|
}
|
56
56
|
|
57
|
-
|
58
|
-
#endif
|
57
|
+
#endif
|
data/lib/fast_mmaped_file.bundle
CHANGED
Binary file
|
@@ -6,8 +6,11 @@ module Prometheus
|
|
6
6
|
module EntryParser
|
7
7
|
class ParsingError < RuntimeError;
|
8
8
|
end
|
9
|
+
|
9
10
|
MINIMUM_SIZE = 8
|
10
11
|
START_POSITION = 8
|
12
|
+
VALUE_BYTES = 8
|
13
|
+
ENCODED_LENGTH_BYTES = 4
|
11
14
|
|
12
15
|
def used
|
13
16
|
slice(0..3).unpack('l')[0]
|
@@ -57,16 +60,18 @@ module Prometheus
|
|
57
60
|
next
|
58
61
|
end
|
59
62
|
|
60
|
-
|
61
|
-
|
63
|
+
entry_len = ENCODED_LENGTH_BYTES + encoded_len
|
64
|
+
padding_len = 8 - entry_len % 8
|
65
|
+
|
66
|
+
value_offset = entry_len + padding_len # align to 8 bytes
|
62
67
|
pos += value_offset
|
63
68
|
|
64
|
-
if value_offset > 0 && (pos +
|
69
|
+
if value_offset > 0 && (pos + VALUE_BYTES) < size # if positions are safe
|
65
70
|
yielder.yield data, encoded_len, value_offset, pos
|
66
71
|
else
|
67
72
|
raise ParsingError, "data slice is nil at pos #{pos}" unless ignore_errors
|
68
73
|
end
|
69
|
-
pos +=
|
74
|
+
pos += VALUE_BYTES
|
70
75
|
end
|
71
76
|
end
|
72
77
|
end
|
@@ -82,7 +87,7 @@ module Prometheus
|
|
82
87
|
end
|
83
88
|
end
|
84
89
|
|
85
|
-
|
90
|
+
metrics.reject!(&:nil?) if ignore_errors
|
86
91
|
result
|
87
92
|
end
|
88
93
|
|
@@ -90,8 +95,9 @@ module Prometheus
|
|
90
95
|
parsed_entries(ignore_errors).each do |key, value|
|
91
96
|
begin
|
92
97
|
metric_name, name, labelnames, labelvalues = JsonParser.load(key)
|
93
|
-
labelnames
|
94
|
-
labelvalues
|
98
|
+
labelnames ||= []
|
99
|
+
labelvalues ||= []
|
100
|
+
|
95
101
|
metric = metrics.fetch(metric_name,
|
96
102
|
metric_name: metric_name,
|
97
103
|
help: 'Multiprocess metric',
|
@@ -111,7 +117,7 @@ module Prometheus
|
|
111
117
|
end
|
112
118
|
end
|
113
119
|
|
114
|
-
metrics.reject
|
120
|
+
metrics.reject!(&:nil?) if ignore_errors
|
115
121
|
metrics
|
116
122
|
end
|
117
123
|
|
@@ -7,8 +7,9 @@ module Prometheus
|
|
7
7
|
module Client
|
8
8
|
module Helper
|
9
9
|
class MmapedFile < Mmap
|
10
|
-
include FastMmapedFile
|
11
10
|
include EntryParser
|
11
|
+
include FastMmapedFile
|
12
|
+
|
12
13
|
attr_reader :filepath, :size
|
13
14
|
|
14
15
|
def initialize(filepath, mode = 'r', protection = Mmap::MAP_SHARED, options = {})
|
@@ -22,10 +23,6 @@ module Prometheus
|
|
22
23
|
super(filepath, mode, protection, options)
|
23
24
|
end
|
24
25
|
|
25
|
-
def used=(value)
|
26
|
-
self[0..3] = [value].pack('l')
|
27
|
-
end
|
28
|
-
|
29
26
|
def close
|
30
27
|
munmap
|
31
28
|
end
|
@@ -6,8 +6,9 @@ module Prometheus
|
|
6
6
|
module Client
|
7
7
|
# A float protected by a mutex backed by a per-process mmaped file.
|
8
8
|
class MmapedValue
|
9
|
-
@@files = {}
|
10
9
|
VALUE_LOCK = Mutex.new
|
10
|
+
|
11
|
+
@@files = {}
|
11
12
|
@@pid = -1
|
12
13
|
|
13
14
|
def initialize(type, metric_name, name, labels, multiprocess_mode = '')
|
@@ -25,7 +26,7 @@ module Prometheus
|
|
25
26
|
initialize_file
|
26
27
|
end
|
27
28
|
|
28
|
-
def increment(amount=1)
|
29
|
+
def increment(amount = 1)
|
29
30
|
@mutex.synchronize do
|
30
31
|
initialize_file if pid_changed?
|
31
32
|
|
@@ -56,35 +57,19 @@ module Prometheus
|
|
56
57
|
@pid != Process.pid
|
57
58
|
end
|
58
59
|
|
59
|
-
|
60
|
-
|
60
|
+
# method needs to be run in VALUE_LOCK mutex
|
61
|
+
def unsafe_reinitialize_file(check_pid = true)
|
62
|
+
unsafe_initialize_file if !check_pid || pid_changed?
|
61
63
|
end
|
62
64
|
|
63
|
-
def
|
65
|
+
def self.reset_and_reinitialize
|
64
66
|
VALUE_LOCK.synchronize do
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
@pid = Process.pid
|
69
|
-
unless @@files.has_key?(@file_prefix)
|
70
|
-
unless @file.nil?
|
71
|
-
@file.close
|
72
|
-
end
|
73
|
-
mmaped_file = Helper::MmapedFile.open_exclusive_file(@file_prefix)
|
74
|
-
|
75
|
-
@@files[@file_prefix] = MmapedDict.new(mmaped_file)
|
76
|
-
end
|
67
|
+
@@pid = Process.pid
|
68
|
+
@@files = {}
|
77
69
|
|
78
|
-
|
79
|
-
|
80
|
-
labelvalues = []
|
81
|
-
@labels.each do |k, v|
|
82
|
-
labelnames << k
|
83
|
-
labelvalues << v
|
70
|
+
ObjectSpace.each_object(MmapedValue).each do |v|
|
71
|
+
v.unsafe_reinitialize_file(false)
|
84
72
|
end
|
85
|
-
|
86
|
-
@key = [@metric_name, @name, labelnames, labelvalues].to_json
|
87
|
-
@value = read_value(@key)
|
88
73
|
end
|
89
74
|
end
|
90
75
|
|
@@ -98,9 +83,9 @@ module Prometheus
|
|
98
83
|
def self.reinitialize_on_pid_change
|
99
84
|
VALUE_LOCK.synchronize do
|
100
85
|
reset_on_pid_change
|
101
|
-
end
|
102
86
|
|
103
|
-
|
87
|
+
ObjectSpace.each_object(MmapedValue, &:unsafe_reinitialize_file)
|
88
|
+
end
|
104
89
|
end
|
105
90
|
|
106
91
|
def self.pid_changed?
|
@@ -113,9 +98,45 @@ module Prometheus
|
|
113
98
|
|
114
99
|
private
|
115
100
|
|
101
|
+
def initialize_file
|
102
|
+
VALUE_LOCK.synchronize do
|
103
|
+
unsafe_initialize_file
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def unsafe_initialize_file
|
108
|
+
self.class.reset_on_pid_change
|
109
|
+
|
110
|
+
@pid = Process.pid
|
111
|
+
unless @@files.has_key?(@file_prefix)
|
112
|
+
unless @file.nil?
|
113
|
+
@file.close
|
114
|
+
end
|
115
|
+
mmaped_file = Helper::MmapedFile.open_exclusive_file(@file_prefix)
|
116
|
+
|
117
|
+
@@files[@file_prefix] = MmapedDict.new(mmaped_file)
|
118
|
+
end
|
119
|
+
|
120
|
+
@file = @@files[@file_prefix]
|
121
|
+
@key = rebuild_key
|
122
|
+
|
123
|
+
@value = read_value(@key)
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
def rebuild_key
|
128
|
+
labelnames = []
|
129
|
+
labelvalues = []
|
130
|
+
@labels.each do |k, v|
|
131
|
+
labelnames << k
|
132
|
+
labelvalues << v
|
133
|
+
end
|
134
|
+
|
135
|
+
[@metric_name, @name, labelnames, labelvalues].to_json
|
136
|
+
end
|
137
|
+
|
116
138
|
def write_value(key, val)
|
117
139
|
@file.write_value(key, val)
|
118
|
-
|
119
140
|
rescue StandardError => e
|
120
141
|
Prometheus::Client.logger.warn("writing value to #{@file.path} failed with #{e}")
|
121
142
|
Prometheus::Client.logger.debug(e.backtrace.join("\n"))
|