@@ -4,6 +4,8 @@ const spec = @import("spec.zig");
4
4
const builtin = @import ("builtin" );
5
5
const Attribute = @import ("../../attributes.zig" ).Attribute ;
6
6
const Attributes = @import ("../../attributes.zig" ).Attributes ;
7
+ const InstrumentationScope = @import ("../../scope.zig" ).InstrumentationScope ;
8
+
7
9
const DataPoint = @import ("measurement.zig" ).DataPoint ;
8
10
const HistogramDataPoint = @import ("measurement.zig" ).HistogramDataPoint ;
9
11
@@ -18,14 +20,18 @@ const Histogram = @import("instrument.zig").Histogram;
18
20
const Gauge = @import ("instrument.zig" ).Gauge ;
19
21
const MetricReader = @import ("../../sdk/metrics/reader.zig" ).MetricReader ;
20
22
21
- const defaultMeterVersion = "0.1.0" ;
22
23
var debug_allocator : std .heap .DebugAllocator (.{}) = .init ;
23
24
24
25
/// MeterProvider is responsble for creating and managing meters.
25
26
/// See https://opentelemetry.io/docs/specs/otel/metrics/api/#meterprovider
26
27
pub const MeterProvider = struct {
27
28
allocator : std.mem.Allocator ,
28
- meters : std .AutoHashMapUnmanaged (u64 , Meter ),
29
+ meters : std .HashMapUnmanaged (
30
+ InstrumentationScope ,
31
+ Meter ,
32
+ InstrumentationScope .HashContext ,
33
+ std .hash_map .default_max_load_percentage ,
34
+ ),
29
35
readers : std .ArrayListUnmanaged (* MetricReader ),
30
36
31
37
const Self = @This ();
@@ -72,39 +78,22 @@ pub const MeterProvider = struct {
72
78
}
73
79
74
80
/// Get a new meter by specifying its name.
75
- /// Options can be passed to specify a version, schemaURL, and attributes.
81
+ /// Scope can be passed to specify a version, schemaURL, and attributes.
76
82
/// SchemaURL and attributes are default to null.
77
83
/// If a meter with the same name already exists, it will be returned.
78
84
/// See https://opentelemetry.io/docs/specs/otel/metrics/api/#get-a-meter
79
- pub fn getMeter (self : * Self , options : MeterOptions ) ! * Meter {
85
+ pub fn getMeter (self : * Self , scope : InstrumentationScope ) ! * Meter {
80
86
const i = Meter {
81
- .name = options .name ,
82
- .version = options .version ,
83
- .attributes = options .attributes ,
84
- .schema_url = options .schema_url ,
87
+ .scope = scope ,
85
88
.instruments = .empty ,
86
89
.allocator = self .allocator ,
87
90
};
88
- // A Meter is identified uniquely by its name, version and schema_url.
89
- // We use a hash of these values to identify the meter.
90
- const meterId = spec .meterIdentifier (options );
91
91
92
- // Raise an error if a meter with the same name/version/schema_url is asked to be fetched with different attributes.
93
- if (self .meterExistsWithDifferentAttributes (meterId , options .attributes )) {
94
- return spec .ResourceError .MeterExistsWithDifferentAttributes ;
95
- }
96
- const meter = try self .meters .getOrPutValue (self .allocator , meterId , i );
92
+ const meter = try self .meters .getOrPutValue (self .allocator , scope , i );
97
93
98
94
return meter .value_ptr ;
99
95
}
100
96
101
- fn meterExistsWithDifferentAttributes (self : * Self , identifier : u64 , attributes : ? []Attribute ) bool {
102
- if (self .meters .get (identifier )) | m | {
103
- return ! std .mem .eql (u8 , & std .mem .toBytes (m .attributes ), & std .mem .toBytes (attributes ));
104
- }
105
- return false ;
106
- }
107
-
108
97
pub fn addReader (self : * Self , m : * MetricReader ) ! void {
109
98
if (m .meterProvider != null ) {
110
99
return spec .ResourceError .MetricReaderAlreadyAttached ;
@@ -114,20 +103,10 @@ pub const MeterProvider = struct {
114
103
}
115
104
};
116
105
117
- pub const MeterOptions = struct {
118
- name : []const u8 ,
119
- version : []const u8 = defaultMeterVersion ,
120
- schema_url : ? []const u8 = null ,
121
- attributes : ? []Attribute = null ,
122
- };
123
-
124
106
/// Meter is a named instance that is used to record measurements.
125
107
/// See https://opentelemetry.io/docs/specs/otel/metrics/api/#meter
126
108
const Meter = struct {
127
- name : []const u8 ,
128
- version : []const u8 ,
129
- schema_url : ? []const u8 ,
130
- attributes : ? []Attribute = null ,
109
+ scope : InstrumentationScope ,
131
110
instruments : std .StringHashMapUnmanaged (* Instrument ),
132
111
allocator : std.mem.Allocator ,
133
112
@@ -198,7 +177,7 @@ const Meter = struct {
198
177
if (self .instruments .contains (id )) {
199
178
std .debug .print (
200
179
"Instrument with identifying name {s} already exists in meter {s}\n " ,
201
- .{ id , self .name },
180
+ .{ id , self .scope . name },
202
181
);
203
182
return spec .ResourceError .InstrumentExistsWithSameNameAndIdentifyingFields ;
204
183
}
@@ -216,7 +195,7 @@ const Meter = struct {
216
195
// Cleanup Meters' Instruments values.
217
196
self .instruments .deinit (self .allocator );
218
197
// Cleanup the meter attributes.
219
- if (self .attributes ) | attrs | self .allocator .free (attrs );
198
+ if (self .scope . attributes ) | attrs | self .allocator .free (attrs );
220
199
}
221
200
};
222
201
@@ -242,10 +221,10 @@ test "meter can be created from custom provider" {
242
221
243
222
const meter = try mp .getMeter (.{ .name = meter_name , .version = meter_version });
244
223
245
- std .debug .assert (std .mem .eql (u8 , meter .name , meter_name ));
246
- std .debug .assert (std .mem .eql (u8 , meter .version , meter_version ));
247
- std .debug .assert (meter .schema_url == null );
248
- std .debug .assert (meter .attributes == null );
224
+ std .debug .assert (std .mem .eql (u8 , meter .scope . name , meter_name ));
225
+ std .debug .assert (std .mem .eql (u8 , meter .scope . version .? , meter_version ));
226
+ std .debug .assert (meter .scope . schema_url == null );
227
+ std .debug .assert (meter .scope . attributes == null );
249
228
}
250
229
251
230
test "meter can be created from default provider with schema url and attributes" {
@@ -259,41 +238,10 @@ test "meter can be created from default provider with schema url and attributes"
259
238
const attributes = try Attributes .from (mp .allocator , .{ "key" , val });
260
239
261
240
const meter = try mp .getMeter (.{ .name = meter_name , .version = meter_version , .schema_url = "http://foo.bar" , .attributes = attributes });
262
- try std .testing .expectEqual (meter .name , meter_name );
263
- try std .testing .expectEqualStrings (meter .version , meter_version );
264
- try std .testing .expectEqualStrings (meter .schema_url .? , "http://foo.bar" );
265
- std .debug .assert (std .mem .eql (u8 , std .mem .sliceAsBytes (meter .attributes .? ), std .mem .sliceAsBytes (attributes .? )));
266
- }
267
-
268
- test "meter has default version when creted with no options" {
269
- const mp = try MeterProvider .default ();
270
- defer mp .shutdown ();
271
-
272
- const meter = try mp .getMeter (.{ .name = "ameter" });
273
- std .debug .assert (std .mem .eql (u8 , meter .version , defaultMeterVersion ));
274
- }
275
-
276
- test "getting same meter with different attributes returns an error" {
277
- const name = "my-meter" ;
278
- const version = "v1.2.3" ;
279
- const schema_url = "http://foo.bar" ;
280
-
281
- const mp = try MeterProvider .default ();
282
- defer mp .shutdown ();
283
-
284
- const val1 : []const u8 = "value1" ;
285
- const val2 : []const u8 = "value2" ;
286
- const attributes = try Attributes .from (mp .allocator , .{ "key1" , val1 });
287
-
288
- _ = try mp .getMeter (.{ .name = name , .version = version , .schema_url = schema_url , .attributes = attributes });
289
-
290
- // modify the attributes adding one/
291
- // these attributes are not allocated with the same allocator as the meter.
292
- const attributesUpdated = try Attributes .from (std .testing .allocator , .{ "key1" , val1 , "key2" , val2 });
293
- defer std .testing .allocator .free (attributesUpdated .? );
294
-
295
- const r = mp .getMeter (.{ .name = name , .version = version , .schema_url = schema_url , .attributes = attributesUpdated });
296
- try std .testing .expectError (spec .ResourceError .MeterExistsWithDifferentAttributes , r );
241
+ try std .testing .expectEqual (meter .scope .name , meter_name );
242
+ try std .testing .expectEqualStrings (meter .scope .version .? , meter_version );
243
+ try std .testing .expectEqualStrings (meter .scope .schema_url .? , "http://foo.bar" );
244
+ std .debug .assert (std .mem .eql (u8 , std .mem .sliceAsBytes (meter .scope .attributes .? ), std .mem .sliceAsBytes (attributes .? )));
297
245
}
298
246
299
247
test "meter register instrument twice with same name fails" {
@@ -555,9 +503,9 @@ pub const AggregatedMetrics = struct {
555
503
// only if there are data points.
556
504
if (aggregated_data ) | agg | {
557
505
try results .append (Measurements {
558
- .meterName = meter .name ,
559
- .meterSchemaUrl = meter .schema_url ,
560
- .meterAttributes = meter .attributes ,
506
+ .meterName = meter .scope . name ,
507
+ .meterSchemaUrl = meter .scope . schema_url ,
508
+ .meterAttributes = meter .scope . attributes ,
561
509
.instrumentKind = instr .* .kind ,
562
510
.instrumentOptions = instr .* .opts ,
563
511
.data = agg ,
@@ -647,8 +595,8 @@ test "aggregated metrics fetch to owned slice" {
647
595
}
648
596
649
597
try std .testing .expectEqual (1 , result .len );
650
- try std .testing .expectEqualStrings (meter .name , result [0 ].meterName );
651
- try std .testing .expectEqualStrings (meter .schema_url .? , result [0 ].meterSchemaUrl .? );
598
+ try std .testing .expectEqualStrings (meter .scope . name , result [0 ].meterName );
599
+ try std .testing .expectEqualStrings (meter .scope . schema_url .? , result [0 ].meterSchemaUrl .? );
652
600
try std .testing .expectEqualStrings ("test-counter" , result [0 ].instrumentOptions .name );
653
601
try std .testing .expectEqual (4 , result [0 ].data .int [0 ].value );
654
602
}
0 commit comments