async-utilization 0.3.2 → 0.4.0

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: 2494a3f35fcbfd987fe6520ceda64225ccc6592ebe4072f0260f38a430d0d3fc
4
- data.tar.gz: '0668665f31e13ac0d00c5eded51ad94f7f394927318e05ef83f7a5cd818e22e3'
3
+ metadata.gz: 522f4b5822343c23f14422555147e2159e2bac50afbd230a06e985e2cfe1cee4
4
+ data.tar.gz: caa61db8daf6f65a77e319a210ee0079f9a647deed614e7cc5333507967964fa
5
5
  SHA512:
6
- metadata.gz: 863148a136e0a8696c337c5c24e18f8751bea2b586f1a703235992103c5454d1621d9296c401ded2d75aa532255beab3ae7ee2ad84211a8eb3b9971aac7b5fc8
7
- data.tar.gz: 4a6e0ee78558c67dd2f8c5e8bb284c0aaed26cb23a3df700b451841a8081dafd9973ff2ef033f7f137cae4e657b60eae29cfeca89a8edd7ca3233f46a7318ce5
6
+ metadata.gz: ebaabb2e0959e3664e4e2a18812d71efa75d967a2fb01a89f8d63af02eb9e36bc564edfc50c7315b4efbbe8ee5f60e865250cb660daa274fa185e6a538994f6c
7
+ data.tar.gz: 7760f55b1383998120a3f7bf0b65b578c8da04bf648c0407f6b3e57040edec2b1487b82356f6d11eaf3bdb02cab9ddc8797eb3c8ee67c930a03d35fec08a5e60
checksums.yaml.gz.sig CHANGED
Binary file
@@ -38,11 +38,14 @@ module Async
38
38
  # @attribute [Symbol] The field name for this metric.
39
39
  attr :name
40
40
 
41
- # @attribute [Numeric] The current value of this metric.
42
- attr :value
43
-
44
- # @attribute [Mutex] The mutex for thread safety.
45
- attr :guard
41
+ # Get the current in-memory metric value.
42
+ #
43
+ # @returns [Numeric] The last value written to this metric.
44
+ def value
45
+ @guard.synchronize do
46
+ @value
47
+ end
48
+ end
46
49
 
47
50
  # Set the observer and rebuild cache.
48
51
  #
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2026, by Samuel Williams.
5
+
6
+ module Async
7
+ module Utilization
8
+ # A registry-like view that prefixes metric names.
9
+ #
10
+ # Namespaces let components use generic metric names while applications decide
11
+ # how those names are composed in the shared registry.
12
+ class Namespace
13
+ # Initialize a new namespace.
14
+ #
15
+ # @parameter registry [Registry] The underlying registry.
16
+ # @parameter name [Symbol] The namespace name.
17
+ def initialize(registry, name)
18
+ @registry = registry
19
+ @name = name.to_sym
20
+ end
21
+
22
+ # @attribute [Registry] The underlying registry.
23
+ attr :registry
24
+
25
+ # @attribute [Symbol] The namespace name.
26
+ attr :name
27
+
28
+ # Get a metric in this namespace.
29
+ #
30
+ # @parameter name [Symbol] The metric name.
31
+ # @returns [Metric] A metric instance for the namespaced field.
32
+ def metric(name)
33
+ @registry.metric(metric_name(name))
34
+ end
35
+
36
+ # Get a nested namespace.
37
+ #
38
+ # @parameter name [Symbol] The nested namespace name.
39
+ # @returns [Namespace] A namespace view with the composed name.
40
+ def namespace(name)
41
+ self.class.new(@registry, metric_name(name))
42
+ end
43
+
44
+ private
45
+
46
+ def metric_name(name)
47
+ :"#{@name}_#{name}"
48
+ end
49
+ end
50
+ end
51
+ end
@@ -4,6 +4,7 @@
4
4
  # Copyright, 2026, by Samuel Williams.
5
5
 
6
6
  require "console"
7
+ require_relative "namespace"
7
8
 
8
9
  module Async
9
10
  module Utilization
@@ -22,9 +23,11 @@ module Async
22
23
  # @example Create a registry and emit metrics:
23
24
  # registry = Async::Utilization::Registry.new
24
25
  #
