yggdrasil-engine 1.1.1-universal-java-17 → 1.2.0-universal-java-17

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
  SHA256:
3
- metadata.gz: 1b8f57f1f079127e31324281d4e6b11eceee03c1fc6b9535e7fffefd2d2817f7
4
- data.tar.gz: 19191e5f88df64758a99b315aee5cf089c284d2830ad8bf02b8307892d6e7690
3
+ metadata.gz: 743de4af671f1321c015f1c9c98b17d755d3addd017329f61840d80bc3e50ba5
4
+ data.tar.gz: 5fc1d28448949c4478d8e0d8cc9f34f1cf4ef8140e7a8fe7e74972a5dd32c84e
5
5
  SHA512:
6
- metadata.gz: 91127174094430a2327e6adc7bdf395bde4249250443b2cf43dd42c1966a220ce492506fd4adcb7b633e028562f1665969e5b4f4a2cd878c98b4c06d01572666
7
- data.tar.gz: 33f0a1b20274bdb46279a5110bf0037494fa77f39c0923d9cdee3e13d4d7fef246bade71fe0084cb932476e34d9627ea9e3aee55ff63ecfa80cb9c491b3a481e
6
+ metadata.gz: e0a2812e76491d84f81560200741c29a85b685b1c35f5d9ae64e9660890b6c908779feb654cbbb75d0f917634ffee8ea7cadc6726e88e3b402f0ecadcb70b45e
7
+ data.tar.gz: 8d0710fe87d9eab9e5379c84bd69ef053b7bb241e1cd243c133cb37951789eaae2efebaeb2fc8d5ad9cdae27edf919e87cc7dcd46374f54c169195cd06d72ebf
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -70,6 +70,15 @@ class YggdrasilEngine
70
70
 
71
71
  attach_function :list_known_toggles, [:pointer], :pointer
72
72
 
73
+ attach_function :define_counter, %i[pointer string string], :pointer
74
+ attach_function :inc_counter, %i[pointer string int64 string], :pointer
75
+ attach_function :collect_impact_metrics, [:pointer], :pointer
76
+ attach_function :restore_impact_metrics, %i[pointer string], :pointer
77
+ attach_function :define_gauge, %i[pointer string string], :pointer
78
+ attach_function :set_gauge, %i[pointer string double string], :pointer
79
+ attach_function :define_histogram, %i[pointer string string string], :pointer
80
+ attach_function :observe_histogram, %i[pointer string double string], :pointer
81
+
73
82
  class << self
74
83
  attr_accessor :logger
75
84
  end
@@ -167,4 +176,67 @@ class YggdrasilEngine
167
176
  def register_custom_strategies(strategies)
168
177
  @custom_strategy_handler.register_custom_strategies(strategies)
169
178
  end
179
+
180
+ def define_counter(name, help_text)
181
+ response_ptr = YggdrasilEngine.define_counter(@engine, name, help_text)
182
+ handle_response(response_ptr)
183
+ end
184
+
185
+ def inc_counter(name, value = 1, labels = nil)
186
+ labels_json = labels&.to_json
187
+ response_ptr = YggdrasilEngine.inc_counter(@engine, name, value, labels_json)
188
+ handle_response(response_ptr)
189
+ end
190
+
191
+ def collect_impact_metrics
192
+ response_ptr = YggdrasilEngine.collect_impact_metrics(@engine)
193
+ response_json = response_ptr.read_string
194
+ YggdrasilEngine.free_response(response_ptr)
195
+ response = JSON.parse(response_json, symbolize_names: true)
196
+
197
+ raise "Error: #{response[:error_message]}" if response[:status_code] == ERROR_RESPONSE
198
+
199
+ response[:value] || []
200
+ end
201
+
202
+ def restore_impact_metrics(metrics)
203
+ metrics_json = metrics.to_json
204
+ response_ptr = YggdrasilEngine.restore_impact_metrics(@engine, metrics_json)
205
+ handle_response(response_ptr)
206
+ end
207
+
208
+ def define_gauge(name, help_text)
209
+ response_ptr = YggdrasilEngine.define_gauge(@engine, name, help_text)
210
+ handle_response(response_ptr)
211
+ end
212
+
213
+ def set_gauge(name, value, labels = nil)
214
+ labels_json = labels&.to_json
215
+ response_ptr = YggdrasilEngine.set_gauge(@engine, name, value, labels_json)
216
+ handle_response(response_ptr)
217
+ end
218
+
219
+ def define_histogram(name, help_text, buckets = nil)
220
+ buckets_json = (buckets || []).to_json
221
+ response_ptr = YggdrasilEngine.define_histogram(@engine, name, help_text, buckets_json)
222
+ handle_response(response_ptr)
223
+ end
224
+
225
+ def observe_histogram(name, value, labels = nil)
226
+ labels_json = labels&.to_json
227
+ response_ptr = YggdrasilEngine.observe_histogram(@engine, name, value, labels_json)
228
+ handle_response(response_ptr)
229
+ end
230
+
231
+ private
232
+
233
+ def handle_response(response_ptr)
234
+ response_json = response_ptr.read_string
235
+ YggdrasilEngine.free_response(response_ptr)
236
+ response = JSON.parse(response_json, symbolize_names: true)
237
+
238
+ raise "Error: #{response[:error_message]}" if response[:status_code] == ERROR_RESPONSE
239
+
240
+ nil
241
+ end
170
242
  end
