prometheus-client-mmap 0.7.0.beta34 → 0.7.0.beta35

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 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