25
- # # Emit metrics - values tracked in registry
26
- # registry.increment(:total_requests)
27
- # registry.track(:active_requests) do
26
+ # total_requests = registry.metric(:total_requests)
27
+ # total_requests.increment
28
+ #
29
+ # active_requests = registry.metric(:active_requests)
30
+ # active_requests.track do
28
31
  # # Handle request - auto-decrements when block completes
29
32
  # end
30
33
  #
@@ -37,7 +40,6 @@ module Async
37
40
  # observer = Async::Utilization::Observer.open(schema, "/path/to/shm", 4096, 0)
38
41
  # registry.observer = observer
39
42
  class Registry
40
-
41
43
  # Initialize a new registry.
42
44
  def initialize
43
45
  @observer = nil
@@ -49,15 +51,12 @@ module Async
49
51
  # @attribute [Object | Nil] The registered observer.
50
52
  attr :observer
51
53
 
52
- # @attribute [Mutex] The mutex for thread safety.
53
- attr :guard
54
-
55
54
  # Get the current values for all metrics.
56
55
  #
57
56
  # @returns [Hash] Hash mapping field names to their current values.
58
57
  def values
59
58
  @metrics.transform_values do |metric|
60
- metric.guard.synchronize{metric.value}
59
+ metric.value
61
60
  end
62
61
  end
63
62
 
@@ -79,48 +78,6 @@ module Async
79
78
 
80
79
  # Console.info(self, "Observer assigned", observer: observer, metric_count: @metrics.size)
81
80
  end
82
-
83
- end
84
-
85
- # Set a field value.
86
- #
87
- # Delegates to the metric instance for the given field.
88
- #
89
- # @parameter field [Symbol] The field name to set.
90
- # @parameter value [Numeric] The value to set.
91
- def set(field, value)
92
- metric(field).set(value)
93
- end
94
-
95
- # Increment a field value.
96
- #
97
- # Delegates to the metric instance for the given field.
98
- #
99
- # @parameter field [Symbol] The field name to increment.
100
- # @returns [Integer] The new value of the field.
101
- def increment(field)
102
- metric(field).increment
103
- end
104
-
105
- # Track an operation: increment before the block, decrement after it completes.
106
- #
107
- # Delegates to the metric instance for the given field.
108
- #
109
- # @parameter field [Symbol] The field name to track.
110
- # @yield The operation to track.
111
- # @returns [Object] The block's return value.
112
- def track(field, &block)
113
- metric(field).track(&block)
114
- end
115
-
116
- # Decrement a field value.
117
- #
118
- # Delegates to the metric instance for the given field.
119
- #
120
- # @parameter field [Symbol] The field name to decrement.
121
- # @returns [Integer] The new value of the field.
122
- def decrement(field)
123
- metric(field).decrement
124
81
  end
125
82
 
126
83
  # Get a cached metric reference for a field.
@@ -137,6 +94,14 @@ module Async
137
94
  @metrics[field] ||= Metric.for(field, @observer)
138
95
  end
139
96
  end
97
+
98
+ # Get a namespace view of this registry.
99
+ #
100
+ # @parameter name [Symbol] The namespace name.
101
+ # @returns [Namespace] A registry-like namespace view.
102
+ def namespace(name)
103
+ Namespace.new(self, name)
104
+ end
140
105
  end
141
106
  end
142
107
  end
@@ -7,6 +7,6 @@
7
7
  module Async
8
8
  # @namespace
9
9
  module Utilization
10
- VERSION = "0.3.2"
10
+ VERSION = "0.4.0"
11
11
  end
12
12
  end
@@ -5,6 +5,7 @@
5
5
 
6
6
  require_relative "utilization/version"
7
7
  require_relative "utilization/schema"
8
+ require_relative "utilization/namespace"
8
9
  require_relative "utilization/registry"
9
10
  require_relative "utilization/observer"
10
11
  require_relative "utilization/metric"