Binary file
Binary file
Binary file
@@ -0,0 +1,166 @@
1
+ require 'rspec'
2
+ require 'json'
3
+ require_relative '../lib/yggdrasil_engine'
4
+
5
+ RSpec.describe YggdrasilEngine do
6
+ let(:yggdrasil_engine) { YggdrasilEngine.new }
7
+
8
+ describe '#inc_counter' do
9
+ it 'should increment counter value' do
10
+ yggdrasil_engine.define_counter('test_counter', 'Test counter')
11
+ yggdrasil_engine.inc_counter('test_counter', 5)
12
+ yggdrasil_engine.inc_counter('test_counter', 3)
13
+
14
+ metrics = yggdrasil_engine.collect_impact_metrics()
15
+ counter = metrics.find { |m| m[:name] == 'test_counter' }
16
+
17
+ expect(counter).not_to be_nil
18
+ expect(counter[:help]).to eq('Test counter')
19
+ expect(counter[:samples].length).to eq(1)
20
+ expect(counter[:samples][0][:value]).to eq(8)
21
+ end
22
+
23
+ it 'should increment counter with labels' do
24
+ yggdrasil_engine.define_counter('test_counter', 'Test counter')
25
+ yggdrasil_engine.inc_counter('test_counter', 5, { 'env' => 'test' })
26
+ yggdrasil_engine.inc_counter('test_counter', 3, { 'env' => 'prod' })
27
+
28
+ metrics = yggdrasil_engine.collect_impact_metrics()
29
+ counter = metrics.find { |m| m[:name] == 'test_counter' }
30
+
31
+ expect(counter).not_to be_nil
32
+ expect(counter[:samples].length).to eq(2)
33
+
34
+ test_sample = counter[:samples].find { |s| s[:labels][:env] == 'test' }
35
+ prod_sample = counter[:samples].find { |s| s[:labels][:env] == 'prod' }
36
+
37
+ expect(test_sample[:value]).to eq(5)
38
+ expect(prod_sample[:value]).to eq(3)
39
+ end
40
+ end
41
+
42
+ describe '#set_gauge' do
43
+ it 'should set gauge value' do
44
+ yggdrasil_engine.define_gauge('test_gauge', 'Test gauge')
45
+ yggdrasil_engine.set_gauge('test_gauge', 5.5)
46
+ yggdrasil_engine.set_gauge('test_gauge', 10.7)
47
+
48
+ metrics = yggdrasil_engine.collect_impact_metrics()
49
+ gauge = metrics.find { |m| m[:name] == 'test_gauge' }
50
+
51
+ expect(gauge).not_to be_nil
52
+ expect(gauge[:help]).to eq('Test gauge')
53
+ expect(gauge[:samples].length).to eq(1)
54
+ expect(gauge[:samples][0][:value]).to eq(10.7)
55
+ end
56
+
57
+ it 'should set gauge with labels' do
58
+ yggdrasil_engine.define_gauge('test_gauge', 'Test gauge')
59
+ yggdrasil_engine.set_gauge('test_gauge', 5.25, { 'env' => 'test' })
60
+ yggdrasil_engine.set_gauge('test_gauge', 3.14, { 'env' => 'prod' })
61
+
62
+ metrics = yggdrasil_engine.collect_impact_metrics()
63
+ gauge = metrics.find { |m| m[:name] == 'test_gauge' }
64
+
65
+ expect(gauge).not_to be_nil
66
+ expect(gauge[:samples].length).to eq(2)
67
+
68
+ test_sample = gauge[:samples].find { |s| s[:labels][:env] == 'test' }
69
+ prod_sample = gauge[:samples].find { |s| s[:labels][:env] == 'prod' }
70
+
71
+ expect(test_sample[:value]).to eq(5.25)
72
+ expect(prod_sample[:value]).to eq(3.14)
73
+ end
74
+ end
75
+
76
+ describe '#observe_histogram' do
77
+ it 'should observe histogram values' do
78
+ yggdrasil_engine.define_histogram('request_duration', 'Request duration', [0.1, 0.5, 1.0, 5.0])
79
+ yggdrasil_engine.observe_histogram('request_duration', 0.05)
80
+ yggdrasil_engine.observe_histogram('request_duration', 0.75)
81
+ yggdrasil_engine.observe_histogram('request_duration', 3.0)
82
+
83
+ metrics = yggdrasil_engine.collect_impact_metrics()
84
+ histogram = metrics.find { |m| m[:name] == 'request_duration' }
85
+
86
+ expect(histogram).not_to be_nil
87
+ expect(histogram[:help]).to eq('Request duration')
88
+ expect(histogram[:type]).to eq('histogram')
89
+ expect(histogram[:samples].length).to eq(1)
90
+ end
91
+
92
+ it 'should observe histogram with labels' do
93
+ yggdrasil_engine.define_histogram('request_duration', 'Request duration', [0.1, 0.5, 1.0, 5.0])
94
+ yggdrasil_engine.observe_histogram('request_duration', 0.05, { 'env' => 'test' })
95
+ yggdrasil_engine.observe_histogram('request_duration', 0.75, { 'env' => 'prod' })
96
+
97
+ metrics = yggdrasil_engine.collect_impact_metrics()
98
+ histogram = metrics.find { |m| m[:name] == 'request_duration' }
99
+
100
+ expect(histogram).not_to be_nil
101
+ expect(histogram[:samples].length).to eq(2)
102
+
103
+ test_sample = histogram[:samples].find { |s| s[:labels][:env] == 'test' }
104
+ prod_sample = histogram[:samples].find { |s| s[:labels][:env] == 'prod' }
105
+
106
+ expect(test_sample).not_to be_nil
107
+ expect(prod_sample).not_to be_nil
108
+ end
109
+ end
110
+
111
+ describe '#define_histogram' do
112
+ it 'should define histogram with default buckets' do
113
+ yggdrasil_engine.define_histogram('request_duration', 'Request duration')
114
+ yggdrasil_engine.observe_histogram('request_duration', 0.05)
115
+
116
+ metrics = yggdrasil_engine.collect_impact_metrics()
117
+ histogram = metrics.find { |m| m[:name] == 'request_duration' }
118
+
119
+ expect(histogram).not_to be_nil
120
+ expect(histogram[:type]).to eq('histogram')
121
+ expect(histogram[:samples].length).to eq(1)
122
+ end
123
+ end
124
+
125
+ describe '#collect_impact_metrics' do
126
+ it 'should return empty list when no metrics' do
127
+ metrics = yggdrasil_engine.collect_impact_metrics()
128
+ expect(metrics).to eq([])
129
+ end
130
+ end
131
+
132
+ describe '#restore_impact_metrics' do
133
+ it 'should restore impact metrics' do
134
+ yggdrasil_engine.define_counter('test_counter', 'Test counter')
135
+ yggdrasil_engine.inc_counter('test_counter', 10)
136
+ yggdrasil_engine.define_gauge('test_gauge', 'Test gauge')
137
+ yggdrasil_engine.set_gauge('test_gauge', 42)
138
+ yggdrasil_engine.define_histogram('test_histogram', 'Test histogram', [0.1, 0.5, 1.0])
139
+ yggdrasil_engine.observe_histogram('test_histogram', 0.25)
140
+
141
+ metrics = yggdrasil_engine.collect_impact_metrics()
142
+ expect(metrics.length).to eq(3)
143
+
144
+ counter = metrics.find { |m| m[:name] == 'test_counter' }
145
+ gauge = metrics.find { |m| m[:name] == 'test_gauge' }
146
+ histogram = metrics.find { |m| m[:name] == 'test_histogram' }
147
+
148
+ expect(counter[:samples][0][:value]).to eq(10)
149
+ expect(gauge[:samples][0][:value]).to eq(42)
150
+ expect(histogram).not_to be_nil
151
+
152
+ yggdrasil_engine.restore_impact_metrics(metrics)
153
+
154
+ restored_metrics = yggdrasil_engine.collect_impact_metrics()
155
+ expect(restored_metrics.length).to eq(3)
156
+
157
+ restored_counter = restored_metrics.find { |m| m[:name] == 'test_counter' }
158
+ restored_gauge = restored_metrics.find { |m| m[:name] == 'test_gauge' }
159
+ restored_histogram = restored_metrics.find { |m| m[:name] == 'test_histogram' }
160
+
161
+ expect(restored_counter[:samples][0][:value]).to eq(10)
162
+ expect(restored_gauge[:samples][0][:value]).to eq(42)
163
+ expect(restored_histogram).not_to be_nil
164
+ end
165
+ end
166
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yggdrasil-engine
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  platform: universal-java-17
6
6
  authors:
7
7
  - Unleash
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-12-04 00:00:00.000000000 Z
10
+ date: 2026-01-23 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: ffi
@@ -42,12 +42,13 @@ files:
42
42
  - lib/yggdrasilffi_i686.dll
43
43
  - lib/yggdrasilffi_x86_64.dll
44
44
  - spec/custom_strategy_spec.rb
45
+ - spec/impact_metrics_spec.rb
45
46
  - spec/yggdrasil_engine_spec.rb
46
47
  homepage: https://github.com/Unleash/yggdrasil-bindings
47
48
  licenses:
48
49
  - MIT
49
50
  metadata:
50
- yggdrasil_core_version: 0.18.2
51
+ yggdrasil_core_version: 0.20.0
51
52
  rdoc_options: []
52
53
  require_paths:
53
54
  - lib