@@ -7,6 +7,7 @@ use super::counter::Counter;
77use super :: gauge:: Gauge ;
88use super :: label_set:: LabelSet ;
99use super :: metric:: Metric ;
10+ use super :: sample:: Sample ;
1011use super :: MetricName ;
1112use crate :: metrics:: sample_collection:: SampleCollection ;
1213use crate :: DurationSinceUnixEpoch ;
@@ -42,7 +43,15 @@ impl MetricCollection {
4243 self . counters . get_value ( name, labels)
4344 }
4445
46+ /// # Panics
47+ ///
48+ /// Panics if a gauge with the same name already exists.
4549 pub fn increase_counter ( & mut self , name : & MetricName , labels : & LabelSet , time : DurationSinceUnixEpoch ) {
50+ assert ! (
51+ !self . gauges. metrics. contains_key( name) ,
52+ "Cannot create counter with name '{name}': a gauge with this name already exists" ,
53+ ) ;
54+
4655 self . counters . increment ( name, labels, time) ;
4756 }
4857
@@ -53,7 +62,15 @@ impl MetricCollection {
5362 self . gauges . get_value ( name, labels)
5463 }
5564
65+ /// # Panics
66+ ///
67+ /// Panics if a counter with the same name already exists.
5668 pub fn set_gauge ( & mut self , name : & MetricName , labels : & LabelSet , value : f64 , time : DurationSinceUnixEpoch ) {
69+ assert ! (
70+ !self . counters. metrics. contains_key( name) ,
71+ "Cannot create gauge with name '{name}': a counter with this name already exists"
72+ ) ;
73+
5774 self . gauges . set ( name, labels, value, time) ;
5875 }
5976
@@ -182,13 +199,30 @@ impl<T> MetricKindCollection<T> {
182199}
183200
184201impl MetricKindCollection < Counter > {
202+ /// # Panics
203+ ///
204+ /// Panics if the metric name already exists in the collection.
185205 pub fn increment ( & mut self , name : & MetricName , labels : & LabelSet , time : DurationSinceUnixEpoch ) {
186- if let Some ( metric) = self . metrics . get_mut ( name) {
187- if let Some ( sample) = metric. samples . get_mut ( labels) {
188- sample. value . increment ( 1 ) ;
189- sample. update_at = time;
190- }
206+ // Create the metric if it doesn't exist
207+ if !self . metrics . contains_key ( name) {
208+ let new_metric = Metric {
209+ name : name. clone ( ) ,
210+ samples : SampleCollection { samples : HashMap :: new ( ) } ,
211+ } ;
212+ self . metrics . insert ( name. clone ( ) , new_metric) ;
191213 }
214+
215+ let metric = self . metrics . get_mut ( name) . unwrap ( ) ;
216+
217+ // Use entry API to handle existing or new sample
218+ let sample = metric. samples . samples . entry ( labels. clone ( ) ) . or_insert_with ( || Sample {
219+ value : Counter :: new ( 0 ) ,
220+ update_at : time,
221+ labels : labels. clone ( ) ,
222+ } ) ;
223+
224+ sample. value . increment ( 1 ) ;
225+ sample. update_at = time;
192226 }
193227
194228 #[ must_use]
@@ -201,13 +235,35 @@ impl MetricKindCollection<Counter> {
201235}
202236
203237impl MetricKindCollection < Gauge > {
238+ /// # Panics
239+ ///
240+ /// Panics if the metric name already exists in the collection.
204241 pub fn set ( & mut self , name : & MetricName , labels : & LabelSet , value : f64 , time : DurationSinceUnixEpoch ) {
205- if let Some ( metric) = self . metrics . get_mut ( name) {
206- // Direct hashmap lookup
207- if let Some ( sample) = metric. samples . get_mut ( labels) {
242+ // Create the metric if it doesn't exist
243+ if !self . metrics . contains_key ( name) {
244+ let new_metric = Metric {
245+ name : name. clone ( ) ,
246+ samples : SampleCollection { samples : HashMap :: new ( ) } ,
247+ } ;
248+ self . metrics . insert ( name. clone ( ) , new_metric) ;
249+ }
250+
251+ let metric = self . metrics . get_mut ( name) . unwrap ( ) ;
252+
253+ // Use entry API to handle existing or new sample
254+ match metric. samples . samples . entry ( labels. clone ( ) ) {
255+ std:: collections:: hash_map:: Entry :: Occupied ( mut entry) => {
256+ let sample = entry. get_mut ( ) ;
208257 sample. value . set ( value) ;
209258 sample. update_at = time;
210259 }
260+ std:: collections:: hash_map:: Entry :: Vacant ( entry) => {
261+ entry. insert ( Sample {
262+ value : Gauge :: new ( value) ,
263+ update_at : time,
264+ labels : labels. clone ( ) ,
265+ } ) ;
266+ }
211267 }
212268 }
213269
@@ -266,6 +322,20 @@ mod tests {
266322 let _unused = MetricCollection :: new ( counter, gauge) ;
267323 }
268324
325+ #[ test]
326+ #[ should_panic( expected = "Cannot create gauge with name 'test_metric': a counter with this name already exists" ) ]
327+ fn it_should_not_allow_duplicate_names_across_types_when_creating_dynamically ( ) {
328+ let mut collection = MetricCollection :: default ( ) ;
329+ let label_set = LabelSet :: default ( ) ;
330+ let time = DurationSinceUnixEpoch :: from_secs ( 1_743_552_000 ) ;
331+
332+ // First create a counter
333+ collection. increase_counter ( & MetricName :: new ( "test_metric" ) , & label_set, time) ;
334+
335+ // Then try to create a gauge with the same name - this should panic
336+ collection. set_gauge ( & MetricName :: new ( "test_metric" ) , & label_set, 1.0 , time) ;
337+ }
338+
269339 #[ test]
270340 fn it_should_allow_serializing_to_json_as_an_array_of_label_objects ( ) {
271341 let time = DurationSinceUnixEpoch :: from_secs ( 1_743_552_000 ) ;
0 commit comments