data/readme.md CHANGED
@@ -14,6 +14,11 @@ Please see the [project documentation](https://socketry.github.io/async-utilizat
14
14
 
15
15
  Please see the [project releases](https://socketry.github.io/async-utilization/releases/index) for all releases.
16
16
 
17
+ ### v0.4.0
18
+
19
+ - Add `Async::Utilization::Namespace` for composing registry metric names.
20
+ - `Async::Utilization::Metric` is the primary interface, remove `#set`, `#increment`, `#decrement` and `#track` from `Registry`.
21
+
17
22
  ### v0.3.2
18
23
 
19
24
  - Better observer state handling.
@@ -40,6 +45,22 @@ We welcome contributions to this project.
40
45
  4. Push to the branch (`git push origin my-new-feature`).
41
46
  5. Create new Pull Request.
42
47
 
48
+ ### Running Tests
49
+
50
+ To run the test suite:
51
+
52
+ ``` shell
53
+ bundle exec sus
54
+ ```
55
+
56
+ ### Making Releases
57
+
58
+ To make a new release:
59
+
60
+ ``` shell
61
+ bundle exec bake gem:release:patch # or minor or major
62
+ ```
63
+
43
64
  ### Developer Certificate of Origin
44
65
 
45
66
  In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed.
data/releases.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Releases
2
2
 
3
+ ## v0.4.0
4
+
5
+ - Add `Async::Utilization::Namespace` for composing registry metric names.
6
+ - `Async::Utilization::Metric` is the primary interface, remove `#set`, `#increment`, `#decrement` and `#track` from `Registry`.
7
+
3
8
  ## v0.3.2
4
9
 
5
10
  - Better observer state handling.
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2026, by Samuel Williams.
5
+
6
+ require "sus"
7
+ require "async/utilization"
8
+
9
+ describe Async::Utilization::Namespace do
10
+ let(:registry) {Async::Utilization::Registry.new}
11
+ let(:namespace) {registry.namespace(:socket_accept)}
12
+
13
+ it "uses namespaced metric names" do
14
+ metric = namespace.metric(:acquired_count)
15
+
16
+ expect(metric).to be_a(Async::Utilization::Metric)
17
+ expect(metric.name).to be == :socket_accept_acquired_count
18
+
19
+ metric.set(2)
20
+ expect(registry.values).to have_keys(socket_accept_acquired_count: be == 2)
21
+ end
22
+
23
+ it "returns the same metric instance for the same namespaced field" do
24
+ metric1 = namespace.metric(:waiting_count)
25
+ metric2 = namespace.metric(:waiting_count)
26
+
27
+ expect(metric1).to be == metric2
28
+ end
29
+
30
+ it "supports nested namespaces" do
31
+ metric = namespace.namespace(:long_task).metric(:waiting_count)
32
+
33
+ expect(metric.name).to be == :socket_accept_long_task_waiting_count
34
+
35
+ metric.increment
36
+ expect(registry.values).to have_keys(socket_accept_long_task_waiting_count: be == 1)
37
+ end
38
+
39
+ it "writes namespaced metrics to an observer" do
40
+ schema = Async::Utilization::Schema.build(socket_accept_acquired_count: :u64)
41
+ buffer = IO::Buffer.new(8)
42
+
43
+ observer = Object.new
44
+ observer.define_singleton_method(:schema){schema}
45
+ observer.define_singleton_method(:buffer){buffer}
46
+
47
+ registry.observer = observer
48
+
49
+ namespace.metric(:acquired_count).set(5)
50
+
51
+ expect(buffer.get_value(:u64, 0)).to be == 5
52
+ end
53
+ end
@@ -8,37 +8,38 @@ require "async/utilization"
8
8
 
9
9
  describe Async::Utilization::Registry do
10
10
  let(:registry) {Async::Utilization::Registry.new}
11
+ let(:test_field_metric) {registry.metric(:test_field)}
11
12
 
12
13
  it "can increment a value" do
13
- value = registry.increment(:test_field)
14
+ value = test_field_metric.increment
14
15
  expect(value).to be == 1
15
16
  expect(registry.values[:test_field]).to be == 1
16
17
  end
17
18
 
18
19
  it "can increment multiple times" do
19
- registry.increment(:test_field)
20
- registry.increment(:test_field)
21
- registry.increment(:test_field)
20
+ test_field_metric.increment
21
+ test_field_metric.increment
22
+ test_field_metric.increment
22
23
 
23
24
  expect(registry.values[:test_field]).to be == 3
24
25
  end
25
26
 
26
27
  it "can decrement a value" do
27
- registry.increment(:test_field)
28
- registry.increment(:test_field)
28
+ test_field_metric.increment
29
+ test_field_metric.increment
29
30
 
30
- value = registry.decrement(:test_field)
31
+ value = test_field_metric.decrement
31
32
  expect(value).to be == 1
32
33
  expect(registry.values[:test_field]).to be == 1
33
34
  end
34
35
 
35
36
  it "can set a value directly" do
36
- registry.set(:test_field, 42)
37
+ test_field_metric.set(42)
37
38
  expect(registry.values[:test_field]).to be == 42
38
39
  end
39
40
 
40
41
  it "can track an operation with auto-decrement" do
41
- registry.track(:test_field) do
42
+ test_field_metric.track do
42
43
  expect(registry.values[:test_field]).to be == 1
43
44
  end
44
45
 
@@ -47,7 +48,7 @@ describe Async::Utilization::Registry do
47
48
 
48
49
  it "decrements even if track block raises an error" do
49
50
  begin
50
- registry.track(:test_field) do
51
+ test_field_metric.track do
51
52
  raise "Error!"
52
53
  end
53
54
  rescue
@@ -64,13 +65,13 @@ describe Async::Utilization::Registry do
64
65
  observer.define_singleton_method(:schema){schema}
65
66
  observer.define_singleton_method(:buffer){buffer}
66
67
 
67
- registry.set(:test_field, 5)
68
+ test_field_metric.set(5)
68
69
  registry.observer = observer
69
70
 
70
71
  # Buffer should be synced with the existing value on observer assignment
71
72
  expect(buffer.get_value(:u64, 0)).to be == 5
72
73
 
73
- registry.increment(:test_field)
74
+ test_field_metric.increment
74
75
 
75
76
  # Buffer should reflect the incremented value
76
77
  expect(buffer.get_value(:u64, 0)).to be == 6
@@ -83,6 +84,14 @@ describe Async::Utilization::Registry do
83
84
  expect(registry.values).to have_keys(module_test: be == 2)
84
85
  end
85
86
 
87
+ it "can create a namespace" do
88
+ namespace = registry.namespace(:socket_accept)
89
+
90
+ expect(namespace).to be_a(Async::Utilization::Namespace)
91
+ expect(namespace.registry).to be == registry
92
+ expect(namespace.name).to be == :socket_accept
93
+ end
94
+
86
95
  it "can use metric for decrement" do
87
96
  registry.metric(:module_decrement_test).increment
88
97
  registry.metric(:module_decrement_test).increment
@@ -104,7 +113,7 @@ describe Async::Utilization::Registry do
104
113
  observer.define_singleton_method(:schema){schema}
105
114
  observer.define_singleton_method(:buffer){buffer}
106
115
 
107
- registry.set(:test_field, 7)
116
+ test_field_metric.set(7)
108
117
  registry.observer = observer
109
118
 
110
119
  expect(buffer.get_value(:u64, 0)).to be == 7
@@ -118,11 +127,11 @@ describe Async::Utilization::Registry do
118
127
  observer.define_singleton_method(:buffer){buffer}
119
128
 
120
129
  registry.observer = observer
121
- registry.set(:test_field, 5)
130
+ test_field_metric.set(5)
122
131
  expect(buffer.get_value(:u64, 0)).to be == 5
123
132
 
124
133
  registry.observer = nil
125
- registry.set(:test_field, 99)
134
+ test_field_metric.set(99)
126
135
 
127
136
  # Buffer unchanged, in-memory value updated
128
137
  expect(buffer.get_value(:u64, 0)).to be == 5
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-utilization
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -58,6 +58,7 @@ extra_rdoc_files: []
58
58
  files:
59
59
  - lib/async/utilization.rb
60
60
  - lib/async/utilization/metric.rb
61
+ - lib/async/utilization/namespace.rb
61
62
  - lib/async/utilization/observer.rb
62
63
  - lib/async/utilization/registry.rb
63
64
  - lib/async/utilization/schema.rb
@@ -67,6 +68,7 @@ files:
67
68
  - releases.md
68
69
  - test/async/utilization.rb
69
70
  - test/async/utilization/metric.rb
71
+ - test/async/utilization/namespace.rb
70
72
  - test/async/utilization/observer.rb
71
73
  - test/async/utilization/registry.rb
72
74
  - test/async/utilization/schema.rb
@@ -90,7 +92,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
90
92
  - !ruby/object:Gem::Version
91
93
  version: '0'
92
94
  requirements: []
93
- rubygems_version: 4.0.3
95
+ rubygems_version: 4.0.6
94
96
  specification_version: 4
95
97
  summary: High-performance utilization metrics for Async services using shared memory.
96
98
  test_files: []
metadata.gz.sig CHANGED
Binary file