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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1225b344f2939116817abcefbfe4483e38c7087c
4
- data.tar.gz: 4fe5ade968d6d4df62d7ab7b9801ee8b1c80aa50
3
+ metadata.gz: d8a992632af121ceb8b2b8049f293e69822afbce
4
+ data.tar.gz: 99c14fe2ced8279e6f02e9ca13fef3293bf55090
5
5
  SHA512:
6
- metadata.gz: f3afd81bf5703647413b61a0762882bc3796325a51fa0db271620d6b0c1d70bbcba0d5191c9acf740e2d856539982a04bdcc253c4f4c1ecb969e9affca7dcb73
7
- data.tar.gz: f083690e3b0e19f3968576c64d7f31e71ffa982b90f29edfb5e8ce6b738f2e97a5345f6dfc2f23ed98dd6a04b0d06f6015fb377b519bd760d1bf9cc3b796ca7a
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/client_ruby)
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
- void expand(mm_ipc *i_mm, size_t len){
15
+ int open_and_extend_file(mm_ipc *i_mm, size_t len) {
16
16
  int fd;
17
- if (munmap(i_mm->t->addr, i_mm->t->len)) {
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 - (key_length + 4) % 8; // padding | 8 byte aligned
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 = 0;
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
- memcpy((char *)i_mm->t->addr, &used, sizeof(uint32_t));
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
- GetMmap(self, i_mm, MM_MODIFY);
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
- GetMmap(self, i_mm, MM_MODIFY);
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
  }
@@ -45,7 +45,7 @@ typedef struct {
45
45
  } mm_ipc;
46
46
 
47
47
 
48
- #define GetMmap(obj, i_mm, t_modify) \
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
Binary file
@@ -27,6 +27,10 @@ module Prometheus
27
27
  def set(labels, value)
28
28
  @values[label_set_for(labels)].set(value)
29
29
  end
30
+
31
+ def increment(labels, value)
32
+ @values[label_set_for(labels)].increment(value)
33
+ end
30
34
  end
31
35
  end
32
36
  end
@@ -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
- padding_len = 8 - (encoded_len + 4) % 8
61
- value_offset = 4 + encoded_len + padding_len
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 + 8) < size # if positions are safe
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 += 8
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
- result.reject { |e| e.nil? } if ignore_errors
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 = [] unless labelnames
94
- labelvalues = [] unless 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 { |e| e.nil? } if ignore_errors
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
@@ -3,6 +3,7 @@ require 'prometheus/client/helper/entry_parser'
3
3
  module Prometheus
4
4
  module Client
5
5
  module Helper
6
+ # Parses DB files without using mmap
6
7
  class PlainFile
7
8
  include EntryParser
8
9
  attr_reader :filepath
@@ -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
- def reinitialize
60
- initialize_file if pid_changed?
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 initialize_file
65
+ def self.reset_and_reinitialize
64
66
  VALUE_LOCK.synchronize do
65
- return if @file && !pid_changed?
66
- self.class.reset_on_pid_change
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
- @file = @@files[@file_prefix]
79
- labelnames = []
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
- ObjectSpace.each_object(MmapedValue, &:reinitialize)
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"))
@@ -4,7 +4,7 @@ require 'mmap'
4
4
  module Prometheus
5
5
  module Client
6
6
  class SimpleValue
7
- def initialize(type, metric_name, name, _labels, *_args)
7
+ def initialize(_type, _metric_name, _name, _labels, *_args)
8
8
  @value = 0.0
9
9
  end
10
10
 
@@ -1,5 +1,5 @@
1
1
  module Prometheus
2
2
  module Client
3
- VERSION = '0.7.0.beta34'.freeze
3
+ VERSION = '0.7.0.beta35'.freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prometheus-client-mmap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0.beta34
4
+ version: 0.7.0.beta35
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Schmidt