yggdrasil-engine 1.1.0-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 +4 -4
- data/lib/libyggdrasilffi_arm64-musl.so +0 -0
- data/lib/libyggdrasilffi_arm64.dylib +0 -0
- data/lib/libyggdrasilffi_arm64.so +0 -0
- data/lib/libyggdrasilffi_x86_64-musl.so +0 -0
- data/lib/libyggdrasilffi_x86_64.dylib +0 -0
- data/lib/libyggdrasilffi_x86_64.so +0 -0
- data/lib/yggdrasil_engine.rb +83 -1
- data/lib/yggdrasilffi_arm64.dll +0 -0
- data/lib/yggdrasilffi_i686.dll +0 -0
- data/lib/yggdrasilffi_x86_64.dll +0 -0
- data/spec/impact_metrics_spec.rb +166 -0
- metadata +8 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 743de4af671f1321c015f1c9c98b17d755d3addd017329f61840d80bc3e50ba5
|
|
4
|
+
data.tar.gz: 5fc1d28448949c4478d8e0d8cc9f34f1cf4ef8140e7a8fe7e74972a5dd32c84e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e0a2812e76491d84f81560200741c29a85b685b1c35f5d9ae64e9660890b6c908779feb654cbbb75d0f917634ffee8ea7cadc6726e88e3b402f0ecadcb70b45e
|
|
7
|
+
data.tar.gz: 8d0710fe87d9eab9e5379c84bd69ef053b7bb241e1cd243c133cb37951789eaae2efebaeb2fc8d5ad9cdae27edf919e87cc7dcd46374f54c169195cd06d72ebf
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/lib/yggdrasil_engine.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require 'ffi'
|
|
2
2
|
require 'json'
|
|
3
|
+
require 'logger'
|
|
3
4
|
require 'custom_strategy'
|
|
4
5
|
|
|
5
6
|
TOGGLE_MISSING_RESPONSE = 'NotFound'.freeze
|
|
@@ -69,6 +70,21 @@ class YggdrasilEngine
|
|
|
69
70
|
|
|
70
71
|
attach_function :list_known_toggles, [:pointer], :pointer
|
|
71
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
|
+
|
|
82
|
+
class << self
|
|
83
|
+
attr_accessor :logger
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
self.logger = Logger.new($stderr, level: Logger::WARN)
|
|
87
|
+
|
|
72
88
|
def initialize
|
|
73
89
|
@engine = YggdrasilEngine.new_engine
|
|
74
90
|
@custom_strategy_handler = CustomStrategyHandler.new
|
|
@@ -83,6 +99,9 @@ class YggdrasilEngine
|
|
|
83
99
|
@custom_strategy_handler.update_strategies(toggles)
|
|
84
100
|
response_ptr = YggdrasilEngine.take_state(@engine, toggles)
|
|
85
101
|
take_toggles_response = JSON.parse(response_ptr.read_string, symbolize_names: true)
|
|
102
|
+
if take_toggles_response[:status_code] == ERROR_RESPONSE
|
|
103
|
+
self.class.logger.error("Error taking state, flags were not updated: #{take_toggles_response[:error_message]}")
|
|
104
|
+
end
|
|
86
105
|
YggdrasilEngine.free_response(response_ptr)
|
|
87
106
|
end
|
|
88
107
|
|
|
@@ -93,7 +112,7 @@ class YggdrasilEngine
|
|
|
93
112
|
response = JSON.parse(response_json, symbolize_names: true)
|
|
94
113
|
|
|
95
114
|
raise "Error: #{response[:error_message]}" if response[:status_code] == ERROR_RESPONSE
|
|
96
|
-
|
|
115
|
+
|
|
97
116
|
response[:value].to_json
|
|
98
117
|
ensure
|
|
99
118
|
YggdrasilEngine.free_response(response_ptr)
|
|
@@ -157,4 +176,67 @@ class YggdrasilEngine
|
|
|
157
176
|
def register_custom_strategies(strategies)
|
|
158
177
|
@custom_strategy_handler.register_custom_strategies(strategies)
|
|
159
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
|
|
160
242
|
end
|
data/lib/yggdrasilffi_arm64.dll
CHANGED
|
Binary file
|
|
Binary file
|
data/lib/yggdrasilffi_x86_64.dll
CHANGED
|
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.
|
|
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:
|
|
10
|
+
date: 2026-01-23 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: ffi
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 1.
|
|
18
|
+
version: 1.17.2
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 1.
|
|
25
|
+
version: 1.17.2
|
|
26
26
|
description: "..."
|
|
27
27
|
email: liquidwicked64@gmail.com
|
|
28
28
|
executables: []
|
|
@@ -39,14 +39,16 @@ files:
|
|
|
39
39
|
- lib/libyggdrasilffi_x86_64.so
|
|
40
40
|
- lib/yggdrasil_engine.rb
|
|
41
41
|
- lib/yggdrasilffi_arm64.dll
|
|
42
|
+
- lib/yggdrasilffi_i686.dll
|
|
42
43
|
- lib/yggdrasilffi_x86_64.dll
|
|
43
44
|
- spec/custom_strategy_spec.rb
|
|
45
|
+
- spec/impact_metrics_spec.rb
|
|
44
46
|
- spec/yggdrasil_engine_spec.rb
|
|
45
|
-
homepage:
|
|
47
|
+
homepage: https://github.com/Unleash/yggdrasil-bindings
|
|
46
48
|
licenses:
|
|
47
49
|
- MIT
|
|
48
50
|
metadata:
|
|
49
|
-
yggdrasil_core_version: 0.
|
|
51
|
+
yggdrasil_core_version: 0.20.0
|
|
50
52
|
rdoc_options: []
|
|
51
53
|
require_paths:
|
|
52
54
|
- lib
|