fast-prometheus 0.3.0 → 0.3.2

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: 567abd58fbe511ba93717dbec96fa202313d689ed1fb30b765dace0de60d141f
4
- data.tar.gz: 6c9cf404e4f7c0b7f54ea65f0f6c009ea488abdbf0bb2e1705d9c8e43e3b3b46
3
+ metadata.gz: 25cba069a74bd1f00499ff8d2c3a3feb84e9646b1447de704d2dff860dc5cea4
4
+ data.tar.gz: 533131b2461c719cb5525695a5abdc26b474bc6ce9fe35ba338855a698e887a3
5
5
  SHA512:
6
- metadata.gz: cc0c6d858de7e4893e84dc615694a1488a84829eefed4511ad8ca445aa2be354f54b382e3edb54c78363bb5b1b4625ae026db395471fc47a49b3e027bbaa1c7e
7
- data.tar.gz: 1e0c1751a0ade41579e5932044b37d5cecd4df4324bdcccc97d4886bf62d0569e1f030312645b8872f327ce2ffda25c3c525e77a3fe23022a7de125b30f5aec3
6
+ metadata.gz: c0a779b8563993d01400a7587852f2ec65c65621facd1bd3e9c44d39404e44eff0656a137a12f6a8da1b60b902d6bfe897b35ab82627064c8238f005171d0623
7
+ data.tar.gz: 8b9c2ce522dc9360c40f1779b7e4240370e5a7dbe4e6b333f9c39583bf2ba5a43805aa4b523763322ca62716b23c619047291beff28cb5b33abe88ad7874f96c
data/CHANGELOG.md CHANGED
@@ -7,6 +7,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.3.2] - 2026-09-19
11
+
12
+ ### Changed
13
+
14
+ - `Formats::Protobuf.render` writes each family and each series straight
15
+ into the output behind a length prefix reserved first and filled in after
16
+ (`Fast::Protowire::Wire.reserve_length` / `close_length` /
17
+ `append_length_delimited_from`), instead of encoding the family header
18
+ to a String and copying every series out of a scratch buffer. Same
19
+ bytes; at 36,000 series x 12 labels a render went from 0.151 s and 29
20
+ objects to 0.144 s and 24, a protobuf scrape over HTTP from 0.162 s to
21
+ 0.151 s (0.200 s to 0.192 s with gzip). Benchmarks page and README
22
+ updated.
23
+
24
+ ## [0.3.1] - 2026-09-19
25
+
26
+ ### Changed
27
+
28
+ - Requires [fast-protowire](https://github.com/jetpks/fast-protowire) `~> 0.2`,
29
+ whose encoder writes nested messages in place and allocates nothing per
30
+ message: the declared-message paths here (family headers, native
31
+ histograms, OTLP export) get that for free, and the `Wire` primitives the
32
+ per-series renderer uses append text as bytes with no binary copy on
33
+ Ruby 3.4+.
34
+ - Benchmarks re-taken on the new dependency and republished on the
35
+ benchmarks page and in the README.
36
+
10
37
  ## [0.3.0] - 2026-09-18
11
38
 
12
39
  ### Changed
data/README.md CHANGED
@@ -94,7 +94,7 @@ Single process, locked, thread-safe by default (`benchmark-ips` and allocation
94
94
  comparisons against `prometheus-client` and `google-protobuf`; see
95
95
  [the benchmarks page](docs/explanation/benchmarks.md) for the full runs and conditions):
96
96
 
97
- - A protobuf scrape of 36,000 series renders in **29 objects**, where the
97
+ - A protobuf scrape of 36,000 series renders in **24 objects**, where the
98
98
  `google-protobuf` encoder needed 3.5 million Ruby objects and 504k native arenas, and
99
99
  in a hundredth of the GC time; taking the snapshot it reads is 1 ms and one Hash per metric
100
100
  - The text renderer allocates **66x fewer objects** than prometheus-client's formatter
@@ -12,10 +12,10 @@ module Fast
12
12
  # Each family's header is a declared Proto::MetricFamily; the series
13
13
  # under it are written straight to the wire with Fast::Protowire::Wire,
14
14
  # no LabelPair/Metric/Counter objects, because a scrape's series count
15
- # is the one thing here that is large. A series' bytes go into one
16
- # scratch buffer reused for the whole render and are copied under the
17
- # family's metric tag, so rendering allocates per series only what
18
- # Array#pack needs for a double. Native histograms, few and irregular,
15
+ # is the one thing here that is large. Each series' bytes are written
16
+ # straight into the output behind a length prefix filled in after them,
17
+ # so rendering allocates nothing per series and copies nothing. Native
18
+ # histograms, few and irregular,
19
19
  # still go through Proto::Histogram. Bytes are identical to what the
20
20
  # declared classes (and google-protobuf) produce; the tests check.
21
21
  module Protobuf
@@ -64,32 +64,31 @@ module Fast
64
64
  DOUBLE_SIZE = 9
65
65
  private_constant :DOUBLE_SIZE
66
66
 
67
- # One varint-length-prefixed MetricFamily frame per metric.
67
+ # One varint-length-prefixed MetricFamily frame per metric, each
68
+ # written straight into the output behind a length prefix reserved
69
+ # first and filled in after (see Fast::Protowire::Wire).
68
70
  def self.render(snapshot)
69
- scratch = String.new
70
- snapshot.metrics.each_with_object(String.new) do |ms, buffer|
71
- family = encode_metric_family(ms, scratch)
72
- Fast::Protowire::Wire.append_varint(buffer, family.bytesize)
73
- buffer << family
71
+ snapshot.metrics.each_with_object(String.new) do |ms, out|
72
+ start = Fast::Protowire::Wire.reserve_length(out)
73
+ append_metric_family(out, ms)
74
+ Fast::Protowire::Wire.close_length(out, start)
74
75
  end
75
76
  end
76
77
 
77
78
  # A family's bytes are its header (name, help, type) followed by one
78
- # metric entry per series, each written into +scratch+ and copied.
79
- private_class_method def self.encode_metric_family(metric_snapshot, scratch)
80
- header = Proto::MetricFamily.new(name: metric_snapshot.name.name, help: metric_snapshot.docstring,
81
- type: TYPE_MAP.fetch(metric_snapshot.type))
79
+ # metric entry per series, in place. A family's series are alike, so
80
+ # the entry prefix width carries from one to the next.
81
+ private_class_method def self.append_metric_family(out, metric_snapshot)
82
+ Proto::MetricFamily.new(name: metric_snapshot.name.name, help: metric_snapshot.docstring,
83
+ type: TYPE_MAP.fetch(metric_snapshot.type)).encode(out)
82
84
  type = metric_snapshot.type
83
85
  names = metric_snapshot.label_names
84
- buffer = header.encode
86
+ width = 1
85
87
  metric_snapshot.series.each_pair do |values, value|
86
- scratch.clear
87
- append_metric(scratch, names, values, value, type)
88
- buffer << FAMILY_METRIC
89
- Fast::Protowire::Wire.append_varint(buffer, scratch.bytesize)
90
- buffer << scratch
88
+ width = Fast::Protowire::Wire.append_length_delimited_from(out, FAMILY_METRIC, width) do |buffer|
89
+ append_metric(buffer, names, values, value, type)
90
+ end
91
91
  end
92
- buffer
93
92
  end
94
93
 
95
94
  # Metric: labels (1) then the one value field for the type, in
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Fast
4
4
  module Prometheus
5
- VERSION = "0.3.0"
5
+ VERSION = "0.3.2"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fast-prometheus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Jacobs
@@ -71,14 +71,14 @@ dependencies:
71
71
  requirements:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: '0.1'
74
+ version: '0.2'
75
75
  type: :runtime
76
76
  prerelease: false
77
77
  version_requirements: !ruby/object:Gem::Requirement
78
78
  requirements:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: '0.1'
81
+ version: '0.2'
82
82
  - !ruby/object:Gem::Dependency
83
83
  name: console
84
84
  requirement: !ruby/object:Gem::Requirement