Prometheus metrics for library and application developers
0

Configure Feed

Select the types of activity you want to include in your feed.

don't use pointer to implementation

Karl Seguin (Feb 27, 2024, 7:17 AM +0800) 8a1aaf32 dfef082c

+167 -187
+39 -67
src/counter.zig
··· 14 14 assertCounterType(V); 15 15 return union(enum) { 16 16 noop: void, 17 - impl: *Impl, 17 + impl: Impl, 18 18 19 19 const Self = @This(); 20 20 21 - pub fn init(allocator: Allocator, comptime name: []const u8, comptime opts: Opts, comptime ropts: RegistryOpts) !Self { 21 + pub fn init(comptime name: []const u8, comptime opts: Opts, comptime ropts: RegistryOpts) !Self { 22 22 switch (ropts.shouldExclude(name)) { 23 23 true => return .{.noop = {}}, 24 - false => { 25 - const impl = try allocator.create(Impl); 26 - errdefer allocator.destroy(impl); 27 - impl.* = try Impl.init(ropts.prefix ++ name, opts); 28 - return .{.impl = impl}; 29 - }, 24 + false => return .{.impl = try Impl.init(ropts.prefix ++ name, opts)}, 30 25 } 31 26 } 32 27 33 - pub fn incr(self: Self) void { 34 - switch (self) { 28 + pub fn incr(self: *Self) void { 29 + switch (self.*) { 35 30 .noop => {}, 36 - .impl => |impl| impl.incr(), 31 + .impl => |*impl| impl.incr(), 37 32 } 38 33 } 39 34 40 - pub fn incrBy(self: Self, count: V) void { 41 - switch (self) { 35 + pub fn incrBy(self: *Self, count: V) void { 36 + switch (self.*) { 42 37 .noop => {}, 43 - .impl => |impl| impl.incrBy(count), 38 + .impl => |*impl| impl.incrBy(count), 44 39 } 45 40 } 46 41 47 - pub fn write(self: Self, writer: anytype) !void { 48 - switch (self) { 42 + pub fn write(self: *Self, writer: anytype) !void { 43 + switch (self.*) { 49 44 .noop => {}, 50 - .impl => |impl| return impl.write(writer), 51 - } 52 - } 53 - 54 - pub fn deinit(self: Self, allocator: Allocator) void { 55 - switch (self) { 56 - .noop => {}, 57 - .impl => |impl| allocator.destroy(impl), 45 + .impl => |*impl| return impl.write(writer), 58 46 } 59 47 } 60 48 ··· 68 56 .preamble = comptime m.preamble(name, .counter, true, opts.help), 69 57 }; 70 58 } 59 + 71 60 pub fn incr(self: *Impl) void { 72 61 self.incrBy(1); 73 62 } ··· 91 80 assertCounterType(V); 92 81 return union(enum) { 93 82 noop: void, 94 - impl: *Impl, 83 + impl: Impl, 95 84 96 85 const Self = @This(); 97 86 98 87 pub fn init(allocator: Allocator, comptime name: []const u8, comptime opts: Opts, comptime ropts: RegistryOpts) !Self { 99 88 switch (ropts.shouldExclude(name)) { 100 89 true => return .{.noop = {}}, 101 - false => { 102 - const impl = try allocator.create(Impl); 103 - errdefer allocator.destroy(impl); 104 - impl.* = try Impl.init(allocator, ropts.prefix ++ name, opts); 105 - return .{.impl = impl}; 106 - }, 90 + false => return .{.impl = try Impl.init(allocator, ropts.prefix ++ name, opts)}, 107 91 } 108 92 } 109 93 110 - // could get the allocator from impl.allocator, but taking it as a parameter 111 - // makes the API the same between Counter and CounterVec 112 - pub fn deinit(self: Self, allocator: Allocator) void { 113 - switch (self) { 94 + pub fn deinit(self: *Self) void { 95 + switch (self.*) { 114 96 .noop => {}, 115 - .impl => |impl| { 116 - impl.deinit(); 117 - allocator.destroy(impl); 118 - }, 97 + .impl => |*impl| impl.deinit(), 119 98 } 120 99 } 121 100 122 - pub fn incr(self: Self, labels: L) !void { 123 - switch (self) { 101 + pub fn incr(self: *Self, labels: L) !void { 102 + switch (self.*) { 124 103 .noop => {}, 125 - .impl => |impl| return impl.incr(labels), 104 + .impl => |*impl| return impl.incr(labels), 126 105 } 127 106 } 128 107 129 - pub fn incrBy(self: Self, labels: L, count: V) !void { 130 - switch (self) { 108 + pub fn incrBy(self: *Self, labels: L, count: V) !void { 109 + switch (self.*) { 131 110 .noop => {}, 132 - .impl => |impl| return impl.incrBy(labels, count), 111 + .impl => |*impl| return impl.incrBy(labels, count), 133 112 } 134 113 } 135 114 136 - pub fn remove(self: Self, labels: L) void { 137 - switch (self) { 115 + pub fn remove(self: *Self, labels: L) void { 116 + switch (self.*) { 138 117 .noop => {}, 139 - .impl => |impl| impl.remove(labels), 118 + .impl => |*impl| impl.remove(labels), 140 119 } 141 120 } 142 121 143 - pub fn write(self: Self, writer: anytype) !void { 144 - switch (self) { 122 + pub fn write(self: *Self, writer: anytype) !void { 123 + switch (self.*) { 145 124 .noop => {}, 146 - .impl => |impl| return impl.write(writer), 125 + .impl => |*impl| return impl.write(writer), 147 126 } 148 127 } 149 128 ··· 272 251 test "Counter: noop incr/incrBy" { 273 252 // these should just not crash 274 253 var c = Counter(u32){.noop = {}}; 275 - defer c.deinit(t.allocator); 276 254 c.incr(); 277 255 c.incrBy(10); 278 256 ··· 283 261 } 284 262 285 263 test "Counter: incr/incrBy" { 286 - var c = try Counter(u32).init(t.allocator, "t1", .{}, .{}); 287 - defer c.deinit(t.allocator); 264 + var c = try Counter(u32).init("t1", .{}, .{}); 288 265 c.incr(); 289 266 try t.expectEqual(1, c.impl.count); 290 267 c.incrBy(10); ··· 295 272 var arr = std.ArrayList(u8).init(t.allocator); 296 273 defer arr.deinit(); 297 274 298 - var c = try Counter(u32).init(t.allocator, "metric_cnt_1_x", .{}, .{.exclude = &.{"t_ex"}}); 299 - defer c.deinit(t.allocator); 275 + var c = try Counter(u32).init("metric_cnt_1_x", .{}, .{.exclude = &.{"t_ex"}}); 300 276 301 277 { 302 278 c.incr(); ··· 313 289 } 314 290 315 291 test "Counter: exclude" { 316 - var c = try Counter(u32).init(t.allocator, "t_ex", .{}, .{.exclude = &.{"t_ex"}}); 317 - defer c.deinit(t.allocator); 292 + var c = try Counter(u32).init("t_ex", .{}, .{.exclude = &.{"t_ex"}}); 318 293 c.incr(); 319 294 320 295 var arr = std.ArrayList(u8).init(t.allocator); ··· 324 299 } 325 300 326 301 test "Counter: prefix" { 327 - var c = try Counter(u32).init(t.allocator, "t1_p", .{}, .{.prefix = "hello_"}); 328 - defer c.deinit(t.allocator); 302 + var c = try Counter(u32).init("t1_p", .{}, .{.prefix = "hello_"}); 329 303 c.incr(); 330 304 331 305 var arr = std.ArrayList(u8).init(t.allocator); ··· 335 309 } 336 310 337 311 test "Counter: float incr/incrBy" { 338 - var c = try Counter(f32).init(t.allocator, "t1", .{}, .{}); 339 - defer c.deinit(t.allocator); 312 + var c = try Counter(f32).init("t1", .{}, .{}); 340 313 c.incr(); 341 314 try t.expectEqual(1, c.impl.count); 342 315 c.incrBy(12.1); ··· 347 320 var arr = std.ArrayList(u8).init(t.allocator); 348 321 defer arr.deinit(); 349 322 350 - var c = try Counter(f64).init(t.allocator, "metric_cnt_2_x", .{}, .{}); 351 - defer c.deinit(t.allocator); 323 + var c = try Counter(f64).init("metric_cnt_2_x", .{}, .{}); 352 324 353 325 { 354 326 c.incr(); ··· 367 339 test "CounterVec: noop incr/incrBy" { 368 340 // these should just not crash 369 341 var c = CounterVec(u32, struct{id: u32}){.noop = {}}; 370 - defer c.deinit(t.allocator); 342 + defer c.deinit(); 371 343 try c.incr(.{.id = 3}); 372 344 try c.incrBy(.{.id = 10}, 20); 373 345 ··· 385 357 386 358 // these should just not crash 387 359 var c = try CounterVec(u64, struct{id: []const u8}).init(t.allocator, "counter_vec_1", .{.help = "h1"}, .{}); 388 - defer c.deinit(t.allocator); 360 + defer c.deinit(); 389 361 390 362 try c.incr(.{.id = "a"}); 391 363 try c.write(arr.writer()); ··· 417 389 418 390 // these should just not crash 419 391 var c = try CounterVec(f32, struct{id: []const u8}).init(t.allocator, "counter_vec_xx_2", .{.help = "h1"}, .{}); 420 - defer c.deinit(t.allocator); 392 + defer c.deinit(); 421 393 422 394 try c.incr(.{.id = "a"}); 423 395 try c.write(arr.writer());
+42 -69
src/gauge.zig
··· 15 15 assertGaugeType(V); 16 16 return union(enum) { 17 17 noop: void, 18 - impl: *Impl, 18 + impl: Impl, 19 19 20 20 const Self = @This(); 21 21 22 - pub fn init(allocator: Allocator, comptime name: []const u8, comptime opts: Opts, comptime ropts: RegistryOpts) !Self { 22 + pub fn init(comptime name: []const u8, comptime opts: Opts, comptime ropts: RegistryOpts) !Self { 23 23 switch (ropts.shouldExclude(name)) { 24 24 true => return .{.noop = {}}, 25 - false => { 26 - const impl = try allocator.create(Impl); 27 - errdefer allocator.destroy(impl); 28 - impl.* = try Impl.init(ropts.prefix ++ name, opts); 29 - return .{.impl = impl}; 30 - }, 31 - } 32 - } 33 - 34 - pub fn incr(self: Self) void { 35 - switch (self) { 36 - .noop => {}, 37 - .impl => |impl| impl.incr(), 25 + false => return .{.impl = try Impl.init(ropts.prefix ++ name, opts)}, 38 26 } 39 27 } 40 28 41 - pub fn set(self: Self, value: V) void { 42 - switch (self) { 29 + pub fn incr(self: *Self) void { 30 + switch (self.*) { 43 31 .noop => {}, 44 - .impl => |impl| impl.set(value), 32 + .impl => |*impl| impl.incr(), 45 33 } 46 34 } 47 35 48 - pub fn incrBy(self: Self, value: V) void { 49 - switch (self) { 36 + pub fn set(self: *Self, value: V) void { 37 + switch (self.*) { 50 38 .noop => {}, 51 - .impl => |impl| impl.incrBy(value), 39 + .impl => |*impl| impl.set(value), 52 40 } 53 41 } 54 42 55 - pub fn write(self: Self, writer: anytype) !void { 56 - switch (self) { 43 + pub fn incrBy(self: *Self, value: V) void { 44 + switch (self.*) { 57 45 .noop => {}, 58 - .impl => |impl| return impl.write(writer), 46 + .impl => |*impl| impl.incrBy(value), 59 47 } 60 48 } 61 49 62 - pub fn deinit(self: Self, allocator: Allocator) void { 63 - switch (self) { 50 + pub fn write(self: *Self, writer: anytype) !void { 51 + switch (self.*) { 64 52 .noop => {}, 65 - .impl => |impl| allocator.destroy(impl), 53 + .impl => |*impl| return impl.write(writer), 66 54 } 67 55 } 68 56 ··· 103 91 assertGaugeType(V); 104 92 return union(enum) { 105 93 noop: void, 106 - impl: *Impl, 94 + impl: Impl, 107 95 108 96 const Self = @This(); 109 97 110 98 pub fn init(allocator: Allocator, comptime name: []const u8, comptime opts: Opts, comptime ropts: RegistryOpts) !Self { 111 99 switch (ropts.shouldExclude(name)) { 112 100 true => return .{.noop = {}}, 113 - false => { 114 - const impl = try allocator.create(Impl); 115 - errdefer allocator.destroy(impl); 116 - impl.* = try Impl.init(allocator, ropts.prefix ++ name, opts); 117 - return .{.impl = impl}; 118 - }, 101 + false => return .{.impl = try Impl.init(allocator, ropts.prefix ++ name, opts)}, 119 102 } 120 103 } 121 104 122 - // could get the allocator from impl.allocator, but taking it as a parameter 123 - // makes the API the same between Gauge and GaugeVec 124 - pub fn deinit(self: Self, allocator: Allocator) void { 125 - switch (self) { 105 + pub fn deinit(self: *Self) void { 106 + switch (self.*) { 126 107 .noop => {}, 127 - .impl => |impl| { 128 - impl.deinit(); 129 - allocator.destroy(impl); 130 - }, 108 + .impl => |*impl| impl.deinit(), 131 109 } 132 110 } 133 111 134 - pub fn incr(self: Self, labels: L) !void { 135 - switch (self) { 112 + pub fn incr(self: *Self, labels: L) !void { 113 + switch (self.*) { 136 114 .noop => {}, 137 - .impl => |impl| return impl.incr(labels), 115 + .impl => |*impl| return impl.incr(labels), 138 116 } 139 117 } 140 118 141 - pub fn incrBy(self: Self, labels: L, value: V) !void { 142 - switch (self) { 119 + pub fn incrBy(self: *Self, labels: L, value: V) !void { 120 + switch (self.*) { 143 121 .noop => {}, 144 - .impl => |impl| return impl.incrBy(labels, value), 122 + .impl => |*impl| return impl.incrBy(labels, value), 145 123 } 146 124 } 147 125 148 - pub fn set(self: Self, labels: L, value: V) !void { 149 - switch (self) { 126 + pub fn set(self: *Self, labels: L, value: V) !void { 127 + switch (self.*) { 150 128 .noop => {}, 151 - .impl => |impl| return impl.set(labels, value), 129 + .impl => |*impl| return impl.set(labels, value), 152 130 } 153 131 } 154 132 155 - pub fn remove(self: Self, labels: L) void { 156 - switch (self) { 133 + pub fn remove(self: *Self, labels: L) void { 134 + switch (self.*) { 157 135 .noop => {}, 158 - .impl => |impl| impl.remove(labels), 136 + .impl => |*impl| impl.remove(labels), 159 137 } 160 138 } 161 139 162 - pub fn write(self: Self, writer: anytype) !void { 163 - switch (self) { 140 + pub fn write(self: *Self, writer: anytype) !void { 141 + switch (self.*) { 164 142 .noop => {}, 165 - .impl => |impl| return impl.write(writer), 143 + .impl => |*impl| return impl.write(writer), 166 144 } 167 145 } 168 146 ··· 316 294 test "Gauge: noop incr/incrBy/set" { 317 295 // these should just not crash 318 296 var c = Gauge(u32){.noop = {}}; 319 - defer c.deinit(t.allocator); 320 297 c.incr(); 321 298 c.incrBy(10); 322 299 c.set(100); ··· 328 305 } 329 306 330 307 test "Gauge: incr/incrBy/set" { 331 - var g = try Gauge(i32).init(t.allocator, "t1", .{}, .{}); 332 - defer g.deinit(t.allocator); 308 + var g = try Gauge(i32).init("t1", .{}, .{}); 333 309 334 310 g.incr(); 335 311 try t.expectEqual(1, g.impl.value); ··· 348 324 var arr = std.ArrayList(u8).init(t.allocator); 349 325 defer arr.deinit(); 350 326 351 - var g = try Gauge(i32).init(t.allocator, "metric_grp_1_x", .{}, .{}); 352 - defer g.deinit(t.allocator); 327 + var g = try Gauge(i32).init("metric_grp_1_x", .{}, .{}); 353 328 354 329 { 355 330 g.incr(); ··· 373 348 } 374 349 375 350 test "Gauge: float incr/incrBy/set" { 376 - var c = try Gauge(f32).init(t.allocator, "t1", .{}, .{}); 377 - defer c.deinit(t.allocator); 351 + var c = try Gauge(f32).init("t1", .{}, .{}); 378 352 c.incr(); 379 353 try t.expectEqual(1, c.impl.value); 380 354 c.incrBy(-3.9); ··· 387 361 var arr = std.ArrayList(u8).init(t.allocator); 388 362 defer arr.deinit(); 389 363 390 - var c = try Gauge(f64).init(t.allocator, "metric_g_2_x", .{}, .{}); 391 - defer c.deinit(t.allocator); 364 + var c = try Gauge(f64).init("metric_g_2_x", .{}, .{}); 392 365 393 366 { 394 367 c.incr(); ··· 414 387 test "GaugeVec: noop incr/incrBy/set" { 415 388 // these should just not crash 416 389 var g = GaugeVec(u32, struct{id: u32}){.noop = {}}; 417 - defer g.deinit(t.allocator); 390 + defer g.deinit(); 418 391 try g.incr(.{.id = 3}); 419 392 try g.incrBy(.{.id = 10}, 20); 420 393 try g.set(.{.id = 3}, 11); ··· 433 406 434 407 // these should just not crash 435 408 var g = try GaugeVec(i64, struct{id: []const u8}).init(t.allocator, "gauge_vec_1", .{.help = "h1"}, .{}); 436 - defer g.deinit(t.allocator); 409 + defer g.deinit(); 437 410 438 411 try g.incr(.{.id = "a"}); 439 412 try g.write(arr.writer()); ··· 467 440 468 441 // these should just not crash 469 442 var g = try GaugeVec(f64, struct{id: []const u8}).init(t.allocator, "gauge_vec_xx_2", .{.help = "h1"}, .{}); 470 - defer g.deinit(t.allocator); 443 + defer g.deinit(); 471 444 472 445 try g.incr(.{.id = "a"}); 473 446 try g.write(arr.writer());
+30 -43
src/histogram.zig
··· 17 17 18 18 return union(enum) { 19 19 noop: void, 20 - impl: *Impl, 20 + impl: Impl, 21 21 22 22 const Self = @This(); 23 23 24 24 pub fn init(allocator: Allocator, comptime name: []const u8, comptime opts: Opts, comptime ropts: RegistryOpts) !Self { 25 25 switch (ropts.shouldExclude(name)) { 26 26 true => return .{.noop = {}}, 27 - false => { 28 - const impl = try allocator.create(Impl); 29 - errdefer allocator.destroy(impl); 30 - impl.* = try Impl.init(allocator, ropts.prefix ++ name, opts); 31 - return .{.impl = impl}; 32 - }, 27 + false => return .{.impl = try Impl.init(allocator, ropts.prefix ++ name, opts)}, 33 28 } 34 29 } 35 30 36 - pub fn observe(self: Self, value: V) void { 37 - switch (self) { 31 + pub fn observe(self: *Self, value: V) void { 32 + switch (self.*) { 38 33 .noop => {}, 39 - .impl => |impl| impl.observe(value), 34 + .impl => |*impl| impl.observe(value), 40 35 } 41 36 } 42 37 43 - pub fn write(self: Self, writer: anytype) !void { 44 - switch (self) { 38 + pub fn write(self: *Self, writer: anytype) !void { 39 + switch (self.*) { 45 40 .noop => {}, 46 - .impl => |impl| return impl.write(writer), 41 + .impl => |*impl| return impl.write(writer), 47 42 } 48 43 } 49 44 50 - pub fn deinit(self: Self, allocator: Allocator) void { 51 - switch (self) { 45 + pub fn deinit(self: *Self) void { 46 + switch (self.*) { 52 47 .noop => {}, 53 - .impl => |impl| { 54 - impl.deinit(allocator); 55 - allocator.destroy(impl); 56 - }, 48 + .impl => |*impl| impl.deinit(), 57 49 } 58 50 } 59 51 60 52 const Impl = struct { 61 53 sum: V, 62 54 count: usize, 55 + allocator: Allocator, 63 56 preamble: []const u8, 64 57 buckets: [upper_bounds.len]V, 65 58 output_sum_prefix: []const u8, ··· 93 86 return .{ 94 87 .sum = 0, 95 88 .count = 0, 89 + .allocator = allocator, 96 90 .preamble = comptime m.preamble(name, .histogram, false, opts.help), 97 91 .output_sum_prefix = output_sum_prefix, 98 92 .output_count_prefix = output_count_prefix, ··· 102 96 }; 103 97 } 104 98 105 - fn deinit(self: Impl, allocator: Allocator) void { 99 + fn deinit(self: Impl) void { 100 + const allocator = self.allocator; 106 101 allocator.free(self.output_sum_prefix); 107 102 allocator.free(self.output_count_prefix); 108 103 allocator.free(self.output_bucket_inf_prefix); ··· 174 169 175 170 return union(enum) { 176 171 noop: void, 177 - impl: *Impl, 172 + impl: Impl, 178 173 179 174 const Self = @This(); 180 175 181 176 pub fn init(allocator: Allocator, comptime name: []const u8, comptime opts: Opts, comptime ropts: RegistryOpts) !Self { 182 177 switch (ropts.shouldExclude(name)) { 183 178 true => return .{.noop = {}}, 184 - false => { 185 - const impl = try allocator.create(Impl); 186 - errdefer allocator.destroy(impl); 187 - impl.* = try Impl.init(allocator, ropts.prefix ++ name, opts); 188 - return .{.impl = impl}; 189 - }, 179 + false => return .{.impl = try Impl.init(allocator, ropts.prefix ++ name, opts)}, 190 180 } 191 181 } 192 182 193 - pub fn observe(self: Self, labels: L, value: V) !void { 194 - switch (self) { 183 + pub fn observe(self: *Self, labels: L, value: V) !void { 184 + switch (self.*) { 195 185 .noop => {}, 196 - .impl => |impl| return impl.observe(labels, value), 186 + .impl => |*impl| return impl.observe(labels, value), 197 187 } 198 188 } 199 189 200 - pub fn write(self: Self, writer: anytype) !void { 201 - switch (self) { 190 + pub fn write(self: *Self, writer: anytype) !void { 191 + switch (self.*) { 202 192 .noop => {}, 203 - .impl => |impl| return impl.write(writer), 193 + .impl => |*impl| return impl.write(writer), 204 194 } 205 195 } 206 196 207 197 // could get the allocator from impl.allocator, but taking it as a parameter 208 198 // makes the API the same between Histogram and HistogramVec 209 - pub fn deinit(self: Self, allocator: Allocator) void { 210 - switch (self) { 199 + pub fn deinit(self: *Self) void { 200 + switch (self.*) { 211 201 .noop => {}, 212 - .impl => |impl| { 213 - impl.deinit(); 214 - allocator.destroy(impl); 215 - }, 202 + .impl => |*impl| impl.deinit(), 216 203 } 217 204 } 218 205 ··· 488 475 test "Histogram: noop " { 489 476 // these should just not crash 490 477 var h = Histogram(u32, &.{0}){.noop = {}}; 491 - defer h.deinit(t.allocator); 478 + defer h.deinit(); 492 479 h.observe(2); 493 480 494 481 var arr = std.ArrayList(u8).init(t.allocator); ··· 499 486 500 487 test "Histogram" { 501 488 var h = try Histogram(f64, &.{0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10}).init(t.allocator, "hst_1", .{}, .{}); 502 - defer h.deinit(t.allocator); 489 + defer h.deinit(); 503 490 504 491 var i: f64 = 0.001; 505 492 for (0..1000) |_| { ··· 553 540 test "HistogramVec: noop " { 554 541 // these should just not crash 555 542 var h = HistogramVec(u32, struct{status: u16}, &.{0}){.noop = {}}; 556 - defer h.deinit(t.allocator); 543 + defer h.deinit(); 557 544 try h.observe(.{.status = 200}, 2); 558 545 559 546 var arr = std.ArrayList(u8).init(t.allocator); ··· 564 551 565 552 test "HistogramVec" { 566 553 var h = try HistogramVec(f64, struct{status: u16}, &.{0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10}).init(t.allocator, "hst_1", .{}, .{}); 567 - defer h.deinit(t.allocator); 554 + defer h.deinit(); 568 555 569 556 var i: f64 = 0.001; 570 557 for (0..1000) |_| {
+56 -8
src/metrics.zig
··· 44 44 } 45 45 46 46 pub fn write(metrics: anytype, writer: anytype) !void { 47 - const fields = @typeInfo(@TypeOf(metrics)).Struct.fields; 47 + const S = @typeInfo(@TypeOf(metrics)).Pointer.child; 48 + const fields = @typeInfo(S).Struct.fields; 49 + 48 50 inline for (fields) |f| { 49 51 switch (@typeInfo(f.type)) { 50 - .Union => try @field(metrics, f.name).write(writer), 52 + .Union => try @constCast(&@field(metrics, f.name)).write(writer), 51 53 else => {} 52 54 } 53 55 } ··· 68 70 69 71 var arr = std.ArrayList(u8).init(t.allocator); 70 72 defer arr.deinit(); 71 - try write(x, arr.writer()); 73 + try write(&x, arr.writer()); 72 74 try t.expectEqual(0, arr.items.len); 73 75 } 74 76 75 - test " write" { 77 + test "metrics: write" { 76 78 const M = struct{ 77 79 hits: Hits, 78 80 active: Gauge(u64), 81 + timing: Timing, 79 82 80 83 const Hits = CounterVec(u32, struct{status: u16}); 84 + const Timing = HistogramVec(u32, struct{path: []const u8}, &.{5, 10, 25, 50, 100, 250, 500, 1000}); 81 85 }; 82 86 83 87 var m = M{ 84 - .active = try Gauge(u64).init(t.allocator, "active", .{}, .{}), 88 + .active = try Gauge(u64).init("active", .{}, .{}), 85 89 .hits = try M.Hits.init(t.allocator, "hits", .{}, .{}), 90 + .timing = try M.Timing.init(t.allocator, "timing", .{.help = "the timing"}, .{.prefix = "x_"}) 86 91 }; 87 - defer m.hits.deinit(t.allocator); 88 - defer m.active.deinit(t.allocator); 92 + defer m.hits.deinit(); 93 + defer m.timing.deinit(); 89 94 90 95 m.active.set(919); 91 96 try m.hits.incr(.{.status = 199}); 92 97 93 98 var arr = std.ArrayList(u8).init(t.allocator); 94 99 defer arr.deinit(); 95 - try write(m, arr.writer()); 100 + try write(&m, arr.writer()); 96 101 try t.expectString(\\# TYPE hits counter 97 102 \\hits{status="199"} 1 98 103 \\# TYPE active gauge 99 104 \\active 919 105 + \\# HELP x_timing the timing 106 + \\# TYPE x_timing histogram 107 + \\ 108 + , arr.items); 109 + 110 + m.active.set(32); 111 + try m.hits.incr(.{.status = 199}); 112 + try m.hits.incr(.{.status = 3}); 113 + try m.timing.observe(.{.path = "/a"}, 2); 114 + try m.timing.observe(.{.path = "/a"}, 8); 115 + try m.timing.observe(.{.path = "/b"}, 7); 116 + 117 + arr.clearRetainingCapacity(); 118 + try write(&m, arr.writer()); 119 + try t.expectString(\\# TYPE hits counter 120 + \\hits{status="3"} 1 121 + \\hits{status="199"} 2 122 + \\# TYPE active gauge 123 + \\active 32 124 + \\# HELP x_timing the timing 125 + \\# TYPE x_timing histogram 126 + \\x_timing_bucket{le="5",path="/b"} 0 127 + \\x_timing_bucket{le="10",path="/b"} 1 128 + \\x_timing_bucket{le="25",path="/b"} 1 129 + \\x_timing_bucket{le="50",path="/b"} 1 130 + \\x_timing_bucket{le="100",path="/b"} 1 131 + \\x_timing_bucket{le="250",path="/b"} 1 132 + \\x_timing_bucket{le="500",path="/b"} 1 133 + \\x_timing_bucket{le="1000",path="/b"} 1 134 + \\x_timing_bucket{le="+Inf",path="/b"} 1 135 + \\x_timing_sum{path="/b"} 7 136 + \\x_timing_count{path="/b"} 1 137 + \\x_timing_bucket{le="5",path="/a"} 1 138 + \\x_timing_bucket{le="10",path="/a"} 2 139 + \\x_timing_bucket{le="25",path="/a"} 2 140 + \\x_timing_bucket{le="50",path="/a"} 2 141 + \\x_timing_bucket{le="100",path="/a"} 2 142 + \\x_timing_bucket{le="250",path="/a"} 2 143 + \\x_timing_bucket{le="500",path="/a"} 2 144 + \\x_timing_bucket{le="1000",path="/a"} 2 145 + \\x_timing_bucket{le="+Inf",path="/a"} 2 146 + \\x_timing_sum{path="/a"} 10 147 + \\x_timing_count{path="/a"} 2 100 148 \\ 101 149 , arr.items); 102 150 }