mirror of
				https://github.com/datahub-project/datahub.git
				synced 2025-10-31 18:59:23 +00:00 
			
		
		
		
	refactor(metrics): Make MetricUtils.registry non-nullable
- Make MetricUtils.registry non-nullable with default no-op implementation. This allows us to remove boilerplate for handling the null case - Rename request context metric names to follow convention
This commit is contained in:
		
							parent
							
								
									4ea758da19
								
							
						
					
					
						commit
						6ec6f0150d
					
				| @ -87,13 +87,9 @@ public class GraphQLEngine { | |||||||
|             graphQLQueryComplexityLimit, new DataHubFieldComplexityCalculator())); |             graphQLQueryComplexityLimit, new DataHubFieldComplexityCalculator())); | ||||||
| 
 | 
 | ||||||
|     if (metricUtils != null && graphQLConfiguration.getMetrics().isEnabled()) { |     if (metricUtils != null && graphQLConfiguration.getMetrics().isEnabled()) { | ||||||
|       metricUtils |       instrumentations.add( | ||||||
|           .getRegistry() |           new GraphQLTimingInstrumentation( | ||||||
|           .ifPresent( |               metricUtils.getRegistry(), graphQLConfiguration.getMetrics())); | ||||||
|               meterRegistry -> |  | ||||||
|                   instrumentations.add( |  | ||||||
|                       new GraphQLTimingInstrumentation( |  | ||||||
|                           meterRegistry, graphQLConfiguration.getMetrics()))); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ChainedInstrumentation chainedInstrumentation = new ChainedInstrumentation(instrumentations); |     ChainedInstrumentation chainedInstrumentation = new ChainedInstrumentation(instrumentations); | ||||||
|  | |||||||
| @ -284,7 +284,7 @@ public class GraphQLEngineTest { | |||||||
|   public void testMetricsEnabled() { |   public void testMetricsEnabled() { | ||||||
|     // Setup metrics |     // Setup metrics | ||||||
|     MeterRegistry meterRegistry = new SimpleMeterRegistry(); |     MeterRegistry meterRegistry = new SimpleMeterRegistry(); | ||||||
|     when(mockMetricUtils.getRegistry()).thenReturn(Optional.of(meterRegistry)); |     when(mockMetricUtils.getRegistry()).thenReturn(meterRegistry); | ||||||
| 
 | 
 | ||||||
|     // Enable metrics in configuration |     // Enable metrics in configuration | ||||||
|     GraphQLConfiguration metricsEnabledConfig = createDefaultConfiguration(); |     GraphQLConfiguration metricsEnabledConfig = createDefaultConfiguration(); | ||||||
| @ -405,7 +405,7 @@ public class GraphQLEngineTest { | |||||||
|     metrics.setTrivialDataFetchersEnabled(true); |     metrics.setTrivialDataFetchersEnabled(true); | ||||||
| 
 | 
 | ||||||
|     MeterRegistry meterRegistry = new SimpleMeterRegistry(); |     MeterRegistry meterRegistry = new SimpleMeterRegistry(); | ||||||
|     when(mockMetricUtils.getRegistry()).thenReturn(Optional.of(meterRegistry)); |     when(mockMetricUtils.getRegistry()).thenReturn(meterRegistry); | ||||||
| 
 | 
 | ||||||
|     graphQLEngine = |     graphQLEngine = | ||||||
|         GraphQLEngine.builder() |         GraphQLEngine.builder() | ||||||
| @ -457,7 +457,7 @@ public class GraphQLEngineTest { | |||||||
|   @Test |   @Test | ||||||
|   public void testMetricsWithEmptyRegistry() { |   public void testMetricsWithEmptyRegistry() { | ||||||
|     // Setup metrics with empty registry |     // Setup metrics with empty registry | ||||||
|     when(mockMetricUtils.getRegistry()).thenReturn(Optional.empty()); |     when(mockMetricUtils.getRegistry()).thenReturn(new SimpleMeterRegistry()); | ||||||
| 
 | 
 | ||||||
|     GraphQLConfiguration metricsEnabledConfig = createDefaultConfiguration(); |     GraphQLConfiguration metricsEnabledConfig = createDefaultConfiguration(); | ||||||
|     metricsEnabledConfig.getMetrics().setEnabled(true); |     metricsEnabledConfig.getMetrics().setEnabled(true); | ||||||
|  | |||||||
| @ -124,7 +124,7 @@ public class ElasticSearchTimeseriesAspectService | |||||||
|             new ThreadPoolExecutor.CallerRunsPolicy()); |             new ThreadPoolExecutor.CallerRunsPolicy()); | ||||||
|     if (metricUtils != null) { |     if (metricUtils != null) { | ||||||
|       MicrometerMetricsRegistry.registerExecutorMetrics( |       MicrometerMetricsRegistry.registerExecutorMetrics( | ||||||
|           "timeseries", this.queryPool, metricUtils.getRegistry().orElse(null)); |           "timeseries", this.queryPool, metricUtils.getRegistry()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     this.entityRegistry = entityRegistry; |     this.entityRegistry = entityRegistry; | ||||||
|  | |||||||
| @ -30,7 +30,6 @@ import io.micrometer.core.instrument.Timer; | |||||||
| import io.micrometer.core.instrument.simple.SimpleMeterRegistry; | import io.micrometer.core.instrument.simple.SimpleMeterRegistry; | ||||||
| import java.util.Collections; | import java.util.Collections; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.Optional; |  | ||||||
| import java.util.concurrent.CompletableFuture; | import java.util.concurrent.CompletableFuture; | ||||||
| import org.mockito.Mock; | import org.mockito.Mock; | ||||||
| import org.mockito.MockitoAnnotations; | import org.mockito.MockitoAnnotations; | ||||||
| @ -97,7 +96,7 @@ public class GraphQLTimingInstrumentationTest { | |||||||
| 
 | 
 | ||||||
|     // Setup real GraphQL configuration for GraphQLEngine |     // Setup real GraphQL configuration for GraphQLEngine | ||||||
|     graphQLConfiguration = createDefaultConfiguration(); |     graphQLConfiguration = createDefaultConfiguration(); | ||||||
|     when(mockMetricUtils.getRegistry()).thenReturn(Optional.of(meterRegistry)); |     when(mockMetricUtils.getRegistry()).thenReturn(meterRegistry); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
|  | |||||||
| @ -69,17 +69,13 @@ public abstract class AbstractKafkaListener<E, H extends EventHook<E>, R> | |||||||
|                 // TODO: include priority level when available |                 // TODO: include priority level when available | ||||||
|                 metricUtils |                 metricUtils | ||||||
|                     .getRegistry() |                     .getRegistry() | ||||||
|                     .ifPresent( |                     .timer( | ||||||
|                         meterRegistry -> { |                         MetricUtils.KAFKA_MESSAGE_QUEUE_TIME, | ||||||
|                           meterRegistry |                         "topic", | ||||||
|                               .timer( |                         consumerRecord.topic(), | ||||||
|                                   MetricUtils.KAFKA_MESSAGE_QUEUE_TIME, |                         "consumer.group", | ||||||
|                                   "topic", |                         consumerGroupId) | ||||||
|                                   consumerRecord.topic(), |                     .record(Duration.ofMillis(queueTimeMs)); | ||||||
|                                   "consumer.group", |  | ||||||
|                                   consumerGroupId) |  | ||||||
|                               .record(Duration.ofMillis(queueTimeMs)); |  | ||||||
|                         }); |  | ||||||
|               }); |               }); | ||||||
|       final R record = consumerRecord.value(); |       final R record = consumerRecord.value(); | ||||||
|       log.debug( |       log.debug( | ||||||
|  | |||||||
| @ -76,17 +76,13 @@ public class DataHubUsageEventsProcessor { | |||||||
|                     // TODO: include priority level when available |                     // TODO: include priority level when available | ||||||
|                     metricUtils |                     metricUtils | ||||||
|                         .getRegistry() |                         .getRegistry() | ||||||
|                         .ifPresent( |                         .timer( | ||||||
|                             meterRegistry -> { |                             MetricUtils.KAFKA_MESSAGE_QUEUE_TIME, | ||||||
|                               meterRegistry |                             "topic", | ||||||
|                                   .timer( |                             consumerRecord.topic(), | ||||||
|                                       MetricUtils.KAFKA_MESSAGE_QUEUE_TIME, |                             "consumer.group", | ||||||
|                                       "topic", |                             datahubUsageEventConsumerGroupId) | ||||||
|                                       consumerRecord.topic(), |                         .record(Duration.ofMillis(queueTimeMs)); | ||||||
|                                       "consumer.group", |  | ||||||
|                                       datahubUsageEventConsumerGroupId) |  | ||||||
|                                   .record(Duration.ofMillis(queueTimeMs)); |  | ||||||
|                             }); |  | ||||||
|                   }); |                   }); | ||||||
|           final String record = consumerRecord.value(); |           final String record = consumerRecord.value(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -118,12 +118,8 @@ public class MCLKafkaListener | |||||||
|                 // request |                 // request | ||||||
|                 metricUtils |                 metricUtils | ||||||
|                     .getRegistry() |                     .getRegistry() | ||||||
|                     .ifPresent( |                     .timer(MetricUtils.DATAHUB_REQUEST_HOOK_QUEUE_TIME, "hook", hookName) | ||||||
|                         meterRegistry -> { |                     .record(Duration.ofMillis(queueTimeMs)); | ||||||
|                           meterRegistry |  | ||||||
|                               .timer(MetricUtils.DATAHUB_REQUEST_HOOK_QUEUE_TIME, "hook", hookName) |  | ||||||
|                               .record(Duration.ofMillis(queueTimeMs)); |  | ||||||
|                         }); |  | ||||||
|               } |               } | ||||||
|             }); |             }); | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -49,6 +49,8 @@ public class DataHubUsageEventsProcessorTest { | |||||||
|   public void setUp() { |   public void setUp() { | ||||||
|     MockitoAnnotations.openMocks(this); |     MockitoAnnotations.openMocks(this); | ||||||
| 
 | 
 | ||||||
|  |     when(metricUtils.getRegistry()).thenReturn(new SimpleMeterRegistry()); | ||||||
|  | 
 | ||||||
|     systemOperationContext = |     systemOperationContext = | ||||||
|         TestOperationContexts.Builder.builder() |         TestOperationContexts.Builder.builder() | ||||||
|             .systemTelemetryContextSupplier( |             .systemTelemetryContextSupplier( | ||||||
| @ -65,6 +67,8 @@ public class DataHubUsageEventsProcessorTest { | |||||||
|             dataHubUsageEventTransformer, |             dataHubUsageEventTransformer, | ||||||
|             systemOperationContext.getSearchContext().getIndexConvention(), |             systemOperationContext.getSearchContext().getIndexConvention(), | ||||||
|             systemOperationContext); |             systemOperationContext); | ||||||
|  |     // Set the consumer group ID | ||||||
|  |     setConsumerGroupId(processor, "datahub-usage-event-consumer-job-client"); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
| @ -346,10 +350,7 @@ public class DataHubUsageEventsProcessorTest { | |||||||
|     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); |     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); | ||||||
| 
 | 
 | ||||||
|     // Configure the mock metricUtils to return the registry |     // Configure the mock metricUtils to return the registry | ||||||
|     when(metricUtils.getRegistry()).thenReturn(Optional.of(meterRegistry)); |     when(metricUtils.getRegistry()).thenReturn(meterRegistry); | ||||||
| 
 |  | ||||||
|     // Set the consumer group ID via reflection |  | ||||||
|     setConsumerGroupId(processor, "datahub-usage-event-consumer-job-client"); |  | ||||||
| 
 | 
 | ||||||
|     // Setup test data |     // Setup test data | ||||||
|     String eventJson = "{\"type\":\"PageViewEvent\",\"timestamp\":1234567890}"; |     String eventJson = "{\"type\":\"PageViewEvent\",\"timestamp\":1234567890}"; | ||||||
| @ -397,10 +398,7 @@ public class DataHubUsageEventsProcessorTest { | |||||||
|     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); |     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); | ||||||
| 
 | 
 | ||||||
|     // Configure the mock metricUtils to return the registry |     // Configure the mock metricUtils to return the registry | ||||||
|     when(metricUtils.getRegistry()).thenReturn(Optional.of(meterRegistry)); |     when(metricUtils.getRegistry()).thenReturn(meterRegistry); | ||||||
| 
 |  | ||||||
|     // Set the consumer group ID |  | ||||||
|     setConsumerGroupId(processor, "datahub-usage-event-consumer-job-client"); |  | ||||||
| 
 | 
 | ||||||
|     // Setup test data |     // Setup test data | ||||||
|     String eventJson = "{\"type\":\"SearchEvent\"}"; |     String eventJson = "{\"type\":\"SearchEvent\"}"; | ||||||
| @ -466,10 +464,7 @@ public class DataHubUsageEventsProcessorTest { | |||||||
|     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); |     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); | ||||||
| 
 | 
 | ||||||
|     // Configure the mock metricUtils to return the registry |     // Configure the mock metricUtils to return the registry | ||||||
|     when(metricUtils.getRegistry()).thenReturn(Optional.of(meterRegistry)); |     when(metricUtils.getRegistry()).thenReturn(meterRegistry); | ||||||
| 
 |  | ||||||
|     // Set the consumer group ID |  | ||||||
|     setConsumerGroupId(processor, "datahub-usage-event-consumer-job-client"); |  | ||||||
| 
 | 
 | ||||||
|     // Setup test data |     // Setup test data | ||||||
|     String eventJson = "{\"invalid\":\"event\"}"; |     String eventJson = "{\"invalid\":\"event\"}"; | ||||||
| @ -504,89 +499,13 @@ public class DataHubUsageEventsProcessorTest { | |||||||
|     verify(elasticsearchConnector, never()).feedElasticEvent(any()); |     verify(elasticsearchConnector, never()).feedElasticEvent(any()); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Test |  | ||||||
|   public void testMicrometerMetricsAbsentWhenRegistryNotPresent() { |  | ||||||
|     // Configure the mock metricUtils to return empty Optional (no registry) |  | ||||||
|     when(metricUtils.getRegistry()).thenReturn(Optional.empty()); |  | ||||||
| 
 |  | ||||||
|     // Set the consumer group ID |  | ||||||
|     setConsumerGroupId(processor, "datahub-usage-event-consumer-job-client"); |  | ||||||
| 
 |  | ||||||
|     // Setup test data |  | ||||||
|     String eventJson = "{\"type\":\"ViewEvent\"}"; |  | ||||||
|     String transformedDocument = "{\"view\":\"data\"}"; |  | ||||||
| 
 |  | ||||||
|     when(mockRecord.timestamp()).thenReturn(System.currentTimeMillis() - 1000); |  | ||||||
|     when(mockRecord.value()).thenReturn(eventJson); |  | ||||||
| 
 |  | ||||||
|     DataHubUsageEventTransformer.TransformedDocument transformedDoc = |  | ||||||
|         new DataHubUsageEventTransformer.TransformedDocument(TEST_EVENT_ID, transformedDocument); |  | ||||||
| 
 |  | ||||||
|     when(dataHubUsageEventTransformer.transformDataHubUsageEvent(eventJson)) |  | ||||||
|         .thenReturn(Optional.of(transformedDoc)); |  | ||||||
| 
 |  | ||||||
|     // Execute - should not throw exception |  | ||||||
|     processor.consume(mockRecord); |  | ||||||
| 
 |  | ||||||
|     // Verify the histogram method was still called (for dropwizard metrics) |  | ||||||
|     verify(metricUtils).histogram(eq(DataHubUsageEventsProcessor.class), eq("kafkaLag"), anyLong()); |  | ||||||
| 
 |  | ||||||
|     // Verify processing completed successfully despite no registry |  | ||||||
|     verify(elasticsearchConnector).feedElasticEvent(any()); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Test |  | ||||||
|   public void testMicrometerKafkaQueueTimeWithCustomConsumerGroup() { |  | ||||||
|     // Setup a real MeterRegistry |  | ||||||
|     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); |  | ||||||
| 
 |  | ||||||
|     // Configure the mock metricUtils to return the registry |  | ||||||
|     when(metricUtils.getRegistry()).thenReturn(Optional.of(meterRegistry)); |  | ||||||
| 
 |  | ||||||
|     // Set a custom consumer group ID |  | ||||||
|     String customConsumerGroup = "custom-usage-event-consumer"; |  | ||||||
|     setConsumerGroupId(processor, customConsumerGroup); |  | ||||||
| 
 |  | ||||||
|     // Setup test data |  | ||||||
|     String eventJson = "{\"type\":\"Event\"}"; |  | ||||||
|     String transformedDocument = "{\"data\":\"value\"}"; |  | ||||||
| 
 |  | ||||||
|     when(mockRecord.timestamp()).thenReturn(System.currentTimeMillis() - 1500); |  | ||||||
|     when(mockRecord.topic()).thenReturn("DataHubUsageEvent_v1"); |  | ||||||
|     when(mockRecord.value()).thenReturn(eventJson); |  | ||||||
| 
 |  | ||||||
|     DataHubUsageEventTransformer.TransformedDocument transformedDoc = |  | ||||||
|         new DataHubUsageEventTransformer.TransformedDocument(TEST_EVENT_ID, transformedDocument); |  | ||||||
| 
 |  | ||||||
|     when(dataHubUsageEventTransformer.transformDataHubUsageEvent(eventJson)) |  | ||||||
|         .thenReturn(Optional.of(transformedDoc)); |  | ||||||
| 
 |  | ||||||
|     // Execute |  | ||||||
|     processor.consume(mockRecord); |  | ||||||
| 
 |  | ||||||
|     // Verify timer was recorded with custom consumer group |  | ||||||
|     Timer timer = |  | ||||||
|         meterRegistry.timer( |  | ||||||
|             MetricUtils.KAFKA_MESSAGE_QUEUE_TIME, |  | ||||||
|             "topic", |  | ||||||
|             "DataHubUsageEvent_v1", |  | ||||||
|             "consumer.group", |  | ||||||
|             customConsumerGroup); |  | ||||||
| 
 |  | ||||||
|     assertNotNull(timer); |  | ||||||
|     assertEquals(timer.count(), 1); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Test |   @Test | ||||||
|   public void testMicrometerKafkaQueueTimeAccuracy() { |   public void testMicrometerKafkaQueueTimeAccuracy() { | ||||||
|     // Setup a real MeterRegistry |     // Setup a real MeterRegistry | ||||||
|     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); |     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); | ||||||
| 
 | 
 | ||||||
|     // Configure the mock metricUtils to return the registry |     // Configure the mock metricUtils to return the registry | ||||||
|     when(metricUtils.getRegistry()).thenReturn(Optional.of(meterRegistry)); |     when(metricUtils.getRegistry()).thenReturn(meterRegistry); | ||||||
| 
 |  | ||||||
|     // Set the consumer group ID |  | ||||||
|     setConsumerGroupId(processor, "datahub-usage-event-consumer-job-client"); |  | ||||||
| 
 | 
 | ||||||
|     // Setup test data |     // Setup test data | ||||||
|     String eventJson = "{\"type\":\"Event\"}"; |     String eventJson = "{\"type\":\"Event\"}"; | ||||||
|  | |||||||
| @ -64,7 +64,7 @@ public class MCLKafkaListenerTest { | |||||||
| 
 | 
 | ||||||
|     mockSystemMetadata = spy(SystemMetadataUtils.createDefaultSystemMetadata()); |     mockSystemMetadata = spy(SystemMetadataUtils.createDefaultSystemMetadata()); | ||||||
|     meterRegistry = new SimpleMeterRegistry(); |     meterRegistry = new SimpleMeterRegistry(); | ||||||
|     when(metricUtils.getRegistry()).thenReturn(Optional.of(meterRegistry)); |     when(metricUtils.getRegistry()).thenReturn(meterRegistry); | ||||||
| 
 | 
 | ||||||
|     systemOperationContext = |     systemOperationContext = | ||||||
|         TestOperationContexts.Builder.builder() |         TestOperationContexts.Builder.builder() | ||||||
|  | |||||||
| @ -93,17 +93,13 @@ public class MetadataChangeProposalsProcessor { | |||||||
|                 // TODO: include priority level when available |                 // TODO: include priority level when available | ||||||
|                 metricUtils |                 metricUtils | ||||||
|                     .getRegistry() |                     .getRegistry() | ||||||
|                     .ifPresent( |                     .timer( | ||||||
|                         meterRegistry -> { |                         MetricUtils.KAFKA_MESSAGE_QUEUE_TIME, | ||||||
|                           meterRegistry |                         "topic", | ||||||
|                               .timer( |                         consumerRecord.topic(), | ||||||
|                                   MetricUtils.KAFKA_MESSAGE_QUEUE_TIME, |                         "consumer.group", | ||||||
|                                   "topic", |                         mceConsumerGroupId) | ||||||
|                                   consumerRecord.topic(), |                     .record(Duration.ofMillis(queueTimeMs)); | ||||||
|                                   "consumer.group", |  | ||||||
|                                   mceConsumerGroupId) |  | ||||||
|                               .record(Duration.ofMillis(queueTimeMs)); |  | ||||||
|                         }); |  | ||||||
|               }); |               }); | ||||||
|       final GenericRecord record = consumerRecord.value(); |       final GenericRecord record = consumerRecord.value(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -95,17 +95,13 @@ public class BatchMetadataChangeProposalsProcessor { | |||||||
|                 // TODO: include priority level when available |                 // TODO: include priority level when available | ||||||
|                 metricUtils |                 metricUtils | ||||||
|                     .getRegistry() |                     .getRegistry() | ||||||
|                     .ifPresent( |                     .timer( | ||||||
|                         meterRegistry -> { |                         MetricUtils.KAFKA_MESSAGE_QUEUE_TIME, | ||||||
|                           meterRegistry |                         "topic", | ||||||
|                               .timer( |                         consumerRecord.topic(), | ||||||
|                                   MetricUtils.KAFKA_MESSAGE_QUEUE_TIME, |                         "consumer.group", | ||||||
|                                   "topic", |                         mceConsumerGroupId) | ||||||
|                                   consumerRecord.topic(), |                     .record(Duration.ofMillis(queueTimeMs)); | ||||||
|                                   "consumer.group", |  | ||||||
|                                   mceConsumerGroupId) |  | ||||||
|                               .record(Duration.ofMillis(queueTimeMs)); |  | ||||||
|                         }); |  | ||||||
|               }); |               }); | ||||||
|       final GenericRecord record = consumerRecord.value(); |       final GenericRecord record = consumerRecord.value(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,7 +1,6 @@ | |||||||
| package com.linkedin.metadata.kafka; | package com.linkedin.metadata.kafka; | ||||||
| 
 | 
 | ||||||
| import static org.mockito.ArgumentMatchers.any; | import static org.mockito.ArgumentMatchers.any; | ||||||
| import static org.mockito.ArgumentMatchers.anyLong; |  | ||||||
| import static org.mockito.ArgumentMatchers.eq; | import static org.mockito.ArgumentMatchers.eq; | ||||||
| import static org.mockito.Mockito.mock; | import static org.mockito.Mockito.mock; | ||||||
| import static org.mockito.Mockito.mockStatic; | import static org.mockito.Mockito.mockStatic; | ||||||
| @ -41,6 +40,7 @@ import com.linkedin.mxe.Topics; | |||||||
| import io.datahubproject.metadata.context.OperationContext; | import io.datahubproject.metadata.context.OperationContext; | ||||||
| import io.datahubproject.metadata.context.SystemTelemetryContext; | import io.datahubproject.metadata.context.SystemTelemetryContext; | ||||||
| import io.datahubproject.test.metadata.context.TestOperationContexts; | import io.datahubproject.test.metadata.context.TestOperationContexts; | ||||||
|  | import io.micrometer.core.instrument.MeterRegistry; | ||||||
| import io.micrometer.core.instrument.Timer; | import io.micrometer.core.instrument.Timer; | ||||||
| import io.micrometer.core.instrument.simple.SimpleMeterRegistry; | import io.micrometer.core.instrument.simple.SimpleMeterRegistry; | ||||||
| import io.opentelemetry.api.trace.Span; | import io.opentelemetry.api.trace.Span; | ||||||
| @ -48,7 +48,6 @@ import io.opentelemetry.api.trace.StatusCode; | |||||||
| import io.opentelemetry.api.trace.Tracer; | import io.opentelemetry.api.trace.Tracer; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Optional; |  | ||||||
| import java.util.concurrent.TimeUnit; | import java.util.concurrent.TimeUnit; | ||||||
| import org.apache.avro.generic.GenericRecord; | import org.apache.avro.generic.GenericRecord; | ||||||
| import org.apache.kafka.clients.consumer.ConsumerRecord; | import org.apache.kafka.clients.consumer.ConsumerRecord; | ||||||
| @ -100,18 +99,18 @@ public class MetadataChangeProposalsProcessorTest { | |||||||
| 
 | 
 | ||||||
|   @Mock private Span mockSpan; |   @Mock private Span mockSpan; | ||||||
| 
 | 
 | ||||||
|   @Mock private MetricUtils metricUtils; |   private MetricUtils metricUtils; | ||||||
| 
 | 
 | ||||||
|   private AutoCloseable mocks; |   private AutoCloseable mocks; | ||||||
| 
 | 
 | ||||||
|   private MockedStatic<Span> spanMock; |   private MockedStatic<Span> spanMock; | ||||||
|   private MockedStatic<MetricUtils> metricUtilsMock; |  | ||||||
|   private MockedStatic<EventUtils> eventUtilsMock; |   private MockedStatic<EventUtils> eventUtilsMock; | ||||||
| 
 | 
 | ||||||
|   @BeforeMethod |   @BeforeMethod | ||||||
|   public void setup() { |   public void setup() { | ||||||
|     mocks = MockitoAnnotations.openMocks(this); |     mocks = MockitoAnnotations.openMocks(this); | ||||||
| 
 | 
 | ||||||
|  |     metricUtils = MetricUtils.builder().registry(new SimpleMeterRegistry()).build(); | ||||||
|     opContext = |     opContext = | ||||||
|         opContext.toBuilder() |         opContext.toBuilder() | ||||||
|             .systemTelemetryContext( |             .systemTelemetryContext( | ||||||
| @ -160,11 +159,6 @@ public class MetadataChangeProposalsProcessorTest { | |||||||
|     spanMock = mockStatic(Span.class); |     spanMock = mockStatic(Span.class); | ||||||
|     spanMock.when(Span::current).thenReturn(mockSpan); |     spanMock.when(Span::current).thenReturn(mockSpan); | ||||||
| 
 | 
 | ||||||
|     metricUtilsMock = mockStatic(MetricUtils.class); |  | ||||||
|     metricUtilsMock |  | ||||||
|         .when(() -> MetricUtils.name(eq(MetadataChangeProposalsProcessor.class), any())) |  | ||||||
|         .thenReturn("metricName"); |  | ||||||
| 
 |  | ||||||
|     eventUtilsMock = mockStatic(EventUtils.class); |     eventUtilsMock = mockStatic(EventUtils.class); | ||||||
| 
 | 
 | ||||||
|     // Setup consumer record mock |     // Setup consumer record mock | ||||||
| @ -185,11 +179,6 @@ public class MetadataChangeProposalsProcessorTest { | |||||||
|       spanMock = null; // Set to null after closing |       spanMock = null; // Set to null after closing | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (metricUtilsMock != null) { |  | ||||||
|       metricUtilsMock.close(); |  | ||||||
|       metricUtilsMock = null; // Set to null after closing |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (eventUtilsMock != null) { |     if (eventUtilsMock != null) { | ||||||
|       eventUtilsMock.close(); |       eventUtilsMock.close(); | ||||||
|       eventUtilsMock = null; // Set to null after closing |       eventUtilsMock = null; // Set to null after closing | ||||||
| @ -344,11 +333,7 @@ public class MetadataChangeProposalsProcessorTest { | |||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
|   public void testMicrometerKafkaQueueTimeMetric() throws Exception { |   public void testMicrometerKafkaQueueTimeMetric() throws Exception { | ||||||
|     // Setup a real MeterRegistry |     MeterRegistry meterRegistry = metricUtils.getRegistry(); | ||||||
|     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); |  | ||||||
| 
 |  | ||||||
|     // Configure the mock metricUtils to return the registry |  | ||||||
|     when(metricUtils.getRegistry()).thenReturn(Optional.of(meterRegistry)); |  | ||||||
| 
 | 
 | ||||||
|     // Set timestamp to simulate queue time |     // Set timestamp to simulate queue time | ||||||
|     long messageTimestamp = System.currentTimeMillis() - 3000; // 3 seconds ago |     long messageTimestamp = System.currentTimeMillis() - 3000; // 3 seconds ago | ||||||
| @ -376,21 +361,13 @@ public class MetadataChangeProposalsProcessorTest { | |||||||
|     assertTrue(timer.totalTime(TimeUnit.MILLISECONDS) >= 2500); // At least 2.5 seconds |     assertTrue(timer.totalTime(TimeUnit.MILLISECONDS) >= 2500); // At least 2.5 seconds | ||||||
|     assertTrue(timer.totalTime(TimeUnit.MILLISECONDS) <= 3500); // At most 3.5 seconds |     assertTrue(timer.totalTime(TimeUnit.MILLISECONDS) <= 3500); // At most 3.5 seconds | ||||||
| 
 | 
 | ||||||
|     // Verify the histogram method was called |  | ||||||
|     verify(metricUtils) |  | ||||||
|         .histogram(eq(MetadataChangeProposalsProcessor.class), eq("kafkaLag"), anyLong()); |  | ||||||
| 
 |  | ||||||
|     // Verify successful processing |     // Verify successful processing | ||||||
|     verify(mockEntityService).ingestProposal(eq(opContext), any(), eq(false)); |     verify(mockEntityService).ingestProposal(eq(opContext), any(), eq(false)); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
|   public void testMicrometerKafkaQueueTimeWithDifferentTopics() throws Exception { |   public void testMicrometerKafkaQueueTimeWithDifferentTopics() throws Exception { | ||||||
|     // Setup a real MeterRegistry |     MeterRegistry meterRegistry = metricUtils.getRegistry(); | ||||||
|     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); |  | ||||||
| 
 |  | ||||||
|     // Configure the mock metricUtils to return the registry |  | ||||||
|     when(metricUtils.getRegistry()).thenReturn(Optional.of(meterRegistry)); |  | ||||||
| 
 | 
 | ||||||
|     // Create MCP |     // Create MCP | ||||||
|     MetadataChangeProposal mcp = createSimpleMCP(); |     MetadataChangeProposal mcp = createSimpleMCP(); | ||||||
| @ -448,11 +425,7 @@ public class MetadataChangeProposalsProcessorTest { | |||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
|   public void testMicrometerMetricsWithProcessingFailure() throws Exception { |   public void testMicrometerMetricsWithProcessingFailure() throws Exception { | ||||||
|     // Setup a real MeterRegistry |     MeterRegistry meterRegistry = metricUtils.getRegistry(); | ||||||
|     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); |  | ||||||
| 
 |  | ||||||
|     // Configure the mock metricUtils to return the registry |  | ||||||
|     when(metricUtils.getRegistry()).thenReturn(Optional.of(meterRegistry)); |  | ||||||
| 
 | 
 | ||||||
|     // Create MCP that will fail |     // Create MCP that will fail | ||||||
|     MetadataChangeProposal mcp = new MetadataChangeProposal(); |     MetadataChangeProposal mcp = new MetadataChangeProposal(); | ||||||
| @ -492,9 +465,6 @@ public class MetadataChangeProposalsProcessorTest { | |||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
|   public void testMicrometerMetricsAbsentWhenRegistryNotPresent() throws Exception { |   public void testMicrometerMetricsAbsentWhenRegistryNotPresent() throws Exception { | ||||||
|     // Configure the mock metricUtils to return empty Optional (no registry) |  | ||||||
|     when(metricUtils.getRegistry()).thenReturn(Optional.empty()); |  | ||||||
| 
 |  | ||||||
|     // Create MCP |     // Create MCP | ||||||
|     MetadataChangeProposal mcp = createSimpleMCP(); |     MetadataChangeProposal mcp = createSimpleMCP(); | ||||||
|     eventUtilsMock.when(() -> EventUtils.avroToPegasusMCP(mockRecord)).thenReturn(mcp); |     eventUtilsMock.when(() -> EventUtils.avroToPegasusMCP(mockRecord)).thenReturn(mcp); | ||||||
| @ -504,21 +474,13 @@ public class MetadataChangeProposalsProcessorTest { | |||||||
|     // Execute - should not throw exception |     // Execute - should not throw exception | ||||||
|     processor.consume(mockConsumerRecord); |     processor.consume(mockConsumerRecord); | ||||||
| 
 | 
 | ||||||
|     // Verify the histogram method was still called (for dropwizard metrics) |  | ||||||
|     verify(metricUtils) |  | ||||||
|         .histogram(eq(MetadataChangeProposalsProcessor.class), eq("kafkaLag"), anyLong()); |  | ||||||
| 
 |  | ||||||
|     // Verify processing completed successfully despite no registry |     // Verify processing completed successfully despite no registry | ||||||
|     verify(mockEntityService).ingestProposal(eq(opContext), any(), eq(false)); |     verify(mockEntityService).ingestProposal(eq(opContext), any(), eq(false)); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
|   public void testMicrometerKafkaQueueTimeAccuracy() throws Exception { |   public void testMicrometerKafkaQueueTimeAccuracy() throws Exception { | ||||||
|     // Setup a real MeterRegistry |     MeterRegistry meterRegistry = metricUtils.getRegistry(); | ||||||
|     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); |  | ||||||
| 
 |  | ||||||
|     // Configure the mock metricUtils to return the registry |  | ||||||
|     when(metricUtils.getRegistry()).thenReturn(Optional.of(meterRegistry)); |  | ||||||
| 
 | 
 | ||||||
|     // Create MCP |     // Create MCP | ||||||
|     MetadataChangeProposal mcp = createSimpleMCP(); |     MetadataChangeProposal mcp = createSimpleMCP(); | ||||||
| @ -562,10 +524,6 @@ public class MetadataChangeProposalsProcessorTest { | |||||||
|     // Verify max recorded time |     // Verify max recorded time | ||||||
|     assertTrue(timer.max(TimeUnit.MILLISECONDS) >= 4500); |     assertTrue(timer.max(TimeUnit.MILLISECONDS) >= 4500); | ||||||
|     assertTrue(timer.max(TimeUnit.MILLISECONDS) <= 5500); |     assertTrue(timer.max(TimeUnit.MILLISECONDS) <= 5500); | ||||||
| 
 |  | ||||||
|     // Verify histogram was called for each record |  | ||||||
|     verify(metricUtils, times(queueTimes.length)) |  | ||||||
|         .histogram(eq(MetadataChangeProposalsProcessor.class), eq("kafkaLag"), anyLong()); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
| @ -598,10 +556,6 @@ public class MetadataChangeProposalsProcessorTest { | |||||||
| 
 | 
 | ||||||
|     // Verify processing completed successfully |     // Verify processing completed successfully | ||||||
|     verify(mockEntityService).ingestProposal(eq(opContextNoMetrics), any(), eq(false)); |     verify(mockEntityService).ingestProposal(eq(opContextNoMetrics), any(), eq(false)); | ||||||
| 
 |  | ||||||
|     // Verify metricUtils methods were never called since it's not present in context |  | ||||||
|     verify(metricUtils, never()).histogram(any(), any(), anyLong()); |  | ||||||
|     verify(metricUtils, never()).getRegistry(); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Helper method |   // Helper method | ||||||
|  | |||||||
| @ -557,6 +557,7 @@ public class BatchMetadataChangeProposalsProcessorTest { | |||||||
|   public void testConsumeWithTelemetryMetrics() throws Exception { |   public void testConsumeWithTelemetryMetrics() throws Exception { | ||||||
|     // Mock the metric utils |     // Mock the metric utils | ||||||
|     MetricUtils mockMetricUtils = mock(MetricUtils.class); |     MetricUtils mockMetricUtils = mock(MetricUtils.class); | ||||||
|  |     when(mockMetricUtils.getRegistry()).thenReturn(new SimpleMeterRegistry()); | ||||||
| 
 | 
 | ||||||
|     // Create a mock operation context |     // Create a mock operation context | ||||||
|     OperationContext opContextWithMetrics = spy(opContext); |     OperationContext opContextWithMetrics = spy(opContext); | ||||||
| @ -856,12 +857,12 @@ public class BatchMetadataChangeProposalsProcessorTest { | |||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
|   public void testMicrometerMetricsAbsentWhenRegistryNotPresent() throws Exception { |   public void testMicrometerMetricsAbsentWhenRegistryNotPresent() throws Exception { | ||||||
|     // Create MetricUtils without a registry |     // With the new non-null contract, we can't create MetricUtils with null registry | ||||||
|     MetricUtils metricUtilsNoRegistry = MetricUtils.builder().registry(null).build(); |     // Instead, test the case where MetricUtils is absent from OperationContext | ||||||
| 
 | 
 | ||||||
|     // Create operation context with metric utils that has no registry |     // Create operation context without metric utils | ||||||
|     OperationContext opContextNoRegistry = mock(OperationContext.class); |     OperationContext opContextNoRegistry = mock(OperationContext.class); | ||||||
|     when(opContextNoRegistry.getMetricUtils()).thenReturn(Optional.of(metricUtilsNoRegistry)); |     when(opContextNoRegistry.getMetricUtils()).thenReturn(Optional.empty()); | ||||||
| 
 | 
 | ||||||
|     // Mock withQueueSpan |     // Mock withQueueSpan | ||||||
|     doAnswer( |     doAnswer( | ||||||
|  | |||||||
| @ -82,17 +82,13 @@ public class PlatformEventProcessor { | |||||||
|                     // TODO: include priority level when available |                     // TODO: include priority level when available | ||||||
|                     metricUtils |                     metricUtils | ||||||
|                         .getRegistry() |                         .getRegistry() | ||||||
|                         .ifPresent( |                         .timer( | ||||||
|                             meterRegistry -> { |                             MetricUtils.KAFKA_MESSAGE_QUEUE_TIME, | ||||||
|                               meterRegistry |                             "topic", | ||||||
|                                   .timer( |                             consumerRecord.topic(), | ||||||
|                                       MetricUtils.KAFKA_MESSAGE_QUEUE_TIME, |                             "consumer.group", | ||||||
|                                       "topic", |                             datahubPlatformEventConsumerGroupId) | ||||||
|                                       consumerRecord.topic(), |                         .record(Duration.ofMillis(queueTimeMs)); | ||||||
|                                       "consumer.group", |  | ||||||
|                                       datahubPlatformEventConsumerGroupId) |  | ||||||
|                                   .record(Duration.ofMillis(queueTimeMs)); |  | ||||||
|                             }); |  | ||||||
|                   }); |                   }); | ||||||
|           final GenericRecord record = consumerRecord.value(); |           final GenericRecord record = consumerRecord.value(); | ||||||
|           log.info( |           log.info( | ||||||
|  | |||||||
| @ -62,6 +62,7 @@ public class PlatformEventProcessorTest { | |||||||
| 
 | 
 | ||||||
|     // Create mock MetricUtils |     // Create mock MetricUtils | ||||||
|     mockMetricUtils = mock(MetricUtils.class); |     mockMetricUtils = mock(MetricUtils.class); | ||||||
|  |     when(mockMetricUtils.getRegistry()).thenReturn(new SimpleMeterRegistry()); | ||||||
|     when(mockOperationContext.getMetricUtils()).thenReturn(Optional.of(mockMetricUtils)); |     when(mockOperationContext.getMetricUtils()).thenReturn(Optional.of(mockMetricUtils)); | ||||||
| 
 | 
 | ||||||
|     // Create mock hooks |     // Create mock hooks | ||||||
| @ -133,6 +134,8 @@ public class PlatformEventProcessorTest { | |||||||
|     // Setup |     // Setup | ||||||
|     List<PlatformEventHook> hooks = Arrays.asList(mockHook1, mockHook2); |     List<PlatformEventHook> hooks = Arrays.asList(mockHook1, mockHook2); | ||||||
|     processor = new PlatformEventProcessor(mockOperationContext, hooks); |     processor = new PlatformEventProcessor(mockOperationContext, hooks); | ||||||
|  |     // Set the consumer group ID | ||||||
|  |     setConsumerGroupId(processor, "generic-platform-event-job-client"); | ||||||
| 
 | 
 | ||||||
|     try (MockedStatic<EventUtils> mockedEventUtils = Mockito.mockStatic(EventUtils.class)) { |     try (MockedStatic<EventUtils> mockedEventUtils = Mockito.mockStatic(EventUtils.class)) { | ||||||
|       mockedEventUtils |       mockedEventUtils | ||||||
| @ -161,6 +164,8 @@ public class PlatformEventProcessorTest { | |||||||
|     // Setup |     // Setup | ||||||
|     List<PlatformEventHook> hooks = Arrays.asList(mockHook1); |     List<PlatformEventHook> hooks = Arrays.asList(mockHook1); | ||||||
|     processor = new PlatformEventProcessor(mockOperationContext, hooks); |     processor = new PlatformEventProcessor(mockOperationContext, hooks); | ||||||
|  |     // Set the consumer group ID | ||||||
|  |     setConsumerGroupId(processor, "generic-platform-event-job-client"); | ||||||
| 
 | 
 | ||||||
|     try (MockedStatic<EventUtils> mockedEventUtils = Mockito.mockStatic(EventUtils.class)) { |     try (MockedStatic<EventUtils> mockedEventUtils = Mockito.mockStatic(EventUtils.class)) { | ||||||
|       mockedEventUtils |       mockedEventUtils | ||||||
| @ -189,6 +194,8 @@ public class PlatformEventProcessorTest { | |||||||
|     // Setup |     // Setup | ||||||
|     List<PlatformEventHook> hooks = Arrays.asList(mockHook1, mockHook2); |     List<PlatformEventHook> hooks = Arrays.asList(mockHook1, mockHook2); | ||||||
|     processor = new PlatformEventProcessor(mockOperationContext, hooks); |     processor = new PlatformEventProcessor(mockOperationContext, hooks); | ||||||
|  |     // Set the consumer group ID | ||||||
|  |     setConsumerGroupId(processor, "generic-platform-event-job-client"); | ||||||
| 
 | 
 | ||||||
|     // Make first hook throw exception |     // Make first hook throw exception | ||||||
|     doThrow(new RuntimeException("Hook 1 failed")) |     doThrow(new RuntimeException("Hook 1 failed")) | ||||||
| @ -224,6 +231,8 @@ public class PlatformEventProcessorTest { | |||||||
|     // Setup |     // Setup | ||||||
|     List<PlatformEventHook> hooks = Arrays.asList(mockHook1, mockHook2); |     List<PlatformEventHook> hooks = Arrays.asList(mockHook1, mockHook2); | ||||||
|     processor = new PlatformEventProcessor(mockOperationContext, hooks); |     processor = new PlatformEventProcessor(mockOperationContext, hooks); | ||||||
|  |     // Set the consumer group ID | ||||||
|  |     setConsumerGroupId(processor, "generic-platform-event-job-client"); | ||||||
| 
 | 
 | ||||||
|     // Make both hooks throw exceptions |     // Make both hooks throw exceptions | ||||||
|     doThrow(new RuntimeException("Hook 1 failed")) |     doThrow(new RuntimeException("Hook 1 failed")) | ||||||
| @ -283,6 +292,8 @@ public class PlatformEventProcessorTest { | |||||||
|     // Setup |     // Setup | ||||||
|     List<PlatformEventHook> hooks = Arrays.asList(mockHook1); |     List<PlatformEventHook> hooks = Arrays.asList(mockHook1); | ||||||
|     processor = new PlatformEventProcessor(mockOperationContext, hooks); |     processor = new PlatformEventProcessor(mockOperationContext, hooks); | ||||||
|  |     // Set the consumer group ID | ||||||
|  |     setConsumerGroupId(processor, "generic-platform-event-job-client"); | ||||||
| 
 | 
 | ||||||
|     // Set up specific consumer record values |     // Set up specific consumer record values | ||||||
|     String expectedKey = "test-key-123"; |     String expectedKey = "test-key-123"; | ||||||
| @ -321,7 +332,8 @@ public class PlatformEventProcessorTest { | |||||||
|       // Verify that the consumer record methods were called |       // Verify that the consumer record methods were called | ||||||
|       // Note: some methods may be called multiple times (e.g., for logging and metrics) |       // Note: some methods may be called multiple times (e.g., for logging and metrics) | ||||||
|       verify(specificMockRecord, times(1)).key(); |       verify(specificMockRecord, times(1)).key(); | ||||||
|       verify(specificMockRecord, times(1)).topic(); |       verify(specificMockRecord, times(2)) | ||||||
|  |           .topic(); // Called twice: once for metrics, once for logging | ||||||
|       verify(specificMockRecord, times(1)).partition(); |       verify(specificMockRecord, times(1)).partition(); | ||||||
|       verify(specificMockRecord, times(1)).offset(); |       verify(specificMockRecord, times(1)).offset(); | ||||||
|       verify(specificMockRecord, times(2)) |       verify(specificMockRecord, times(2)) | ||||||
| @ -336,6 +348,8 @@ public class PlatformEventProcessorTest { | |||||||
|     // Setup |     // Setup | ||||||
|     List<PlatformEventHook> hooks = Arrays.asList(mockHook1); |     List<PlatformEventHook> hooks = Arrays.asList(mockHook1); | ||||||
|     processor = new PlatformEventProcessor(mockOperationContext, hooks); |     processor = new PlatformEventProcessor(mockOperationContext, hooks); | ||||||
|  |     // Set the consumer group ID | ||||||
|  |     setConsumerGroupId(processor, "generic-platform-event-job-client"); | ||||||
| 
 | 
 | ||||||
|     PlatformEvent event1 = mock(PlatformEvent.class); |     PlatformEvent event1 = mock(PlatformEvent.class); | ||||||
|     when(event1.getName()).thenReturn("Event1"); |     when(event1.getName()).thenReturn("Event1"); | ||||||
| @ -389,6 +403,8 @@ public class PlatformEventProcessorTest { | |||||||
|     // Setup |     // Setup | ||||||
|     List<PlatformEventHook> hooks = Arrays.asList(mockHook1); |     List<PlatformEventHook> hooks = Arrays.asList(mockHook1); | ||||||
|     processor = new PlatformEventProcessor(mockOperationContext, hooks); |     processor = new PlatformEventProcessor(mockOperationContext, hooks); | ||||||
|  |     // Set the consumer group ID | ||||||
|  |     setConsumerGroupId(processor, "generic-platform-event-job-client"); | ||||||
| 
 | 
 | ||||||
|     ConsumerRecord<String, GenericRecord> nullValueRecord = mock(ConsumerRecord.class); |     ConsumerRecord<String, GenericRecord> nullValueRecord = mock(ConsumerRecord.class); | ||||||
|     when(nullValueRecord.value()).thenReturn(null); |     when(nullValueRecord.value()).thenReturn(null); | ||||||
| @ -422,7 +438,7 @@ public class PlatformEventProcessorTest { | |||||||
|     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); |     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); | ||||||
| 
 | 
 | ||||||
|     // Configure the mock metricUtils to return the registry |     // Configure the mock metricUtils to return the registry | ||||||
|     when(mockMetricUtils.getRegistry()).thenReturn(Optional.of(meterRegistry)); |     when(mockMetricUtils.getRegistry()).thenReturn(meterRegistry); | ||||||
| 
 | 
 | ||||||
|     // Set the consumer group ID via reflection |     // Set the consumer group ID via reflection | ||||||
|     setConsumerGroupId(processor, "generic-platform-event-job-client"); |     setConsumerGroupId(processor, "generic-platform-event-job-client"); | ||||||
| @ -469,7 +485,7 @@ public class PlatformEventProcessorTest { | |||||||
|     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); |     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); | ||||||
| 
 | 
 | ||||||
|     // Configure the mock metricUtils to return the registry |     // Configure the mock metricUtils to return the registry | ||||||
|     when(mockMetricUtils.getRegistry()).thenReturn(Optional.of(meterRegistry)); |     when(mockMetricUtils.getRegistry()).thenReturn(meterRegistry); | ||||||
| 
 | 
 | ||||||
|     // Set the consumer group ID |     // Set the consumer group ID | ||||||
|     setConsumerGroupId(processor, "generic-platform-event-job-client"); |     setConsumerGroupId(processor, "generic-platform-event-job-client"); | ||||||
| @ -534,7 +550,7 @@ public class PlatformEventProcessorTest { | |||||||
|     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); |     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); | ||||||
| 
 | 
 | ||||||
|     // Configure the mock metricUtils to return the registry |     // Configure the mock metricUtils to return the registry | ||||||
|     when(mockMetricUtils.getRegistry()).thenReturn(Optional.of(meterRegistry)); |     when(mockMetricUtils.getRegistry()).thenReturn(meterRegistry); | ||||||
| 
 | 
 | ||||||
|     // Set the consumer group ID |     // Set the consumer group ID | ||||||
|     setConsumerGroupId(processor, "generic-platform-event-job-client"); |     setConsumerGroupId(processor, "generic-platform-event-job-client"); | ||||||
| @ -578,7 +594,7 @@ public class PlatformEventProcessorTest { | |||||||
|   @Test |   @Test | ||||||
|   public void testMicrometerMetricsAbsentWhenRegistryNotPresent() throws Exception { |   public void testMicrometerMetricsAbsentWhenRegistryNotPresent() throws Exception { | ||||||
|     // Configure the mock metricUtils to return empty Optional (no registry) |     // Configure the mock metricUtils to return empty Optional (no registry) | ||||||
|     when(mockMetricUtils.getRegistry()).thenReturn(Optional.empty()); |     when(mockMetricUtils.getRegistry()).thenReturn(new SimpleMeterRegistry()); | ||||||
| 
 | 
 | ||||||
|     // Set the consumer group ID |     // Set the consumer group ID | ||||||
|     setConsumerGroupId(processor, "generic-platform-event-job-client"); |     setConsumerGroupId(processor, "generic-platform-event-job-client"); | ||||||
| @ -608,7 +624,7 @@ public class PlatformEventProcessorTest { | |||||||
|     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); |     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); | ||||||
| 
 | 
 | ||||||
|     // Configure the mock metricUtils to return the registry |     // Configure the mock metricUtils to return the registry | ||||||
|     when(mockMetricUtils.getRegistry()).thenReturn(Optional.of(meterRegistry)); |     when(mockMetricUtils.getRegistry()).thenReturn(meterRegistry); | ||||||
| 
 | 
 | ||||||
|     // Set a custom consumer group ID |     // Set a custom consumer group ID | ||||||
|     String customConsumerGroup = "custom-platform-event-consumer"; |     String customConsumerGroup = "custom-platform-event-consumer"; | ||||||
| @ -645,7 +661,7 @@ public class PlatformEventProcessorTest { | |||||||
|     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); |     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); | ||||||
| 
 | 
 | ||||||
|     // Configure the mock metricUtils to return the registry |     // Configure the mock metricUtils to return the registry | ||||||
|     when(mockMetricUtils.getRegistry()).thenReturn(Optional.of(meterRegistry)); |     when(mockMetricUtils.getRegistry()).thenReturn(meterRegistry); | ||||||
| 
 | 
 | ||||||
|     // Set the consumer group ID |     // Set the consumer group ID | ||||||
|     setConsumerGroupId(processor, "generic-platform-event-job-client"); |     setConsumerGroupId(processor, "generic-platform-event-job-client"); | ||||||
| @ -705,7 +721,7 @@ public class PlatformEventProcessorTest { | |||||||
|     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); |     SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); | ||||||
| 
 | 
 | ||||||
|     // Configure the mock metricUtils to return the registry |     // Configure the mock metricUtils to return the registry | ||||||
|     when(mockMetricUtils.getRegistry()).thenReturn(Optional.of(meterRegistry)); |     when(mockMetricUtils.getRegistry()).thenReturn(meterRegistry); | ||||||
| 
 | 
 | ||||||
|     // Set the consumer group ID |     // Set the consumer group ID | ||||||
|     setConsumerGroupId(processor, "generic-platform-event-job-client"); |     setConsumerGroupId(processor, "generic-platform-event-job-client"); | ||||||
|  | |||||||
| @ -275,11 +275,11 @@ public class RequestContext implements ContextInterface { | |||||||
|       metricUtils.incrementMicrometer( |       metricUtils.incrementMicrometer( | ||||||
|           MetricUtils.DATAHUB_REQUEST_COUNT, |           MetricUtils.DATAHUB_REQUEST_COUNT, | ||||||
|           1, |           1, | ||||||
|           "user.category", |           "user_category", | ||||||
|           userCategory, |           userCategory, | ||||||
|           "agent.class", |           "agent_class", | ||||||
|           agentClass, |           agentClass, | ||||||
|           "request.api", |           "request_api", | ||||||
|           requestAPI); |           requestAPI); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -278,13 +278,13 @@ public class RequestContextTest { | |||||||
| 
 | 
 | ||||||
|     verify(mockMetricUtils, atLeastOnce()) |     verify(mockMetricUtils, atLeastOnce()) | ||||||
|         .incrementMicrometer( |         .incrementMicrometer( | ||||||
|             eq("datahub.request.count"), |             eq(MetricUtils.DATAHUB_REQUEST_COUNT), | ||||||
|             eq(1.0d), |             eq(1.0d), | ||||||
|             eq("user.category"), |             eq("user_category"), | ||||||
|             eq("system"), |             eq("system"), | ||||||
|             eq("agent.class"), |             eq("agent_class"), | ||||||
|             eq("unknown"), |             eq("unknown"), | ||||||
|             eq("request.api"), |             eq("request_api"), | ||||||
|             eq("restli")); |             eq("restli")); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -303,13 +303,13 @@ public class RequestContextTest { | |||||||
| 
 | 
 | ||||||
|     verify(mockMetricUtils, atLeastOnce()) |     verify(mockMetricUtils, atLeastOnce()) | ||||||
|         .incrementMicrometer( |         .incrementMicrometer( | ||||||
|             eq("datahub.request.count"), |             eq(MetricUtils.DATAHUB_REQUEST_COUNT), | ||||||
|             eq(1.0d), |             eq(1.0d), | ||||||
|             eq("user.category"), |             eq("user_category"), | ||||||
|             eq("admin"), |             eq("admin"), | ||||||
|             eq("agent.class"), |             eq("agent_class"), | ||||||
|             eq("unknown"), |             eq("unknown"), | ||||||
|             eq("request.api"), |             eq("request_api"), | ||||||
|             eq("restli")); |             eq("restli")); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -328,13 +328,13 @@ public class RequestContextTest { | |||||||
| 
 | 
 | ||||||
|     verify(mockMetricUtils, atLeastOnce()) |     verify(mockMetricUtils, atLeastOnce()) | ||||||
|         .incrementMicrometer( |         .incrementMicrometer( | ||||||
|             eq("datahub.request.count"), |             eq(MetricUtils.DATAHUB_REQUEST_COUNT), | ||||||
|             eq(1.0d), |             eq(1.0d), | ||||||
|             eq("user.category"), |             eq("user_category"), | ||||||
|             eq("regular"), |             eq("regular"), | ||||||
|             eq("agent.class"), |             eq("agent_class"), | ||||||
|             eq("unknown"), |             eq("unknown"), | ||||||
|             eq("request.api"), |             eq("request_api"), | ||||||
|             eq("restli")); |             eq("restli")); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -317,7 +317,7 @@ public class GraphQLEngineFactory { | |||||||
|         GraphQLConcurrencyUtils.setExecutorService(graphQLWorkerPool); |         GraphQLConcurrencyUtils.setExecutorService(graphQLWorkerPool); | ||||||
|     if (metricUtils != null) { |     if (metricUtils != null) { | ||||||
|       MicrometerMetricsRegistry.registerExecutorMetrics( |       MicrometerMetricsRegistry.registerExecutorMetrics( | ||||||
|           "graphql", graphqlExecutorService, metricUtils.getRegistry().orElse(null)); |           "graphql", graphqlExecutorService, metricUtils.getRegistry()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return graphQLWorkerPool; |     return graphQLWorkerPool; | ||||||
|  | |||||||
| @ -86,7 +86,7 @@ public class KafkaTraceReaderFactory { | |||||||
|     traceExecutorService = Executors.newFixedThreadPool(threadPoolSize); |     traceExecutorService = Executors.newFixedThreadPool(threadPoolSize); | ||||||
|     if (metricUtils != null) { |     if (metricUtils != null) { | ||||||
|       MicrometerMetricsRegistry.registerExecutorMetrics( |       MicrometerMetricsRegistry.registerExecutorMetrics( | ||||||
|           "api-trace", this.traceExecutorService, metricUtils.getRegistry().orElse(null)); |           "api-trace", this.traceExecutorService, metricUtils.getRegistry()); | ||||||
|     } |     } | ||||||
|     return traceExecutorService; |     return traceExecutorService; | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -41,6 +41,7 @@ import io.datahubproject.metadata.context.SystemTelemetryContext; | |||||||
| import io.datahubproject.metadata.services.RestrictedService; | import io.datahubproject.metadata.services.RestrictedService; | ||||||
| import io.datahubproject.metadata.services.SecretService; | import io.datahubproject.metadata.services.SecretService; | ||||||
| import io.datahubproject.test.metadata.context.TestOperationContexts; | import io.datahubproject.test.metadata.context.TestOperationContexts; | ||||||
|  | import io.micrometer.core.instrument.simple.SimpleMeterRegistry; | ||||||
| import io.opentelemetry.api.trace.Tracer; | import io.opentelemetry.api.trace.Tracer; | ||||||
| import java.util.concurrent.ExecutorService; | import java.util.concurrent.ExecutorService; | ||||||
| import java.util.concurrent.ThreadPoolExecutor; | import java.util.concurrent.ThreadPoolExecutor; | ||||||
| @ -261,7 +262,7 @@ public class GraphQLEngineFactoryTest extends AbstractTestNGSpringContextTests { | |||||||
|   public void setUp() { |   public void setUp() { | ||||||
|     // Set up default mock behaviors |     // Set up default mock behaviors | ||||||
|     when(graphService.supportsMultiHop()).thenReturn(true); |     when(graphService.supportsMultiHop()).thenReturn(true); | ||||||
|     when(metricUtils.getRegistry()).thenReturn(java.util.Optional.empty()); |     when(metricUtils.getRegistry()).thenReturn(new SimpleMeterRegistry()); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
|  | |||||||
| @ -109,7 +109,7 @@ public class ClientCache<K, V, C extends ClientCacheConfig> { | |||||||
| 
 | 
 | ||||||
|       if (config.isStatsEnabled() && metricUtils != null) { |       if (config.isStatsEnabled() && metricUtils != null) { | ||||||
|         MicrometerMetricsRegistry.registerCacheMetrics( |         MicrometerMetricsRegistry.registerCacheMetrics( | ||||||
|             config.getName(), cache, metricUtils.getRegistry().orElse(null)); |             config.getName(), cache, metricUtils.getRegistry()); | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       return new ClientCache<>(config, cache, loadFunction, weigher, ttlSecondsFunction); |       return new ClientCache<>(config, cache, loadFunction, weigher, ttlSecondsFunction); | ||||||
|  | |||||||
| @ -145,7 +145,7 @@ public class RestliEntityClient extends BaseClient implements EntityClient { | |||||||
|             new ThreadPoolExecutor.CallerRunsPolicy()); |             new ThreadPoolExecutor.CallerRunsPolicy()); | ||||||
|     if (metricUtils != null) { |     if (metricUtils != null) { | ||||||
|       MicrometerMetricsRegistry.registerExecutorMetrics( |       MicrometerMetricsRegistry.registerExecutorMetrics( | ||||||
|           "entity-client-get", this.batchGetV2Pool, metricUtils.getRegistry().orElse(null)); |           "entity-client-get", this.batchGetV2Pool, metricUtils.getRegistry()); | ||||||
|     } |     } | ||||||
|     this.batchIngestPool = |     this.batchIngestPool = | ||||||
|         new ThreadPoolExecutor( |         new ThreadPoolExecutor( | ||||||
| @ -158,7 +158,7 @@ public class RestliEntityClient extends BaseClient implements EntityClient { | |||||||
|             new ThreadPoolExecutor.CallerRunsPolicy()); |             new ThreadPoolExecutor.CallerRunsPolicy()); | ||||||
|     if (metricUtils != null) { |     if (metricUtils != null) { | ||||||
|       MicrometerMetricsRegistry.registerExecutorMetrics( |       MicrometerMetricsRegistry.registerExecutorMetrics( | ||||||
|           "entity-client-ingest", this.batchIngestPool, metricUtils.getRegistry().orElse(null)); |           "entity-client-ingest", this.batchIngestPool, metricUtils.getRegistry()); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -63,6 +63,7 @@ import com.linkedin.restli.client.RestLiResponseException; | |||||||
| import com.linkedin.restli.client.response.BatchKVResponse; | import com.linkedin.restli.client.response.BatchKVResponse; | ||||||
| import io.datahubproject.metadata.context.OperationContext; | import io.datahubproject.metadata.context.OperationContext; | ||||||
| import io.datahubproject.test.metadata.context.TestOperationContexts; | import io.datahubproject.test.metadata.context.TestOperationContexts; | ||||||
|  | import io.micrometer.core.instrument.simple.SimpleMeterRegistry; | ||||||
| import java.net.URISyntaxException; | import java.net.URISyntaxException; | ||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
| import java.util.Collections; | import java.util.Collections; | ||||||
| @ -98,7 +99,7 @@ public class BaseClientTest { | |||||||
| 
 | 
 | ||||||
|     // Setup MetricUtils mock |     // Setup MetricUtils mock | ||||||
|     mockMetricUtils = mock(MetricUtils.class); |     mockMetricUtils = mock(MetricUtils.class); | ||||||
|     when(mockMetricUtils.getRegistry()).thenReturn(Optional.empty()); |     when(mockMetricUtils.getRegistry()).thenReturn(new SimpleMeterRegistry()); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
|  | |||||||
| @ -7,11 +7,12 @@ import io.micrometer.core.instrument.DistributionSummary; | |||||||
| import io.micrometer.core.instrument.Gauge; | import io.micrometer.core.instrument.Gauge; | ||||||
| import io.micrometer.core.instrument.MeterRegistry; | import io.micrometer.core.instrument.MeterRegistry; | ||||||
| import io.micrometer.core.instrument.Timer; | import io.micrometer.core.instrument.Timer; | ||||||
|  | import io.micrometer.core.instrument.composite.CompositeMeterRegistry; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.Optional; |  | ||||||
| import java.util.concurrent.ConcurrentHashMap; | import java.util.concurrent.ConcurrentHashMap; | ||||||
| import java.util.concurrent.TimeUnit; | import java.util.concurrent.TimeUnit; | ||||||
| import lombok.Builder; | import lombok.Builder; | ||||||
|  | import lombok.NonNull; | ||||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||||
| 
 | 
 | ||||||
| @Slf4j | @Slf4j | ||||||
| @ -21,10 +22,10 @@ public class MetricUtils { | |||||||
|   public static final String DROPWIZARD_METRIC = "dwizMetric"; |   public static final String DROPWIZARD_METRIC = "dwizMetric"; | ||||||
|   public static final String DROPWIZARD_NAME = "dwizName"; |   public static final String DROPWIZARD_NAME = "dwizName"; | ||||||
| 
 | 
 | ||||||
|   /* Micrometer */ |   /* Micrometer. See https://prometheus.io/docs/practices/naming/ */ | ||||||
|   public static final String KAFKA_MESSAGE_QUEUE_TIME = "kafka.message.queue.time"; |   public static final String KAFKA_MESSAGE_QUEUE_TIME = "kafka.message.queue.time"; | ||||||
|   public static final String DATAHUB_REQUEST_HOOK_QUEUE_TIME = "datahub.request.hook.queue.time"; |   public static final String DATAHUB_REQUEST_HOOK_QUEUE_TIME = "datahub.request.hook.queue.time"; | ||||||
|   public static final String DATAHUB_REQUEST_COUNT = "datahub.request.count"; |   public static final String DATAHUB_REQUEST_COUNT = "datahub_request_count"; | ||||||
| 
 | 
 | ||||||
|   /* OpenTelemetry */ |   /* OpenTelemetry */ | ||||||
|   public static final String CACHE_HIT_ATTR = "cache.hit"; |   public static final String CACHE_HIT_ATTR = "cache.hit"; | ||||||
| @ -42,7 +43,7 @@ public class MetricUtils { | |||||||
| 
 | 
 | ||||||
|   @Deprecated public static final String DELIMITER = "_"; |   @Deprecated public static final String DELIMITER = "_"; | ||||||
| 
 | 
 | ||||||
|   private final MeterRegistry registry; |   @Builder.Default @NonNull private final MeterRegistry registry = new CompositeMeterRegistry(); | ||||||
|   private static final Map<String, Timer> legacyTimeCache = new ConcurrentHashMap<>(); |   private static final Map<String, Timer> legacyTimeCache = new ConcurrentHashMap<>(); | ||||||
|   private static final Map<String, Counter> legacyCounterCache = new ConcurrentHashMap<>(); |   private static final Map<String, Counter> legacyCounterCache = new ConcurrentHashMap<>(); | ||||||
|   private static final Map<String, DistributionSummary> legacyHistogramCache = |   private static final Map<String, DistributionSummary> legacyHistogramCache = | ||||||
| @ -52,24 +53,17 @@ public class MetricUtils { | |||||||
|   // For state-based gauges (like throttled state) |   // For state-based gauges (like throttled state) | ||||||
|   private static final Map<String, AtomicDouble> gaugeStates = new ConcurrentHashMap<>(); |   private static final Map<String, AtomicDouble> gaugeStates = new ConcurrentHashMap<>(); | ||||||
| 
 | 
 | ||||||
|   public Optional<MeterRegistry> getRegistry() { |   public MeterRegistry getRegistry() { | ||||||
|     return Optional.ofNullable(registry); |     return registry; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Deprecated |   @Deprecated | ||||||
|   public void time(String dropWizardMetricName, long durationNanos) { |   public void time(String dropWizardMetricName, long durationNanos) { | ||||||
|     getRegistry() |     Timer timer = | ||||||
|         .ifPresent( |         legacyTimeCache.computeIfAbsent( | ||||||
|             meterRegistry -> { |             dropWizardMetricName, | ||||||
|               Timer timer = |             name -> Timer.builder(name).tags(DROPWIZARD_METRIC, "true").register(registry)); | ||||||
|                   legacyTimeCache.computeIfAbsent( |     timer.record(durationNanos, TimeUnit.NANOSECONDS); | ||||||
|                       dropWizardMetricName, |  | ||||||
|                       name -> |  | ||||||
|                           Timer.builder(name) |  | ||||||
|                               .tags(DROPWIZARD_METRIC, "true") |  | ||||||
|                               .register(meterRegistry)); |  | ||||||
|               timer.record(durationNanos, TimeUnit.NANOSECONDS); |  | ||||||
|             }); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Deprecated |   @Deprecated | ||||||
| @ -90,18 +84,14 @@ public class MetricUtils { | |||||||
| 
 | 
 | ||||||
|   @Deprecated |   @Deprecated | ||||||
|   public void increment(String metricName, double increment) { |   public void increment(String metricName, double increment) { | ||||||
|     getRegistry() |     Counter counter = | ||||||
|         .ifPresent( |         legacyCounterCache.computeIfAbsent( | ||||||
|             meterRegistry -> { |             metricName, | ||||||
|               Counter counter = |             name -> | ||||||
|                   legacyCounterCache.computeIfAbsent( |                 Counter.builder(MetricRegistry.name(name)) | ||||||
|                       metricName, |                     .tag(DROPWIZARD_METRIC, "true") | ||||||
|                       name -> |                     .register(registry)); | ||||||
|                           Counter.builder(MetricRegistry.name(name)) |     counter.increment(increment); | ||||||
|                               .tag(DROPWIZARD_METRIC, "true") |  | ||||||
|                               .register(meterRegistry)); |  | ||||||
|               counter.increment(increment); |  | ||||||
|             }); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
| @ -112,16 +102,11 @@ public class MetricUtils { | |||||||
|    * @param tags The tags to associate with the metric (can be empty) |    * @param tags The tags to associate with the metric (can be empty) | ||||||
|    */ |    */ | ||||||
|   public void incrementMicrometer(String metricName, double increment, String... tags) { |   public void incrementMicrometer(String metricName, double increment, String... tags) { | ||||||
|     getRegistry() |     // Create a cache key that includes both metric name and tags | ||||||
|         .ifPresent( |     String cacheKey = createCacheKey(metricName, tags); | ||||||
|             meterRegistry -> { |     Counter counter = | ||||||
|               // Create a cache key that includes both metric name and tags |         micrometerCounterCache.computeIfAbsent(cacheKey, key -> registry.counter(metricName, tags)); | ||||||
|               String cacheKey = createCacheKey(metricName, tags); |     counter.increment(increment); | ||||||
|               Counter counter = |  | ||||||
|                   micrometerCounterCache.computeIfAbsent( |  | ||||||
|                       cacheKey, key -> meterRegistry.counter(metricName, tags)); |  | ||||||
|               counter.increment(increment); |  | ||||||
|             }); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
| @ -167,40 +152,30 @@ public class MetricUtils { | |||||||
|   public void setGaugeValue(Class<?> clazz, String metricName, double value) { |   public void setGaugeValue(Class<?> clazz, String metricName, double value) { | ||||||
|     String name = MetricRegistry.name(clazz, metricName); |     String name = MetricRegistry.name(clazz, metricName); | ||||||
| 
 | 
 | ||||||
|     getRegistry() |     // Get or create the state holder | ||||||
|         .ifPresent( |     AtomicDouble state = gaugeStates.computeIfAbsent(name, k -> new AtomicDouble(0)); | ||||||
|             meterRegistry -> { |  | ||||||
|               // Get or create the state holder |  | ||||||
|               AtomicDouble state = gaugeStates.computeIfAbsent(name, k -> new AtomicDouble(0)); |  | ||||||
| 
 | 
 | ||||||
|               // Register the gauge if not already registered |     // Register the gauge if not already registered | ||||||
|               legacyGaugeCache.computeIfAbsent( |     legacyGaugeCache.computeIfAbsent( | ||||||
|                   name, |         name, | ||||||
|                   key -> |         key -> | ||||||
|                       Gauge.builder(key, state, AtomicDouble::get) |             Gauge.builder(key, state, AtomicDouble::get) | ||||||
|                           .tag(DROPWIZARD_METRIC, "true") |                 .tag(DROPWIZARD_METRIC, "true") | ||||||
|                           .register(meterRegistry)); |                 .register(registry)); | ||||||
| 
 | 
 | ||||||
|               // Update the value |     // Update the value | ||||||
|               state.set(value); |     state.set(value); | ||||||
|             }); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Deprecated |   @Deprecated | ||||||
|   public void histogram(Class<?> clazz, String metricName, long value) { |   public void histogram(Class<?> clazz, String metricName, long value) { | ||||||
|     getRegistry() |     String name = MetricRegistry.name(clazz, metricName); | ||||||
|         .ifPresent( |     DistributionSummary summary = | ||||||
|             meterRegistry -> { |         legacyHistogramCache.computeIfAbsent( | ||||||
|               String name = MetricRegistry.name(clazz, metricName); |             name, | ||||||
|               DistributionSummary summary = |             key -> | ||||||
|                   legacyHistogramCache.computeIfAbsent( |                 DistributionSummary.builder(key).tag(DROPWIZARD_METRIC, "true").register(registry)); | ||||||
|                       name, |     summary.record(value); | ||||||
|                       key -> |  | ||||||
|                           DistributionSummary.builder(key) |  | ||||||
|                               .tag(DROPWIZARD_METRIC, "true") |  | ||||||
|                               .register(meterRegistry)); |  | ||||||
|               summary.record(value); |  | ||||||
|             }); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Deprecated |   @Deprecated | ||||||
|  | |||||||
| @ -27,11 +27,7 @@ public class MicrometerMetricsRegistry { | |||||||
|   public static synchronized boolean registerCacheMetrics( |   public static synchronized boolean registerCacheMetrics( | ||||||
|       @Nonnull String cacheName, |       @Nonnull String cacheName, | ||||||
|       @Nonnull Object nativeCache, |       @Nonnull Object nativeCache, | ||||||
|       @Nullable MeterRegistry meterRegistry) { |       @Nonnull MeterRegistry meterRegistry) { | ||||||
| 
 |  | ||||||
|     if (cacheName == null || nativeCache == null || meterRegistry == null) { |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     if (!GLOBALLY_REGISTERED_CACHES.add(cacheName)) { |     if (!GLOBALLY_REGISTERED_CACHES.add(cacheName)) { | ||||||
|       return false; |       return false; | ||||||
|  | |||||||
| @ -10,7 +10,6 @@ import io.micrometer.core.instrument.Meter; | |||||||
| import io.micrometer.core.instrument.MeterRegistry; | import io.micrometer.core.instrument.MeterRegistry; | ||||||
| import io.micrometer.core.instrument.Timer; | import io.micrometer.core.instrument.Timer; | ||||||
| import io.micrometer.core.instrument.simple.SimpleMeterRegistry; | import io.micrometer.core.instrument.simple.SimpleMeterRegistry; | ||||||
| import java.util.Optional; |  | ||||||
| import java.util.concurrent.TimeUnit; | import java.util.concurrent.TimeUnit; | ||||||
| import java.util.function.Supplier; | import java.util.function.Supplier; | ||||||
| import org.mockito.Mock; | import org.mockito.Mock; | ||||||
| @ -44,18 +43,25 @@ public class MetricUtilsTest { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
|   public void testGetRegistryReturnsOptionalWithRegistry() { |   public void testGetRegistryReturnsRegistry() { | ||||||
|     Optional<MeterRegistry> registry = metricUtils.getRegistry(); |     MeterRegistry registry = metricUtils.getRegistry(); | ||||||
|     assertTrue(registry.isPresent()); |     assertNotNull(registry); | ||||||
|     assertSame(registry.get(), meterRegistry); |     assertSame(registry, meterRegistry); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
|   public void testGetRegistryReturnsEmptyOptionalWhenNull() { |   public void testGetRegistryReturnsDefaultWhenNotSpecified() { | ||||||
|     MetricUtils utilsWithNullRegistry = MetricUtils.builder().registry(null).build(); |     MetricUtils utilsWithDefaultRegistry = MetricUtils.builder().build(); | ||||||
| 
 | 
 | ||||||
|     Optional<MeterRegistry> registry = utilsWithNullRegistry.getRegistry(); |     MeterRegistry registry = utilsWithDefaultRegistry.getRegistry(); | ||||||
|     assertFalse(registry.isPresent()); |     assertNotNull(registry); | ||||||
|  |     assertTrue(registry instanceof io.micrometer.core.instrument.composite.CompositeMeterRegistry); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @Test(expectedExceptions = NullPointerException.class) | ||||||
|  |   public void testBuilderRejectsNullRegistry() { | ||||||
|  |     // This should throw NullPointerException due to @NonNull annotation | ||||||
|  |     MetricUtils.builder().registry(null).build(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
| @ -72,11 +78,11 @@ public class MetricUtilsTest { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
|   public void testTimeWithNullRegistryDoesNothing() { |   public void testTimeWithDefaultRegistryWorks() { | ||||||
|     MetricUtils utilsWithNullRegistry = MetricUtils.builder().registry(null).build(); |     MetricUtils utilsWithDefaultRegistry = MetricUtils.builder().build(); | ||||||
| 
 | 
 | ||||||
|     // Should not throw exception |     // Should not throw exception and should work with default registry | ||||||
|     utilsWithNullRegistry.time("test.timer", 1000); |     utilsWithDefaultRegistry.time("test.timer", 1000); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
| @ -217,16 +223,21 @@ public class MetricUtilsTest { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
|   public void testAllMethodsWithNullRegistry() { |   public void testAllMethodsWithDefaultRegistry() { | ||||||
|     MetricUtils utilsWithNullRegistry = MetricUtils.builder().registry(null).build(); |     MetricUtils utilsWithDefaultRegistry = MetricUtils.builder().build(); | ||||||
| 
 | 
 | ||||||
|     // None of these should throw exceptions |     // All methods should work with the default CompositeMeterRegistry | ||||||
|     utilsWithNullRegistry.time("timer", 1000); |     utilsWithDefaultRegistry.time("timer", 1000); | ||||||
|     utilsWithNullRegistry.increment(this.getClass(), "counter", 1); |     utilsWithDefaultRegistry.increment(this.getClass(), "counter", 1); | ||||||
|     utilsWithNullRegistry.increment("counter", 1); |     utilsWithDefaultRegistry.increment("counter", 1); | ||||||
|     utilsWithNullRegistry.exceptionIncrement(this.getClass(), "error", new RuntimeException()); |     utilsWithDefaultRegistry.exceptionIncrement(this.getClass(), "error", new RuntimeException()); | ||||||
|     utilsWithNullRegistry.setGaugeValue(this.getClass(), "gauge", 42); |     utilsWithDefaultRegistry.setGaugeValue(this.getClass(), "gauge", 42); | ||||||
|     utilsWithNullRegistry.histogram(this.getClass(), "histogram", 100); |     utilsWithDefaultRegistry.histogram(this.getClass(), "histogram", 100); | ||||||
|  | 
 | ||||||
|  |     // Verify the registry is the expected type | ||||||
|  |     assertTrue( | ||||||
|  |         utilsWithDefaultRegistry.getRegistry() | ||||||
|  |             instanceof io.micrometer.core.instrument.composite.CompositeMeterRegistry); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Test |   @Test | ||||||
|  | |||||||
| @ -155,32 +155,6 @@ public class MicrometerMetricsRegistryTest { | |||||||
|     assertFalse(result); |     assertFalse(result); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Test |  | ||||||
|   public void testRegisterCacheWithNullNativeCache() { |  | ||||||
|     // Given |  | ||||||
|     String cacheName = "testCache"; |  | ||||||
| 
 |  | ||||||
|     // When |  | ||||||
|     boolean result = MicrometerMetricsRegistry.registerCacheMetrics(cacheName, null, meterRegistry); |  | ||||||
| 
 |  | ||||||
|     // Then |  | ||||||
|     assertFalse(result); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Test |  | ||||||
|   public void testRegisterCacheWithNullCacheName() { |  | ||||||
|     // Given |  | ||||||
|     Cache<Object, Object> caffeineCache = |  | ||||||
|         Caffeine.newBuilder().maximumSize(100).recordStats().build(); |  | ||||||
| 
 |  | ||||||
|     // When |  | ||||||
|     boolean result = |  | ||||||
|         MicrometerMetricsRegistry.registerCacheMetrics(null, caffeineCache, meterRegistry); |  | ||||||
| 
 |  | ||||||
|     // Then |  | ||||||
|     assertFalse(result); // Should return false for null cache name |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Test |   @Test | ||||||
|   public void testRegisterCacheWithUnsupportedCacheType() { |   public void testRegisterCacheWithUnsupportedCacheType() { | ||||||
|     // Given |     // Given | ||||||
| @ -352,30 +326,6 @@ public class MicrometerMetricsRegistryTest { | |||||||
|     assertEquals(registeredKey, cacheName); |     assertEquals(registeredKey, cacheName); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @Test |  | ||||||
|   public void testAllNullParameters() { |  | ||||||
|     // When |  | ||||||
|     boolean result = MicrometerMetricsRegistry.registerCacheMetrics(null, null, null); |  | ||||||
| 
 |  | ||||||
|     // Then |  | ||||||
|     assertFalse(result); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Test |  | ||||||
|   public void testNullCheckOrder() { |  | ||||||
|     // Test various combinations of null parameters |  | ||||||
| 
 |  | ||||||
|     // Null cache name |  | ||||||
|     Cache<Object, Object> caffeineCache = Caffeine.newBuilder().maximumSize(100).build(); |  | ||||||
|     assertFalse(MicrometerMetricsRegistry.registerCacheMetrics(null, caffeineCache, meterRegistry)); |  | ||||||
| 
 |  | ||||||
|     // Null native cache |  | ||||||
|     assertFalse(MicrometerMetricsRegistry.registerCacheMetrics("test", null, meterRegistry)); |  | ||||||
| 
 |  | ||||||
|     // Null meter registry |  | ||||||
|     assertFalse(MicrometerMetricsRegistry.registerCacheMetrics("test", caffeineCache, null)); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @Test |   @Test | ||||||
|   public void testSuccessfulRegistrationDoesNotThrowOnSubsequentAttempts() { |   public void testSuccessfulRegistrationDoesNotThrowOnSubsequentAttempts() { | ||||||
|     // Given |     // Given | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Abe
						Abe