88import static io .opentelemetry .sdk .testing .assertj .OpenTelemetryAssertions .assertThat ;
99
1010import io .github .netmikey .logunit .api .LogCapturer ;
11+ import io .opentelemetry .extension .incubator .metrics .ExtendedDoubleHistogramBuilder ;
1112import io .opentelemetry .internal .testing .slf4j .SuppressLogger ;
1213import io .opentelemetry .sdk .common .InstrumentationScopeInfo ;
1314import io .opentelemetry .sdk .metrics .internal .state .MetricStorageRegistry ;
1415import io .opentelemetry .sdk .metrics .internal .view .ViewRegistry ;
1516import io .opentelemetry .sdk .testing .exporter .InMemoryMetricReader ;
17+ import java .util .Arrays ;
1618import java .util .concurrent .atomic .AtomicLong ;
1719import org .junit .jupiter .api .BeforeEach ;
1820import org .junit .jupiter .api .Test ;
@@ -106,7 +108,7 @@ void sameMeterSameInstrumentNoViews() {
106108 }
107109
108110 @ Test
109- void sameMeterDifferentInstrumentNoViews () {
111+ void sameMeterDifferentInstrumentNameNoViews () {
110112 SdkMeterProvider meterProvider = builder .build ();
111113
112114 meterProvider .get ("meter1" ).counterBuilder ("counter1" ).build ().add (10 );
@@ -130,6 +132,139 @@ void sameMeterDifferentInstrumentNoViews() {
130132 assertThat (metricStorageRegistryLogs .getEvents ()).hasSize (0 );
131133 }
132134
135+ @ Test
136+ void sameMeterDifferentInstrumentNameCaseNoViews () {
137+ SdkMeterProvider meterProvider = builder .build ();
138+
139+ meterProvider .get ("meter1" ).counterBuilder ("Counter1" ).build ().add (10 );
140+ meterProvider .get ("meter1" ).counterBuilder ("counter1" ).build ().add (10 );
141+
142+ assertThat (reader .collectAllMetrics ())
143+ .satisfiesExactlyInAnyOrder (
144+ metricData ->
145+ assertThat (metricData )
146+ .hasInstrumentationScope (forMeter ("meter1" ))
147+ .hasName ("Counter1" )
148+ .hasLongSumSatisfying (
149+ sum -> sum .hasPointsSatisfying (point -> point .hasValue (20 ))));
150+
151+ assertThat (metricStorageRegistryLogs .getEvents ()).hasSize (0 );
152+ }
153+
154+ @ Test
155+ @ SuppressLogger (MetricStorageRegistry .class )
156+ void sameMeterSameInstrumentNameDifferentIdentifyingFieldsNoViews () {
157+ SdkMeterProvider meterProvider = builder .build ();
158+
159+ meterProvider .get ("meter1" ).counterBuilder ("counter1" ).build ().add (10 );
160+ // Same name, different unit
161+ meterProvider .get ("meter1" ).counterBuilder ("counter1" ).setUnit ("unit1" ).build ().add (10 );
162+ // Same name, different description
163+ meterProvider
164+ .get ("meter1" )
165+ .counterBuilder ("counter1" )
166+ .setDescription ("description1" )
167+ .build ()
168+ .add (10 );
169+ // Same name, different value type
170+ meterProvider .get ("meter1" ).counterBuilder ("counter1" ).ofDoubles ().build ().add (10 );
171+ // Same name, different instrument type
172+ meterProvider .get ("meter1" ).upDownCounterBuilder ("counter1" ).build ().add (10 );
173+
174+ // When name is the same, but some identifying field is different (unit, description, value
175+ // type, instrument type) we produce different metric streams are produced and log a warning
176+ assertThat (reader .collectAllMetrics ())
177+ .satisfiesExactlyInAnyOrder (
178+ metricData ->
179+ assertThat (metricData )
180+ .hasInstrumentationScope (forMeter ("meter1" ))
181+ .hasName ("counter1" )
182+ .hasLongSumSatisfying (
183+ sum -> sum .isMonotonic ().hasPointsSatisfying (point -> point .hasValue (10 ))),
184+ metricData ->
185+ assertThat (metricData )
186+ .hasInstrumentationScope (forMeter ("meter1" ))
187+ .hasName ("counter1" )
188+ .hasUnit ("unit1" )
189+ .hasLongSumSatisfying (
190+ sum -> sum .isMonotonic ().hasPointsSatisfying (point -> point .hasValue (10 ))),
191+ metricData ->
192+ assertThat (metricData )
193+ .hasInstrumentationScope (forMeter ("meter1" ))
194+ .hasName ("counter1" )
195+ .hasDescription ("description1" )
196+ .hasLongSumSatisfying (
197+ sum -> sum .isMonotonic ().hasPointsSatisfying (point -> point .hasValue (10 ))),
198+ metricData ->
199+ assertThat (metricData )
200+ .hasInstrumentationScope (forMeter ("meter1" ))
201+ .hasName ("counter1" )
202+ .hasDoubleSumSatisfying (
203+ sum -> sum .isMonotonic ().hasPointsSatisfying (point -> point .hasValue (10 ))),
204+ metricData ->
205+ assertThat (metricData )
206+ .hasInstrumentationScope (forMeter ("meter1" ))
207+ .hasName ("counter1" )
208+ .hasLongSumSatisfying (
209+ sum ->
210+ sum .isNotMonotonic ().hasPointsSatisfying (point -> point .hasValue (10 ))));
211+
212+ assertThat (metricStorageRegistryLogs .getEvents ())
213+ .allSatisfy (
214+ logEvent ->
215+ assertThat (logEvent .getMessage ()).contains ("Found duplicate metric definition" ))
216+ .hasSize (4 );
217+ }
218+
219+ @ Test
220+ void sameMeterSameInstrumentNameDifferentNonIdentifyingFieldsNoViews () {
221+ SdkMeterProvider meterProvider = builder .build ();
222+
223+ // Register histogram1, with and without advice. First registration without advice wins.
224+ meterProvider .get ("meter1" ).histogramBuilder ("histogram1" ).build ().record (8 );
225+ ((ExtendedDoubleHistogramBuilder ) meterProvider .get ("meter1" ).histogramBuilder ("histogram1" ))
226+ .setAdvice (advice -> advice .setExplicitBucketBoundaries (Arrays .asList (10.0 , 20.0 , 30.0 )))
227+ .build ()
228+ .record (8 );
229+
230+ // Register histogram2, with and without advice. First registration with advice wins.
231+ ((ExtendedDoubleHistogramBuilder ) meterProvider .get ("meter1" ).histogramBuilder ("histogram2" ))
232+ .setAdvice (advice -> advice .setExplicitBucketBoundaries (Arrays .asList (10.0 , 20.0 , 30.0 )))
233+ .build ()
234+ .record (8 );
235+ meterProvider .get ("meter1" ).histogramBuilder ("histogram2" ).build ().record (8 );
236+
237+ assertThat (reader .collectAllMetrics ())
238+ .satisfiesExactlyInAnyOrder (
239+ metricData ->
240+ assertThat (metricData )
241+ .hasInstrumentationScope (forMeter ("meter1" ))
242+ .hasName ("histogram1" )
243+ .hasHistogramSatisfying (
244+ histogram ->
245+ histogram .hasPointsSatisfying (
246+ point ->
247+ point
248+ .hasBucketCounts (
249+ 0 , 0 , 2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 )
250+ .hasBucketBoundaries (
251+ 0d , 5d , 10d , 25d , 50d , 75d , 100d , 250d , 500d , 750d ,
252+ 1_000d , 2_500d , 5_000d , 7_500d , 10_000d ))),
253+ metricData ->
254+ assertThat (metricData )
255+ .hasInstrumentationScope (forMeter ("meter1" ))
256+ .hasName ("histogram2" )
257+ .hasHistogramSatisfying (
258+ histogram ->
259+ histogram .hasPointsSatisfying (
260+ point ->
261+ point
262+ .hasBucketCounts (2 , 0 , 0 , 0 )
263+ .hasBucketBoundaries (10.0 , 20.0 , 30.0 ))));
264+
265+ assertThat (metricStorageRegistryLogs .getEvents ()).hasSize (0 );
266+ }
267+
133268 @ Test
134269 void differentMeterSameInstrumentNoViews () {
135270 // Meters are the same if their name, version, and scope are all equals
0 commit comments