diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/AlertingSubsystemInit.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/AlertingSubsystemInit.java index b7c5b3a5b85..d8e2d633694 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/AlertingSubsystemInit.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/AlertingSubsystemInit.java @@ -16,6 +16,7 @@ import com.microsoft.applicationinsights.agent.internal.profiler.Profiler; import com.microsoft.applicationinsights.agent.internal.profiler.ProfilerControl; import com.microsoft.applicationinsights.agent.internal.profiler.upload.ServiceProfilerIndex; +import com.microsoft.applicationinsights.agent.internal.sampling.SamplerUtil; import com.microsoft.applicationinsights.agent.internal.telemetry.TelemetryClient; import com.microsoft.applicationinsights.agent.internal.telemetry.TelemetryObservers; import com.microsoft.applicationinsights.alerting.AlertingSubsystem; @@ -149,6 +150,7 @@ private static void sendServiceProfilerIndex( EventTelemetryBuilder telemetryBuilder = telemetryClient.newEventTelemetryBuilder(); telemetryBuilder.setName("ServiceProfilerIndex"); + telemetryBuilder.setSampleRate((float) SamplerUtil.SAMPLE_RATE_TO_DISABLE_INGESTION_SAMPLING); for (Map.Entry entry : serviceProfilerIndex.getProperties().entrySet()) { telemetryBuilder.addProperty(entry.getKey(), entry.getValue()); @@ -170,6 +172,7 @@ private static void sendMessageTelemetry(TelemetryClient telemetryClient, String MessageTelemetryBuilder telemetryBuilder = telemetryClient.newMessageTelemetryBuilder(); telemetryBuilder.setMessage(message); + telemetryBuilder.setSampleRate((float) SamplerUtil.SAMPLE_RATE_TO_DISABLE_INGESTION_SAMPLING); telemetryBuilder.setTime(FormattedTime.offSetDateTimeFromNow()); telemetryClient.trackAsync(telemetryBuilder.build()); diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/GcEventInit.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/GcEventInit.java index 8f58ccfa30d..71cac16643a 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/GcEventInit.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/GcEventInit.java @@ -7,6 +7,7 @@ import com.azure.monitor.opentelemetry.autoconfigure.implementation.utils.FormattedTime; import com.microsoft.applicationinsights.agent.internal.configuration.GcReportingLevel; import com.microsoft.applicationinsights.agent.internal.profiler.util.ServiceLoaderUtil; +import com.microsoft.applicationinsights.agent.internal.sampling.SamplerUtil; import com.microsoft.applicationinsights.agent.internal.telemetry.TelemetryClient; import com.microsoft.applicationinsights.alerting.AlertingSubsystem; import com.microsoft.applicationinsights.alerting.config.AlertMetricType; @@ -125,6 +126,7 @@ private static void emitGcEvent( EventTelemetryBuilder telemetryBuilder = telemetryClient.newEventTelemetryBuilder(); telemetryBuilder.setName("GcEvent"); + telemetryBuilder.setSampleRate((float) SamplerUtil.SAMPLE_RATE_TO_DISABLE_INGESTION_SAMPLING); telemetryBuilder.addProperty("collector", event.getCollector().getName()); telemetryBuilder.addProperty("type", event.getGcCause()); diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/sampling/SamplerUtil.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/sampling/SamplerUtil.java index fd810248a09..ad16cae0ec1 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/sampling/SamplerUtil.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/sampling/SamplerUtil.java @@ -12,7 +12,7 @@ public class SamplerUtil { - private static final double SAMPLE_RATE_TO_DISABLE_INGESTION_SAMPLING = 99.99; + public static final double SAMPLE_RATE_TO_DISABLE_INGESTION_SAMPLING = 99.99; private static final Cache recordAndSampleWithSampleRateMap = Cache.bounded(100); diff --git a/agent/agent-tooling/src/test/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/GcEventInitTest.java b/agent/agent-tooling/src/test/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/GcEventInitTest.java index 5b1257d5f16..da62321a329 100644 --- a/agent/agent-tooling/src/test/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/GcEventInitTest.java +++ b/agent/agent-tooling/src/test/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/GcEventInitTest.java @@ -5,9 +5,14 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.azure.monitor.opentelemetry.autoconfigure.implementation.models.TelemetryEventData; +import com.azure.monitor.opentelemetry.autoconfigure.implementation.models.TelemetryItem; +import com.azure.monitor.opentelemetry.autoconfigure.implementation.statsbeat.StatsbeatModule; import com.microsoft.applicationinsights.agent.internal.configuration.GcReportingLevel; import com.microsoft.applicationinsights.agent.internal.profiler.testutil.TestTimeSource; +import com.microsoft.applicationinsights.agent.internal.sampling.SamplerUtil; import com.microsoft.applicationinsights.agent.internal.telemetry.TelemetryClient; +import com.microsoft.applicationinsights.agent.internal.telemetry.TelemetryObservers; import com.microsoft.applicationinsights.alerting.AlertingSubsystem; import com.microsoft.applicationinsights.alerting.alert.AlertBreach; import com.microsoft.applicationinsights.alerting.analysis.TimeSource; @@ -19,7 +24,10 @@ import com.microsoft.gcmonitor.MemoryManagement; import com.microsoft.gcmonitor.garbagecollectors.GarbageCollector; import com.microsoft.gcmonitor.memorypools.MemoryPool; +import io.opentelemetry.sdk.resources.Resource; import java.lang.management.MemoryUsage; +import java.util.ArrayList; +import java.util.HashMap; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -27,12 +35,82 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; import javax.management.MBeanServerConnection; import org.junit.jupiter.api.Test; import org.mockito.Mockito; class GcEventInitTest { + @Test + void gcEventIsEmittedWithSampleRateThatBypassesIngestionSampling() + throws ExecutionException, InterruptedException, TimeoutException { + + CompletableFuture gcEventFuture = new CompletableFuture<>(); + Consumer observer = + telemetryItem -> { + if (telemetryItem.getData().getBaseData() instanceof TelemetryEventData + && "GcEvent" + .equals(((TelemetryEventData) telemetryItem.getData().getBaseData()).getName())) { + gcEventFuture.complete(telemetryItem); + } + }; + TelemetryObservers.INSTANCE.getObservers().add(observer); + + try { + CompletableFuture alertFuture = new CompletableFuture<>(); + TestTimeSource timeSource = new TestTimeSource(); + AlertingSubsystem alertingSubsystem = getAlertingSubsystem(alertFuture, timeSource); + + GcMonitorFactory factory = + new GcMonitorFactory() { + @Override + public MemoryManagement monitorSelf( + ExecutorService executorService, GcEventConsumer consumer) { + consumer.accept(fullyMockedGcEvent()); + return null; + } + + @Override + public MemoryManagement monitor( + MBeanServerConnection connection, + ExecutorService executorService, + GcEventConsumer consumer) { + return null; + } + }; + + TelemetryClient telemetryClient = + TelemetryClient.builder() + .setCustomDimensions(new HashMap<>()) + .setMetricFilters(new ArrayList<>()) + .setStatsbeatModule(new StatsbeatModule(response -> {})) + .setConnectionStrings( + "InstrumentationKey=00000000-0000-0000-0000-000000000000;IngestionEndpoint=https://test.in.applicationinsights.azure.com/") + .build(); + telemetryClient.setOtelResource(Resource.empty()); + + ExecutorService executorService = Executors.newSingleThreadExecutor(); + try { + GcEventInit.init( + alertingSubsystem, + telemetryClient, + executorService, + new GcEventInit.GcEventMonitorConfiguration(GcReportingLevel.ALL), + factory); + + TelemetryItem gcEvent = gcEventFuture.get(30, TimeUnit.SECONDS); + + assertThat(gcEvent.getSampleRate()) + .isEqualTo((float) SamplerUtil.SAMPLE_RATE_TO_DISABLE_INGESTION_SAMPLING); + } finally { + executorService.shutdownNow(); + } + } finally { + TelemetryObservers.INSTANCE.getObservers().remove(observer); + } + } + @Test void endToEndAlertIsTriggered() throws ExecutionException, InterruptedException, TimeoutException { @@ -102,4 +180,25 @@ private static GcCollectionEvent mockGcEvent() { .thenReturn(new MemoryUsage(1, 9, 10, 10)); return event; } + + private static GcCollectionEvent fullyMockedGcEvent() { + GcCollectionEvent event = Mockito.mock(GcCollectionEvent.class); + GarbageCollector collector = Mockito.mock(GarbageCollector.class); + MemoryPool tenuredPool = Mockito.mock(MemoryPool.class); + MemoryUsage memoryUsage = new MemoryUsage(1, 9, 10, 10); + + Mockito.when(collector.isTenuredCollector()).thenReturn(true); + Mockito.when(collector.getName()).thenReturn("test-collector"); + Mockito.when(event.getCollector()).thenReturn(collector); + Mockito.when(event.getGcCause()).thenReturn("test-cause"); + Mockito.when(event.getGcAction()).thenReturn("test-action"); + Mockito.when(event.getTenuredPool()).thenReturn(Optional.of(tenuredPool)); + Mockito.when(event.getMemoryUsageBeforeGc(Mockito.any(MemoryPool.class))) + .thenReturn(memoryUsage); + Mockito.when(event.getMemoryUsageAfterGc(Mockito.any(MemoryPool.class))) + .thenReturn(memoryUsage); + Mockito.when(event.getMemoryUsageBeforeGc(Mockito.anyList())).thenReturn(memoryUsage); + Mockito.when(event.getMemoryUsageAfterGc(Mockito.anyList())).thenReturn(memoryUsage); + return event; + } }