From caec82ae49bb0e6a400908b18692384f3265cc56 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Fri, 10 Feb 2023 03:55:47 +0000 Subject: [PATCH 01/40] Cosmos Metrics: allow enabling only metrics of certain categories --- .../com/azure/cosmos/CosmosAsyncClient.java | 10 + .../implementation/AsyncDocumentClient.java | 8 + .../ImplementationBridgeHelpers.java | 3 + .../clienttelemetry/ClientTelemetry.java | 4 + .../ClientTelemetryMetrics.java | 305 +++++++++++------- .../clienttelemetry/CosmosMetricNames.java | 147 +++++++++ .../clienttelemetry/MetricCategory.java | 47 +++ .../RntbdTransportClient.java | 20 +- .../rntbd/RntbdClientChannelPool.java | 24 ++ .../rntbd/RntbdEndpoint.java | 10 + .../rntbd/RntbdMetrics.java | 3 +- .../rntbd/RntbdMetricsCompletionRecorder.java | 11 + .../rntbd/RntbdRequestArgs.java | 8 +- .../rntbd/RntbdRequestRecord.java | 8 +- .../rntbd/RntbdServiceEndpoint.java | 31 +- .../models/CosmosClientTelemetryConfig.java | 66 +++- .../RntbdTransportClientTest.java | 10 + 17 files changed, 579 insertions(+), 136 deletions(-) create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMetricNames.java create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/MetricCategory.java diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java index 19adde3d4f86f..f8ebf00733e74 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java @@ -19,6 +19,7 @@ import com.azure.cosmos.implementation.TracerProvider; import com.azure.cosmos.implementation.clienttelemetry.ClientTelemetry; import com.azure.cosmos.implementation.clienttelemetry.ClientTelemetryMetrics; +import com.azure.cosmos.implementation.clienttelemetry.MetricCategory; import com.azure.cosmos.implementation.clienttelemetry.TagName; import com.azure.cosmos.implementation.directconnectivity.rntbd.RntbdMetrics; import com.azure.cosmos.implementation.throughputControl.config.ThroughputControlGroupInternal; @@ -84,6 +85,7 @@ public final class CosmosAsyncClient implements Closeable { private final Tag clientCorrelationTag; private final String accountTagValue; private final EnumSet metricTagNames; + private final EnumSet metricCategories; private final boolean clientMetricsEnabled; private final boolean isSendClientTelemetryToServiceEnabled; private final MeterRegistry clientMetricRegistrySnapshot; @@ -139,6 +141,8 @@ public final class CosmosAsyncClient implements Closeable { .getClientCorrelationId(effectiveTelemetryConfig); this.metricTagNames = telemetryConfigAccessor .getMetricTagNames(effectiveTelemetryConfig); + this.metricCategories = telemetryConfigAccessor + .getMetricCategories(effectiveTelemetryConfig); List permissionList = new ArrayList<>(); if (this.permissions != null) { @@ -168,6 +172,7 @@ public final class CosmosAsyncClient implements Closeable { .withClientTelemetryConfig(this.clientTelemetryConfig) .withClientCorrelationId(this.clientCorrelationId) .withMetricTagNames(this.metricTagNames) + .withMetricCategories(this.metricCategories) .build(); String effectiveClientCorrelationId = this.asyncDocumentClient.getClientCorrelationId(); @@ -728,6 +733,11 @@ public EnumSet getMetricTagNames(CosmosAsyncClient client) { return client.metricTagNames; } + @Override + public EnumSet getMetricCategories(CosmosAsyncClient client) { + return client.metricCategories; + } + @Override public boolean isClientTelemetryMetricsEnabled(CosmosAsyncClient client) { return client.clientMetricsEnabled; diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/AsyncDocumentClient.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/AsyncDocumentClient.java index 76510cf85cb98..76448b0c62926 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/AsyncDocumentClient.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/AsyncDocumentClient.java @@ -11,6 +11,7 @@ import com.azure.cosmos.implementation.caches.RxClientCollectionCache; import com.azure.cosmos.implementation.caches.RxPartitionKeyRangeCache; import com.azure.cosmos.implementation.clienttelemetry.ClientTelemetry; +import com.azure.cosmos.implementation.clienttelemetry.MetricCategory; import com.azure.cosmos.implementation.clienttelemetry.TagName; import com.azure.cosmos.implementation.query.PartitionedQueryExecutionInfo; import com.azure.cosmos.implementation.throughputControl.config.ThroughputControlGroupInternal; @@ -99,6 +100,7 @@ class Builder { CosmosClientTelemetryConfig clientTelemetryConfig; private String clientCorrelationId = null; private EnumSet metricTagNames = EnumSet.allOf(TagName.class); + private EnumSet metricCategories = MetricCategory.DEFAULT_CATEGORIES; public Builder withServiceEndpoint(String serviceEndpoint) { try { @@ -131,6 +133,12 @@ public Builder withMetricTagNames(EnumSet tagNames) { return this; } + public Builder withMetricCategories(EnumSet categories) { + this.metricCategories = categories; + + return this; + } + /** * New method withMasterKeyOrResourceToken will take either master key or resource token * and perform authentication for accessing resource. diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ImplementationBridgeHelpers.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ImplementationBridgeHelpers.java index 0ad2d2c605a7f..ee0233ba0c43a 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ImplementationBridgeHelpers.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ImplementationBridgeHelpers.java @@ -19,6 +19,7 @@ import com.azure.cosmos.ThroughputControlGroupConfig; import com.azure.cosmos.implementation.batch.ItemBatchOperation; import com.azure.cosmos.implementation.batch.PartitionScopeThresholds; +import com.azure.cosmos.implementation.clienttelemetry.MetricCategory; import com.azure.cosmos.implementation.clienttelemetry.TagName; import com.azure.cosmos.implementation.patch.PatchOperation; import com.azure.cosmos.implementation.routing.PartitionKeyInternal; @@ -1040,6 +1041,7 @@ public interface CosmosAsyncClientAccessor { Tag getClientCorrelationTag(CosmosAsyncClient client); String getAccountTagValue(CosmosAsyncClient client); EnumSet getMetricTagNames(CosmosAsyncClient client); + EnumSet getMetricCategories(CosmosAsyncClient client); boolean isClientTelemetryMetricsEnabled(CosmosAsyncClient client); boolean isSendClientTelemetryToServiceEnabled(CosmosAsyncClient client); List getPreferredRegions(CosmosAsyncClient client); @@ -1124,6 +1126,7 @@ public interface CosmosClientTelemetryConfigAccessor { int getMaxConnectionPoolSize(CosmosClientTelemetryConfig config); Duration getIdleHttpConnectionTimeout(CosmosClientTelemetryConfig config); ProxyOptions getProxy(CosmosClientTelemetryConfig config); + EnumSet getMetricCategories(CosmosClientTelemetryConfig config); EnumSet getMetricTagNames(CosmosClientTelemetryConfig config); String getClientCorrelationId(CosmosClientTelemetryConfig config); MeterRegistry getClientMetricRegistry(CosmosClientTelemetryConfig config); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetry.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetry.java index fa5fccc928119..4c776c7abeb0b 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetry.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetry.java @@ -163,6 +163,10 @@ public ClientTelemetryInfo getClientTelemetryInfo() { return clientTelemetryInfo; } + public CosmosClientTelemetryConfig getClientTelemetryConfig() { + return clientTelemetryConfig; + } + public static String getMachineId(DiagnosticsClientContext.DiagnosticsClientConfig diagnosticsClientConfig) { AzureVMMetadata metadataSnapshot = azureVmMetaDataSingleton.get(); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java index e7c3cab3bbc58..f69fa62253d2d 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java @@ -16,8 +16,6 @@ import com.azure.cosmos.implementation.directconnectivity.RntbdTransportClient; import com.azure.cosmos.implementation.directconnectivity.StoreResponseDiagnostics; import com.azure.cosmos.implementation.directconnectivity.StoreResultDiagnostics; -import com.azure.cosmos.implementation.directconnectivity.rntbd.RntbdChannelAcquisitionEvent; -import com.azure.cosmos.implementation.directconnectivity.rntbd.RntbdChannelAcquisitionTimeline; import com.azure.cosmos.implementation.directconnectivity.rntbd.RntbdEndpoint; import com.azure.cosmos.implementation.directconnectivity.rntbd.RntbdEndpointStatistics; import com.azure.cosmos.implementation.directconnectivity.rntbd.RntbdMetricsCompletionRecorder; @@ -26,6 +24,7 @@ import com.azure.cosmos.implementation.query.QueryInfo; import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.DistributionSummary; +import io.micrometer.core.instrument.FunctionCounter; import io.micrometer.core.instrument.Gauge; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Tag; @@ -40,6 +39,7 @@ import java.io.StringWriter; import java.time.Duration; import java.util.ArrayList; +import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Map; @@ -98,7 +98,7 @@ public static void recordSystemUsage( } DistributionSummary averageSystemCpuUsageMeter = DistributionSummary - .builder(nameOf("system.avgCpuLoad")) + .builder(nameOf(CosmosMetricNames.System.AvgCpuLoad)) .baseUnit("%") .description("Avg. System CPU load") .maximumExpectedValue(100d) @@ -108,7 +108,7 @@ public static void recordSystemUsage( averageSystemCpuUsageMeter.record(averageSystemCpuUsage); DistributionSummary freeMemoryAvailableInMBMeter = DistributionSummary - .builder(nameOf("system.freeMemoryAvailable")) + .builder(nameOf(CosmosMetricNames.System.FreeMemoryAvailable)) .baseUnit("MB") .description("Free memory available") .publishPercentiles() @@ -140,8 +140,12 @@ public static void recordOperation( boolean isPointOperation = maxItemCount == null || maxItemCount < 0; EnumSet metricTagNames = clientAccessor.getMetricTagNames(cosmosAsyncClient); + EnumSet metricCategories = clientAccessor.getMetricCategories(cosmosAsyncClient); - Set contactedRegions = cosmosDiagnostics.getContactedRegionNames(); + Set contactedRegions = Collections.emptySet(); + if (metricCategories.contains(MetricCategory.OperationDetails)) { + contactedRegions = cosmosDiagnostics.getContactedRegionNames(); + } Tags operationTags = createOperationTags( metricTagNames, @@ -157,7 +161,7 @@ public static void recordOperation( contactedRegions ); - OperationMetricProducer metricProducer = new OperationMetricProducer(metricTagNames, operationTags); + OperationMetricProducer metricProducer = new OperationMetricProducer(metricCategories, metricTagNames, operationTags); metricProducer.recordOperation( requestCharge, latency, @@ -276,9 +280,11 @@ private static Tags createOperationTags( private static class OperationMetricProducer { private final EnumSet metricTagNames; + private final EnumSet metricCategories; private final Tags operationTags; - public OperationMetricProducer(EnumSet metricTagNames, Tags operationTags) { + public OperationMetricProducer(EnumSet metricCategories, EnumSet metricTagNames, Tags operationTags) { + this.metricCategories = metricCategories; this.metricTagNames = metricTagNames; this.operationTags = operationTags; } @@ -292,7 +298,7 @@ public void recordOperation( Set contactedRegions) { Counter operationsCounter = Counter - .builder(nameOf("op.calls")) + .builder(nameOf(CosmosMetricNames.Operation.Calls)) .baseUnit("calls") .description("Operation calls") .tags(operationTags) @@ -300,7 +306,7 @@ public void recordOperation( operationsCounter.increment(); DistributionSummary requestChargeMeter = DistributionSummary - .builder(nameOf("op.RUs")) + .builder(nameOf(CosmosMetricNames.Operation.RequestCharge)) .baseUnit("RU (request unit)") .description("Operation RU charge") .maximumExpectedValue(10_000_000d) @@ -310,21 +316,25 @@ public void recordOperation( .register(compositeRegistry); requestChargeMeter.record(Math.min(requestCharge, 10_000_000d)); - DistributionSummary regionsContactedMeter = DistributionSummary - .builder(nameOf("op.regionsContacted")) - .baseUnit("Regions contacted") - .description("Operation - regions contacted") - .maximumExpectedValue(100d) - .publishPercentiles(0.95, 0.99) - .publishPercentileHistogram(true) - .tags(operationTags) - .register(compositeRegistry); - if (contactedRegions != null && contactedRegions.size() > 0) { - regionsContactedMeter.record(Math.min(contactedRegions.size(), 100d)); + if (this.metricCategories.contains(MetricCategory.OperationDetails)) { + DistributionSummary regionsContactedMeter = DistributionSummary + .builder(nameOf(CosmosMetricNames.Operation.RegionsContacted)) + .baseUnit("Regions contacted") + .description("Operation - regions contacted") + .maximumExpectedValue(100d) + .publishPercentiles(0.95, 0.99) + .publishPercentileHistogram(true) + .tags(operationTags) + .register(compositeRegistry); + if (contactedRegions != null && contactedRegions.size() > 0) { + regionsContactedMeter.record(Math.min(contactedRegions.size(), 100d)); + } + + this.recordItemCounts(maxItemCount, actualItemCount); } Timer latencyMeter = Timer - .builder(nameOf("op.latency")) + .builder(nameOf(CosmosMetricNames.Operation.Latency)) .description("Operation latency") .maximumExpectedValue(Duration.ofSeconds(300)) .publishPercentiles(0.95, 0.99) @@ -333,8 +343,6 @@ public void recordOperation( .register(compositeRegistry); latencyMeter.record(latency); - this.recordItemCounts(maxItemCount, actualItemCount); - List clientSideRequestStatistics = diagnosticsAccessor.getClientSideRequestStatistics(diagnostics); @@ -364,7 +372,7 @@ public void recordOperation( private void recordQueryPlanDiagnostics( QueryInfo.QueryPlanDiagnosticsContext queryPlanDiagnostics ) { - if (queryPlanDiagnostics == null) { + if (queryPlanDiagnostics == null || !this.metricCategories.contains(MetricCategory.RequestSummary)) { return; } @@ -373,7 +381,7 @@ private void recordQueryPlanDiagnostics( ); Counter requestCounter = Counter - .builder(nameOf("req.gw.requests")) + .builder(nameOf(CosmosMetricNames.Request.Gateway.Requests)) .baseUnit("requests") .description("Gateway requests") .tags(requestTags) @@ -384,7 +392,7 @@ private void recordQueryPlanDiagnostics( if (latency != null) { Timer requestLatencyMeter = Timer - .builder(nameOf("req.gw.latency")) + .builder(nameOf(CosmosMetricNames.Request.Gateway.Latency)) .description("Gateway Request latency") .maximumExpectedValue(Duration.ofSeconds(300)) .publishPercentiles(0.95, 0.99) @@ -394,7 +402,9 @@ private void recordQueryPlanDiagnostics( requestLatencyMeter.record(latency); } - recordRequestTimeline("req.gw.timeline.", queryPlanDiagnostics.getRequestTimeline(), requestTags); + recordRequestTimeline( + CosmosMetricNames.Request.Gateway.TimelinePrefix, + queryPlanDiagnostics.getRequestTimeline(), requestTags); } private void recordRequestPayloadSizes( @@ -402,7 +412,7 @@ private void recordRequestPayloadSizes( int responsePayloadSizeInBytes ) { DistributionSummary requestPayloadSizeMeter = DistributionSummary - .builder(nameOf("req.reqPayloadSize")) + .builder(nameOf(CosmosMetricNames.Request.RequestPayloadSize)) .baseUnit("bytes") .description("Request payload size in bytes") .maximumExpectedValue(16d * 1024) @@ -413,7 +423,7 @@ private void recordRequestPayloadSizes( requestPayloadSizeMeter.record(requestPayloadSizeInBytes); DistributionSummary responsePayloadSizeMeter = DistributionSummary - .builder(nameOf("req.rspPayloadSize")) + .builder(nameOf(CosmosMetricNames.Request.ResponsePayloadSize)) .baseUnit("bytes") .description("Response payload size in bytes") .maximumExpectedValue(16d * 1024) @@ -428,9 +438,9 @@ private void recordItemCounts( int maxItemCount, int actualItemCount ) { - if (maxItemCount > 0) { + if (maxItemCount > 0 && this.metricCategories.contains(MetricCategory.OperationDetails)) { DistributionSummary maxItemCountMeter = DistributionSummary - .builder(nameOf("op.maxItemCount")) + .builder(nameOf(CosmosMetricNames.Operation.MaxItemCount)) .baseUnit("item count") .description("Request max. item count") .maximumExpectedValue(1_000_000d) @@ -441,7 +451,7 @@ private void recordItemCounts( maxItemCountMeter.record(Math.max(0, Math.min(maxItemCount, 1_000_000d))); DistributionSummary actualItemCountMeter = DistributionSummary - .builder(nameOf("op.actualItemCount")) + .builder(nameOf(CosmosMetricNames.Operation.ActualItemCount)) .baseUnit("item count") .description("Response actual item count") .maximumExpectedValue(1_000_000d) @@ -550,12 +560,13 @@ private Tags createAddressResolutionTags( } private void recordRntbdEndpointStatistics(RntbdEndpointStatistics endpointStatistics, Tags requestTags) { - if (endpointStatistics == null) { + if (endpointStatistics == null && this.metricCategories.contains(MetricCategory.Legacy)) { return; } DistributionSummary acquiredChannelsMeter = DistributionSummary - .builder(nameOf("req.rntbd.stats.endpoint.acquiredChannels")) + .builder( + nameOf(CosmosMetricNames.DisabledByDefaultLegacy.RntbdRequestEndpointStatistics.AcquiredChannels)) .baseUnit("#") .description("Endpoint statistics(acquired channels)") .maximumExpectedValue(100_000d) @@ -566,7 +577,8 @@ private void recordRntbdEndpointStatistics(RntbdEndpointStatistics endpointStati acquiredChannelsMeter.record(endpointStatistics.getAcquiredChannels()); DistributionSummary availableChannelsMeter = DistributionSummary - .builder(nameOf("req.rntbd.stats.endpoint.availableChannels")) + .builder( + nameOf(CosmosMetricNames.DisabledByDefaultLegacy.RntbdRequestEndpointStatistics.AvailableChannels)) .baseUnit("#") .description("Endpoint statistics(available channels)") .maximumExpectedValue(100_000d) @@ -577,7 +589,8 @@ private void recordRntbdEndpointStatistics(RntbdEndpointStatistics endpointStati availableChannelsMeter.record(endpointStatistics.getAvailableChannels()); DistributionSummary inflightRequestsMeter = DistributionSummary - .builder(nameOf("req.rntbd.stats.endpoint.inflightRequests")) + .builder( + nameOf(CosmosMetricNames.DisabledByDefaultLegacy.RntbdRequestEndpointStatistics.InflightRequests)) .baseUnit("#") .description("Endpoint statistics(inflight requests)") .tags(requestTags) @@ -589,7 +602,7 @@ private void recordRntbdEndpointStatistics(RntbdEndpointStatistics endpointStati } private void recordRequestTimeline(String prefix, RequestTimeline requestTimeline, Tags requestTags) { - if (requestTimeline == null) { + if (requestTimeline == null || !this.metricCategories.contains(MetricCategory.RequestDetails)) { return; } @@ -614,6 +627,10 @@ private void recordRequestTimeline(String prefix, RequestTimeline requestTimelin private void recordStoreResponseStatistics( List storeResponseStatistics) { + if (!this.metricCategories.contains(MetricCategory.RequestSummary)) { + return; + } + for (ClientSideRequestStatistics.StoreResponseStatistics responseStatistics: storeResponseStatistics) { StoreResultDiagnostics storeResultDiagnostics = responseStatistics.getStoreResult(); StoreResponseDiagnostics storeResponseDiagnostics = @@ -636,7 +653,7 @@ private void recordStoreResponseStatistics( if (backendLatency != null) { DistributionSummary backendRequestLatencyMeter = DistributionSummary - .builder(nameOf("req.rntbd.backendLatency")) + .builder(nameOf(CosmosMetricNames.Request.Direct.BackendLatency)) .baseUnit("ms") .description("Backend service latency") .maximumExpectedValue(6_000d) @@ -649,7 +666,7 @@ private void recordStoreResponseStatistics( double requestCharge = storeResponseDiagnostics.getRequestCharge(); DistributionSummary requestChargeMeter = DistributionSummary - .builder(nameOf("req.rntbd.RUs")) + .builder(nameOf(CosmosMetricNames.Request.Direct.RequestCharge)) .baseUnit("RU (request unit)") .description("RNTBD Request RU charge") .maximumExpectedValue(1_000_000d) @@ -662,7 +679,7 @@ private void recordStoreResponseStatistics( Duration latency = responseStatistics.getDuration(); if (latency != null) { Timer requestLatencyMeter = Timer - .builder(nameOf("req.rntbd.latency")) + .builder(nameOf(CosmosMetricNames.Request.Direct.Latency)) .description("RNTBD Request latency") .maximumExpectedValue(Duration.ofSeconds(6)) .publishPercentiles(0.95, 0.99) @@ -673,7 +690,7 @@ private void recordStoreResponseStatistics( } Counter requestCounter = Counter - .builder(nameOf("req.rntbd.requests")) + .builder(nameOf(CosmosMetricNames.Request.Direct.Requests)) .baseUnit("requests") .description("RNTBD requests") .tags(requestTags) @@ -681,7 +698,7 @@ private void recordStoreResponseStatistics( requestCounter.increment(); recordRequestTimeline( - "req.rntbd.timeline.", + CosmosMetricNames.Request.Direct.TimelinePrefix, storeResponseDiagnostics.getRequestTimeline(), requestTags); recordRequestPayloadSizes( @@ -699,7 +716,7 @@ private void recordGatewayStatistics( Duration latency, ClientSideRequestStatistics.GatewayStatistics gatewayStatistics) { - if (gatewayStatistics == null) { + if (gatewayStatistics == null || !this.metricCategories.contains(MetricCategory.RequestSummary)) { return; } @@ -722,7 +739,7 @@ private void recordGatewayStatistics( ); Counter requestCounter = Counter - .builder(nameOf("req.gw.requests")) + .builder(nameOf(CosmosMetricNames.Request.Gateway.Requests)) .baseUnit("requests") .description("Gateway requests") .tags(requestTags) @@ -731,7 +748,7 @@ private void recordGatewayStatistics( double requestCharge = gatewayStatistics.getRequestCharge(); DistributionSummary requestChargeMeter = DistributionSummary - .builder(nameOf("req.gw.RUs")) + .builder(nameOf(CosmosMetricNames.Request.Gateway.RequestCharge)) .baseUnit("RU (request unit)") .description("Gateway Request RU charge") .maximumExpectedValue(1_000_000d) @@ -743,7 +760,7 @@ private void recordGatewayStatistics( if (latency != null) { Timer requestLatencyMeter = Timer - .builder(nameOf("req.gw.latency")) + .builder(nameOf(CosmosMetricNames.Request.Gateway.Latency)) .description("Gateway Request latency") .maximumExpectedValue(Duration.ofSeconds(300)) .publishPercentiles(0.95, 0.99) @@ -753,13 +770,18 @@ private void recordGatewayStatistics( requestLatencyMeter.record(latency); } - recordRequestTimeline("req.gw.timeline.", gatewayStatistics.getRequestTimeline(), requestTags); + recordRequestTimeline( + CosmosMetricNames.Request.Gateway.TimelinePrefix, + gatewayStatistics.getRequestTimeline(), requestTags); } private void recordAddressResolutionStatistics( Map addressResolutionStatisticsMap) { - if (addressResolutionStatisticsMap == null || addressResolutionStatisticsMap.size() == 0) { + if (addressResolutionStatisticsMap == null + || addressResolutionStatisticsMap.size() == 0 + || !this.metricCategories.contains(MetricCategory.AddressResolutions) ) { + return; } @@ -789,7 +811,7 @@ private void recordAddressResolutionStatistics( addressResolutionStatistics.getEndTimeUTC()); Timer addressResolutionLatencyMeter = Timer - .builder(nameOf("rntbd.addressResolution.latency")) + .builder(nameOf(CosmosMetricNames.Direct.AddressResolution.Latency)) .description("Address resolution latency") .maximumExpectedValue(Duration.ofSeconds(6)) .publishPercentiles(0.95, 0.99) @@ -799,7 +821,7 @@ private void recordAddressResolutionStatistics( addressResolutionLatencyMeter.record(latency); Counter requestCounter = Counter - .builder(nameOf("rntbd.addressResolution.requests")) + .builder(nameOf(CosmosMetricNames.Direct.AddressResolution.Requests)) .baseUnit("requests") .description("Address resolution requests") .tags(addressResolutionTags) @@ -815,90 +837,123 @@ private static class RntbdMetricsV2 implements RntbdMetricsCompletionRecorder { private final Timer responseErrors; private final DistributionSummary responseSize; private final Timer responseSuccesses; + private final EnumSet metricCategories; private RntbdMetricsV2(MeterRegistry registry, RntbdTransportClient client, RntbdEndpoint endpoint) { Tags tags = Tags.of(endpoint.clientMetricTag()); - this.requests = Timer - .builder(nameOf("rntbd.requests.latency")) - .description("RNTBD request latency") - .tags(tags) - .maximumExpectedValue(Duration.ofSeconds(300)) - .publishPercentileHistogram(true) - .publishPercentiles(0.95, 0.99) - .register(registry); + this.metricCategories = client.getMetricCategories(); - this.responseErrors = Timer - .builder(nameOf("rntbd.requests.failed.latency")) - .description("RNTBD failed request latency") - .tags(tags) - .maximumExpectedValue(Duration.ofSeconds(300)) - .publishPercentileHistogram(true) - .publishPercentiles(0.95, 0.99) - .register(registry); + if (metricCategories.contains(MetricCategory.DirectRequests)) { + this.requests = Timer + .builder(nameOf(CosmosMetricNames.Direct.Requests.Latency)) + .description("RNTBD request latency") + .tags(tags) + .maximumExpectedValue(Duration.ofSeconds(300)) + .publishPercentileHistogram(true) + .publishPercentiles(0.95, 0.99) + .register(registry); - this.responseSuccesses = Timer - .builder(nameOf("rntbd.requests.successful.latency")) - .description("RNTBD successful request latency") - .tags(tags) - .maximumExpectedValue(Duration.ofSeconds(300)) - .publishPercentileHistogram(true) - .publishPercentiles(0.95, 0.99) - .register(registry); - - Gauge.builder(nameOf("rntbd.endpoints.count"), client, RntbdTransportClient::endpointCount) - .description("RNTBD endpoint count") - .register(registry); - - Gauge.builder(nameOf("rntbd.endpoints.evicted"), client, RntbdTransportClient::endpointEvictionCount) - .description("RNTBD endpoint eviction count") - .register(registry); - - Gauge.builder(nameOf("rntbd.requests.concurrent.count"), endpoint, RntbdEndpoint::concurrentRequests) - .description("RNTBD concurrent requests (executing or queued request count)") - .tags(tags) - .register(registry); - - Gauge.builder(nameOf("rntbd.requests.queued.count"), endpoint, RntbdEndpoint::requestQueueLength) - .description("RNTBD queued request count") - .tags(tags) - .register(registry); - - Gauge.builder(nameOf("rntbd.channels.acquired.count"), endpoint, RntbdEndpoint::channelsAcquiredMetric) - .description("RNTBD acquired channel count") - .tags(tags) - .register(registry); - - Gauge.builder(nameOf("rntbd.channels.available.count"), endpoint, RntbdEndpoint::channelsAvailableMetric) - .description("RNTBD available channel count") - .tags(tags) - .register(registry); - - this.requestSize = DistributionSummary.builder(nameOf("rntbd.req.reqSize")) - .description("RNTBD request size (bytes)") - .baseUnit("bytes") - .tags(tags) - .maximumExpectedValue(16_000_000d) - .publishPercentileHistogram(false) - .publishPercentiles() - .register(registry); - - this.responseSize = DistributionSummary.builder(nameOf("rntbd.req.rspSize")) - .description("RNTBD response size (bytes)") - .baseUnit("bytes") - .tags(tags) - .maximumExpectedValue(16_000_000d) - .publishPercentileHistogram(false) - .publishPercentiles() - .register(registry); + this.responseErrors = Timer + .builder(nameOf(CosmosMetricNames.Direct.Requests.FailedRequestLatency)) + .description("RNTBD failed request latency") + .tags(tags) + .maximumExpectedValue(Duration.ofSeconds(300)) + .publishPercentileHistogram(true) + .publishPercentiles(0.95, 0.99) + .register(registry); + + this.responseSuccesses = Timer + .builder(nameOf(CosmosMetricNames.Direct.Requests.SuccessRequestLatency)) + .description("RNTBD successful request latency") + .tags(tags) + .maximumExpectedValue(Duration.ofSeconds(300)) + .publishPercentileHistogram(true) + .publishPercentiles(0.95, 0.99) + .register(registry); + + Gauge.builder(nameOf(CosmosMetricNames.Direct.Requests.Concurrent), endpoint, RntbdEndpoint::concurrentRequests) + .description("RNTBD concurrent requests (executing or queued request count)") + .tags(tags) + .register(registry); + + Gauge.builder(nameOf(CosmosMetricNames.Direct.Requests.Queued), endpoint, RntbdEndpoint::requestQueueLength) + .description("RNTBD queued request count") + .tags(tags) + .register(registry); + + this.requestSize = DistributionSummary.builder(nameOf(CosmosMetricNames.Direct.Requests.RequestPayloadSize)) + .description("RNTBD request size (bytes)") + .baseUnit("bytes") + .tags(tags) + .maximumExpectedValue(16_000_000d) + .publishPercentileHistogram(false) + .publishPercentiles() + .register(registry); + + this.responseSize = DistributionSummary.builder(nameOf(CosmosMetricNames.Direct.Requests.ResponsePayloadSize)) + .description("RNTBD response size (bytes)") + .baseUnit("bytes") + .tags(tags) + .maximumExpectedValue(16_000_000d) + .publishPercentileHistogram(false) + .publishPercentiles() + .register(registry); + } else { + this.requests = null; + this.responseErrors = null; + this.responseSuccesses = null; + this.requestSize = null; + this.responseSize= null; + } + + if (metricCategories.contains(MetricCategory.DirectEndpoints)) { + Gauge.builder(nameOf(CosmosMetricNames.Direct.Endpoints.Count), client, RntbdTransportClient::endpointCount) + .description("RNTBD endpoint count") + .register(registry); + + FunctionCounter.builder( + nameOf(CosmosMetricNames.Direct.Endpoints.EvictedCount), + client, + RntbdTransportClient::endpointEvictionCount) + .description("RNTBD endpoint eviction count") + .register(registry); + } + + if (metricCategories.contains(MetricCategory.DirectChannels)) { + FunctionCounter.builder( + nameOf(CosmosMetricNames.Direct.Channels.Acquired), + endpoint, + RntbdEndpoint::totalChannelsAcquiredMetric) + .description("RNTBD acquired channel count") + .tags(tags) + .register(registry); + + FunctionCounter.builder( + nameOf(CosmosMetricNames.Direct.Channels.Closed), + endpoint, + RntbdEndpoint::totalChannelsClosedMetric) + .description("RNTBD closed channel count") + .tags(tags) + .register(registry); + + Gauge.builder(nameOf(CosmosMetricNames.Direct.Channels.Available), endpoint, RntbdEndpoint::channelsAvailableMetric) + .description("RNTBD available channel count") + .tags(tags) + .register(registry); + } } public void markComplete(RntbdRequestRecord requestRecord) { - requestRecord.stop(this.requests, requestRecord.isCompletedExceptionally() - ? this.responseErrors - : this.responseSuccesses); - this.requestSize.record(requestRecord.requestLength()); - this.responseSize.record(requestRecord.responseLength()); + if (this.metricCategories.contains(MetricCategory.DirectRequests)) { + requestRecord.stop(this.requests, requestRecord.isCompletedExceptionally() + ? this.responseErrors + : this.responseSuccesses); + this.requestSize.record(requestRecord.requestLength()); + this.responseSize.record(requestRecord.responseLength()); + } else { + requestRecord.stop(); + } } } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMetricNames.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMetricNames.java new file mode 100644 index 0000000000000..610c0783037ec --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMetricNames.java @@ -0,0 +1,147 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.cosmos.implementation.clienttelemetry; + +public final class CosmosMetricNames { + + private CosmosMetricNames() {} + + public final static class Direct { + public final static class AddressResolution { + // Latency of the RNTBD address resolution request (Timer) + public final static String Latency = "rntbd.addressResolution.latency"; + + // Number of RNTBD address resolution requests (Counter) + public final static String Requests = "rntbd.addressResolution.requests"; + } + + public final static class Channels { + // Snapshot of the number of acquired channels for this endpoint (FunctionCounter) + public final static String Acquired = "rntbd.channels.acquired.count"; + + // Snapshot of the number of available channels for this endpoint (Gauge) + public final static String Available = "rntbd.channels.available.count"; + + // Snapshot of the number of closed channels for this endpoint (FunctionCounter) + public final static String Closed = "rntbd.channels.closed.count"; + } + + public final static class Requests { + // Latency of RNTBD requests for this endpoint (Timer) + public final static String Latency = "rntbd.requests.latency"; + + // Latency of failed RNTBD requests for this endpoint (Timer) + public final static String FailedRequestLatency = "rntbd.requests.failed.latency"; + + // Latency of successful RNTBD requests for this endpoint (Timer) + public final static String SuccessRequestLatency = "rntbd.requests.successful.latency"; + + // Snapshot of number of concurrent RNTBD requests for this endpoint (Gauge) + public final static String Concurrent = "rntbd.requests.concurrent.count"; + + // Snapshot of number of queued RNTBD requests for this endpoint (Gauge) + public final static String Queued = "rntbd.requests.queued.count"; + + // Size of the request payload (DistributionSummary) + public final static String RequestPayloadSize = "rntbd.req.reqSize"; + + // Size of the response payload (DistributionSummary) + public final static String ResponsePayloadSize = "rntbd.req.rspSize"; + } + + public final static class Endpoints { + // Snapshot of the number of endpoints (Gauge) + public final static String Count = "rntbd.endpoints.count"; + + // Snapshot of the number of evicted/closed endpoints (FunctionCounter) + public final static String EvictedCount = "rntbd.endpoints.evicted"; + } + } + + public final static class Operation { + // Number of operation calls (Counter) + public final static String Calls = "op.calls"; + + // Total latency (across requests including retries) of the operation (Timer) + public final static String Latency = "op.latency"; + + // Actual item count - relevant for non-point-operations - indicating the actual number of + // docs returned in the response (DistributionSummary) + public final static String ActualItemCount = "op.actualItemCount"; + + // Max. item count - relevant for non-point-operations - indicating the requested max. number of + // docs returned in a single response (DistributionSummary) + public final static String MaxItemCount = "op.maxItemCount"; + + // Request charge for the operation (DistributionSummary) + public final static String RequestCharge = "op.RUs"; + + // Number of regions contacted for processing the operation (DistributionSummary) + public final static String RegionsContacted = "op.regionsContacted"; + } + + public final static class Request { + + // Size of the request payload (DistributionSummary) + public final static String RequestPayloadSize = "req.reqPayloadSize"; + + // Size of the response payload (DistributionSummary) + public final static String ResponsePayloadSize = "req.rspPayloadSize"; + + public final static class Direct { + // Backend-latency of the request (DistributionSummary) + public final static String BackendLatency = "req.rntbd.backendLatency"; + + // Latency of the request (Timer) + public final static String Latency = "req.rntbd.latency"; + + // Request charge for a request (DistributionSummary) + public final static String RequestCharge = "req.rntbd.RUs"; + + // Number of requests (Counter) + public final static String Requests = "req.rntbd.requests"; + + // Set of latencies in different steps of the request pipeline (all Timers) + public final static String TimelinePrefix = "req.rntbd.timeline."; + } + + public final static class Gateway { + // Latency of the request (Timer) + public final static String Latency = "req.gw.latency"; + + // Request charge for a request (DistributionSummary) + public final static String RequestCharge = "req.gw.RUs"; + + // Number of requests (Counter) + public final static String Requests = "req.gw.requests"; + + // Set of latencies in different steps of the request pipeline (all Timers) + public final static String TimelinePrefix = "req.gw.timeline."; + } + } + + public final static class System { + // JVM's Free available memory (DistributionSummary) + public final static String FreeMemoryAvailable = "system.freeMemoryAvailable"; + + // Avg. system-wide CPU load (DistributionSummary) + public final static String AvgCpuLoad = "system.avgCpuLoad"; + } + + public final static class DisabledByDefaultLegacy { + + public final static String LegacyDirectTcpMetricsPrefix = "azure.cosmos.directTcp."; + + public final static class RntbdRequestEndpointStatistics { + + // Snapshot of acquired channels for the endpoint at time of request (DistributionSummary) + public final static String AcquiredChannels = "req.rntbd.stats.endpoint.acquiredChannels"; + + // Snapshot of available channels for the endpoint at time of request (DistributionSummary) + public final static String AvailableChannels = "req.rntbd.stats.endpoint.availableChannels"; + + // Snapshot of number of inflight requests for the endpoint at time of request (DistributionSummary) + public final static String InflightRequests = "req.rntbd.stats.endpoint.inflightRequests"; + } + } +} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/MetricCategory.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/MetricCategory.java new file mode 100644 index 0000000000000..be8adf7178501 --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/MetricCategory.java @@ -0,0 +1,47 @@ +package com.azure.cosmos.implementation.clienttelemetry; + +import java.util.EnumSet; +import java.util.Locale; + +public enum MetricCategory { + OperationSummary("OperationSummary", 1 << 0), + OperationDetails("OperationDetails", 1 << 1), + RequestSummary("RequestSummary", 1 << 2), + RequestDetails("RequestDetails", 1 << 3), + AddressResolutions("AddressResolutions", 1 << 4), + DirectChannels("DirectChannels", 1 << 5), + DirectEndpoints("DirectEndpoints", 1 << 6), + DirectRequests("DirectRequests", 1 << 7), + System("System", 1 << 8), + Legacy("Legacy", 1 << 9); + + private final int value; + private final String stringValue; + private final String toLowerStringValue; + + MetricCategory(String stringValue, int value) { + this.stringValue = stringValue; + this.value = value; + this.toLowerStringValue = stringValue.toLowerCase(Locale.ROOT); + } + + @Override + public String toString() { + return this.stringValue; + } + + public String toLowerCase() { + return this.toLowerStringValue; + } + + public int value() { + return this.value; + } + + public static final EnumSet DEFAULT_CATEGORIES = EnumSet.of( + MetricCategory.OperationSummary, + MetricCategory.RequestSummary, + MetricCategory.DirectRequests, + MetricCategory.DirectChannels + ); +} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/RntbdTransportClient.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/RntbdTransportClient.java index 1b4865ce38888..487bfa7152575 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/RntbdTransportClient.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/RntbdTransportClient.java @@ -9,11 +9,13 @@ import com.azure.cosmos.implementation.ConnectionPolicy; import com.azure.cosmos.implementation.GlobalEndpointManager; import com.azure.cosmos.implementation.GoneException; +import com.azure.cosmos.implementation.ImplementationBridgeHelpers; import com.azure.cosmos.implementation.OpenConnectionResponse; import com.azure.cosmos.implementation.RequestTimeline; import com.azure.cosmos.implementation.RxDocumentServiceRequest; import com.azure.cosmos.implementation.UserAgentContainer; import com.azure.cosmos.implementation.clienttelemetry.ClientTelemetry; +import com.azure.cosmos.implementation.clienttelemetry.MetricCategory; import com.azure.cosmos.implementation.directconnectivity.rntbd.*; import com.azure.cosmos.implementation.guava25.base.Strings; import com.fasterxml.jackson.annotation.JsonCreator; @@ -37,6 +39,7 @@ import java.io.InputStream; import java.net.URI; import java.time.Duration; +import java.util.EnumSet; import java.util.Iterator; import java.util.Locale; import java.util.concurrent.CancellationException; @@ -90,6 +93,7 @@ public class RntbdTransportClient extends TransportClient { private final Tag tag; private boolean channelAcquisitionContextEnabled; private final GlobalEndpointManager globalEndpointManager; + private final EnumSet metricCategories; // endregion @@ -126,6 +130,7 @@ public RntbdTransportClient( this.id = instanceCount.incrementAndGet(); this.tag = RntbdTransportClient.tag(this.id); this.globalEndpointManager = null; + this.metricCategories = MetricCategory.DEFAULT_CATEGORIES; } RntbdTransportClient( @@ -146,6 +151,16 @@ public RntbdTransportClient( this.tag = RntbdTransportClient.tag(this.id); this.channelAcquisitionContextEnabled = options.channelAcquisitionContextEnabled; this.globalEndpointManager = globalEndpointManager; + if (clientTelemetry != null && + clientTelemetry.getClientTelemetryConfig() != null) { + + this.metricCategories = ImplementationBridgeHelpers + .CosmosClientTelemetryConfigHelper + .getCosmosClientTelemetryConfigAccessor() + .getMetricCategories(clientTelemetry.getClientTelemetryConfig()); + } else { + this.metricCategories = MetricCategory.DEFAULT_CATEGORIES; + } } // endregion @@ -355,6 +370,10 @@ private void throwIfClosed() { } } + public EnumSet getMetricCategories() { + return this.metricCategories; + } + // endregion // region Types @@ -622,7 +641,6 @@ public int transientTimeoutDetectionThreshold() { return this.transientTimeoutDetectionThreshold; } - // endregion // region Methods diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdClientChannelPool.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdClientChannelPool.java index 34d99894b56ca..9bbe281f8751a 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdClientChannelPool.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdClientChannelPool.java @@ -48,6 +48,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import static com.azure.cosmos.implementation.directconnectivity.rntbd.RntbdReporter.reportIssueUnless; @@ -167,6 +169,8 @@ public final class RntbdClientChannelPool implements ChannelPool { private final int maxRequestsPerChannel; private final ChannelPoolHandler poolHandler; private final boolean releaseHealthCheck; + private final AtomicInteger totalAcquiredChannels = new AtomicInteger(0); + private final AtomicInteger totalClosedChannels = new AtomicInteger(0); // Because state from these fields can be requested on any thread... @@ -319,6 +323,24 @@ public int channelsAcquiredMetrics() { return this.acquiredChannels.size(); } + /** + * Gets the total acquired channel count. + * + * @return the total acquired channel count. + */ + public int totalChannelsAcquiredMetrics() { + return this.totalAcquiredChannels.get(); + } + + /** + * Gets the total closed channel count. + * + * @return the total closed channel count. + */ + public int totalChannelsClosedMetrics() { + return this.totalClosedChannels.get(); + } + /** * Gets the current available channel count. * @@ -816,6 +838,7 @@ private void addTaskToPendingAcquisitionQueue(ChannelPromiseWithExpiryTime promi */ private void closeChannel(final Channel channel) { this.ensureInEventLoop(); + totalClosedChannels.incrementAndGet(); this.acquiredChannels.remove(channel); this.availableChannels.remove(channel); channel.attr(POOL_KEY).set(null); @@ -877,6 +900,7 @@ private double computeLoadFactor() { private void doAcquireChannel(final ChannelPromiseWithExpiryTime promise, final Channel candidate) { this.ensureInEventLoop(); acquiredChannels.put(candidate, candidate); + totalAcquiredChannels.incrementAndGet(); final ChannelPromiseWithExpiryTime anotherPromise = this.newChannelPromiseForAvailableChannel(promise, candidate); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdEndpoint.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdEndpoint.java index 8cf8029d7ffb2..bafc70dc29bf8 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdEndpoint.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdEndpoint.java @@ -30,6 +30,16 @@ public interface RntbdEndpoint extends AutoCloseable { */ int channelsAcquiredMetric(); + /** + * @return total number of acquired channels. + */ + int totalChannelsAcquiredMetric(); + + /** + * @return total number of closed channels. + */ + int totalChannelsClosedMetric(); + /** * @return approximate number of available channels. */ diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdMetrics.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdMetrics.java index 32355df37aa84..db9df787ee817 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdMetrics.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdMetrics.java @@ -4,6 +4,7 @@ package com.azure.cosmos.implementation.directconnectivity.rntbd; import com.azure.cosmos.implementation.ConsoleLoggingRegistryFactory; +import com.azure.cosmos.implementation.clienttelemetry.CosmosMetricNames; import com.azure.cosmos.implementation.directconnectivity.RntbdTransportClient; import com.azure.cosmos.implementation.guava25.net.PercentEscaper; import com.fasterxml.jackson.annotation.JsonProperty; @@ -262,7 +263,7 @@ static String escape(String value) { } private static String nameOf(final String member) { - return "azure.cosmos.directTcp." + member; + return CosmosMetricNames.DisabledByDefaultLegacy.LegacyDirectTcpMetricsPrefix + member; } // endregion diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdMetricsCompletionRecorder.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdMetricsCompletionRecorder.java index a425711031345..48fd14ec107e4 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdMetricsCompletionRecorder.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdMetricsCompletionRecorder.java @@ -4,5 +4,16 @@ package com.azure.cosmos.implementation.directconnectivity.rntbd; public interface RntbdMetricsCompletionRecorder { + public final static RntbdMetricsCompletionRecorder NoOpSingletonInstance = new NoOpRecorder(); void markComplete(RntbdRequestRecord requestRecord); + + public final static class NoOpRecorder implements RntbdMetricsCompletionRecorder { + + private NoOpRecorder() {} + + @Override + public void markComplete(RntbdRequestRecord requestRecord) { + requestRecord.stop(); + } + } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdRequestArgs.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdRequestArgs.java index 523b4e6e4a786..9aca9c70986ab 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdRequestArgs.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdRequestArgs.java @@ -17,6 +17,7 @@ import java.time.Duration; import java.time.Instant; import java.util.UUID; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -107,10 +108,13 @@ public long transportRequestId() { // region Methods + public void stop() { + this.lifetime.stop(); + } + public long stop(Timer requests, Timer responses) { this.lifetime.stop(); - this.sample.stop(requests); - return this.sample.stop(responses); + return this.lifetime.elapsed(TimeUnit.MILLISECONDS); } @Override diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdRequestRecord.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdRequestRecord.java index db675142b6a26..8134e0004c26f 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdRequestRecord.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdRequestRecord.java @@ -320,8 +320,12 @@ public RequestTimeline takeTimelineSnapshot() { timeCompleted, now)); } - public long stop(Timer requests, Timer responses) { - return this.args.stop(requests, responses); + public void stop() { + this.args.stop(); + } + + public void stop(Timer requests, Timer responses) { + this.args.stop(requests, responses); } @Override diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdServiceEndpoint.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdServiceEndpoint.java index c8c685d15491e..c19bf08db8bda 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdServiceEndpoint.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdServiceEndpoint.java @@ -9,6 +9,7 @@ import com.azure.cosmos.implementation.HttpConstants; import com.azure.cosmos.implementation.clienttelemetry.ClientTelemetry; import com.azure.cosmos.implementation.clienttelemetry.ClientTelemetryMetrics; +import com.azure.cosmos.implementation.clienttelemetry.MetricCategory; import com.azure.cosmos.implementation.clienttelemetry.TagName; import com.azure.cosmos.implementation.directconnectivity.IAddressResolver; import com.azure.cosmos.implementation.directconnectivity.RntbdTransportClient; @@ -133,7 +134,13 @@ private RntbdServiceEndpoint( this.channelPool = new RntbdClientChannelPool(this, bootstrap, config, clientTelemetry, this.connectionStateListener); if (clientTelemetry != null && - clientTelemetry.isClientMetricsEnabled()) { + clientTelemetry.isClientMetricsEnabled() && + ( + provider.transportClient.getMetricCategories().contains(MetricCategory.DirectEndpoints) + || provider.transportClient.getMetricCategories().contains(MetricCategory.DirectChannels) + || provider.transportClient.getMetricCategories().contains(MetricCategory.DirectRequests) + ) + ) { RntbdMetricsCompletionRecorder rntbdMetricsV2 = ClientTelemetryMetrics.createRntbdMetrics(provider.transportClient, this); @@ -149,7 +156,11 @@ private RntbdServiceEndpoint( } } else { - this.metricsComplectionRecorder = RntbdMetrics.create(provider.transportClient, this); + if (RntbdMetrics.isEmpty()) { + this.metricsComplectionRecorder = RntbdMetricsCompletionRecorder.NoOpSingletonInstance; + } else { + this.metricsComplectionRecorder = RntbdMetrics.create(provider.transportClient, this); + } } } @@ -191,6 +202,22 @@ public int channelsAcquiredMetric() { return this.channelPool.channelsAcquiredMetrics(); } + /** + * @return approximate number of acquired channels. + */ + @Override + public int totalChannelsAcquiredMetric() { + return this.channelPool.totalChannelsAcquiredMetrics(); + } + + /** + * @return approximate number of closed channels. + */ + @Override + public int totalChannelsClosedMetric() { + return this.channelPool.totalChannelsClosedMetrics(); + } + /** * @return approximate number of available channels. */ diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java index f920d745d158a..be767e7fdd2e8 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java @@ -5,15 +5,13 @@ import com.azure.core.http.ProxyOptions; import com.azure.core.util.MetricsOptions; -import com.azure.cosmos.CosmosClient; -import com.azure.cosmos.CosmosClientBuilder; import com.azure.cosmos.implementation.Configs; import com.azure.cosmos.implementation.ImplementationBridgeHelpers; import com.azure.cosmos.implementation.Strings; import com.azure.cosmos.implementation.Utils; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; +import com.azure.cosmos.implementation.clienttelemetry.MetricCategory; import com.azure.cosmos.implementation.clienttelemetry.TagName; -import com.azure.cosmos.util.Beta; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import io.micrometer.core.instrument.MeterRegistry; @@ -57,6 +55,7 @@ public final class CosmosClientTelemetryConfig { private final ProxyOptions proxy; private String clientCorrelationId = null; private EnumSet metricTagNames = DEFAULT_TAGS; + private EnumSet metricCategories = MetricCategory.DEFAULT_CATEGORIES; private MeterRegistry clientMetricRegistry = null; private boolean isClientMetricsEnabled = false; @@ -205,6 +204,62 @@ EnumSet getMetricTagNames() { return this.metricTagNames; } + /** + * Sets the categories of metrics that should be emitted. By default the following categories will be enabled: + * OperationSummary, RequestSummary, DirectChannels, DirectRequests, System + * (the System and OperationSummary metrics are always collected and can't be disabled when enabling Cosmos metrics) + * For most use-cases that should be sufficient. An overview of the different metric categories can be found here: + * https://aka.ms/azure-cosmos-metrics + * + * @param categories - a comma-separated list of metric categories that should be emitted + * @return current CosmosClientTelemetryConfig + */ + public CosmosClientTelemetryConfig metricCategories(String... categories) { + if (categories == null || categories.length == 0) { + this.metricCategories = MetricCategory.DEFAULT_CATEGORIES; + } + + Map categoryMap = new HashMap<>(); + for (MetricCategory level : MetricCategory.values()) { + categoryMap.put(level.toLowerCase(), level); + } + + Stream categoryStream = + Arrays.stream(categories) + .map(rawCategory -> rawCategory.toLowerCase(Locale.ROOT)) + .filter(category -> !Strings.isNullOrWhiteSpace(category)) + .map(category -> { + String trimmedCategory = category.trim(); + + if (!categoryMap.containsKey(trimmedCategory)) { + + String validCategories = String.join( + ", ", + (String[]) Arrays.stream(MetricCategory.values()).map(level -> level.toString()).toArray()); + + throw new IllegalArgumentException( + String.format( + "Metric category '%s' is invalid. Valid Metric categories are:" + + " %s", + category, + validCategories)); + } + + return categoryMap.get(trimmedCategory); + }); + + EnumSet newCategories = EnumSet.of(MetricCategory.System, MetricCategory.OperationSummary); + categoryStream.forEach(category -> newCategories.add(category)); + + this.metricCategories= newCategories; + + return this; + } + + EnumSet getMetricCategories() { + return this.metricCategories; + } + Duration getHttpNetworkRequestTimeout() { return this.httpNetworkRequestTimeout; } @@ -314,6 +369,11 @@ public ProxyOptions getProxy(CosmosClientTelemetryConfig config) { return config.getProxy(); } + @Override + public EnumSet getMetricCategories(CosmosClientTelemetryConfig config) { + return config.getMetricCategories(); + } + @Override public EnumSet getMetricTagNames(CosmosClientTelemetryConfig config) { return config.getMetricTagNames(); diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/RntbdTransportClientTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/RntbdTransportClientTest.java index 7d59a7386dc27..f399875aee25c 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/RntbdTransportClientTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/RntbdTransportClientTest.java @@ -980,6 +980,16 @@ public int channelsAcquiredMetric() { return 0; } + @Override + public int totalChannelsAcquiredMetric() { + return 0; + } + + @Override + public int totalChannelsClosedMetric() { + return 0; + } + @Override public int channelsAvailableMetric() { return 0; From f2faf85df331e531e2cff66f53d6a836f2f180cb Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Fri, 10 Feb 2023 19:57:16 +0000 Subject: [PATCH 02/40] Updating changelogs --- sdk/cosmos/azure-cosmos-spark_3-1_2-12/CHANGELOG.md | 2 +- sdk/cosmos/azure-cosmos-spark_3-2_2-12/CHANGELOG.md | 2 +- sdk/cosmos/azure-cosmos-spark_3-3_2-12/CHANGELOG.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/cosmos/azure-cosmos-spark_3-1_2-12/CHANGELOG.md b/sdk/cosmos/azure-cosmos-spark_3-1_2-12/CHANGELOG.md index d0a36682dde4d..ebc56c40ed55e 100644 --- a/sdk/cosmos/azure-cosmos-spark_3-1_2-12/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos-spark_3-1_2-12/CHANGELOG.md @@ -3,7 +3,7 @@ ### 4.17.0-beta.1 (Unreleased) #### Features Added -* Added Service Principle based AAD Auth - See [PR 32393](https://github.com/Azure/azure-sdk-for-java/pull/32393) +* Added Service Principle based AAD Auth - See [PR 32393](https://github.com/Azure/azure-sdk-for-java/pull/32393) and [PR 33449](https://github.com/Azure/azure-sdk-for-java/pull/33449) * Added capability to allow modification of throughput in Spark via `ALTER TABLE` or `ALTER DATABASE` command. - See [PR 33369](https://github.com/Azure/azure-sdk-for-java/pull/33369) #### Breaking Changes diff --git a/sdk/cosmos/azure-cosmos-spark_3-2_2-12/CHANGELOG.md b/sdk/cosmos/azure-cosmos-spark_3-2_2-12/CHANGELOG.md index 4403683fd992e..e0f42e705d9b6 100644 --- a/sdk/cosmos/azure-cosmos-spark_3-2_2-12/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos-spark_3-2_2-12/CHANGELOG.md @@ -3,7 +3,7 @@ ### 4.17.0-beta.1 (Unreleased) #### Features Added -* Added Service Principle based AAD Auth - See [PR 32393](https://github.com/Azure/azure-sdk-for-java/pull/32393) +* Added Service Principle based AAD Auth - See [PR 32393](https://github.com/Azure/azure-sdk-for-java/pull/32393) and [PR 33449](https://github.com/Azure/azure-sdk-for-java/pull/33449) * Added capability to allow modification of throughput in Spark via `ALTER TABLE` or `ALTER DATABASE` command. - See [PR 33369](https://github.com/Azure/azure-sdk-for-java/pull/33369) #### Breaking Changes diff --git a/sdk/cosmos/azure-cosmos-spark_3-3_2-12/CHANGELOG.md b/sdk/cosmos/azure-cosmos-spark_3-3_2-12/CHANGELOG.md index e521ba5ac27b6..71f2bf650cc28 100644 --- a/sdk/cosmos/azure-cosmos-spark_3-3_2-12/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos-spark_3-3_2-12/CHANGELOG.md @@ -3,7 +3,7 @@ ### 4.17.0-beta.1 (Unreleased) #### Features Added -* Added Service Principle based AAD Auth - See [PR 32393](https://github.com/Azure/azure-sdk-for-java/pull/32393) +* Added Service Principle based AAD Auth - See [PR 32393](https://github.com/Azure/azure-sdk-for-java/pull/32393) and [PR 33449](https://github.com/Azure/azure-sdk-for-java/pull/33449) * Added capability to allow modification of throughput in Spark via `ALTER TABLE` or `ALTER DATABASE` command. - See [PR 33369](https://github.com/Azure/azure-sdk-for-java/pull/33369) #### Breaking Changes From 94ec79f1024aaaecc7646b86e92a9eed7fb487d4 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Fri, 10 Feb 2023 21:29:12 +0000 Subject: [PATCH 03/40] Small refactoring removing unnecessary metricTagNames/metricCategories fields in AsyncDoclmplementations --- .../com/azure/cosmos/CosmosAsyncClient.java | 2 -- .../implementation/AsyncDocumentClient.java | 20 +-------------- .../implementation/RxDocumentClientImpl.java | 25 ++++++------------- .../clienttelemetry/MetricCategory.java | 2 ++ .../RxDocumentClientImplTest.java | 3 +-- .../RxDocumentClientUnderTest.java | 5 +--- .../SpyClientUnderTestFactory.java | 3 +-- .../BarrierRequestHelperTest.java | 3 +-- 8 files changed, 14 insertions(+), 49 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java index f8ebf00733e74..0cc86a19fc78c 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java @@ -171,8 +171,6 @@ public final class CosmosAsyncClient implements Closeable { .withApiType(this.apiType) .withClientTelemetryConfig(this.clientTelemetryConfig) .withClientCorrelationId(this.clientCorrelationId) - .withMetricTagNames(this.metricTagNames) - .withMetricCategories(this.metricCategories) .build(); String effectiveClientCorrelationId = this.asyncDocumentClient.getClientCorrelationId(); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/AsyncDocumentClient.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/AsyncDocumentClient.java index 76448b0c62926..7461d373137ea 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/AsyncDocumentClient.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/AsyncDocumentClient.java @@ -11,8 +11,6 @@ import com.azure.cosmos.implementation.caches.RxClientCollectionCache; import com.azure.cosmos.implementation.caches.RxPartitionKeyRangeCache; import com.azure.cosmos.implementation.clienttelemetry.ClientTelemetry; -import com.azure.cosmos.implementation.clienttelemetry.MetricCategory; -import com.azure.cosmos.implementation.clienttelemetry.TagName; import com.azure.cosmos.implementation.query.PartitionedQueryExecutionInfo; import com.azure.cosmos.implementation.throughputControl.config.ThroughputControlGroupInternal; import com.azure.cosmos.models.CosmosClientTelemetryConfig; @@ -31,7 +29,6 @@ import java.net.URI; import java.net.URISyntaxException; -import java.util.EnumSet; import java.util.List; import java.util.Map; @@ -99,8 +96,6 @@ class Builder { private ApiType apiType; CosmosClientTelemetryConfig clientTelemetryConfig; private String clientCorrelationId = null; - private EnumSet metricTagNames = EnumSet.allOf(TagName.class); - private EnumSet metricCategories = MetricCategory.DEFAULT_CATEGORIES; public Builder withServiceEndpoint(String serviceEndpoint) { try { @@ -127,18 +122,6 @@ public Builder withClientCorrelationId(String clientCorrelationId) { return this; } - public Builder withMetricTagNames(EnumSet tagNames) { - this.metricTagNames = tagNames; - - return this; - } - - public Builder withMetricCategories(EnumSet categories) { - this.metricCategories = categories; - - return this; - } - /** * New method withMasterKeyOrResourceToken will take either master key or resource token * and perform authentication for accessing resource. @@ -281,8 +264,7 @@ public AsyncDocumentClient build() { state, apiType, clientTelemetryConfig, - clientCorrelationId, - metricTagNames); + clientCorrelationId); client.init(state, null); return client; diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java index 50c458e859955..fe6863b645860 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java @@ -21,7 +21,6 @@ import com.azure.cosmos.implementation.caches.RxCollectionCache; import com.azure.cosmos.implementation.caches.RxPartitionKeyRangeCache; import com.azure.cosmos.implementation.clienttelemetry.ClientTelemetry; -import com.azure.cosmos.implementation.clienttelemetry.TagName; import com.azure.cosmos.implementation.cpu.CpuMemoryListener; import com.azure.cosmos.implementation.cpu.CpuMemoryMonitor; import com.azure.cosmos.implementation.directconnectivity.GatewayServiceConfigurationReader; @@ -86,7 +85,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -188,7 +186,6 @@ public class RxDocumentClientImpl implements AsyncDocumentClient, IAuthorization private ThroughputControlStore throughputControlStore; private final CosmosClientTelemetryConfig clientTelemetryConfig; private final String clientCorrelationId; - private final EnumSet metricTagNames; public RxDocumentClientImpl(URI serviceEndpoint, String masterKeyOrResourceToken, @@ -204,8 +201,7 @@ public RxDocumentClientImpl(URI serviceEndpoint, CosmosClientMetadataCachesSnapshot metadataCachesSnapshot, ApiType apiType, CosmosClientTelemetryConfig clientTelemetryConfig, - String clientCorrelationId, - EnumSet tagNames) { + String clientCorrelationId) { this( serviceEndpoint, masterKeyOrResourceToken, @@ -221,8 +217,7 @@ public RxDocumentClientImpl(URI serviceEndpoint, metadataCachesSnapshot, apiType, clientTelemetryConfig, - clientCorrelationId, - tagNames); + clientCorrelationId); this.cosmosAuthorizationTokenResolver = cosmosAuthorizationTokenResolver; } @@ -241,8 +236,7 @@ public RxDocumentClientImpl(URI serviceEndpoint, CosmosClientMetadataCachesSnapshot metadataCachesSnapshot, ApiType apiType, CosmosClientTelemetryConfig clientTelemetryConfig, - String clientCorrelationId, - EnumSet tagNames) { + String clientCorrelationId) { this( serviceEndpoint, masterKeyOrResourceToken, @@ -258,8 +252,7 @@ public RxDocumentClientImpl(URI serviceEndpoint, metadataCachesSnapshot, apiType, clientTelemetryConfig, - clientCorrelationId, - tagNames); + clientCorrelationId); this.cosmosAuthorizationTokenResolver = cosmosAuthorizationTokenResolver; } @@ -277,8 +270,7 @@ private RxDocumentClientImpl(URI serviceEndpoint, CosmosClientMetadataCachesSnapshot metadataCachesSnapshot, ApiType apiType, CosmosClientTelemetryConfig clientTelemetryConfig, - String clientCorrelationId, - EnumSet tagNames) { + String clientCorrelationId) { this( serviceEndpoint, masterKeyOrResourceToken, @@ -293,8 +285,7 @@ private RxDocumentClientImpl(URI serviceEndpoint, metadataCachesSnapshot, apiType, clientTelemetryConfig, - clientCorrelationId, - tagNames); + clientCorrelationId); if (permissionFeed != null && permissionFeed.size() > 0) { this.resourceTokensMap = new HashMap<>(); @@ -351,8 +342,7 @@ private RxDocumentClientImpl(URI serviceEndpoint, CosmosClientMetadataCachesSnapshot metadataCachesSnapshot, ApiType apiType, CosmosClientTelemetryConfig clientTelemetryConfig, - String clientCorrelationId, - EnumSet tagNames) { + String clientCorrelationId) { assert(clientTelemetryConfig != null); Boolean clientTelemetryEnabled = ImplementationBridgeHelpers @@ -364,7 +354,6 @@ private RxDocumentClientImpl(URI serviceEndpoint, this.clientId = clientIdGenerator.incrementAndGet(); this.clientCorrelationId = Strings.isNullOrWhiteSpace(clientCorrelationId) ? String.format("%05d",this.clientId): clientCorrelationId; - this.metricTagNames = tagNames; clientMap.put(serviceEndpoint.toString(), clientMap.getOrDefault(serviceEndpoint.toString(), 0) + 1); this.diagnosticsClientConfig = new DiagnosticsClientConfig(); this.diagnosticsClientConfig.withClientId(this.clientId); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/MetricCategory.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/MetricCategory.java index be8adf7178501..2425836f6e59b 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/MetricCategory.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/MetricCategory.java @@ -1,3 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. package com.azure.cosmos.implementation.clienttelemetry; import java.util.EnumSet; diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/RxDocumentClientImplTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/RxDocumentClientImplTest.java index aec8f157d5923..45bb8eba26715 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/RxDocumentClientImplTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/RxDocumentClientImplTest.java @@ -208,8 +208,7 @@ public void readMany() { this.metadataCachesSnapshotMock, this.apiTypeMock, this.cosmosClientTelemetryConfigMock, - this.clientCorrelationIdMock, - null + this.clientCorrelationIdMock ); ReflectionUtils.setCollectionCache(rxDocumentClient, this.collectionCacheMock); diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/RxDocumentClientUnderTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/RxDocumentClientUnderTest.java index 1960ad2c46130..a76d37a18bd0d 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/RxDocumentClientUnderTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/RxDocumentClientUnderTest.java @@ -5,7 +5,6 @@ import com.azure.core.credential.AzureKeyCredential; import com.azure.cosmos.ClientUnderTestBuilder; import com.azure.cosmos.ConsistencyLevel; -import com.azure.cosmos.implementation.clienttelemetry.TagName; import com.azure.cosmos.implementation.http.HttpClient; import com.azure.cosmos.implementation.http.HttpRequest; import com.azure.cosmos.implementation.http.HttpResponse; @@ -18,7 +17,6 @@ import java.time.Duration; import java.util.ArrayList; import java.util.Collections; -import java.util.EnumSet; import java.util.List; import static org.mockito.Mockito.doAnswer; @@ -57,8 +55,7 @@ public RxDocumentClientUnderTest(URI serviceEndpoint, null, apiType, clientTelemetryConfig, - null, - EnumSet.allOf(TagName.class)); + null); init(null, null); } diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/SpyClientUnderTestFactory.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/SpyClientUnderTestFactory.java index 6b200dd1e577c..00a2ea261dbbb 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/SpyClientUnderTestFactory.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/SpyClientUnderTestFactory.java @@ -61,8 +61,7 @@ public SpyBaseClass( null, null, clientTelemetryConfig, - null, - EnumSet.allOf(TagName.class)); + null); } public abstract List getCapturedRequests(); diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/BarrierRequestHelperTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/BarrierRequestHelperTest.java index 37b7a29252c2e..3f070c3ea996a 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/BarrierRequestHelperTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/BarrierRequestHelperTest.java @@ -179,8 +179,7 @@ public void barrierWithAadAuthorizationTokenProviderType() throws URISyntaxExcep null, null, new CosmosClientTelemetryConfig().sendClientTelemetryToService(false), - null, - EnumSet.allOf(TagName.class)); + null); ResourceType resourceType = ResourceType.DocumentCollection; OperationType operationType = OperationType.Read; From 1edf43dbbd2de4482df02193f8b78675d8b24010 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Fri, 10 Feb 2023 21:33:59 +0000 Subject: [PATCH 04/40] Linting fixes --- .../clienttelemetry/ClientTelemetryMetrics.java | 3 ++- .../directconnectivity/rntbd/RntbdRequestArgs.java | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java index f69fa62253d2d..8bce98111a151 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java @@ -560,7 +560,7 @@ private Tags createAddressResolutionTags( } private void recordRntbdEndpointStatistics(RntbdEndpointStatistics endpointStatistics, Tags requestTags) { - if (endpointStatistics == null && this.metricCategories.contains(MetricCategory.Legacy)) { + if (endpointStatistics == null || !this.metricCategories.contains(MetricCategory.Legacy)) { return; } @@ -574,6 +574,7 @@ private void recordRntbdEndpointStatistics(RntbdEndpointStatistics endpointStati .publishPercentileHistogram(false) .tags(requestTags) .register(compositeRegistry); + acquiredChannelsMeter.record(endpointStatistics.getAcquiredChannels()); DistributionSummary availableChannelsMeter = DistributionSummary diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdRequestArgs.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdRequestArgs.java index 9aca9c70986ab..3c1daecb2333f 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdRequestArgs.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdRequestArgs.java @@ -17,7 +17,6 @@ import java.time.Duration; import java.time.Instant; import java.util.UUID; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -114,7 +113,8 @@ public void stop() { public long stop(Timer requests, Timer responses) { this.lifetime.stop(); - return this.lifetime.elapsed(TimeUnit.MILLISECONDS); + this.sample.stop(requests); + return this.sample.stop(responses); } @Override From 37fbe707e6ae5abc32c7a87f756045d48725dd53 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Sat, 11 Feb 2023 00:06:01 +0000 Subject: [PATCH 05/40] Fixing test regressions --- .../clienttelemetry/ClientTelemetry.java | 2 + .../rntbd/RntbdClientChannelPool.java | 4 +- .../com/azure/cosmos/ClientMetricsTest.java | 41 ++++++++++++------- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetry.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetry.java index 4c776c7abeb0b..cd62c7ede9ab5 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetry.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetry.java @@ -26,6 +26,7 @@ import com.azure.cosmos.implementation.http.HttpRequest; import com.azure.cosmos.implementation.http.HttpResponse; import com.azure.cosmos.models.CosmosClientTelemetryConfig; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.handler.codec.http.HttpMethod; @@ -163,6 +164,7 @@ public ClientTelemetryInfo getClientTelemetryInfo() { return clientTelemetryInfo; } + @JsonIgnore public CosmosClientTelemetryConfig getClientTelemetryConfig() { return clientTelemetryConfig; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdClientChannelPool.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdClientChannelPool.java index 9bbe281f8751a..8862e4c8885c3 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdClientChannelPool.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdClientChannelPool.java @@ -49,7 +49,6 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import static com.azure.cosmos.implementation.directconnectivity.rntbd.RntbdReporter.reportIssueUnless; @@ -900,7 +899,6 @@ private double computeLoadFactor() { private void doAcquireChannel(final ChannelPromiseWithExpiryTime promise, final Channel candidate) { this.ensureInEventLoop(); acquiredChannels.put(candidate, candidate); - totalAcquiredChannels.incrementAndGet(); final ChannelPromiseWithExpiryTime anotherPromise = this.newChannelPromiseForAvailableChannel(promise, candidate); @@ -1174,6 +1172,8 @@ private void notifyChannelConnect(final ChannelFuture future, final Promise { reportIssueUnless(logger, acquiredChannel == null, this, "Channel({}) to be acquired has already been acquired", diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java index 63ac6d8b0157c..80b7253944ee7 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java @@ -331,9 +331,11 @@ public void readAllItems() throws Exception { this.assertMetrics("cosmos.client.req.rntbd", false, queryPlanTag); this.assertMetrics("cosmos.client.req.gw.requests", true, queryPlanTag); this.assertMetrics("cosmos.client.req.gw.RUs", false, queryPlanTag); - this.assertMetrics("cosmos.client.req.gw.timeline", true, queryPlanTag); - this.assertMetrics("cosmos.client.op.maxItemCount", true); + // @fabianm TODO add back test coverage + // this.assertMetrics("cosmos.client.req.gw.timeline", true, queryPlanTag); + + // this.assertMetrics("cosmos.client.op.maxItemCount", true); } finally { this.afterTest(); } @@ -633,8 +635,9 @@ private void validateMetrics(int minRu, int maxRu) { } private void validateItemCountMetrics(Tag expectedOperationTag) { - this.assertMetrics("cosmos.client.op.maxItemCount", true, expectedOperationTag); - this.assertMetrics("cosmos.client.op.actualItemCount", true, expectedOperationTag); + // @fabianm TODO add back test coverage + // this.assertMetrics("cosmos.client.op.maxItemCount", true, expectedOperationTag); + // this.assertMetrics("cosmos.client.op.actualItemCount", true, expectedOperationTag); } private void validateReasonableRUs(Meter reportedRequestChargeMeter, int expectedMinRu, int expectedMaxRu) { @@ -654,12 +657,13 @@ private void validateMetrics(Tag expectedOperationTag, Tag expectedRequestTag, i "cosmos.client.op.RUs", true, expectedOperationTag); validateReasonableRUs(reportedOpRequestCharge, minRu, maxRu); - this.assertMetrics("cosmos.client.op.regionsContacted", true, expectedOperationTag); + // @fabianm TODO add back test coverage + // this.assertMetrics("cosmos.client.op.regionsContacted", true, expectedOperationTag); - this.assertMetrics( - "cosmos.client.op.regionsContacted", - true, - Tag.of(TagName.RegionName.toString(), this.preferredRegion)); + // this.assertMetrics( + // "cosmos.client.op.regionsContacted", + // true, + // Tag.of(TagName.RegionName.toString(), this.preferredRegion)); if (this.client.asyncClient().getConnectionPolicy().getConnectionMode() == ConnectionMode.DIRECT) { this.assertMetrics("cosmos.client.req.rntbd.latency", true, expectedRequestTag); @@ -672,19 +676,26 @@ private void validateMetrics(Tag expectedOperationTag, Tag expectedRequestTag, i Meter reportedRntbdRequestCharge = this.assertMetrics("cosmos.client.req.rntbd.RUs", true, expectedRequestTag); validateReasonableRUs(reportedRntbdRequestCharge, minRu, maxRu); - this.assertMetrics("cosmos.client.req.rntbd.timeline", true, expectedRequestTag); + + // @fabianm TODO add back test coverage + //this.assertMetrics("cosmos.client.req.rntbd.timeline", true, expectedRequestTag); } else { this.assertMetrics("cosmos.client.req.gw.latency", true, expectedRequestTag); - this.assertMetrics( - "cosmos.client.req.gw.latency", - true, - Tag.of(TagName.RegionName.toString(), this.preferredRegion)); + + // @fabianm TODO add back test coverage + // this.assertMetrics( + // "cosmos.client.req.gw.latency", + // true, + // Tag.of(TagName.RegionName.toString(), this.preferredRegion)); this.assertMetrics("cosmos.client.req.gw.backendLatency", false, expectedRequestTag); this.assertMetrics("cosmos.client.req.gw.requests", true, expectedRequestTag); Meter reportedGatewayRequestCharge = this.assertMetrics("cosmos.client.req.gw.RUs", true, expectedRequestTag); validateReasonableRUs(reportedGatewayRequestCharge, minRu, maxRu); - this.assertMetrics("cosmos.client.req.gw.timeline", true, expectedRequestTag); + + // @fabianm TODO add back test coverage + //this.assertMetrics("cosmos.client.req.gw.timeline", true, expectedRequestTag); + this.assertMetrics("cosmos.client.req.rntbd", false); } } From cbdf1e203e36dfc677109bad27c1da600dd04d98 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Mon, 13 Feb 2023 18:26:35 +0000 Subject: [PATCH 06/40] Adding tests --- .../clienttelemetry/MetricCategory.java | 13 + .../models/CosmosClientTelemetryConfig.java | 36 ++- .../com/azure/cosmos/ClientMetricsTest.java | 240 +++++++++++++++--- 3 files changed, 249 insertions(+), 40 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/MetricCategory.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/MetricCategory.java index 2425836f6e59b..9f16c313fdaaa 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/MetricCategory.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/MetricCategory.java @@ -40,6 +40,19 @@ public int value() { return this.value; } + public static final EnumSet ALL_CATEGORIES = EnumSet.of( + MetricCategory.OperationSummary, + MetricCategory.OperationDetails, + MetricCategory.RequestSummary, + MetricCategory.RequestDetails, + MetricCategory.AddressResolutions, + MetricCategory.DirectChannels, + MetricCategory.DirectEndpoints, + MetricCategory.DirectRequests, + MetricCategory.System, + MetricCategory.Legacy + ); + public static final EnumSet DEFAULT_CATEGORIES = EnumSet.of( MetricCategory.OperationSummary, MetricCategory.RequestSummary, diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java index be767e7fdd2e8..11dcb217e488a 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java @@ -23,6 +23,7 @@ import java.util.Arrays; import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.stream.Stream; @@ -66,6 +67,7 @@ public final class CosmosClientTelemetryConfig { this.proxy = toBeCopied.proxy; this.clientCorrelationId = toBeCopied.clientCorrelationId; this.metricTagNames = toBeCopied.metricTagNames; + this.metricCategories = toBeCopied.metricCategories; this.clientMetricRegistry = toBeCopied.clientMetricRegistry; this.isClientMetricsEnabled = toBeCopied.isClientMetricsEnabled; this.clientTelemetryEnabled = effectiveIsClientTelemetryEnabled; @@ -224,18 +226,38 @@ public CosmosClientTelemetryConfig metricCategories(String... categories) { categoryMap.put(level.toLowerCase(), level); } + HashSet categoryStrings = new HashSet(); + Arrays.stream(categories) + .filter(category -> !Strings.isNullOrWhiteSpace(category)) + .forEach(rawCategory -> { + String lowerCaseCategory = rawCategory.trim().toLowerCase(Locale.ROOT); + if ("all".equalsIgnoreCase(lowerCaseCategory)) { + MetricCategory + .ALL_CATEGORIES + .stream() + .forEach(c -> categoryStrings.add(c.toLowerCase())); + } else if ("default".equalsIgnoreCase(lowerCaseCategory)) { + MetricCategory + .DEFAULT_CATEGORIES + .stream() + .forEach(c -> categoryStrings.add(c.toLowerCase())); + } else { + categoryStrings.add(lowerCaseCategory); + } + }); + Stream categoryStream = - Arrays.stream(categories) - .map(rawCategory -> rawCategory.toLowerCase(Locale.ROOT)) - .filter(category -> !Strings.isNullOrWhiteSpace(category)) + Arrays.stream(categoryStrings.toArray()) .map(category -> { - String trimmedCategory = category.trim(); + if (!categoryMap.containsKey(category)) { - if (!categoryMap.containsKey(trimmedCategory)) { + String[] transformed = Arrays.stream(MetricCategory.values()) + .map(level -> level.toLowerCase()) + .toArray(i -> new String[i]); String validCategories = String.join( ", ", - (String[]) Arrays.stream(MetricCategory.values()).map(level -> level.toString()).toArray()); + transformed); throw new IllegalArgumentException( String.format( @@ -245,7 +267,7 @@ public CosmosClientTelemetryConfig metricCategories(String... categories) { validCategories)); } - return categoryMap.get(trimmedCategory); + return categoryMap.get(category); }); EnumSet newCategories = EnumSet.of(MetricCategory.System, MetricCategory.OperationSummary); diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java index 80b7253944ee7..7825fc4b96a09 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java @@ -9,8 +9,10 @@ import com.azure.cosmos.implementation.AsyncDocumentClient; import com.azure.cosmos.implementation.ConsoleLoggingRegistryFactory; import com.azure.cosmos.implementation.GlobalEndpointManager; +import com.azure.cosmos.implementation.ImplementationBridgeHelpers; import com.azure.cosmos.implementation.InternalObjectNode; import com.azure.cosmos.implementation.RxDocumentClientImpl; +import com.azure.cosmos.implementation.clienttelemetry.MetricCategory; import com.azure.cosmos.implementation.clienttelemetry.TagName; import com.azure.cosmos.implementation.directconnectivity.ReflectionUtils; import com.azure.cosmos.implementation.guava25.collect.Lists; @@ -44,6 +46,7 @@ import java.time.Duration; import java.util.ArrayList; import java.util.Collections; +import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -61,6 +64,7 @@ public class ClientMetricsTest extends BatchTestBase { private String containerId; private MeterRegistry meterRegistry; private String preferredRegion; + private EnumSet effectiveMetricCategories; @Factory(dataProvider = "clientBuildersWithDirectTcpSession") public ClientMetricsTest(CosmosClientBuilder clientBuilder) { @@ -68,14 +72,19 @@ public ClientMetricsTest(CosmosClientBuilder clientBuilder) { super(clientBuilder); } - public void beforeTest() { + public void beforeTest(String... metricCategories) { assertThat(this.client).isNull(); assertThat(this.meterRegistry).isNull(); this.meterRegistry = ConsoleLoggingRegistryFactory.create(1); CosmosClientTelemetryConfig telemetryConfig = new CosmosClientTelemetryConfig() - .metricsOptions(new CosmosMicrometerMetricsOptions().meterRegistry(this.meterRegistry)); + .metricsOptions(new CosmosMicrometerMetricsOptions().meterRegistry(this.meterRegistry)) + .metricCategories(metricCategories); + this.effectiveMetricCategories = ImplementationBridgeHelpers + .CosmosClientTelemetryConfigHelper + .getCosmosClientTelemetryConfigAccessor() + .getMetricCategories(telemetryConfig); this.client = getClientBuilder() .clientTelemetryConfig(telemetryConfig) @@ -119,7 +128,7 @@ public void maxValueExceedingDefinedLimitStillWorksWithoutException() throws Exc // Expected behavior is that higher values than the expected max value can still be recorded // it would only result in getting less accurate "estimates" for percentile histograms - this.beforeTest(); + this.beforeTest("Default"); try { Tag dummyOperationTag = Tag.of(TagName.Operation.toString(), "TestDummy"); @@ -156,7 +165,40 @@ public void maxValueExceedingDefinedLimitStillWorksWithoutException() throws Exc @Test(groups = { "simple" }, timeOut = TIMEOUT) public void createItem() throws Exception { - this.beforeTest(); + this.beforeTest("Default"); + try { + InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); + CosmosItemResponse itemResponse = container.createItem(properties); + assertThat(itemResponse.getRequestCharge()).isGreaterThan(0); + validateItemResponse(properties, itemResponse); + + properties = getDocumentDefinition(UUID.randomUUID().toString()); + CosmosItemResponse itemResponse1 = container.createItem(properties, new CosmosItemRequestOptions()); + validateItemResponse(properties, itemResponse1); + + this.validateMetrics( + Tag.of(TagName.OperationStatusCode.toString(), "201"), + Tag.of(TagName.RequestStatusCode.toString(), "201/0"), + 1, + 100 + ); + + this.validateMetrics( + Tag.of( + TagName.Operation.toString(), "Document/Create"), + Tag.of(TagName.RequestOperationType.toString(), "Document/Create"), + 1, + 100 + ); + + } finally { + this.afterTest(); + } + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void createItemWithAllMetrics() throws Exception { + this.beforeTest("All"); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); CosmosItemResponse itemResponse = container.createItem(properties); @@ -189,7 +231,7 @@ public void createItem() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void readItem() throws Exception { - this.beforeTest(); + this.beforeTest("Default"); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); container.createItem(properties); @@ -225,7 +267,7 @@ public void readItem() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void replaceItem() throws Exception { - this.beforeTest(); + this.beforeTest("Default"); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); CosmosItemResponse itemResponse = container.createItem(properties); @@ -263,7 +305,7 @@ public void replaceItem() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void deleteItem() throws Exception { - this.beforeTest(); + this.beforeTest("Default"); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); container.createItem(properties); @@ -295,7 +337,7 @@ public void deleteItem() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void readAllItems() throws Exception { - this.beforeTest(); + this.beforeTest("Default"); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); container.createItem(properties); @@ -331,11 +373,52 @@ public void readAllItems() throws Exception { this.assertMetrics("cosmos.client.req.rntbd", false, queryPlanTag); this.assertMetrics("cosmos.client.req.gw.requests", true, queryPlanTag); this.assertMetrics("cosmos.client.req.gw.RUs", false, queryPlanTag); + } finally { + this.afterTest(); + } + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void readAllItemsWithDetailMetrics() throws Exception { + this.beforeTest("Default", "RequestDetails", "OperationDetails"); + try { + InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); + container.createItem(properties); + + CosmosQueryRequestOptions cosmosQueryRequestOptions = new CosmosQueryRequestOptions(); + + CosmosPagedIterable feedResponseIterator3 = + container.readAllItems(cosmosQueryRequestOptions, InternalObjectNode.class); + assertThat(feedResponseIterator3.iterator().hasNext()).isTrue(); + + this.validateMetrics( + Tag.of(TagName.OperationStatusCode.toString(), "200"), + Tag.of(TagName.RequestStatusCode.toString(), "200/0"), + 1, + 100 + ); + + this.validateMetrics( + Tag.of( + TagName.Operation.toString(), "Document/ReadFeed/readAllItems." + container.getId()), + Tag.of(TagName.RequestOperationType.toString(), "Document/Query"), + 1, + 1000 + ); - // @fabianm TODO add back test coverage - // this.assertMetrics("cosmos.client.req.gw.timeline", true, queryPlanTag); + this.validateItemCountMetrics( + Tag.of( + TagName.Operation.toString(), "Document/ReadFeed/readAllItems." + container.getId()) + ); - // this.assertMetrics("cosmos.client.op.maxItemCount", true); + Tag queryPlanTag = Tag.of(TagName.RequestOperationType.toString(), "DocumentCollection/QueryPlan"); + this.assertMetrics("cosmos.client.req.gw", true, queryPlanTag); + this.assertMetrics("cosmos.client.req.rntbd", false, queryPlanTag); + this.assertMetrics("cosmos.client.req.gw.requests", true, queryPlanTag); + this.assertMetrics("cosmos.client.req.gw.RUs", false, queryPlanTag); + + this.assertMetrics("cosmos.client.req.gw.timeline", true, queryPlanTag); + this.assertMetrics("cosmos.client.op.maxItemCount", true); } finally { this.afterTest(); } @@ -343,7 +426,7 @@ public void readAllItems() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void queryItems() throws Exception { - this.beforeTest(); + this.beforeTest("Default"); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); container.createItem(properties); @@ -392,7 +475,7 @@ public void queryItems() throws Exception { @Test(groups = { "emulator" }, timeOut = TIMEOUT * 100) public void itemPatchSuccess() { - this.beforeTest(); + this.beforeTest("Default"); try { PatchTest.ToDoActivity testItem = PatchTest.ToDoActivity.createRandomItem(this.container); PatchTest.ToDoActivity testItem1 = PatchTest.ToDoActivity.createRandomItem(this.container); @@ -461,7 +544,7 @@ public void itemPatchSuccess() { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void createItem_withBulk() { - this.beforeTest(); + this.beforeTest("Default"); try { int totalRequest = 5; @@ -515,7 +598,7 @@ public void createItem_withBulk() { @Test(groups = {"simple"}, timeOut = TIMEOUT) public void batchMultipleItemExecution() { - this.beforeTest(); + this.beforeTest("Default"); try { TestDoc firstDoc = this.populateTestDoc(this.partitionKey1); TestDoc replaceDoc = this.getTestDocCopy(firstDoc); @@ -575,6 +658,92 @@ public void batchMultipleItemExecution() { } } + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void effectiveMetricCategoriesForDefault() { + this.beforeTest("Default"); + try { + assertThat(this.effectiveMetricCategories.size()).isEqualTo(5); + + EnumSet clientMetricCategories = ImplementationBridgeHelpers + .CosmosAsyncClientHelper + .getCosmosAsyncClientAccessor() + .getMetricCategories(client.asyncClient()); + assertThat(clientMetricCategories).isEqualTo(this.effectiveMetricCategories); + + assertThat(this.effectiveMetricCategories.contains(MetricCategory.RequestSummary)).isEqualTo(true); + assertThat(this.effectiveMetricCategories.contains(MetricCategory.OperationSummary)).isEqualTo(true); + assertThat(this.effectiveMetricCategories.contains(MetricCategory.DirectChannels)).isEqualTo(true); + assertThat(this.effectiveMetricCategories.contains(MetricCategory.DirectRequests)).isEqualTo(true); + assertThat(this.effectiveMetricCategories.contains(MetricCategory.System)).isEqualTo(true); + } finally { + this.afterTest(); + } + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void effectiveMetricCategoriesForDefaultPlusDetails() { + this.beforeTest("Default", "RequestDetails", "OperationDETAILS"); + try { + assertThat(this.effectiveMetricCategories.size()).isEqualTo(7); + + EnumSet clientMetricCategories = ImplementationBridgeHelpers + .CosmosAsyncClientHelper + .getCosmosAsyncClientAccessor() + .getMetricCategories(client.asyncClient()); + assertThat(clientMetricCategories).isEqualTo(this.effectiveMetricCategories); + + assertThat(this.effectiveMetricCategories.contains(MetricCategory.RequestSummary)).isEqualTo(true); + assertThat(this.effectiveMetricCategories.contains(MetricCategory.RequestDetails)).isEqualTo(true); + assertThat(this.effectiveMetricCategories.contains(MetricCategory.OperationSummary)).isEqualTo(true); + assertThat(this.effectiveMetricCategories.contains(MetricCategory.OperationDetails)).isEqualTo(true); + assertThat(this.effectiveMetricCategories.contains(MetricCategory.DirectChannels)).isEqualTo(true); + assertThat(this.effectiveMetricCategories.contains(MetricCategory.DirectRequests)).isEqualTo(true); + assertThat(this.effectiveMetricCategories.contains(MetricCategory.System)).isEqualTo(true); + } finally { + this.afterTest(); + } + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void effectiveMetricCategoriesInvalidCategory() { + try { + this.beforeTest("Default", "InvalidCategory"); + + fail("Should have thrown exception"); + } catch (IllegalArgumentException argError) { + assertThat(argError.getMessage()).contains("invalidcategory"); + } finally { + this.afterTest(); + } + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void effectiveMetricCategoriesForAll() { + this.beforeTest("All"); + try { + assertThat(this.effectiveMetricCategories.size()).isEqualTo(10); + + EnumSet clientMetricCategories = ImplementationBridgeHelpers + .CosmosAsyncClientHelper + .getCosmosAsyncClientAccessor() + .getMetricCategories(client.asyncClient()); + assertThat(clientMetricCategories).isEqualTo(this.effectiveMetricCategories); + + assertThat(this.effectiveMetricCategories.contains(MetricCategory.RequestSummary)).isEqualTo(true); + assertThat(this.effectiveMetricCategories.contains(MetricCategory.RequestDetails)).isEqualTo(true); + assertThat(this.effectiveMetricCategories.contains(MetricCategory.OperationSummary)).isEqualTo(true); + assertThat(this.effectiveMetricCategories.contains(MetricCategory.OperationDetails)).isEqualTo(true); + assertThat(this.effectiveMetricCategories.contains(MetricCategory.DirectChannels)).isEqualTo(true); + assertThat(this.effectiveMetricCategories.contains(MetricCategory.DirectRequests)).isEqualTo(true); + assertThat(this.effectiveMetricCategories.contains(MetricCategory.DirectEndpoints)).isEqualTo(true); + assertThat(this.effectiveMetricCategories.contains(MetricCategory.System)).isEqualTo(true); + assertThat(this.effectiveMetricCategories.contains(MetricCategory.Legacy)).isEqualTo(true); + assertThat(this.effectiveMetricCategories.contains(MetricCategory.AddressResolutions)).isEqualTo(true); + } finally { + this.afterTest(); + } + } + private InternalObjectNode getDocumentDefinition(String documentId) { final String uuid = UUID.randomUUID().toString(); return @@ -635,9 +804,10 @@ private void validateMetrics(int minRu, int maxRu) { } private void validateItemCountMetrics(Tag expectedOperationTag) { - // @fabianm TODO add back test coverage - // this.assertMetrics("cosmos.client.op.maxItemCount", true, expectedOperationTag); - // this.assertMetrics("cosmos.client.op.actualItemCount", true, expectedOperationTag); + if (this.effectiveMetricCategories.contains(MetricCategory.OperationDetails)) { + this.assertMetrics("cosmos.client.op.maxItemCount", true, expectedOperationTag); + this.assertMetrics("cosmos.client.op.actualItemCount", true, expectedOperationTag); + } } private void validateReasonableRUs(Meter reportedRequestChargeMeter, int expectedMinRu, int expectedMaxRu) { @@ -657,13 +827,14 @@ private void validateMetrics(Tag expectedOperationTag, Tag expectedRequestTag, i "cosmos.client.op.RUs", true, expectedOperationTag); validateReasonableRUs(reportedOpRequestCharge, minRu, maxRu); - // @fabianm TODO add back test coverage - // this.assertMetrics("cosmos.client.op.regionsContacted", true, expectedOperationTag); + if (this.effectiveMetricCategories.contains(MetricCategory.OperationDetails)) { + this.assertMetrics("cosmos.client.op.regionsContacted", true, expectedOperationTag); - // this.assertMetrics( - // "cosmos.client.op.regionsContacted", - // true, - // Tag.of(TagName.RegionName.toString(), this.preferredRegion)); + this.assertMetrics( + "cosmos.client.op.regionsContacted", + true, + Tag.of(TagName.RegionName.toString(), this.preferredRegion)); + } if (this.client.asyncClient().getConnectionPolicy().getConnectionMode() == ConnectionMode.DIRECT) { this.assertMetrics("cosmos.client.req.rntbd.latency", true, expectedRequestTag); @@ -677,24 +848,27 @@ private void validateMetrics(Tag expectedOperationTag, Tag expectedRequestTag, i this.assertMetrics("cosmos.client.req.rntbd.RUs", true, expectedRequestTag); validateReasonableRUs(reportedRntbdRequestCharge, minRu, maxRu); - // @fabianm TODO add back test coverage - //this.assertMetrics("cosmos.client.req.rntbd.timeline", true, expectedRequestTag); + if (this.effectiveMetricCategories.contains(MetricCategory.RequestDetails)) { + this.assertMetrics("cosmos.client.req.rntbd.timeline", true, expectedRequestTag); + } } else { this.assertMetrics("cosmos.client.req.gw.latency", true, expectedRequestTag); - // @fabianm TODO add back test coverage - // this.assertMetrics( - // "cosmos.client.req.gw.latency", - // true, - // Tag.of(TagName.RegionName.toString(), this.preferredRegion)); + if (this.effectiveMetricCategories.contains(MetricCategory.OperationDetails)) { + this.assertMetrics( + "cosmos.client.req.gw.latency", + true, + Tag.of(TagName.RegionName.toString(), this.preferredRegion)); + } this.assertMetrics("cosmos.client.req.gw.backendLatency", false, expectedRequestTag); this.assertMetrics("cosmos.client.req.gw.requests", true, expectedRequestTag); Meter reportedGatewayRequestCharge = this.assertMetrics("cosmos.client.req.gw.RUs", true, expectedRequestTag); validateReasonableRUs(reportedGatewayRequestCharge, minRu, maxRu); - // @fabianm TODO add back test coverage - //this.assertMetrics("cosmos.client.req.gw.timeline", true, expectedRequestTag); + if (this.effectiveMetricCategories.contains(MetricCategory.RequestDetails)) { + this.assertMetrics("cosmos.client.req.gw.timeline", true, expectedRequestTag); + } this.assertMetrics("cosmos.client.req.rntbd", false); } From 7ec76c3841e0115410232232d8a1693be52bc598 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Mon, 13 Feb 2023 18:53:07 +0000 Subject: [PATCH 07/40] Fixing test failure --- .../com/azure/cosmos/spark/SparkE2EChangeFeedITest.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/SparkE2EChangeFeedITest.scala b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/SparkE2EChangeFeedITest.scala index 1eaf6ba611d05..bb643a280c9b2 100644 --- a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/SparkE2EChangeFeedITest.scala +++ b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/SparkE2EChangeFeedITest.scala @@ -331,7 +331,10 @@ class SparkE2EChangeFeedITest assertMetrics(meterRegistry, "cosmos.client.req.gw", expectedToFind = true) assertMetrics(meterRegistry, "cosmos.client.req.rntbd", expectedToFind = true) assertMetrics(meterRegistry, "cosmos.client.rntbd", expectedToFind = true) - assertMetrics(meterRegistry, "cosmos.client.rntbd.addressResolution", expectedToFind = true) + + // not part of default metric - no custom categories for now - can be added if needed as config override + // on a per client base + assertMetrics(meterRegistry, "cosmos.client.rntbd.addressResolution", expectedToFind = false) } "spark change feed query (incremental)" can "filter feed ranges" in { From 5c39a295494a79305c1e814daa592ef46836a30b Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Mon, 13 Feb 2023 19:01:58 +0000 Subject: [PATCH 08/40] Aligning MetricNames with the new categories --- .../ClientTelemetryMetrics.java | 46 ++++++++++--------- .../clienttelemetry/CosmosMetricNames.java | 24 ++++++---- 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java index 8bce98111a151..ff116796d63f9 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java @@ -298,7 +298,7 @@ public void recordOperation( Set contactedRegions) { Counter operationsCounter = Counter - .builder(nameOf(CosmosMetricNames.Operation.Calls)) + .builder(nameOf(CosmosMetricNames.OperationSummary.Calls)) .baseUnit("calls") .description("Operation calls") .tags(operationTags) @@ -306,7 +306,7 @@ public void recordOperation( operationsCounter.increment(); DistributionSummary requestChargeMeter = DistributionSummary - .builder(nameOf(CosmosMetricNames.Operation.RequestCharge)) + .builder(nameOf(CosmosMetricNames.OperationSummary.RequestCharge)) .baseUnit("RU (request unit)") .description("Operation RU charge") .maximumExpectedValue(10_000_000d) @@ -318,7 +318,7 @@ public void recordOperation( if (this.metricCategories.contains(MetricCategory.OperationDetails)) { DistributionSummary regionsContactedMeter = DistributionSummary - .builder(nameOf(CosmosMetricNames.Operation.RegionsContacted)) + .builder(nameOf(CosmosMetricNames.OperationDetails.RegionsContacted)) .baseUnit("Regions contacted") .description("Operation - regions contacted") .maximumExpectedValue(100d) @@ -334,7 +334,7 @@ public void recordOperation( } Timer latencyMeter = Timer - .builder(nameOf(CosmosMetricNames.Operation.Latency)) + .builder(nameOf(CosmosMetricNames.OperationSummary.Latency)) .description("Operation latency") .maximumExpectedValue(Duration.ofSeconds(300)) .publishPercentiles(0.95, 0.99) @@ -381,7 +381,7 @@ private void recordQueryPlanDiagnostics( ); Counter requestCounter = Counter - .builder(nameOf(CosmosMetricNames.Request.Gateway.Requests)) + .builder(nameOf(CosmosMetricNames.RequestSummary.Gateway.Requests)) .baseUnit("requests") .description("Gateway requests") .tags(requestTags) @@ -392,7 +392,7 @@ private void recordQueryPlanDiagnostics( if (latency != null) { Timer requestLatencyMeter = Timer - .builder(nameOf(CosmosMetricNames.Request.Gateway.Latency)) + .builder(nameOf(CosmosMetricNames.RequestSummary.Gateway.Latency)) .description("Gateway Request latency") .maximumExpectedValue(Duration.ofSeconds(300)) .publishPercentiles(0.95, 0.99) @@ -403,7 +403,7 @@ private void recordQueryPlanDiagnostics( } recordRequestTimeline( - CosmosMetricNames.Request.Gateway.TimelinePrefix, + CosmosMetricNames.RequestDetails.Gateway.TimelinePrefix, queryPlanDiagnostics.getRequestTimeline(), requestTags); } @@ -412,7 +412,7 @@ private void recordRequestPayloadSizes( int responsePayloadSizeInBytes ) { DistributionSummary requestPayloadSizeMeter = DistributionSummary - .builder(nameOf(CosmosMetricNames.Request.RequestPayloadSize)) + .builder(nameOf(CosmosMetricNames.RequestSummary.RequestPayloadSize)) .baseUnit("bytes") .description("Request payload size in bytes") .maximumExpectedValue(16d * 1024) @@ -423,7 +423,7 @@ private void recordRequestPayloadSizes( requestPayloadSizeMeter.record(requestPayloadSizeInBytes); DistributionSummary responsePayloadSizeMeter = DistributionSummary - .builder(nameOf(CosmosMetricNames.Request.ResponsePayloadSize)) + .builder(nameOf(CosmosMetricNames.RequestSummary.ResponsePayloadSize)) .baseUnit("bytes") .description("Response payload size in bytes") .maximumExpectedValue(16d * 1024) @@ -440,7 +440,7 @@ private void recordItemCounts( ) { if (maxItemCount > 0 && this.metricCategories.contains(MetricCategory.OperationDetails)) { DistributionSummary maxItemCountMeter = DistributionSummary - .builder(nameOf(CosmosMetricNames.Operation.MaxItemCount)) + .builder(nameOf(CosmosMetricNames.OperationSummary.MaxItemCount)) .baseUnit("item count") .description("Request max. item count") .maximumExpectedValue(1_000_000d) @@ -451,7 +451,7 @@ private void recordItemCounts( maxItemCountMeter.record(Math.max(0, Math.min(maxItemCount, 1_000_000d))); DistributionSummary actualItemCountMeter = DistributionSummary - .builder(nameOf(CosmosMetricNames.Operation.ActualItemCount)) + .builder(nameOf(CosmosMetricNames.OperationSummary.ActualItemCount)) .baseUnit("item count") .description("Response actual item count") .maximumExpectedValue(1_000_000d) @@ -654,7 +654,7 @@ private void recordStoreResponseStatistics( if (backendLatency != null) { DistributionSummary backendRequestLatencyMeter = DistributionSummary - .builder(nameOf(CosmosMetricNames.Request.Direct.BackendLatency)) + .builder(nameOf(CosmosMetricNames.RequestSummary.Direct.BackendLatency)) .baseUnit("ms") .description("Backend service latency") .maximumExpectedValue(6_000d) @@ -667,7 +667,7 @@ private void recordStoreResponseStatistics( double requestCharge = storeResponseDiagnostics.getRequestCharge(); DistributionSummary requestChargeMeter = DistributionSummary - .builder(nameOf(CosmosMetricNames.Request.Direct.RequestCharge)) + .builder(nameOf(CosmosMetricNames.RequestSummary.Direct.RequestCharge)) .baseUnit("RU (request unit)") .description("RNTBD Request RU charge") .maximumExpectedValue(1_000_000d) @@ -680,7 +680,7 @@ private void recordStoreResponseStatistics( Duration latency = responseStatistics.getDuration(); if (latency != null) { Timer requestLatencyMeter = Timer - .builder(nameOf(CosmosMetricNames.Request.Direct.Latency)) + .builder(nameOf(CosmosMetricNames.RequestSummary.Direct.Latency)) .description("RNTBD Request latency") .maximumExpectedValue(Duration.ofSeconds(6)) .publishPercentiles(0.95, 0.99) @@ -691,16 +691,18 @@ private void recordStoreResponseStatistics( } Counter requestCounter = Counter - .builder(nameOf(CosmosMetricNames.Request.Direct.Requests)) + .builder(nameOf(CosmosMetricNames.RequestSummary.Direct.Requests)) .baseUnit("requests") .description("RNTBD requests") .tags(requestTags) .register(compositeRegistry); requestCounter.increment(); - recordRequestTimeline( - CosmosMetricNames.Request.Direct.TimelinePrefix, - storeResponseDiagnostics.getRequestTimeline(), requestTags); + if (this.metricCategories.contains(MetricCategory.RequestDetails)) { + recordRequestTimeline( + CosmosMetricNames.RequestDetails.Direct.TimelinePrefix, + storeResponseDiagnostics.getRequestTimeline(), requestTags); + } recordRequestPayloadSizes( storeResponseDiagnostics.getRequestPayloadLength(), @@ -740,7 +742,7 @@ private void recordGatewayStatistics( ); Counter requestCounter = Counter - .builder(nameOf(CosmosMetricNames.Request.Gateway.Requests)) + .builder(nameOf(CosmosMetricNames.RequestSummary.Gateway.Requests)) .baseUnit("requests") .description("Gateway requests") .tags(requestTags) @@ -749,7 +751,7 @@ private void recordGatewayStatistics( double requestCharge = gatewayStatistics.getRequestCharge(); DistributionSummary requestChargeMeter = DistributionSummary - .builder(nameOf(CosmosMetricNames.Request.Gateway.RequestCharge)) + .builder(nameOf(CosmosMetricNames.RequestSummary.Gateway.RequestCharge)) .baseUnit("RU (request unit)") .description("Gateway Request RU charge") .maximumExpectedValue(1_000_000d) @@ -761,7 +763,7 @@ private void recordGatewayStatistics( if (latency != null) { Timer requestLatencyMeter = Timer - .builder(nameOf(CosmosMetricNames.Request.Gateway.Latency)) + .builder(nameOf(CosmosMetricNames.RequestSummary.Gateway.Latency)) .description("Gateway Request latency") .maximumExpectedValue(Duration.ofSeconds(300)) .publishPercentiles(0.95, 0.99) @@ -772,7 +774,7 @@ private void recordGatewayStatistics( } recordRequestTimeline( - CosmosMetricNames.Request.Gateway.TimelinePrefix, + CosmosMetricNames.RequestDetails.Gateway.TimelinePrefix, gatewayStatistics.getRequestTimeline(), requestTags); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMetricNames.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMetricNames.java index 610c0783037ec..9fda15ca67a7f 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMetricNames.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMetricNames.java @@ -58,7 +58,7 @@ public final static class Endpoints { } } - public final static class Operation { + public final static class OperationSummary { // Number of operation calls (Counter) public final static String Calls = "op.calls"; @@ -75,12 +75,26 @@ public final static class Operation { // Request charge for the operation (DistributionSummary) public final static String RequestCharge = "op.RUs"; + } + public final static class OperationDetails { // Number of regions contacted for processing the operation (DistributionSummary) public final static String RegionsContacted = "op.regionsContacted"; } - public final static class Request { + public final static class RequestDetails { + public final static class Direct { + // Set of latencies in different steps of the request pipeline (all Timers) + public final static String TimelinePrefix = "req.rntbd.timeline."; + } + + public final static class Gateway { + // Set of latencies in different steps of the request pipeline (all Timers) + public final static String TimelinePrefix = "req.gw.timeline."; + } + } + + public final static class RequestSummary { // Size of the request payload (DistributionSummary) public final static String RequestPayloadSize = "req.reqPayloadSize"; @@ -100,9 +114,6 @@ public final static class Direct { // Number of requests (Counter) public final static String Requests = "req.rntbd.requests"; - - // Set of latencies in different steps of the request pipeline (all Timers) - public final static String TimelinePrefix = "req.rntbd.timeline."; } public final static class Gateway { @@ -114,9 +125,6 @@ public final static class Gateway { // Number of requests (Counter) public final static String Requests = "req.gw.requests"; - - // Set of latencies in different steps of the request pipeline (all Timers) - public final static String TimelinePrefix = "req.gw.timeline."; } } From d5ca35bcfaf1d5c0bc7e39d4d71d24bcfed5405f Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Mon, 13 Feb 2023 19:06:50 +0000 Subject: [PATCH 09/40] Update CosmosClientTelemetryConfig.java --- .../com/azure/cosmos/models/CosmosClientTelemetryConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java index 11dcb217e488a..4bba38f0a3a25 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java @@ -172,8 +172,8 @@ public CosmosClientTelemetryConfig metricTagNames(String... tagNames) { Stream tagNameStream = Arrays.stream(tagNames) - .map(rawTagName -> rawTagName.toLowerCase(Locale.ROOT)) .filter(tagName -> !Strings.isNullOrWhiteSpace(tagName)) + .map(rawTagName -> rawTagName.toLowerCase(Locale.ROOT)) .map(tagName -> { String trimmedTagName = tagName.trim(); From 4e775888f98526153e24d7edac83de5872bc4acf Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Mon, 13 Feb 2023 19:08:30 +0000 Subject: [PATCH 10/40] Update RntbdServiceEndpoint.java --- .../directconnectivity/rntbd/RntbdServiceEndpoint.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdServiceEndpoint.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdServiceEndpoint.java index c19bf08db8bda..534f96e4ed32f 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdServiceEndpoint.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdServiceEndpoint.java @@ -137,7 +137,7 @@ private RntbdServiceEndpoint( clientTelemetry.isClientMetricsEnabled() && ( provider.transportClient.getMetricCategories().contains(MetricCategory.DirectEndpoints) - || provider.transportClient.getMetricCategories().contains(MetricCategory.DirectChannels) + || provider.transportClient.getMetricCategories().contains(MetricCategory.DirectChannels) || provider.transportClient.getMetricCategories().contains(MetricCategory.DirectRequests) ) ) { From 60666edf73e6f6edf5eedf2d95590563dd851d7c Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Mon, 13 Feb 2023 21:46:00 +0000 Subject: [PATCH 11/40] Test changes --- .../spark/SparkE2EChangeFeedITest.scala | 4 - .../cosmos/spark/SparkE2EQueryITestBase.scala | 1 - .../com/azure/cosmos/CosmosAsyncClient.java | 21 ++- .../com/azure/cosmos/CosmosClientBuilder.java | 2 - .../models/CosmosClientTelemetryConfig.java | 32 +++-- .../com/azure/cosmos/ClientMetricsTest.java | 129 ++++++++++++------ 6 files changed, 113 insertions(+), 76 deletions(-) diff --git a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/SparkE2EChangeFeedITest.scala b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/SparkE2EChangeFeedITest.scala index bb643a280c9b2..89d550c60f76b 100644 --- a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/SparkE2EChangeFeedITest.scala +++ b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/SparkE2EChangeFeedITest.scala @@ -331,10 +331,6 @@ class SparkE2EChangeFeedITest assertMetrics(meterRegistry, "cosmos.client.req.gw", expectedToFind = true) assertMetrics(meterRegistry, "cosmos.client.req.rntbd", expectedToFind = true) assertMetrics(meterRegistry, "cosmos.client.rntbd", expectedToFind = true) - - // not part of default metric - no custom categories for now - can be added if needed as config override - // on a per client base - assertMetrics(meterRegistry, "cosmos.client.rntbd.addressResolution", expectedToFind = false) } "spark change feed query (incremental)" can "filter feed ranges" in { diff --git a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/SparkE2EQueryITestBase.scala b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/SparkE2EQueryITestBase.scala index e5141bee2647b..ae7579effe50c 100644 --- a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/SparkE2EQueryITestBase.scala +++ b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/SparkE2EQueryITestBase.scala @@ -80,7 +80,6 @@ abstract class SparkE2EQueryITestBase //assertMetrics(meterRegistry, "cosmos.client.req.gw", expectedToFind = true) assertMetrics(meterRegistry, "cosmos.client.req.rntbd", expectedToFind = true) assertMetrics(meterRegistry, "cosmos.client.rntbd", expectedToFind = true) - assertMetrics(meterRegistry, "cosmos.client.rntbd.addressResolution", expectedToFind = true) } private def insertDummyValue() : Unit = { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java index 0cc86a19fc78c..16ade31a66555 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java @@ -63,6 +63,11 @@ isAsync = true) public final class CosmosAsyncClient implements Closeable { + private static final ImplementationBridgeHelpers.CosmosClientTelemetryConfigHelper.CosmosClientTelemetryConfigAccessor + telemetryConfigAccessor = ImplementationBridgeHelpers + .CosmosClientTelemetryConfigHelper + .getCosmosClientTelemetryConfigAccessor(); + // Async Cosmos client wrapper private final Configs configs; private final AsyncDocumentClient asyncDocumentClient; @@ -84,8 +89,6 @@ public final class CosmosAsyncClient implements Closeable { private final String clientCorrelationId; private final Tag clientCorrelationTag; private final String accountTagValue; - private final EnumSet metricTagNames; - private final EnumSet metricCategories; private final boolean clientMetricsEnabled; private final boolean isSendClientTelemetryToServiceEnabled; private final MeterRegistry clientMetricRegistrySnapshot; @@ -116,10 +119,6 @@ public final class CosmosAsyncClient implements Closeable { this.sessionCapturingOverride = builder.isSessionCapturingOverrideEnabled(); this.enableTransportClientSharing = builder.isConnectionSharingAcrossClientsEnabled(); this.proactiveContainerInitConfig = builder.getProactiveContainerInitConfig(); - ImplementationBridgeHelpers.CosmosClientTelemetryConfigHelper.CosmosClientTelemetryConfigAccessor - telemetryConfigAccessor = ImplementationBridgeHelpers - .CosmosClientTelemetryConfigHelper - .getCosmosClientTelemetryConfigAccessor(); CosmosClientTelemetryConfig effectiveTelemetryConfig = telemetryConfigAccessor .createSnapshot( @@ -139,10 +138,6 @@ public final class CosmosAsyncClient implements Closeable { this.apiType = builder.apiType(); this.clientCorrelationId = telemetryConfigAccessor .getClientCorrelationId(effectiveTelemetryConfig); - this.metricTagNames = telemetryConfigAccessor - .getMetricTagNames(effectiveTelemetryConfig); - this.metricCategories = telemetryConfigAccessor - .getMetricCategories(effectiveTelemetryConfig); List permissionList = new ArrayList<>(); if (this.permissions != null) { @@ -728,12 +723,14 @@ public String getAccountTagValue(CosmosAsyncClient client) { @Override public EnumSet getMetricTagNames(CosmosAsyncClient client) { - return client.metricTagNames; + return telemetryConfigAccessor + .getMetricTagNames(client.clientTelemetryConfig); } @Override public EnumSet getMetricCategories(CosmosAsyncClient client) { - return client.metricCategories; + return telemetryConfigAccessor + .getMetricCategories(client.clientTelemetryConfig); } @Override diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosClientBuilder.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosClientBuilder.java index 6caf966c374c4..14901b8933475 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosClientBuilder.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosClientBuilder.java @@ -796,8 +796,6 @@ boolean isClientTelemetryEnabled() { .getCosmosClientTelemetryConfigAccessor() .isSendClientTelemetryToServiceEnabled(this.clientTelemetryConfig); - assert(this.clientTelemetryEnabledOverride == null || explicitlySetInConfig == null); - if (this.clientTelemetryEnabledOverride != null) { return this.clientTelemetryEnabledOverride; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java index 4bba38f0a3a25..7f69c1c9bd81b 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java @@ -59,25 +59,14 @@ public final class CosmosClientTelemetryConfig { private EnumSet metricCategories = MetricCategory.DEFAULT_CATEGORIES; private MeterRegistry clientMetricRegistry = null; private boolean isClientMetricsEnabled = false; - - CosmosClientTelemetryConfig(CosmosClientTelemetryConfig toBeCopied, boolean effectiveIsClientTelemetryEnabled) { - this.httpNetworkRequestTimeout = toBeCopied.httpNetworkRequestTimeout; - this.maxConnectionPoolSize = toBeCopied.maxConnectionPoolSize; - this.idleHttpConnectionTimeout = toBeCopied.idleHttpConnectionTimeout; - this.proxy = toBeCopied.proxy; - this.clientCorrelationId = toBeCopied.clientCorrelationId; - this.metricTagNames = toBeCopied.metricTagNames; - this.metricCategories = toBeCopied.metricCategories; - this.clientMetricRegistry = toBeCopied.clientMetricRegistry; - this.isClientMetricsEnabled = toBeCopied.isClientMetricsEnabled; - this.clientTelemetryEnabled = effectiveIsClientTelemetryEnabled; - } + private Boolean effectiveIsClientTelemetryEnabled = null; /** * Instantiates a new Cosmos client telemetry configuration. */ public CosmosClientTelemetryConfig() { this.clientTelemetryEnabled = null; + this.effectiveIsClientTelemetryEnabled = null; this.httpNetworkRequestTimeout = DEFAULT_NETWORK_REQUEST_TIMEOUT; this.maxConnectionPoolSize = DEFAULT_MAX_CONNECTION_POOL_SIZE; this.idleHttpConnectionTimeout = DEFAULT_IDLE_CONNECTION_TIMEOUT; @@ -97,7 +86,10 @@ public CosmosClientTelemetryConfig sendClientTelemetryToService(boolean enabled) } Boolean isSendClientTelemetryToServiceEnabled() { - return this.clientTelemetryEnabled; + Boolean effectiveSnapshot = this.effectiveIsClientTelemetryEnabled; + Boolean currentSnapshot = this.clientTelemetryEnabled; + + return effectiveSnapshot != null ? effectiveSnapshot : currentSnapshot; } void resetIsSendClientTelemetryToServiceEnabled() { @@ -206,12 +198,22 @@ EnumSet getMetricTagNames() { return this.metricTagNames; } + private CosmosClientTelemetryConfig setEffectiveIsClientTelemetryEnabled( + boolean effectiveIsClientTelemetryEnabled) { + + this.effectiveIsClientTelemetryEnabled = effectiveIsClientTelemetryEnabled; + return this; + } + /** * Sets the categories of metrics that should be emitted. By default the following categories will be enabled: * OperationSummary, RequestSummary, DirectChannels, DirectRequests, System * (the System and OperationSummary metrics are always collected and can't be disabled when enabling Cosmos metrics) * For most use-cases that should be sufficient. An overview of the different metric categories can be found here: * https://aka.ms/azure-cosmos-metrics + * NOTE: metric categories are mutable. You can safely modify the categories on the CosmosClientTelemetryConfig + * instance passed into the CosmosClinetBuilder after the CosmosClient was created - and changes to the config + * instance will be reflected at runtime by the client. * * @param categories - a comma-separated list of metric categories that should be emitted * @return current CosmosClientTelemetryConfig @@ -426,7 +428,7 @@ public CosmosClientTelemetryConfig createSnapshot( CosmosClientTelemetryConfig config, boolean effectiveIsClientTelemetryEnabled) { - return new CosmosClientTelemetryConfig(config, effectiveIsClientTelemetryEnabled); + return config.setEffectiveIsClientTelemetryEnabled(effectiveIsClientTelemetryEnabled); } @Override diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java index 7825fc4b96a09..7815f7e466512 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java @@ -64,7 +64,7 @@ public class ClientMetricsTest extends BatchTestBase { private String containerId; private MeterRegistry meterRegistry; private String preferredRegion; - private EnumSet effectiveMetricCategories; + private CosmosClientTelemetryConfig inputClientTelemetryConfig; @Factory(dataProvider = "clientBuildersWithDirectTcpSession") public ClientMetricsTest(CosmosClientBuilder clientBuilder) { @@ -72,24 +72,34 @@ public ClientMetricsTest(CosmosClientBuilder clientBuilder) { super(clientBuilder); } + private EnumSet getEffectiveMetricCategories() { + return ImplementationBridgeHelpers + .CosmosClientTelemetryConfigHelper + .getCosmosClientTelemetryConfigAccessor() + .getMetricCategories(this.inputClientTelemetryConfig); + } + public void beforeTest(String... metricCategories) { assertThat(this.client).isNull(); assertThat(this.meterRegistry).isNull(); this.meterRegistry = ConsoleLoggingRegistryFactory.create(1); - CosmosClientTelemetryConfig telemetryConfig = new CosmosClientTelemetryConfig() + this.inputClientTelemetryConfig = new CosmosClientTelemetryConfig() .metricsOptions(new CosmosMicrometerMetricsOptions().meterRegistry(this.meterRegistry)) .metricCategories(metricCategories); - this.effectiveMetricCategories = ImplementationBridgeHelpers - .CosmosClientTelemetryConfigHelper - .getCosmosClientTelemetryConfigAccessor() - .getMetricCategories(telemetryConfig); this.client = getClientBuilder() - .clientTelemetryConfig(telemetryConfig) + .clientTelemetryConfig(inputClientTelemetryConfig) .buildClient(); + assertThat( + ImplementationBridgeHelpers + .CosmosAsyncClientHelper + .getCosmosAsyncClientAccessor() + .getMetricCategories(this.client.asyncClient()) + ).isSameAs(this.getEffectiveMetricCategories()); + AsyncDocumentClient asyncDocumentClient = ReflectionUtils.getAsyncDocumentClient(this.client.asyncClient()); RxDocumentClientImpl rxDocumentClient = (RxDocumentClientImpl) asyncDocumentClient; @@ -662,19 +672,19 @@ public void batchMultipleItemExecution() { public void effectiveMetricCategoriesForDefault() { this.beforeTest("Default"); try { - assertThat(this.effectiveMetricCategories.size()).isEqualTo(5); + assertThat(this.getEffectiveMetricCategories().size()).isEqualTo(5); EnumSet clientMetricCategories = ImplementationBridgeHelpers .CosmosAsyncClientHelper .getCosmosAsyncClientAccessor() .getMetricCategories(client.asyncClient()); - assertThat(clientMetricCategories).isEqualTo(this.effectiveMetricCategories); + assertThat(clientMetricCategories).isEqualTo(this.getEffectiveMetricCategories()); - assertThat(this.effectiveMetricCategories.contains(MetricCategory.RequestSummary)).isEqualTo(true); - assertThat(this.effectiveMetricCategories.contains(MetricCategory.OperationSummary)).isEqualTo(true); - assertThat(this.effectiveMetricCategories.contains(MetricCategory.DirectChannels)).isEqualTo(true); - assertThat(this.effectiveMetricCategories.contains(MetricCategory.DirectRequests)).isEqualTo(true); - assertThat(this.effectiveMetricCategories.contains(MetricCategory.System)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.RequestSummary)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.OperationSummary)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.DirectChannels)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.DirectRequests)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.System)).isEqualTo(true); } finally { this.afterTest(); } @@ -684,21 +694,21 @@ public void effectiveMetricCategoriesForDefault() { public void effectiveMetricCategoriesForDefaultPlusDetails() { this.beforeTest("Default", "RequestDetails", "OperationDETAILS"); try { - assertThat(this.effectiveMetricCategories.size()).isEqualTo(7); + assertThat(this.getEffectiveMetricCategories().size()).isEqualTo(7); EnumSet clientMetricCategories = ImplementationBridgeHelpers .CosmosAsyncClientHelper .getCosmosAsyncClientAccessor() .getMetricCategories(client.asyncClient()); - assertThat(clientMetricCategories).isEqualTo(this.effectiveMetricCategories); - - assertThat(this.effectiveMetricCategories.contains(MetricCategory.RequestSummary)).isEqualTo(true); - assertThat(this.effectiveMetricCategories.contains(MetricCategory.RequestDetails)).isEqualTo(true); - assertThat(this.effectiveMetricCategories.contains(MetricCategory.OperationSummary)).isEqualTo(true); - assertThat(this.effectiveMetricCategories.contains(MetricCategory.OperationDetails)).isEqualTo(true); - assertThat(this.effectiveMetricCategories.contains(MetricCategory.DirectChannels)).isEqualTo(true); - assertThat(this.effectiveMetricCategories.contains(MetricCategory.DirectRequests)).isEqualTo(true); - assertThat(this.effectiveMetricCategories.contains(MetricCategory.System)).isEqualTo(true); + assertThat(clientMetricCategories).isEqualTo(this.getEffectiveMetricCategories()); + + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.RequestSummary)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.RequestDetails)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.OperationSummary)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.OperationDetails)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.DirectChannels)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.DirectRequests)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.System)).isEqualTo(true); } finally { this.afterTest(); } @@ -721,24 +731,59 @@ public void effectiveMetricCategoriesInvalidCategory() { public void effectiveMetricCategoriesForAll() { this.beforeTest("All"); try { - assertThat(this.effectiveMetricCategories.size()).isEqualTo(10); + assertThat(this.getEffectiveMetricCategories().size()).isEqualTo(10); + + EnumSet clientMetricCategories = ImplementationBridgeHelpers + .CosmosAsyncClientHelper + .getCosmosAsyncClientAccessor() + .getMetricCategories(client.asyncClient()); + assertThat(clientMetricCategories).isEqualTo(this.getEffectiveMetricCategories()); + + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.RequestSummary)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.RequestDetails)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.OperationSummary)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.OperationDetails)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.DirectChannels)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.DirectRequests)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.DirectEndpoints)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.System)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.Legacy)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.AddressResolutions)).isEqualTo(true); + } finally { + this.afterTest(); + } + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void effectiveMetricCategoriesForAllLatebound() { + this.beforeTest("Default"); + try { + + assertThat(this.getEffectiveMetricCategories().size()).isEqualTo(5); EnumSet clientMetricCategories = ImplementationBridgeHelpers .CosmosAsyncClientHelper .getCosmosAsyncClientAccessor() .getMetricCategories(client.asyncClient()); - assertThat(clientMetricCategories).isEqualTo(this.effectiveMetricCategories); - - assertThat(this.effectiveMetricCategories.contains(MetricCategory.RequestSummary)).isEqualTo(true); - assertThat(this.effectiveMetricCategories.contains(MetricCategory.RequestDetails)).isEqualTo(true); - assertThat(this.effectiveMetricCategories.contains(MetricCategory.OperationSummary)).isEqualTo(true); - assertThat(this.effectiveMetricCategories.contains(MetricCategory.OperationDetails)).isEqualTo(true); - assertThat(this.effectiveMetricCategories.contains(MetricCategory.DirectChannels)).isEqualTo(true); - assertThat(this.effectiveMetricCategories.contains(MetricCategory.DirectRequests)).isEqualTo(true); - assertThat(this.effectiveMetricCategories.contains(MetricCategory.DirectEndpoints)).isEqualTo(true); - assertThat(this.effectiveMetricCategories.contains(MetricCategory.System)).isEqualTo(true); - assertThat(this.effectiveMetricCategories.contains(MetricCategory.Legacy)).isEqualTo(true); - assertThat(this.effectiveMetricCategories.contains(MetricCategory.AddressResolutions)).isEqualTo(true); + assertThat(clientMetricCategories).isEqualTo(this.getEffectiveMetricCategories()); + + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.RequestSummary)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.OperationSummary)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.DirectChannels)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.DirectRequests)).isEqualTo(true); + assertThat(this.getEffectiveMetricCategories().contains(MetricCategory.System)).isEqualTo(true); + + // Now change the metricCategories on the config passed into the CosmosClientBuilder + // and validate that these changes take effect immediately on the client build via the builder + this.inputClientTelemetryConfig.metricCategories("All"); + + assertThat(this.getEffectiveMetricCategories().size()).isEqualTo(10); + + clientMetricCategories = ImplementationBridgeHelpers + .CosmosAsyncClientHelper + .getCosmosAsyncClientAccessor() + .getMetricCategories(client.asyncClient()); + assertThat(clientMetricCategories).isEqualTo(this.getEffectiveMetricCategories()); } finally { this.afterTest(); } @@ -804,7 +849,7 @@ private void validateMetrics(int minRu, int maxRu) { } private void validateItemCountMetrics(Tag expectedOperationTag) { - if (this.effectiveMetricCategories.contains(MetricCategory.OperationDetails)) { + if (this.getEffectiveMetricCategories().contains(MetricCategory.OperationDetails)) { this.assertMetrics("cosmos.client.op.maxItemCount", true, expectedOperationTag); this.assertMetrics("cosmos.client.op.actualItemCount", true, expectedOperationTag); } @@ -827,7 +872,7 @@ private void validateMetrics(Tag expectedOperationTag, Tag expectedRequestTag, i "cosmos.client.op.RUs", true, expectedOperationTag); validateReasonableRUs(reportedOpRequestCharge, minRu, maxRu); - if (this.effectiveMetricCategories.contains(MetricCategory.OperationDetails)) { + if (this.getEffectiveMetricCategories().contains(MetricCategory.OperationDetails)) { this.assertMetrics("cosmos.client.op.regionsContacted", true, expectedOperationTag); this.assertMetrics( @@ -848,13 +893,13 @@ private void validateMetrics(Tag expectedOperationTag, Tag expectedRequestTag, i this.assertMetrics("cosmos.client.req.rntbd.RUs", true, expectedRequestTag); validateReasonableRUs(reportedRntbdRequestCharge, minRu, maxRu); - if (this.effectiveMetricCategories.contains(MetricCategory.RequestDetails)) { + if (this.getEffectiveMetricCategories().contains(MetricCategory.RequestDetails)) { this.assertMetrics("cosmos.client.req.rntbd.timeline", true, expectedRequestTag); } } else { this.assertMetrics("cosmos.client.req.gw.latency", true, expectedRequestTag); - if (this.effectiveMetricCategories.contains(MetricCategory.OperationDetails)) { + if (this.getEffectiveMetricCategories().contains(MetricCategory.OperationDetails)) { this.assertMetrics( "cosmos.client.req.gw.latency", true, @@ -866,7 +911,7 @@ private void validateMetrics(Tag expectedOperationTag, Tag expectedRequestTag, i this.assertMetrics("cosmos.client.req.gw.RUs", true, expectedRequestTag); validateReasonableRUs(reportedGatewayRequestCharge, minRu, maxRu); - if (this.effectiveMetricCategories.contains(MetricCategory.RequestDetails)) { + if (this.getEffectiveMetricCategories().contains(MetricCategory.RequestDetails)) { this.assertMetrics("cosmos.client.req.gw.timeline", true, expectedRequestTag); } From 718f8318c96b40dff66727b0018e789586573df6 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Mon, 13 Feb 2023 23:13:48 +0000 Subject: [PATCH 12/40] Fixing test issues --- .../java/com/azure/cosmos/CosmosClientBuilder.java | 14 -------------- .../com/azure/cosmos/CosmosClientBuilderTest.java | 10 ++++++++-- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosClientBuilder.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosClientBuilder.java index 14901b8933475..1ccc28ee2500b 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosClientBuilder.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosClientBuilder.java @@ -658,20 +658,6 @@ public CosmosClientBuilder multipleWriteRegionsEnabled(boolean multipleWriteRegi * @return current CosmosClientBuilder */ public CosmosClientBuilder clientTelemetryEnabled(boolean clientTelemetryEnabled) { - ImplementationBridgeHelpers.CosmosClientTelemetryConfigHelper.CosmosClientTelemetryConfigAccessor accessor = - ImplementationBridgeHelpers - .CosmosClientTelemetryConfigHelper - .getCosmosClientTelemetryConfigAccessor(); - - Boolean explicitlySetInConfig = accessor.isSendClientTelemetryToServiceEnabled(this.clientTelemetryConfig); - - if (explicitlySetInConfig != null) { - CosmosClientTelemetryConfig newTelemetryConfig = accessor - .createSnapshot(this.clientTelemetryConfig, clientTelemetryEnabled); - accessor.resetIsSendClientTelemetryToServiceEnabled(newTelemetryConfig); - this.clientTelemetryConfig = newTelemetryConfig; - } - this.clientTelemetryEnabledOverride = clientTelemetryEnabled; return this; } diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/CosmosClientBuilderTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/CosmosClientBuilderTest.java index 878088a67897f..18b1231ed5e0c 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/CosmosClientBuilderTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/CosmosClientBuilderTest.java @@ -71,7 +71,8 @@ public void validateIsClientTelemetryEnabledConflicts() { .isEqualTo(false); client.close(); - // Enabling via telemetryConfig + // trying to enable via telemetryConfig - should fail because the same CosmosClientTelemetryConfig instance + // has been used to built another Cosmos Client - enabling/disabling ClientTelemetry is immutable right now telemetryConfig.sendClientTelemetryToService(true); client = new CosmosClientBuilder() .endpoint(TestConfigurations.HOST) @@ -80,10 +81,11 @@ public void validateIsClientTelemetryEnabledConflicts() { .buildAsyncClient(); assertThat(telemetryAccessor.isSendClientTelemetryToServiceEnabled(client.getClientTelemetryConfig())) - .isEqualTo(true); + .isEqualTo(false); client.close(); // Enabling via telemetryConfig and disabled via builder.isClientTelemetryEnabled --> Disabled + telemetryConfig = new CosmosClientTelemetryConfig(); telemetryConfig.sendClientTelemetryToService(true); client = new CosmosClientBuilder() .endpoint(TestConfigurations.HOST) @@ -97,6 +99,7 @@ public void validateIsClientTelemetryEnabledConflicts() { client.close(); // Enabling via telemetryConfig, disabling via builder.isClientTelemetryEnabled and re-enabling again --> Enabled + telemetryConfig = new CosmosClientTelemetryConfig(); telemetryConfig.sendClientTelemetryToService(true); client = new CosmosClientBuilder() .endpoint(TestConfigurations.HOST) @@ -111,6 +114,7 @@ public void validateIsClientTelemetryEnabledConflicts() { client.close(); // Disabling via telemetryConfig, enabling via builder.isClientTelemetryEnabled --> Enabled + telemetryConfig = new CosmosClientTelemetryConfig(); telemetryConfig.sendClientTelemetryToService(false); client = new CosmosClientBuilder() .endpoint(TestConfigurations.HOST) @@ -125,6 +129,7 @@ public void validateIsClientTelemetryEnabledConflicts() { // Disabling via telemetryConfig, enabling via builder.isClientTelemetryEnabled and // re-disabling again --> Disabled + telemetryConfig = new CosmosClientTelemetryConfig(); telemetryConfig.sendClientTelemetryToService(false); client = new CosmosClientBuilder() .endpoint(TestConfigurations.HOST) @@ -139,6 +144,7 @@ public void validateIsClientTelemetryEnabledConflicts() { client.close(); // Enabling via telemetryConfig, enabling via builder.isClientTelemetryEnabled --> Enabled + telemetryConfig = new CosmosClientTelemetryConfig(); telemetryConfig.sendClientTelemetryToService(true); client = new CosmosClientBuilder() .endpoint(TestConfigurations.HOST) From fbb12a2a050d0db117cc016fd397efadfa67f205 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Tue, 14 Feb 2023 14:15:26 +0000 Subject: [PATCH 13/40] Public API refactoring --- .../clienttelemetry/MetricCategory.java | 8 +- .../models/CosmosClientTelemetryConfig.java | 122 +++++++----- .../cosmos/models/CosmosMetricCategory.java | 182 ++++++++++++++++++ .../src/main/java/module-info.java | 2 +- .../com/azure/cosmos/ClientMetricsTest.java | 52 +++-- 5 files changed, 291 insertions(+), 75 deletions(-) create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/MetricCategory.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/MetricCategory.java index 9f16c313fdaaa..c760cbd6be01a 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/MetricCategory.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/MetricCategory.java @@ -57,6 +57,12 @@ public int value() { MetricCategory.OperationSummary, MetricCategory.RequestSummary, MetricCategory.DirectRequests, - MetricCategory.DirectChannels + MetricCategory.DirectChannels, + MetricCategory.System + ); + + public static final EnumSet MINIMAL_CATEGORIES = EnumSet.of( + MetricCategory.OperationSummary, + MetricCategory.System ); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java index 7f69c1c9bd81b..557c384d410d3 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java @@ -56,7 +56,7 @@ public final class CosmosClientTelemetryConfig { private final ProxyOptions proxy; private String clientCorrelationId = null; private EnumSet metricTagNames = DEFAULT_TAGS; - private EnumSet metricCategories = MetricCategory.DEFAULT_CATEGORIES; + private EnumSet metricCategories = MetricCategory.DEFAULT_CATEGORIES.clone(); private MeterRegistry clientMetricRegistry = null; private boolean isClientMetricsEnabled = false; private Boolean effectiveIsClientTelemetryEnabled = null; @@ -207,75 +207,93 @@ private CosmosClientTelemetryConfig setEffectiveIsClientTelemetryEnabled( /** * Sets the categories of metrics that should be emitted. By default the following categories will be enabled: - * OperationSummary, RequestSummary, DirectChannels, DirectRequests, System + * OperationSummary (required), RequestSummary, DirectChannels, DirectRequests, System (required) * (the System and OperationSummary metrics are always collected and can't be disabled when enabling Cosmos metrics) * For most use-cases that should be sufficient. An overview of the different metric categories can be found here: * https://aka.ms/azure-cosmos-metrics * NOTE: metric categories are mutable. You can safely modify the categories on the CosmosClientTelemetryConfig - * instance passed into the CosmosClinetBuilder after the CosmosClient was created - and changes to the config + * instance passed into the CosmosClientBuilder after the CosmosClient was created - and changes to the config * instance will be reflected at runtime by the client. * * @param categories - a comma-separated list of metric categories that should be emitted * @return current CosmosClientTelemetryConfig */ - public CosmosClientTelemetryConfig metricCategories(String... categories) { + public CosmosClientTelemetryConfig setMetricCategories(CosmosMetricCategory... categories) { if (categories == null || categories.length == 0) { - this.metricCategories = MetricCategory.DEFAULT_CATEGORIES; + this.metricCategories = MetricCategory.DEFAULT_CATEGORIES.clone(); + } else { + EnumSet newMetricCategories = MetricCategory.MINIMAL_CATEGORIES.clone(); + for (CosmosMetricCategory c: categories) { + for (MetricCategory metricCategory: c.getCategories()) { + newMetricCategories.add(metricCategory); + } + } + + this.metricCategories = newMetricCategories; } - Map categoryMap = new HashMap<>(); - for (MetricCategory level : MetricCategory.values()) { - categoryMap.put(level.toLowerCase(), level); + return this; + } + + /** + * Adds categories of metrics that should be emitted. By default the following categories will be enabled: + * OperationSummary (required), RequestSummary, DirectChannels, DirectRequests, System (required) + * (the System and OperationSummary metrics are always collected and can't be disabled when enabling Cosmos metrics) + * An overview of the different metric categories can be found here: + * https://aka.ms/azure-cosmos-metrics + * NOTE: metric categories are mutable. You can safely modify the categories on the CosmosClientTelemetryConfig + * instance passed into the CosmosClientBuilder after the CosmosClient was created - and changes to the config + * instance will be reflected at runtime by the client. + * + * @param categories - a comma-separated list of metric categories that should be emitted + * @return current CosmosClientTelemetryConfig + */ + public CosmosClientTelemetryConfig addMetricCategories(CosmosMetricCategory... categories) { + if (categories == null || categories.length == 0) { + return this; } - HashSet categoryStrings = new HashSet(); - Arrays.stream(categories) - .filter(category -> !Strings.isNullOrWhiteSpace(category)) - .forEach(rawCategory -> { - String lowerCaseCategory = rawCategory.trim().toLowerCase(Locale.ROOT); - if ("all".equalsIgnoreCase(lowerCaseCategory)) { - MetricCategory - .ALL_CATEGORIES - .stream() - .forEach(c -> categoryStrings.add(c.toLowerCase())); - } else if ("default".equalsIgnoreCase(lowerCaseCategory)) { - MetricCategory - .DEFAULT_CATEGORIES - .stream() - .forEach(c -> categoryStrings.add(c.toLowerCase())); - } else { - categoryStrings.add(lowerCaseCategory); - } - }); - - Stream categoryStream = - Arrays.stream(categoryStrings.toArray()) - .map(category -> { - if (!categoryMap.containsKey(category)) { - - String[] transformed = Arrays.stream(MetricCategory.values()) - .map(level -> level.toLowerCase()) - .toArray(i -> new String[i]); - - String validCategories = String.join( - ", ", - transformed); + EnumSet newMetricCategories = this.metricCategories.clone(); + for (CosmosMetricCategory c: categories) { + for (MetricCategory metricCategory: c.getCategories()) { + newMetricCategories.add(metricCategory); + } + } - throw new IllegalArgumentException( - String.format( - "Metric category '%s' is invalid. Valid Metric categories are:" - + " %s", - category, - validCategories)); - } + this.metricCategories = newMetricCategories; + return this; + } - return categoryMap.get(category); - }); + /** + * Removes categories of metrics that should be emitted. By default the following categories will be enabled: + * OperationSummary (required), RequestSummary, DirectChannels, DirectRequests, System (required) + * (the System and OperationSummary metrics are always collected and can't be disabled when enabling Cosmos metrics) + * An overview of the different metric categories can be found here: + * https://aka.ms/azure-cosmos-metrics + * NOTE: metric categories are mutable. You can safely modify the categories on the CosmosClientTelemetryConfig + * instance passed into the CosmosClientBuilder after the CosmosClient was created - and changes to the config + * instance will be reflected at runtime by the client. + * + * @param categories - a comma-separated list of metric categories that should be emitted + * @return current CosmosClientTelemetryConfig + */ + public CosmosClientTelemetryConfig removeMetricCategories(CosmosMetricCategory... categories) { + if (categories == null || categories.length == 0) { + return this; + } - EnumSet newCategories = EnumSet.of(MetricCategory.System, MetricCategory.OperationSummary); - categoryStream.forEach(category -> newCategories.add(category)); + EnumSet newMetricCategories = this.metricCategories.clone(); + for (CosmosMetricCategory c: categories) { + for (MetricCategory metricCategory: c.getCategories()) { + newMetricCategories.remove(metricCategory); + } + } + + for (MetricCategory metricCategory: CosmosMetricCategory.MINIMUM.getCategories()) { + newMetricCategories.add(metricCategory); + } - this.metricCategories= newCategories; + this.metricCategories = newMetricCategories; return this; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java new file mode 100644 index 0000000000000..b88dc30c6cec0 --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java @@ -0,0 +1,182 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.models; + +import com.azure.core.models.GeoObjectType; +import com.azure.core.util.ExpandableStringEnum; +import com.azure.cosmos.implementation.clienttelemetry.MetricCategory; + +import java.util.EnumSet; +import java.util.Locale; +import java.util.StringJoiner; + +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; + +public class CosmosMetricCategory extends ExpandableStringEnum { + + private EnumSet metricCategories; + + /** + * Creates a new instance of {@link GeoObjectType} without a {@link #toString()} value. + *

+ * This constructor shouldn't be called as it will produce a {@link GeoObjectType} which doesn't + * have a String enum value. + * + * @deprecated Use one of the constants or the {@link #fromString(String)} factory method. + */ + CosmosMetricCategory() { + } + + /** + * All metrics enabled + */ + public static final CosmosMetricCategory ALL = fromString("All", CosmosMetricCategory.class) + .setCategories(MetricCategory.ALL_CATEGORIES); + + /** + * Default metrics (categories OperationSummary, RequestSummary, System, DirectChannels and DirectRequests) enabled. + * These metrics provide good overview of end-to-end telemetry and help with triaging for most common issues + */ + public static final CosmosMetricCategory DEFAULT = fromString("Default", CosmosMetricCategory.class) + .setCategories(MetricCategory.DEFAULT_CATEGORIES); + + /** + * Minimum set of metrics (categories OperationSummary and System) enabled. + * These metrics provide a basic overview of end-to-end telemetry but won't be sufficient for triaging + * most issues + */ + public static final CosmosMetricCategory MINIMUM = fromString("Minimum", CosmosMetricCategory.class) + .setCategories(EnumSet.of(MetricCategory.OperationSummary, MetricCategory.System)); + + /** + * The metrics in the OperationSummary category emit most important end-to-end metrics (like latency, request rate, + * request charge, request- and response-payload size etc.) for SDK operations + * These metrics are intended to visualize health state and impact - but alone not sufficient for triaging issues. + */ + public static final CosmosMetricCategory OPERATION_SUMMARY = + fromString("OperationSummary", CosmosMetricCategory.class) + .setCategories(EnumSet.of(MetricCategory.OperationSummary)); + + /** + * The metrics in the OperationDetails category emit additional end-to-end metrics (like item count) for SDK + * operations. + */ + public static final CosmosMetricCategory OPERATION_DETAILS = + fromString("OperationDetails", CosmosMetricCategory.class) + .setCategories(EnumSet.of(MetricCategory.OperationDetails)); + + /** + * The metrics in the RequestSummary category emit most important end-to-end metrics (like latency, request rate, + * request charge, request- and response-payload size etc.) for physical network requests - they have tags + * allowing to distinguish by service endpoint in the backend as well as the client-machine. So, these metrics + * can be very useful to triage whether impact (high latency, error rate) is skewed around certain client-machines + * and/or backend service endpoints. + */ + public static final CosmosMetricCategory REQUEST_SUMMARY = + fromString("RequestSummary", CosmosMetricCategory.class) + .setCategories(EnumSet.of(MetricCategory.RequestSummary)); + + /** + * The metrics in the RequestDetails category emit additional end-to-end metrics (like timeline metrics showing + * where in the request pipeline latency was spent etc.) for physical network requests - they have tags + * allowing to distinguish by service endpoint in the backend as well as the client-machine. So, these metrics + * can be very useful to triage whether impact (high latency, error rate) is skewed around certain client-machines + * and/or backend service endpoints. + */ + public static final CosmosMetricCategory REQUEST_DETAILS = + fromString("RequestDetails", CosmosMetricCategory.class) + .setCategories(EnumSet.of(MetricCategory.RequestDetails)); + + /** + * The metrics in the AddressResolutions category emit metrics for calls made to get replica addresses for a + * certain physical partition when using direct mode. A higher number of calls for a certain partition can + * indicate either network/connectivity issues or the fact that at least one of the replica in this + * partition has an issue. + */ + public static final CosmosMetricCategory ADDRESS_RESOLUTIONS = + fromString("AddressResolutions", CosmosMetricCategory.class) + .setCategories(EnumSet.of(MetricCategory.AddressResolutions)); + + /** + * The metrics in the DirectChannels category emit metrics allowing to monitor connection handling by service + * endpoint. These metrics can be used to identify how many connections to a certain endpoint have been + * established, closed or are currently active. This information can help triaging whether there are any + * connectivity/network issues for certain endpoints (high number of closed/re-opened connections). + */ + public static final CosmosMetricCategory DIRECT_CHANNELS = + fromString("DirectChannels", CosmosMetricCategory.class) + .setCategories(EnumSet.of(MetricCategory.DirectChannels)); + + /** + * The metrics in the DirectEndpoints category emit metrics allowing to monitor state by service + * endpoint. These metrics can be used to identify when a service endpoint was evicted (due to reaching + * idle time threshold etc.). In most cases it should be sufficient to monitor DirectChannels instead. + */ + public static final CosmosMetricCategory DIRECT_ENDPOINTS = + fromString("DirectEndpoints", CosmosMetricCategory.class) + .setCategories(EnumSet.of(MetricCategory.DirectEndpoints)); + + /** + * The metrics in the DirectRequests category emit metrics allowing to monitor requests by service + * endpoint (request rate, error rate, latency etc.). These metrics can be used to triage whether high latency or + * error rate is caused by a certain endpoint. + */ + public static final CosmosMetricCategory DIRECT_REQUESTS = + fromString("DirectRequests", CosmosMetricCategory.class) + .setCategories(EnumSet.of(MetricCategory.DirectRequests)); + + /** + * The metrics in the Legacy category emit metrics that should not be used anymore and exist only for + * backwards compatibility reasons. + */ + public static final CosmosMetricCategory LEGACY = + fromString("Legacy", CosmosMetricCategory.class) + .setCategories(EnumSet.of(MetricCategory.Legacy)); + + public static CosmosMetricCategory fromString(String name) { + checkNotNull(name, "Argument 'name' must not be null."); + + String normalizedName = name.trim().toLowerCase(Locale.ROOT); + switch (normalizedName) { + case "all": return CosmosMetricCategory.ALL; + case "default": return CosmosMetricCategory.DEFAULT; + case "minimum": return CosmosMetricCategory.MINIMUM; + case "operationsummary": return CosmosMetricCategory.OPERATION_SUMMARY; + case "operationdetails": return CosmosMetricCategory.OPERATION_DETAILS; + case "requestsummary": return CosmosMetricCategory.REQUEST_SUMMARY; + case "requestdetails": return CosmosMetricCategory.REQUEST_DETAILS; + case "addressresolutions": return CosmosMetricCategory.ADDRESS_RESOLUTIONS; + case "directchannels": return CosmosMetricCategory.DIRECT_CHANNELS; + case "directendpoints": return CosmosMetricCategory.DIRECT_ENDPOINTS; + case "directrequests": return CosmosMetricCategory.DIRECT_REQUESTS; + case "legacy": return CosmosMetricCategory.LEGACY; + + default: + String errorMessage = String.format( + "Argument 'name' has invalid value '%s' - valid values are: %s", + name, + getValidValues()); + + throw new IllegalArgumentException(errorMessage); + } + } + + private static String getValidValues() { + StringJoiner sj = new StringJoiner(", "); + for (CosmosMetricCategory c: CosmosMetricCategory.values(CosmosMetricCategory.class)) { + sj.add(c.toString()); + } + + return sj.toString(); + } + + private CosmosMetricCategory setCategories(EnumSet metricCategories) { + this.metricCategories = metricCategories; + return this; + } + + EnumSet getCategories() { + return this.metricCategories; + } +} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/module-info.java b/sdk/cosmos/azure-cosmos/src/main/java/module-info.java index 352bf1c37ac6b..dd8b1048b62e1 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/module-info.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/module-info.java @@ -70,7 +70,7 @@ opens com.azure.cosmos.util to com.fasterxml.jackson.databind; opens com.azure.cosmos.implementation.throughputControl to com.fasterxml.jackson.databind; opens com.azure.cosmos.implementation.throughputControl.controller.group.global to com.fasterxml.jackson.databind; - opens com.azure.cosmos.models to com.fasterxml.jackson.databind, com.fasterxml.jackson.module.afterburner, java.logging; + opens com.azure.cosmos.models to com.fasterxml.jackson.databind, com.fasterxml.jackson.module.afterburner, java.logging, com.azure.core; uses com.azure.cosmos.implementation.guava25.base.PatternCompiler; uses com.azure.core.util.tracing.Tracer; diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java index 7815f7e466512..45df28262a28c 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java @@ -25,6 +25,7 @@ import com.azure.cosmos.models.CosmosItemOperation; import com.azure.cosmos.models.CosmosItemRequestOptions; import com.azure.cosmos.models.CosmosItemResponse; +import com.azure.cosmos.models.CosmosMetricCategory; import com.azure.cosmos.models.CosmosMicrometerMetricsOptions; import com.azure.cosmos.models.CosmosPatchItemRequestOptions; import com.azure.cosmos.models.CosmosQueryRequestOptions; @@ -79,7 +80,7 @@ private EnumSet getEffectiveMetricCategories() { .getMetricCategories(this.inputClientTelemetryConfig); } - public void beforeTest(String... metricCategories) { + public void beforeTest(CosmosMetricCategory... metricCategories) { assertThat(this.client).isNull(); assertThat(this.meterRegistry).isNull(); @@ -87,7 +88,7 @@ public void beforeTest(String... metricCategories) { this.inputClientTelemetryConfig = new CosmosClientTelemetryConfig() .metricsOptions(new CosmosMicrometerMetricsOptions().meterRegistry(this.meterRegistry)) - .metricCategories(metricCategories); + .setMetricCategories(metricCategories); this.client = getClientBuilder() .clientTelemetryConfig(inputClientTelemetryConfig) @@ -138,7 +139,7 @@ public void maxValueExceedingDefinedLimitStillWorksWithoutException() throws Exc // Expected behavior is that higher values than the expected max value can still be recorded // it would only result in getting less accurate "estimates" for percentile histograms - this.beforeTest("Default"); + this.beforeTest(CosmosMetricCategory.DEFAULT); try { Tag dummyOperationTag = Tag.of(TagName.Operation.toString(), "TestDummy"); @@ -175,7 +176,7 @@ public void maxValueExceedingDefinedLimitStillWorksWithoutException() throws Exc @Test(groups = { "simple" }, timeOut = TIMEOUT) public void createItem() throws Exception { - this.beforeTest("Default"); + this.beforeTest(CosmosMetricCategory.DEFAULT); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); CosmosItemResponse itemResponse = container.createItem(properties); @@ -208,7 +209,7 @@ public void createItem() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void createItemWithAllMetrics() throws Exception { - this.beforeTest("All"); + this.beforeTest(CosmosMetricCategory.ALL); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); CosmosItemResponse itemResponse = container.createItem(properties); @@ -241,7 +242,7 @@ public void createItemWithAllMetrics() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void readItem() throws Exception { - this.beforeTest("Default"); + this.beforeTest(CosmosMetricCategory.DEFAULT); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); container.createItem(properties); @@ -277,7 +278,7 @@ public void readItem() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void replaceItem() throws Exception { - this.beforeTest("Default"); + this.beforeTest(CosmosMetricCategory.DEFAULT); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); CosmosItemResponse itemResponse = container.createItem(properties); @@ -315,7 +316,7 @@ public void replaceItem() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void deleteItem() throws Exception { - this.beforeTest("Default"); + this.beforeTest(CosmosMetricCategory.DEFAULT); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); container.createItem(properties); @@ -347,7 +348,7 @@ public void deleteItem() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void readAllItems() throws Exception { - this.beforeTest("Default"); + this.beforeTest(CosmosMetricCategory.DEFAULT); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); container.createItem(properties); @@ -390,7 +391,10 @@ public void readAllItems() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void readAllItemsWithDetailMetrics() throws Exception { - this.beforeTest("Default", "RequestDetails", "OperationDetails"); + this.beforeTest( + CosmosMetricCategory.DEFAULT, + CosmosMetricCategory.OPERATION_DETAILS, + CosmosMetricCategory.REQUEST_DETAILS); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); container.createItem(properties); @@ -436,7 +440,7 @@ public void readAllItemsWithDetailMetrics() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void queryItems() throws Exception { - this.beforeTest("Default"); + this.beforeTest(CosmosMetricCategory.DEFAULT); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); container.createItem(properties); @@ -485,7 +489,7 @@ public void queryItems() throws Exception { @Test(groups = { "emulator" }, timeOut = TIMEOUT * 100) public void itemPatchSuccess() { - this.beforeTest("Default"); + this.beforeTest(CosmosMetricCategory.DEFAULT); try { PatchTest.ToDoActivity testItem = PatchTest.ToDoActivity.createRandomItem(this.container); PatchTest.ToDoActivity testItem1 = PatchTest.ToDoActivity.createRandomItem(this.container); @@ -554,7 +558,7 @@ public void itemPatchSuccess() { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void createItem_withBulk() { - this.beforeTest("Default"); + this.beforeTest(CosmosMetricCategory.DEFAULT); try { int totalRequest = 5; @@ -608,7 +612,7 @@ public void createItem_withBulk() { @Test(groups = {"simple"}, timeOut = TIMEOUT) public void batchMultipleItemExecution() { - this.beforeTest("Default"); + this.beforeTest(CosmosMetricCategory.DEFAULT); try { TestDoc firstDoc = this.populateTestDoc(this.partitionKey1); TestDoc replaceDoc = this.getTestDocCopy(firstDoc); @@ -670,7 +674,7 @@ public void batchMultipleItemExecution() { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void effectiveMetricCategoriesForDefault() { - this.beforeTest("Default"); + this.beforeTest(CosmosMetricCategory.DEFAULT); try { assertThat(this.getEffectiveMetricCategories().size()).isEqualTo(5); @@ -692,7 +696,10 @@ public void effectiveMetricCategoriesForDefault() { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void effectiveMetricCategoriesForDefaultPlusDetails() { - this.beforeTest("Default", "RequestDetails", "OperationDETAILS"); + this.beforeTest( + CosmosMetricCategory.DEFAULT, + CosmosMetricCategory.fromString("RequestDetails"), + CosmosMetricCategory.fromString("OperationDETAILS")); try { assertThat(this.getEffectiveMetricCategories().size()).isEqualTo(7); @@ -716,12 +723,15 @@ public void effectiveMetricCategoriesForDefaultPlusDetails() { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void effectiveMetricCategoriesInvalidCategory() { + String badCategoryName = "InvalidCategory"; try { - this.beforeTest("Default", "InvalidCategory"); + this.beforeTest( + CosmosMetricCategory.DEFAULT, + CosmosMetricCategory.fromString(badCategoryName)); fail("Should have thrown exception"); } catch (IllegalArgumentException argError) { - assertThat(argError.getMessage()).contains("invalidcategory"); + assertThat(argError.getMessage()).contains(badCategoryName); } finally { this.afterTest(); } @@ -729,7 +739,7 @@ public void effectiveMetricCategoriesInvalidCategory() { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void effectiveMetricCategoriesForAll() { - this.beforeTest("All"); + this.beforeTest(CosmosMetricCategory.ALL); try { assertThat(this.getEffectiveMetricCategories().size()).isEqualTo(10); @@ -756,7 +766,7 @@ public void effectiveMetricCategoriesForAll() { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void effectiveMetricCategoriesForAllLatebound() { - this.beforeTest("Default"); + this.beforeTest(CosmosMetricCategory.DEFAULT); try { assertThat(this.getEffectiveMetricCategories().size()).isEqualTo(5); @@ -775,7 +785,7 @@ public void effectiveMetricCategoriesForAllLatebound() { // Now change the metricCategories on the config passed into the CosmosClientBuilder // and validate that these changes take effect immediately on the client build via the builder - this.inputClientTelemetryConfig.metricCategories("All"); + this.inputClientTelemetryConfig.setMetricCategories(CosmosMetricCategory.ALL); assertThat(this.getEffectiveMetricCategories().size()).isEqualTo(10); From 504ce9b0585a9c52cb43f27ee6a79685b0613230 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Tue, 14 Feb 2023 14:57:00 +0000 Subject: [PATCH 14/40] Update ci.yml --- eng/pipelines/templates/jobs/ci.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/eng/pipelines/templates/jobs/ci.yml b/eng/pipelines/templates/jobs/ci.yml index 695e8d7231968..328bb68f594f9 100644 --- a/eng/pipelines/templates/jobs/ci.yml +++ b/eng/pipelines/templates/jobs/ci.yml @@ -57,10 +57,15 @@ jobs: - job: 'Build' variables: - ArtifactName: 'packages' - Codeql.Enabled: true - Codeql.BuildIdentifier: ${{ parameters.ServiceDirectory }} - Codeql.SkipTaskAutoInjection: false + - template: /eng/pipelines/templates/variables/globals.yml + - name: 'ArtifactName' + value: 'packages' + - name: 'Codeql.Enabled' + value: 'true' + - name: 'Codeql.BuildIdentifier' + value: '${{ parameters.ServiceDirectory }}' + - name: 'Codeql.SkipTaskAutoInjection' + value: 'false' pool: name: azsdk-pool-mms-ubuntu-2004-general From b3bead8127981397f0bb0e8a53af12b8b1684b24 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Tue, 14 Feb 2023 15:20:45 +0000 Subject: [PATCH 15/40] Trying to fix build issue --- eng/pipelines/templates/jobs/ci.yml | 13 ++++--------- .../templates/stages/cosmos-sdk-client.yml | 3 +++ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/eng/pipelines/templates/jobs/ci.yml b/eng/pipelines/templates/jobs/ci.yml index 328bb68f594f9..695e8d7231968 100644 --- a/eng/pipelines/templates/jobs/ci.yml +++ b/eng/pipelines/templates/jobs/ci.yml @@ -57,15 +57,10 @@ jobs: - job: 'Build' variables: - - template: /eng/pipelines/templates/variables/globals.yml - - name: 'ArtifactName' - value: 'packages' - - name: 'Codeql.Enabled' - value: 'true' - - name: 'Codeql.BuildIdentifier' - value: '${{ parameters.ServiceDirectory }}' - - name: 'Codeql.SkipTaskAutoInjection' - value: 'false' + ArtifactName: 'packages' + Codeql.Enabled: true + Codeql.BuildIdentifier: ${{ parameters.ServiceDirectory }} + Codeql.SkipTaskAutoInjection: false pool: name: azsdk-pool-mms-ubuntu-2004-general diff --git a/eng/pipelines/templates/stages/cosmos-sdk-client.yml b/eng/pipelines/templates/stages/cosmos-sdk-client.yml index 5822fecb403a2..1e0afbc5d0fe9 100644 --- a/eng/pipelines/templates/stages/cosmos-sdk-client.yml +++ b/eng/pipelines/templates/stages/cosmos-sdk-client.yml @@ -28,6 +28,9 @@ parameters: type: boolean default: true +variables: + - template: /eng/pipelines/templates/variables/globals.yml + stages: - stage: Build jobs: From 8ca19f2e67b881b960969bf698c1ef2e2db5ec3f Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Tue, 14 Feb 2023 15:41:51 +0000 Subject: [PATCH 16/40] Trying to fix build issue --- .../main/java/com/azure/cosmos/models/CosmosMetricCategory.java | 1 + sdk/cosmos/ci.yml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java index b88dc30c6cec0..8bb1ecbb03512 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java @@ -25,6 +25,7 @@ public class CosmosMetricCategory extends ExpandableStringEnum Date: Tue, 14 Feb 2023 17:10:16 +0000 Subject: [PATCH 17/40] Adding missing javadoc comments --- .../com/azure/cosmos/models/CosmosMetricCategory.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java index 8bb1ecbb03512..05e60c17d411f 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java @@ -13,6 +13,9 @@ import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; +/** + * Categories for Cosmos DB client-side metrics + */ public class CosmosMetricCategory extends ExpandableStringEnum { private EnumSet metricCategories; @@ -135,6 +138,13 @@ public class CosmosMetricCategory extends ExpandableStringEnum Date: Wed, 15 Feb 2023 04:06:49 +0000 Subject: [PATCH 18/40] Refactoring to allow more granular option definition for metrics --- .../java/com/azure/cosmos/BridgeInternal.java | 1 + .../com/azure/cosmos/CosmosAsyncClient.java | 8 + .../ImplementationBridgeHelpers.java | 42 + .../ClientTelemetryMetrics.java | 866 +++++++++++------- .../clienttelemetry/CosmosMetricNames.java | 155 ---- .../clienttelemetry/TagName.java | 37 + .../RntbdTransportClient.java | 32 +- .../rntbd/RntbdMetrics.java | 4 +- .../models/CosmosClientTelemetryConfig.java | 160 +--- ...Category.java => CosmosMeterCategory.java} | 90 +- .../azure/cosmos/models/CosmosMeterName.java | 392 ++++++++ .../cosmos/models/CosmosMeterOptions.java | 121 +++ .../cosmos/models/CosmosMeterTagName.java | 212 +++++ .../CosmosMicrometerMetricsOptions.java | 209 +++++ .../cosmos/models/ModelBridgeInternal.java | 1 + .../com/azure/cosmos/ClientMetricsTest.java | 58 +- 16 files changed, 1715 insertions(+), 673 deletions(-) delete mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMetricNames.java rename sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/{CosmosMetricCategory.java => CosmosMeterCategory.java} (65%) create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterName.java create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterOptions.java create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterTagName.java diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/BridgeInternal.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/BridgeInternal.java index 705075aed3755..6e0143ba76607 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/BridgeInternal.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/BridgeInternal.java @@ -40,6 +40,7 @@ import com.azure.cosmos.implementation.query.metrics.ClientSideMetrics; import com.azure.cosmos.implementation.routing.PartitionKeyInternal; import com.azure.cosmos.models.CosmosItemResponse; +import com.azure.cosmos.models.CosmosMeterOptions; import com.azure.cosmos.models.CosmosStoredProcedureProperties; import com.azure.cosmos.models.FeedResponse; import com.azure.cosmos.models.ModelBridgeInternal; diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java index 16ade31a66555..e962aafafe178 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java @@ -28,6 +28,8 @@ import com.azure.cosmos.models.CosmosDatabaseProperties; import com.azure.cosmos.models.CosmosDatabaseRequestOptions; import com.azure.cosmos.models.CosmosDatabaseResponse; +import com.azure.cosmos.models.CosmosMeterName; +import com.azure.cosmos.models.CosmosMeterOptions; import com.azure.cosmos.models.CosmosPermissionProperties; import com.azure.cosmos.models.CosmosQueryRequestOptions; import com.azure.cosmos.models.ModelBridgeInternal; @@ -752,6 +754,12 @@ public List getPreferredRegions(CosmosAsyncClient client) { public boolean isEndpointDiscoveryEnabled(CosmosAsyncClient client) { return client.connectionPolicy.isEndpointDiscoveryEnabled(); } + + @Override + public CosmosMeterOptions getMeterOptions(CosmosAsyncClient client, CosmosMeterName name) { + return telemetryConfigAccessor + .getMeterOptions(client.clientTelemetryConfig, name); + } } ); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ImplementationBridgeHelpers.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ImplementationBridgeHelpers.java index ee0233ba0c43a..c36a14e8a3745 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ImplementationBridgeHelpers.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ImplementationBridgeHelpers.java @@ -38,6 +38,8 @@ import com.azure.cosmos.models.CosmosContainerProperties; import com.azure.cosmos.models.CosmosItemRequestOptions; import com.azure.cosmos.models.CosmosItemResponse; +import com.azure.cosmos.models.CosmosMeterName; +import com.azure.cosmos.models.CosmosMeterOptions; import com.azure.cosmos.models.CosmosPatchOperations; import com.azure.cosmos.models.CosmosQueryRequestOptions; import com.azure.cosmos.models.FeedResponse; @@ -1046,6 +1048,44 @@ public interface CosmosAsyncClientAccessor { boolean isSendClientTelemetryToServiceEnabled(CosmosAsyncClient client); List getPreferredRegions(CosmosAsyncClient client); boolean isEndpointDiscoveryEnabled(CosmosAsyncClient client); + CosmosMeterOptions getMeterOptions(CosmosAsyncClient client, CosmosMeterName name); + } + } + + public static final class CosmosMeterOptionsHelper { + private static final AtomicReference accessor = new AtomicReference<>(); + private static final AtomicBoolean cosmosMeterOptionsClassLoaded = new AtomicBoolean(false); + + private CosmosMeterOptionsHelper() {} + + public static void setCosmosMeterOptionsAccessor(final CosmosMeterOptionsAccessor newAccessor) { + if (!accessor.compareAndSet(null, newAccessor)) { + logger.debug("CosmosMeterOptionsAccessor already initialized!"); + } else { + logger.debug("Setting CosmosMeterOptionsAccessor..."); + cosmosMeterOptionsClassLoaded.set(true); + } + } + + public static CosmosMeterOptionsAccessor getCosmosMeterOptionsAccessor() { + if (!cosmosMeterOptionsClassLoaded.get()) { + logger.debug("Initializing CosmosMeterOptionsAccessor..."); + initializeAllAccessors(); + } + + CosmosMeterOptionsHelper.CosmosMeterOptionsAccessor snapshot = accessor.get(); + if (snapshot == null) { + logger.error("CosmosMeterOptionsAccessor is not initialized yet!"); + System.exit(9726); // Using a unique status code here to help debug the issue. + } + + return snapshot; + } + + public interface CosmosMeterOptionsAccessor { + EnumSet getSuppressedTagNames(CosmosMeterOptions options); + boolean isHistogramPublishingEnabled(CosmosMeterOptions options); + double[] getPercentiles(CosmosMeterOptions options); } } @@ -1133,6 +1173,8 @@ public interface CosmosClientTelemetryConfigAccessor { Boolean isSendClientTelemetryToServiceEnabled(CosmosClientTelemetryConfig config); boolean isClientMetricsEnabled(CosmosClientTelemetryConfig config); void resetIsSendClientTelemetryToServiceEnabled(CosmosClientTelemetryConfig config); + CosmosMeterOptions getMeterOptions(CosmosClientTelemetryConfig config, CosmosMeterName name); + CosmosMeterOptions createDisabledMeterOptions(CosmosMeterName name); CosmosClientTelemetryConfig createSnapshot( CosmosClientTelemetryConfig config, boolean effectiveIsClientTelemetryEnabled); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java index ff116796d63f9..2b0915f4c38e4 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java @@ -22,6 +22,8 @@ import com.azure.cosmos.implementation.directconnectivity.rntbd.RntbdRequestRecord; import com.azure.cosmos.implementation.guava25.net.PercentEscaper; import com.azure.cosmos.implementation.query.QueryInfo; +import com.azure.cosmos.models.CosmosMeterName; +import com.azure.cosmos.models.CosmosMeterOptions; import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.DistributionSummary; import io.micrometer.core.instrument.FunctionCounter; @@ -41,6 +43,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -51,6 +54,8 @@ public final class ClientTelemetryMetrics { private static final Logger logger = LoggerFactory.getLogger(ClientTelemetryMetrics.class); private static final ImplementationBridgeHelpers.CosmosAsyncClientHelper.CosmosAsyncClientAccessor clientAccessor = ImplementationBridgeHelpers.CosmosAsyncClientHelper.getCosmosAsyncClientAccessor(); + private static final ImplementationBridgeHelpers.CosmosMeterOptionsHelper.CosmosMeterOptionsAccessor optionsAccessor = + ImplementationBridgeHelpers.CosmosMeterOptionsHelper.getCosmosMeterOptionsAccessor(); private static final ImplementationBridgeHelpers.CosmosDiagnosticsHelper.CosmosDiagnosticsAccessor diagnosticsAccessor = ImplementationBridgeHelpers.CosmosDiagnosticsHelper.getCosmosDiagnosticsAccessor(); @@ -98,7 +103,7 @@ public static void recordSystemUsage( } DistributionSummary averageSystemCpuUsageMeter = DistributionSummary - .builder(nameOf(CosmosMetricNames.System.AvgCpuLoad)) + .builder(CosmosMeterName.SYSTEM_CPU.toString()) .baseUnit("%") .description("Avg. System CPU load") .maximumExpectedValue(100d) @@ -108,7 +113,7 @@ public static void recordSystemUsage( averageSystemCpuUsageMeter.record(averageSystemCpuUsage); DistributionSummary freeMemoryAvailableInMBMeter = DistributionSummary - .builder(nameOf(CosmosMetricNames.System.FreeMemoryAvailable)) + .builder(CosmosMeterName.SYSTEM_MEMORY_FREE.toString()) .baseUnit("MB") .description("Free memory available") .publishPercentiles() @@ -163,6 +168,7 @@ public static void recordOperation( OperationMetricProducer metricProducer = new OperationMetricProducer(metricCategories, metricTagNames, operationTags); metricProducer.recordOperation( + cosmosAsyncClient, requestCharge, latency, maxItemCount == null ? -1 : maxItemCount, @@ -211,10 +217,6 @@ public static String escape(String value) { return PERCENT_ESCAPER.escape(value); } - private static String nameOf(final String member) { - return "cosmos.client." + member; - } - private static Tags createOperationTags( EnumSet metricTagNames, CosmosAsyncClient cosmosAsyncClient, @@ -278,6 +280,27 @@ private static Tags createOperationTags( return Tags.of(effectiveTags); } + private static Tags getEffectiveTags(Tags tags, CosmosMeterOptions meterOptions) { + EnumSet suppressedTags = optionsAccessor.getSuppressedTagNames(meterOptions); + if (suppressedTags == null || suppressedTags.isEmpty()) { + return tags; + } + + Tags result = Tags.empty(); + HashSet suppressedNames = new HashSet<>(); + for (TagName t: suppressedTags) { + suppressedNames.add(t.name()); + } + + for (Tag t: tags) { + if (!suppressedNames.contains(t.getKey())) { + result.and(t); + } + } + + return result; + } + private static class OperationMetricProducer { private final EnumSet metricTagNames; private final EnumSet metricCategories; @@ -290,6 +313,7 @@ public OperationMetricProducer(EnumSet metricCategories, EnumSet } public void recordOperation( + CosmosAsyncClient cosmosAsyncClient, float requestCharge, Duration latency, int maxItemCount, @@ -297,51 +321,72 @@ public void recordOperation( CosmosDiagnostics diagnostics, Set contactedRegions) { - Counter operationsCounter = Counter - .builder(nameOf(CosmosMetricNames.OperationSummary.Calls)) - .baseUnit("calls") - .description("Operation calls") - .tags(operationTags) - .register(compositeRegistry); - operationsCounter.increment(); - - DistributionSummary requestChargeMeter = DistributionSummary - .builder(nameOf(CosmosMetricNames.OperationSummary.RequestCharge)) - .baseUnit("RU (request unit)") - .description("Operation RU charge") - .maximumExpectedValue(10_000_000d) - .publishPercentiles(0.95, 0.99) - .publishPercentileHistogram(true) - .tags(operationTags) - .register(compositeRegistry); - requestChargeMeter.record(Math.min(requestCharge, 10_000_000d)); + CosmosMeterOptions callsOptions = clientAccessor.getMeterOptions( + cosmosAsyncClient, + CosmosMeterName.OPERATION_SUMMARY_CALLS); - if (this.metricCategories.contains(MetricCategory.OperationDetails)) { - DistributionSummary regionsContactedMeter = DistributionSummary - .builder(nameOf(CosmosMetricNames.OperationDetails.RegionsContacted)) - .baseUnit("Regions contacted") - .description("Operation - regions contacted") - .maximumExpectedValue(100d) - .publishPercentiles(0.95, 0.99) - .publishPercentileHistogram(true) - .tags(operationTags) + if (callsOptions.isEnabled()) { + Counter operationsCounter = Counter + .builder(callsOptions.getMeterName().toString()) + .baseUnit("calls") + .description("Operation calls") + .tags(getEffectiveTags(operationTags, callsOptions)) + .register(compositeRegistry); + operationsCounter.increment(); + } + + CosmosMeterOptions requestChargeOptions = clientAccessor.getMeterOptions( + cosmosAsyncClient, + CosmosMeterName.OPERATION_SUMMARY_REQUEST_CHARGE); + if (requestChargeOptions.isEnabled()) { + DistributionSummary requestChargeMeter = DistributionSummary + .builder(requestChargeOptions.getMeterName().toString()) + .baseUnit("RU (request unit)") + .description("Operation RU charge") + .maximumExpectedValue(100_000d) + .publishPercentiles(optionsAccessor.getPercentiles(requestChargeOptions)) + .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(requestChargeOptions)) + .tags(getEffectiveTags(operationTags, requestChargeOptions)) .register(compositeRegistry); - if (contactedRegions != null && contactedRegions.size() > 0) { - regionsContactedMeter.record(Math.min(contactedRegions.size(), 100d)); + requestChargeMeter.record(Math.min(requestCharge, 100_000d)); + } + + if (this.metricCategories.contains(MetricCategory.OperationDetails)) { + CosmosMeterOptions regionsOptions = clientAccessor.getMeterOptions( + cosmosAsyncClient, + CosmosMeterName.OPERATION_DETAILS_REGIONS_CONTACTED); + if (regionsOptions.isEnabled()) { + DistributionSummary regionsContactedMeter = DistributionSummary + .builder(regionsOptions.getMeterName().toString()) + .baseUnit("Regions contacted") + .description("Operation - regions contacted") + .maximumExpectedValue(100d) + .publishPercentiles(optionsAccessor.getPercentiles(regionsOptions)) + .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(regionsOptions)) + .tags(getEffectiveTags(operationTags, regionsOptions)) + .register(compositeRegistry); + if (contactedRegions != null && contactedRegions.size() > 0) { + regionsContactedMeter.record(Math.min(contactedRegions.size(), 100d)); + } } - this.recordItemCounts(maxItemCount, actualItemCount); + this.recordItemCounts(cosmosAsyncClient, maxItemCount, actualItemCount); } - Timer latencyMeter = Timer - .builder(nameOf(CosmosMetricNames.OperationSummary.Latency)) - .description("Operation latency") - .maximumExpectedValue(Duration.ofSeconds(300)) - .publishPercentiles(0.95, 0.99) - .publishPercentileHistogram(true) - .tags(operationTags) - .register(compositeRegistry); - latencyMeter.record(latency); + CosmosMeterOptions latencyOptions = clientAccessor.getMeterOptions( + cosmosAsyncClient, + CosmosMeterName.OPERATION_SUMMARY_LATENCY); + if (latencyOptions.isEnabled()) { + Timer latencyMeter = Timer + .builder(latencyOptions.getMeterName().toString()) + .description("Operation latency") + .maximumExpectedValue(Duration.ofSeconds(300)) + .publishPercentiles(optionsAccessor.getPercentiles(latencyOptions)) + .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(latencyOptions)) + .tags(getEffectiveTags(operationTags, latencyOptions)) + .register(compositeRegistry); + latencyMeter.record(latency); + } List clientSideRequestStatistics = diagnosticsAccessor.getClientSideRequestStatistics(diagnostics); @@ -349,10 +394,18 @@ public void recordOperation( if (clientSideRequestStatistics != null) { for (ClientSideRequestStatistics requestStatistics : clientSideRequestStatistics) { - recordStoreResponseStatistics(requestStatistics.getResponseStatisticsList()); - recordStoreResponseStatistics(requestStatistics.getSupplementalResponseStatisticsList()); - recordGatewayStatistics(requestStatistics.getDuration(), requestStatistics.getGatewayStatistics()); - recordAddressResolutionStatistics(requestStatistics.getAddressResolutionStatistics()); + recordStoreResponseStatistics( + cosmosAsyncClient, + requestStatistics.getResponseStatisticsList()); + recordStoreResponseStatistics( + cosmosAsyncClient, + requestStatistics.getSupplementalResponseStatisticsList()); + recordGatewayStatistics( + cosmosAsyncClient, + requestStatistics.getDuration(), requestStatistics.getGatewayStatistics()); + recordAddressResolutionStatistics( + cosmosAsyncClient, + requestStatistics.getAddressResolutionStatistics()); } } @@ -366,10 +419,11 @@ public void recordOperation( QueryInfo.QueryPlanDiagnosticsContext queryPlanDiagnostics = feedDiagnostics.getQueryPlanDiagnosticsContext(); - recordQueryPlanDiagnostics(queryPlanDiagnostics); + recordQueryPlanDiagnostics(cosmosAsyncClient, queryPlanDiagnostics); } private void recordQueryPlanDiagnostics( + CosmosAsyncClient cosmosAsyncClient, QueryInfo.QueryPlanDiagnosticsContext queryPlanDiagnostics ) { if (queryPlanDiagnostics == null || !this.metricCategories.contains(MetricCategory.RequestSummary)) { @@ -380,86 +434,120 @@ private void recordQueryPlanDiagnostics( createQueryPlanTags(metricTagNames) ); - Counter requestCounter = Counter - .builder(nameOf(CosmosMetricNames.RequestSummary.Gateway.Requests)) - .baseUnit("requests") - .description("Gateway requests") - .tags(requestTags) - .register(compositeRegistry); - requestCounter.increment(); + CosmosMeterOptions requestsOptions = clientAccessor.getMeterOptions( + cosmosAsyncClient, + CosmosMeterName.REQUEST_SUMMARY_GATEWAY_REQUESTS); + if (requestsOptions.isEnabled()) { + Counter requestCounter = Counter + .builder(requestsOptions.getMeterName().toString()) + .baseUnit("requests") + .description("Gateway requests") + .tags(getEffectiveTags(requestTags, requestsOptions)) + .register(compositeRegistry); + requestCounter.increment(); + } Duration latency = queryPlanDiagnostics.getDuration(); if (latency != null) { - Timer requestLatencyMeter = Timer - .builder(nameOf(CosmosMetricNames.RequestSummary.Gateway.Latency)) - .description("Gateway Request latency") - .maximumExpectedValue(Duration.ofSeconds(300)) - .publishPercentiles(0.95, 0.99) - .publishPercentileHistogram(true) - .tags(requestTags) - .register(compositeRegistry); - requestLatencyMeter.record(latency); + CosmosMeterOptions latencyOptions = clientAccessor.getMeterOptions( + cosmosAsyncClient, + CosmosMeterName.REQUEST_SUMMARY_GATEWAY_LATENCY); + if (latencyOptions.isEnabled()) { + Timer requestLatencyMeter = Timer + .builder(latencyOptions.getMeterName().toString()) + .description("Gateway Request latency") + .maximumExpectedValue(Duration.ofSeconds(300)) + .publishPercentiles(optionsAccessor.getPercentiles(latencyOptions)) + .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(latencyOptions)) + .tags(getEffectiveTags(requestTags, latencyOptions)) + .register(compositeRegistry); + requestLatencyMeter.record(latency); + } } recordRequestTimeline( - CosmosMetricNames.RequestDetails.Gateway.TimelinePrefix, + cosmosAsyncClient, + CosmosMeterName.REQUEST_DETAILS_GATEWAY_TIMELINE, queryPlanDiagnostics.getRequestTimeline(), requestTags); } private void recordRequestPayloadSizes( + CosmosAsyncClient client, int requestPayloadSizeInBytes, int responsePayloadSizeInBytes ) { - DistributionSummary requestPayloadSizeMeter = DistributionSummary - .builder(nameOf(CosmosMetricNames.RequestSummary.RequestPayloadSize)) - .baseUnit("bytes") - .description("Request payload size in bytes") - .maximumExpectedValue(16d * 1024) - .publishPercentiles() - .publishPercentileHistogram(false) - .tags(operationTags) - .register(compositeRegistry); - requestPayloadSizeMeter.record(requestPayloadSizeInBytes); - - DistributionSummary responsePayloadSizeMeter = DistributionSummary - .builder(nameOf(CosmosMetricNames.RequestSummary.ResponsePayloadSize)) - .baseUnit("bytes") - .description("Response payload size in bytes") - .maximumExpectedValue(16d * 1024) - .publishPercentiles() - .publishPercentileHistogram(false) - .tags(operationTags) - .register(compositeRegistry); - responsePayloadSizeMeter.record(responsePayloadSizeInBytes); + CosmosMeterOptions reqSizeOptions = clientAccessor.getMeterOptions( + client, + CosmosMeterName.REQUEST_SUMMARY_SIZE_REQUEST); + if (reqSizeOptions.isEnabled()) { + DistributionSummary requestPayloadSizeMeter = DistributionSummary + .builder(reqSizeOptions.getMeterName().toString()) + .baseUnit("bytes") + .description("Request payload size in bytes") + .maximumExpectedValue(16d * 1024) + .publishPercentiles() + .publishPercentileHistogram(false) + .tags(getEffectiveTags(operationTags, reqSizeOptions)) + .register(compositeRegistry); + requestPayloadSizeMeter.record(requestPayloadSizeInBytes); + } + + CosmosMeterOptions rspSizeOptions = clientAccessor.getMeterOptions( + client, + CosmosMeterName.REQUEST_SUMMARY_SIZE_RESPONSE); + if (rspSizeOptions.isEnabled()) { + DistributionSummary responsePayloadSizeMeter = DistributionSummary + .builder(rspSizeOptions.getMeterName().toString()) + .baseUnit("bytes") + .description("Response payload size in bytes") + .maximumExpectedValue(16d * 1024) + .publishPercentiles() + .publishPercentileHistogram(false) + .tags(getEffectiveTags(operationTags, rspSizeOptions)) + .register(compositeRegistry); + responsePayloadSizeMeter.record(responsePayloadSizeInBytes); + } } private void recordItemCounts( + CosmosAsyncClient client, int maxItemCount, int actualItemCount ) { if (maxItemCount > 0 && this.metricCategories.contains(MetricCategory.OperationDetails)) { - DistributionSummary maxItemCountMeter = DistributionSummary - .builder(nameOf(CosmosMetricNames.OperationSummary.MaxItemCount)) - .baseUnit("item count") - .description("Request max. item count") - .maximumExpectedValue(1_000_000d) - .publishPercentiles() - .publishPercentileHistogram(false) - .tags(operationTags) - .register(compositeRegistry); - maxItemCountMeter.record(Math.max(0, Math.min(maxItemCount, 1_000_000d))); - DistributionSummary actualItemCountMeter = DistributionSummary - .builder(nameOf(CosmosMetricNames.OperationSummary.ActualItemCount)) - .baseUnit("item count") - .description("Response actual item count") - .maximumExpectedValue(1_000_000d) - .publishPercentiles() - .publishPercentileHistogram(false) - .tags(operationTags) - .register(compositeRegistry); - actualItemCountMeter.record(Math.max(0, Math.min(actualItemCount, 1_000_000d))); + CosmosMeterOptions maxItemCountOptions = clientAccessor.getMeterOptions( + client, + CosmosMeterName.OPERATION_DETAILS_MAX_ITEM_COUNT); + if (maxItemCountOptions.isEnabled()) { + DistributionSummary maxItemCountMeter = DistributionSummary + .builder(maxItemCountOptions.getMeterName().toString()) + .baseUnit("item count") + .description("Request max. item count") + .maximumExpectedValue(100_000d) + .publishPercentiles() + .publishPercentileHistogram(false) + .tags(getEffectiveTags(operationTags, maxItemCountOptions)) + .register(compositeRegistry); + maxItemCountMeter.record(Math.max(0, Math.min(maxItemCount, 100_000d))); + } + + CosmosMeterOptions actualItemCountOptions = clientAccessor.getMeterOptions( + client, + CosmosMeterName.OPERATION_DETAILS_ACTUAL_ITEM_COUNT); + if (actualItemCountOptions.isEnabled()) { + DistributionSummary actualItemCountMeter = DistributionSummary + .builder(actualItemCountOptions.getMeterName().toString()) + .baseUnit("item count") + .description("Response actual item count") + .maximumExpectedValue(100_000d) + .publishPercentiles() + .publishPercentileHistogram(false) + .tags(getEffectiveTags(operationTags, actualItemCountOptions)) + .register(compositeRegistry); + actualItemCountMeter.record(Math.max(0, Math.min(actualItemCount, 100_000d))); + } } } @@ -559,54 +647,80 @@ private Tags createAddressResolutionTags( return Tags.of(effectiveTags); } - private void recordRntbdEndpointStatistics(RntbdEndpointStatistics endpointStatistics, Tags requestTags) { + private void recordRntbdEndpointStatistics( + CosmosAsyncClient client, + RntbdEndpointStatistics endpointStatistics, + Tags requestTags) { if (endpointStatistics == null || !this.metricCategories.contains(MetricCategory.Legacy)) { return; } - DistributionSummary acquiredChannelsMeter = DistributionSummary - .builder( - nameOf(CosmosMetricNames.DisabledByDefaultLegacy.RntbdRequestEndpointStatistics.AcquiredChannels)) - .baseUnit("#") - .description("Endpoint statistics(acquired channels)") - .maximumExpectedValue(100_000d) - .publishPercentiles() - .publishPercentileHistogram(false) - .tags(requestTags) - .register(compositeRegistry); - - acquiredChannelsMeter.record(endpointStatistics.getAcquiredChannels()); - - DistributionSummary availableChannelsMeter = DistributionSummary - .builder( - nameOf(CosmosMetricNames.DisabledByDefaultLegacy.RntbdRequestEndpointStatistics.AvailableChannels)) - .baseUnit("#") - .description("Endpoint statistics(available channels)") - .maximumExpectedValue(100_000d) - .publishPercentiles() - .publishPercentileHistogram(false) - .tags(requestTags) - .register(compositeRegistry); - availableChannelsMeter.record(endpointStatistics.getAvailableChannels()); - - DistributionSummary inflightRequestsMeter = DistributionSummary - .builder( - nameOf(CosmosMetricNames.DisabledByDefaultLegacy.RntbdRequestEndpointStatistics.InflightRequests)) - .baseUnit("#") - .description("Endpoint statistics(inflight requests)") - .tags(requestTags) - .maximumExpectedValue(1_000_000d) - .publishPercentiles(0.95, 0.99) - .publishPercentileHistogram(true) - .register(compositeRegistry); - inflightRequestsMeter.record(endpointStatistics.getInflightRequests()); - } - - private void recordRequestTimeline(String prefix, RequestTimeline requestTimeline, Tags requestTags) { + CosmosMeterOptions acquiredOptions = clientAccessor.getMeterOptions( + client, + CosmosMeterName.LEGACY_DIRECT_ENDPOINT_STATISTICS_ACQUIRED); + if (acquiredOptions.isEnabled()) { + DistributionSummary acquiredChannelsMeter = DistributionSummary + .builder(acquiredOptions.getMeterName().toString()) + .baseUnit("#") + .description("Endpoint statistics(acquired channels)") + .maximumExpectedValue(100_000d) + .publishPercentiles() + .publishPercentileHistogram(false) + .tags(getEffectiveTags(requestTags, acquiredOptions)) + .register(compositeRegistry); + + acquiredChannelsMeter.record(endpointStatistics.getAcquiredChannels()); + } + + CosmosMeterOptions availableOptions = clientAccessor.getMeterOptions( + client, + CosmosMeterName.LEGACY_DIRECT_ENDPOINT_STATISTICS_AVAILABLE); + if (availableOptions.isEnabled()) { + DistributionSummary availableChannelsMeter = DistributionSummary + .builder(availableOptions.getMeterName().toString()) + .baseUnit("#") + .description("Endpoint statistics(available channels)") + .maximumExpectedValue(100_000d) + .publishPercentiles() + .publishPercentileHistogram(false) + .tags(getEffectiveTags(requestTags, availableOptions)) + .register(compositeRegistry); + availableChannelsMeter.record(endpointStatistics.getAvailableChannels()); + } + + CosmosMeterOptions inflightOptions = clientAccessor.getMeterOptions( + client, + CosmosMeterName.LEGACY_DIRECT_ENDPOINT_STATISTICS_INFLIGHT); + if (inflightOptions.isEnabled()) { + DistributionSummary inflightRequestsMeter = DistributionSummary + .builder(inflightOptions.getMeterName().toString()) + .baseUnit("#") + .description("Endpoint statistics(inflight requests)") + .tags(getEffectiveTags(requestTags, inflightOptions)) + .maximumExpectedValue(1_000_000d) + .publishPercentiles(optionsAccessor.getPercentiles(inflightOptions)) + .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(inflightOptions)) + .register(compositeRegistry); + inflightRequestsMeter.record(endpointStatistics.getInflightRequests()); + } + } + + private void recordRequestTimeline( + CosmosAsyncClient client, + CosmosMeterName name, + RequestTimeline requestTimeline, + Tags requestTags) { + if (requestTimeline == null || !this.metricCategories.contains(MetricCategory.RequestDetails)) { return; } + CosmosMeterOptions timelineOptions = clientAccessor.getMeterOptions( + client, + name); + if (!timelineOptions.isEnabled()) { + return; + } for (RequestTimeline.Event event : requestTimeline) { Duration duration = event.getDuration(); if (duration == null || duration == Duration.ZERO) { @@ -614,18 +728,19 @@ private void recordRequestTimeline(String prefix, RequestTimeline requestTimelin } Timer eventMeter = Timer - .builder(nameOf(prefix + escape(event.getName()))) + .builder(timelineOptions.getMeterName().toString() + "." + escape(event.getName())) .description(String.format("Request timeline (%s)", event.getName())) .maximumExpectedValue(Duration.ofSeconds(300)) - .publishPercentiles(0.95, 0.99) - .publishPercentileHistogram(true) - .tags(requestTags) + .publishPercentiles(optionsAccessor.getPercentiles(timelineOptions)) + .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(timelineOptions)) + .tags(getEffectiveTags(requestTags, timelineOptions)) .register(compositeRegistry); eventMeter.record(duration); } } private void recordStoreResponseStatistics( + CosmosAsyncClient client, List storeResponseStatistics) { if (!this.metricCategories.contains(MetricCategory.RequestSummary)) { @@ -653,69 +768,94 @@ private void recordStoreResponseStatistics( Double backendLatency = storeResultDiagnostics.getBackendLatencyInMs(); if (backendLatency != null) { - DistributionSummary backendRequestLatencyMeter = DistributionSummary - .builder(nameOf(CosmosMetricNames.RequestSummary.Direct.BackendLatency)) - .baseUnit("ms") - .description("Backend service latency") - .maximumExpectedValue(6_000d) - .publishPercentiles(0.95, 0.99) - .publishPercentileHistogram(true) - .tags(requestTags) + + CosmosMeterOptions beLatencyOptions = clientAccessor.getMeterOptions( + client, + CosmosMeterName.REQUEST_SUMMARY_DIRECT_BACKEND_LATENCY); + if (beLatencyOptions.isEnabled()) { + DistributionSummary backendRequestLatencyMeter = DistributionSummary + .builder(beLatencyOptions.getMeterName().toString()) + .baseUnit("ms") + .description("Backend service latency") + .maximumExpectedValue(6_000d) + .publishPercentiles(optionsAccessor.getPercentiles(beLatencyOptions)) + .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(beLatencyOptions)) + .tags(getEffectiveTags(requestTags, beLatencyOptions)) + .register(compositeRegistry); + backendRequestLatencyMeter.record(storeResultDiagnostics.getBackendLatencyInMs()); + } + } + + CosmosMeterOptions ruOptions = clientAccessor.getMeterOptions( + client, + CosmosMeterName.REQUEST_SUMMARY_DIRECT_REQUEST_CHARGE); + if (ruOptions.isEnabled()) { + double requestCharge = storeResponseDiagnostics.getRequestCharge(); + DistributionSummary requestChargeMeter = DistributionSummary + .builder(ruOptions.getMeterName().toString()) + .baseUnit("RU (request unit)") + .description("RNTBD Request RU charge") + .maximumExpectedValue(100_000d) + .publishPercentiles(optionsAccessor.getPercentiles(ruOptions)) + .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(ruOptions)) + .tags(getEffectiveTags(requestTags, ruOptions)) .register(compositeRegistry); - backendRequestLatencyMeter.record(storeResultDiagnostics.getBackendLatencyInMs()); + requestChargeMeter.record(Math.min(requestCharge, 100_000d)); } - double requestCharge = storeResponseDiagnostics.getRequestCharge(); - DistributionSummary requestChargeMeter = DistributionSummary - .builder(nameOf(CosmosMetricNames.RequestSummary.Direct.RequestCharge)) - .baseUnit("RU (request unit)") - .description("RNTBD Request RU charge") - .maximumExpectedValue(1_000_000d) - .publishPercentiles(0.95, 0.99) - .publishPercentileHistogram(true) - .tags(requestTags) - .register(compositeRegistry); - requestChargeMeter.record(Math.min(requestCharge, 1_000_000d)); + CosmosMeterOptions latencyOptions = clientAccessor.getMeterOptions( + client, + CosmosMeterName.REQUEST_SUMMARY_DIRECT_LATENCY); + if (latencyOptions.isEnabled()) { + Duration latency = responseStatistics.getDuration(); + if (latency != null) { + Timer requestLatencyMeter = Timer + .builder(latencyOptions.getMeterName().toString()) + .description("RNTBD Request latency") + .maximumExpectedValue(Duration.ofSeconds(6)) + .publishPercentiles(optionsAccessor.getPercentiles(latencyOptions)) + .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(latencyOptions)) + .tags(getEffectiveTags(requestTags, latencyOptions)) + .register(compositeRegistry); + requestLatencyMeter.record(latency); + } + } - Duration latency = responseStatistics.getDuration(); - if (latency != null) { - Timer requestLatencyMeter = Timer - .builder(nameOf(CosmosMetricNames.RequestSummary.Direct.Latency)) - .description("RNTBD Request latency") - .maximumExpectedValue(Duration.ofSeconds(6)) - .publishPercentiles(0.95, 0.99) - .publishPercentileHistogram(true) - .tags(requestTags) + CosmosMeterOptions reqOptions = clientAccessor.getMeterOptions( + client, + CosmosMeterName.REQUEST_SUMMARY_DIRECT_REQUESTS); + if (reqOptions.isEnabled()) { + Counter requestCounter = Counter + .builder(reqOptions.getMeterName().toString()) + .baseUnit("requests") + .description("RNTBD requests") + .tags(getEffectiveTags(requestTags, reqOptions)) .register(compositeRegistry); - requestLatencyMeter.record(latency); + requestCounter.increment(); } - Counter requestCounter = Counter - .builder(nameOf(CosmosMetricNames.RequestSummary.Direct.Requests)) - .baseUnit("requests") - .description("RNTBD requests") - .tags(requestTags) - .register(compositeRegistry); - requestCounter.increment(); - if (this.metricCategories.contains(MetricCategory.RequestDetails)) { recordRequestTimeline( - CosmosMetricNames.RequestDetails.Direct.TimelinePrefix, + client, + CosmosMeterName.REQUEST_DETAILS_DIRECT_TIMELINE, storeResponseDiagnostics.getRequestTimeline(), requestTags); } recordRequestPayloadSizes( + client, storeResponseDiagnostics.getRequestPayloadLength(), storeResponseDiagnostics.getResponsePayloadLength() ); recordRntbdEndpointStatistics( + client, storeResponseDiagnostics.getRntbdEndpointStatistics(), requestTags); } } private void recordGatewayStatistics( + CosmosAsyncClient client, Duration latency, ClientSideRequestStatistics.GatewayStatistics gatewayStatistics) { @@ -741,44 +881,61 @@ private void recordGatewayStatistics( null) ); - Counter requestCounter = Counter - .builder(nameOf(CosmosMetricNames.RequestSummary.Gateway.Requests)) - .baseUnit("requests") - .description("Gateway requests") - .tags(requestTags) - .register(compositeRegistry); - requestCounter.increment(); - - double requestCharge = gatewayStatistics.getRequestCharge(); - DistributionSummary requestChargeMeter = DistributionSummary - .builder(nameOf(CosmosMetricNames.RequestSummary.Gateway.RequestCharge)) - .baseUnit("RU (request unit)") - .description("Gateway Request RU charge") - .maximumExpectedValue(1_000_000d) - .publishPercentiles(0.95, 0.99) - .publishPercentileHistogram(true) - .tags(requestTags) - .register(compositeRegistry); - requestChargeMeter.record(Math.min(requestCharge, 1_000_000d)); + CosmosMeterOptions reqOptions = clientAccessor.getMeterOptions( + client, + CosmosMeterName.REQUEST_SUMMARY_GATEWAY_REQUESTS); + if (reqOptions.isEnabled()) { + Counter requestCounter = Counter + .builder(reqOptions.getMeterName().toString()) + .baseUnit("requests") + .description("Gateway requests") + .tags(getEffectiveTags(requestTags, reqOptions)) + .register(compositeRegistry); + requestCounter.increment(); + } - if (latency != null) { - Timer requestLatencyMeter = Timer - .builder(nameOf(CosmosMetricNames.RequestSummary.Gateway.Latency)) - .description("Gateway Request latency") - .maximumExpectedValue(Duration.ofSeconds(300)) - .publishPercentiles(0.95, 0.99) - .publishPercentileHistogram(true) - .tags(requestTags) + CosmosMeterOptions ruOptions = clientAccessor.getMeterOptions( + client, + CosmosMeterName.REQUEST_SUMMARY_GATEWAY_REQUEST_CHARGE); + if (ruOptions.isEnabled()) { + double requestCharge = gatewayStatistics.getRequestCharge(); + DistributionSummary requestChargeMeter = DistributionSummary + .builder(ruOptions.getMeterName().toString()) + .baseUnit("RU (request unit)") + .description("Gateway Request RU charge") + .maximumExpectedValue(100_000d) + .publishPercentiles(optionsAccessor.getPercentiles(ruOptions)) + .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(ruOptions)) + .tags(getEffectiveTags(requestTags, ruOptions)) .register(compositeRegistry); - requestLatencyMeter.record(latency); + requestChargeMeter.record(Math.min(requestCharge, 100_000d)); + } + + if (latency != null) { + CosmosMeterOptions latencyOptions = clientAccessor.getMeterOptions( + client, + CosmosMeterName.REQUEST_SUMMARY_GATEWAY_LATENCY); + if (latencyOptions.isEnabled()) { + Timer requestLatencyMeter = Timer + .builder(latencyOptions.getMeterName().toString()) + .description("Gateway Request latency") + .maximumExpectedValue(Duration.ofSeconds(300)) + .publishPercentiles(optionsAccessor.getPercentiles(latencyOptions)) + .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(latencyOptions)) + .tags(getEffectiveTags(requestTags, latencyOptions)) + .register(compositeRegistry); + requestLatencyMeter.record(latency); + } } recordRequestTimeline( - CosmosMetricNames.RequestDetails.Gateway.TimelinePrefix, + client, + CosmosMeterName.REQUEST_DETAILS_GATEWAY_TIMELINE, gatewayStatistics.getRequestTimeline(), requestTags); } private void recordAddressResolutionStatistics( + CosmosAsyncClient client, Map addressResolutionStatisticsMap) { if (addressResolutionStatisticsMap == null @@ -813,23 +970,33 @@ private void recordAddressResolutionStatistics( addressResolutionStatistics.getStartTimeUTC(), addressResolutionStatistics.getEndTimeUTC()); - Timer addressResolutionLatencyMeter = Timer - .builder(nameOf(CosmosMetricNames.Direct.AddressResolution.Latency)) - .description("Address resolution latency") - .maximumExpectedValue(Duration.ofSeconds(6)) - .publishPercentiles(0.95, 0.99) - .publishPercentileHistogram(true) - .tags(addressResolutionTags) - .register(compositeRegistry); - addressResolutionLatencyMeter.record(latency); + CosmosMeterOptions latencyOptions = clientAccessor.getMeterOptions( + client, + CosmosMeterName.DIRECT_ADDRESS_RESOLUTION_LATENCY); + if (latencyOptions.isEnabled()) { + Timer addressResolutionLatencyMeter = Timer + .builder(latencyOptions.getMeterName().toString()) + .description("Address resolution latency") + .maximumExpectedValue(Duration.ofSeconds(6)) + .publishPercentiles(optionsAccessor.getPercentiles(latencyOptions)) + .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(latencyOptions)) + .tags(getEffectiveTags(addressResolutionTags, latencyOptions)) + .register(compositeRegistry); + addressResolutionLatencyMeter.record(latency); + } - Counter requestCounter = Counter - .builder(nameOf(CosmosMetricNames.Direct.AddressResolution.Requests)) - .baseUnit("requests") - .description("Address resolution requests") - .tags(addressResolutionTags) - .register(compositeRegistry); - requestCounter.increment(); + CosmosMeterOptions reqOptions = clientAccessor.getMeterOptions( + client, + CosmosMeterName.DIRECT_ADDRESS_RESOLUTION_REQUESTS); + if (reqOptions.isEnabled()) { + Counter requestCounter = Counter + .builder(reqOptions.getMeterName().toString()) + .baseUnit("requests") + .description("Address resolution requests") + .tags(getEffectiveTags(addressResolutionTags, reqOptions)) + .register(compositeRegistry); + requestCounter.increment(); + } } } } @@ -844,64 +1011,101 @@ private static class RntbdMetricsV2 implements RntbdMetricsCompletionRecorder { private RntbdMetricsV2(MeterRegistry registry, RntbdTransportClient client, RntbdEndpoint endpoint) { Tags tags = Tags.of(endpoint.clientMetricTag()); - this.metricCategories = client.getMetricCategories(); - if (metricCategories.contains(MetricCategory.DirectRequests)) { - this.requests = Timer - .builder(nameOf(CosmosMetricNames.Direct.Requests.Latency)) - .description("RNTBD request latency") - .tags(tags) - .maximumExpectedValue(Duration.ofSeconds(300)) - .publishPercentileHistogram(true) - .publishPercentiles(0.95, 0.99) - .register(registry); - - this.responseErrors = Timer - .builder(nameOf(CosmosMetricNames.Direct.Requests.FailedRequestLatency)) - .description("RNTBD failed request latency") - .tags(tags) - .maximumExpectedValue(Duration.ofSeconds(300)) - .publishPercentileHistogram(true) - .publishPercentiles(0.95, 0.99) - .register(registry); - - this.responseSuccesses = Timer - .builder(nameOf(CosmosMetricNames.Direct.Requests.SuccessRequestLatency)) - .description("RNTBD successful request latency") - .tags(tags) - .maximumExpectedValue(Duration.ofSeconds(300)) - .publishPercentileHistogram(true) - .publishPercentiles(0.95, 0.99) - .register(registry); - - Gauge.builder(nameOf(CosmosMetricNames.Direct.Requests.Concurrent), endpoint, RntbdEndpoint::concurrentRequests) - .description("RNTBD concurrent requests (executing or queued request count)") - .tags(tags) - .register(registry); - - Gauge.builder(nameOf(CosmosMetricNames.Direct.Requests.Queued), endpoint, RntbdEndpoint::requestQueueLength) - .description("RNTBD queued request count") - .tags(tags) - .register(registry); - - this.requestSize = DistributionSummary.builder(nameOf(CosmosMetricNames.Direct.Requests.RequestPayloadSize)) - .description("RNTBD request size (bytes)") - .baseUnit("bytes") - .tags(tags) - .maximumExpectedValue(16_000_000d) - .publishPercentileHistogram(false) - .publishPercentiles() - .register(registry); - - this.responseSize = DistributionSummary.builder(nameOf(CosmosMetricNames.Direct.Requests.ResponsePayloadSize)) - .description("RNTBD response size (bytes)") - .baseUnit("bytes") - .tags(tags) - .maximumExpectedValue(16_000_000d) - .publishPercentileHistogram(false) - .publishPercentiles() - .register(registry); + + CosmosMeterOptions options = client + .getMeterOptions(CosmosMeterName.DIRECT_REQUEST_LATENCY); + if (options.isEnabled()) { + this.requests = Timer + .builder(options.getMeterName().toString()) + .description("RNTBD request latency") + .maximumExpectedValue(Duration.ofSeconds(300)) + .publishPercentiles(optionsAccessor.getPercentiles(options)) + .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(options)) + .tags(getEffectiveTags(tags, options)) + .register(registry); + } else { + this.requests = null; + } + + options = client + .getMeterOptions(CosmosMeterName.DIRECT_REQUEST_LATENCY_FAILED); + if (options.isEnabled()) { + this.responseErrors = Timer + .builder(options.getMeterName().toString()) + .description("RNTBD failed request latency") + .maximumExpectedValue(Duration.ofSeconds(300)) + .publishPercentiles(optionsAccessor.getPercentiles(options)) + .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(options)) + .tags(getEffectiveTags(tags, options)) + .register(registry); + } else { + this.responseErrors = null; + } + + options = client + .getMeterOptions(CosmosMeterName.DIRECT_REQUEST_LATENCY_SUCCESS); + if (options.isEnabled()) { + this.responseSuccesses = Timer + .builder(options.getMeterName().toString()) + .description("RNTBD successful request latency") + .maximumExpectedValue(Duration.ofSeconds(300)) + .publishPercentiles(optionsAccessor.getPercentiles(options)) + .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(options)) + .tags(getEffectiveTags(tags, options)) + .register(registry); + } else { + this.responseSuccesses = null; + } + + options = client + .getMeterOptions(CosmosMeterName.DIRECT_REQUEST_CONCURRENT_COUNT); + if (options.isEnabled()) { + Gauge.builder(options.getMeterName().toString(), endpoint, RntbdEndpoint::concurrentRequests) + .description("RNTBD concurrent requests (executing or queued request count)") + .tags(getEffectiveTags(tags, options)) + .register(registry); + } + + options = client + .getMeterOptions(CosmosMeterName.DIRECT_REQUEST_QUEUED_COUNT); + if (options.isEnabled()) { + Gauge.builder(options.getMeterName().toString(), endpoint, RntbdEndpoint::requestQueueLength) + .description("RNTBD queued request count") + .tags(getEffectiveTags(tags, options)) + .register(registry); + } + + options = client + .getMeterOptions(CosmosMeterName.DIRECT_REQUEST_SIZE_REQUEST); + if (options.isEnabled()) { + this.requestSize = DistributionSummary.builder(options.getMeterName().toString()) + .description("RNTBD request size (bytes)") + .baseUnit("bytes") + .tags(getEffectiveTags(tags, options)) + .maximumExpectedValue(16_000_000d) + .publishPercentileHistogram(false) + .publishPercentiles() + .register(registry); + } else { + this.requestSize = null; + } + + options = client + .getMeterOptions(CosmosMeterName.DIRECT_REQUEST_SIZE_RESPONSE); + if (options.isEnabled()) { + this.responseSize = DistributionSummary.builder(options.getMeterName().toString()) + .description("RNTBD response size (bytes)") + .baseUnit("bytes") + .tags(getEffectiveTags(tags, options)) + .maximumExpectedValue(16_000_000d) + .publishPercentileHistogram(false) + .publishPercentiles() + .register(registry); + } else { + this.responseSize = null; + } } else { this.requests = null; this.responseErrors = null; @@ -911,39 +1115,59 @@ private RntbdMetricsV2(MeterRegistry registry, RntbdTransportClient client, Rntb } if (metricCategories.contains(MetricCategory.DirectEndpoints)) { - Gauge.builder(nameOf(CosmosMetricNames.Direct.Endpoints.Count), client, RntbdTransportClient::endpointCount) - .description("RNTBD endpoint count") - .register(registry); + CosmosMeterOptions options = client + .getMeterOptions(CosmosMeterName.DIRECT_ENDPOINTS_COUNT); + if (options.isEnabled()) { + Gauge.builder(options.getMeterName().toString(), client, RntbdTransportClient::endpointCount) + .description("RNTBD endpoint count") + .register(registry); + } - FunctionCounter.builder( - nameOf(CosmosMetricNames.Direct.Endpoints.EvictedCount), - client, - RntbdTransportClient::endpointEvictionCount) - .description("RNTBD endpoint eviction count") - .register(registry); + options = client + .getMeterOptions(CosmosMeterName.DIRECT_ENDPOINTS_EVICTED); + if (options.isEnabled()) { + FunctionCounter.builder( + options.getMeterName().toString(), + client, + RntbdTransportClient::endpointEvictionCount) + .description("RNTBD endpoint eviction count") + .register(registry); + } } if (metricCategories.contains(MetricCategory.DirectChannels)) { - FunctionCounter.builder( - nameOf(CosmosMetricNames.Direct.Channels.Acquired), - endpoint, - RntbdEndpoint::totalChannelsAcquiredMetric) - .description("RNTBD acquired channel count") - .tags(tags) - .register(registry); - - FunctionCounter.builder( - nameOf(CosmosMetricNames.Direct.Channels.Closed), - endpoint, - RntbdEndpoint::totalChannelsClosedMetric) - .description("RNTBD closed channel count") - .tags(tags) - .register(registry); - - Gauge.builder(nameOf(CosmosMetricNames.Direct.Channels.Available), endpoint, RntbdEndpoint::channelsAvailableMetric) - .description("RNTBD available channel count") - .tags(tags) - .register(registry); + CosmosMeterOptions options = client + .getMeterOptions(CosmosMeterName.DIRECT_CHANNELS_ACQUIRED_COUNT); + if (options.isEnabled()) { + FunctionCounter.builder( + options.getMeterName().toString(), + endpoint, + RntbdEndpoint::totalChannelsAcquiredMetric) + .description("RNTBD acquired channel count") + .tags(getEffectiveTags(tags, options)) + .register(registry); + } + + options = client + .getMeterOptions(CosmosMeterName.DIRECT_CHANNELS_CLOSED_COUNT); + if (options.isEnabled()) { + FunctionCounter.builder( + options.getMeterName().toString(), + endpoint, + RntbdEndpoint::totalChannelsClosedMetric) + .description("RNTBD closed channel count") + .tags(getEffectiveTags(tags, options)) + .register(registry); + } + + options = client + .getMeterOptions(CosmosMeterName.DIRECT_CHANNELS_AVAILABLE_COUNT); + if (options.isEnabled()) { + Gauge.builder(options.getMeterName().toString(), endpoint, RntbdEndpoint::channelsAvailableMetric) + .description("RNTBD available channel count") + .tags(getEffectiveTags(tags, options)) + .register(registry); + } } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMetricNames.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMetricNames.java deleted file mode 100644 index 9fda15ca67a7f..0000000000000 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMetricNames.java +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -package com.azure.cosmos.implementation.clienttelemetry; - -public final class CosmosMetricNames { - - private CosmosMetricNames() {} - - public final static class Direct { - public final static class AddressResolution { - // Latency of the RNTBD address resolution request (Timer) - public final static String Latency = "rntbd.addressResolution.latency"; - - // Number of RNTBD address resolution requests (Counter) - public final static String Requests = "rntbd.addressResolution.requests"; - } - - public final static class Channels { - // Snapshot of the number of acquired channels for this endpoint (FunctionCounter) - public final static String Acquired = "rntbd.channels.acquired.count"; - - // Snapshot of the number of available channels for this endpoint (Gauge) - public final static String Available = "rntbd.channels.available.count"; - - // Snapshot of the number of closed channels for this endpoint (FunctionCounter) - public final static String Closed = "rntbd.channels.closed.count"; - } - - public final static class Requests { - // Latency of RNTBD requests for this endpoint (Timer) - public final static String Latency = "rntbd.requests.latency"; - - // Latency of failed RNTBD requests for this endpoint (Timer) - public final static String FailedRequestLatency = "rntbd.requests.failed.latency"; - - // Latency of successful RNTBD requests for this endpoint (Timer) - public final static String SuccessRequestLatency = "rntbd.requests.successful.latency"; - - // Snapshot of number of concurrent RNTBD requests for this endpoint (Gauge) - public final static String Concurrent = "rntbd.requests.concurrent.count"; - - // Snapshot of number of queued RNTBD requests for this endpoint (Gauge) - public final static String Queued = "rntbd.requests.queued.count"; - - // Size of the request payload (DistributionSummary) - public final static String RequestPayloadSize = "rntbd.req.reqSize"; - - // Size of the response payload (DistributionSummary) - public final static String ResponsePayloadSize = "rntbd.req.rspSize"; - } - - public final static class Endpoints { - // Snapshot of the number of endpoints (Gauge) - public final static String Count = "rntbd.endpoints.count"; - - // Snapshot of the number of evicted/closed endpoints (FunctionCounter) - public final static String EvictedCount = "rntbd.endpoints.evicted"; - } - } - - public final static class OperationSummary { - // Number of operation calls (Counter) - public final static String Calls = "op.calls"; - - // Total latency (across requests including retries) of the operation (Timer) - public final static String Latency = "op.latency"; - - // Actual item count - relevant for non-point-operations - indicating the actual number of - // docs returned in the response (DistributionSummary) - public final static String ActualItemCount = "op.actualItemCount"; - - // Max. item count - relevant for non-point-operations - indicating the requested max. number of - // docs returned in a single response (DistributionSummary) - public final static String MaxItemCount = "op.maxItemCount"; - - // Request charge for the operation (DistributionSummary) - public final static String RequestCharge = "op.RUs"; - } - - public final static class OperationDetails { - // Number of regions contacted for processing the operation (DistributionSummary) - public final static String RegionsContacted = "op.regionsContacted"; - } - - public final static class RequestDetails { - public final static class Direct { - // Set of latencies in different steps of the request pipeline (all Timers) - public final static String TimelinePrefix = "req.rntbd.timeline."; - } - - public final static class Gateway { - // Set of latencies in different steps of the request pipeline (all Timers) - public final static String TimelinePrefix = "req.gw.timeline."; - } - } - - public final static class RequestSummary { - - // Size of the request payload (DistributionSummary) - public final static String RequestPayloadSize = "req.reqPayloadSize"; - - // Size of the response payload (DistributionSummary) - public final static String ResponsePayloadSize = "req.rspPayloadSize"; - - public final static class Direct { - // Backend-latency of the request (DistributionSummary) - public final static String BackendLatency = "req.rntbd.backendLatency"; - - // Latency of the request (Timer) - public final static String Latency = "req.rntbd.latency"; - - // Request charge for a request (DistributionSummary) - public final static String RequestCharge = "req.rntbd.RUs"; - - // Number of requests (Counter) - public final static String Requests = "req.rntbd.requests"; - } - - public final static class Gateway { - // Latency of the request (Timer) - public final static String Latency = "req.gw.latency"; - - // Request charge for a request (DistributionSummary) - public final static String RequestCharge = "req.gw.RUs"; - - // Number of requests (Counter) - public final static String Requests = "req.gw.requests"; - } - } - - public final static class System { - // JVM's Free available memory (DistributionSummary) - public final static String FreeMemoryAvailable = "system.freeMemoryAvailable"; - - // Avg. system-wide CPU load (DistributionSummary) - public final static String AvgCpuLoad = "system.avgCpuLoad"; - } - - public final static class DisabledByDefaultLegacy { - - public final static String LegacyDirectTcpMetricsPrefix = "azure.cosmos.directTcp."; - - public final static class RntbdRequestEndpointStatistics { - - // Snapshot of acquired channels for the endpoint at time of request (DistributionSummary) - public final static String AcquiredChannels = "req.rntbd.stats.endpoint.acquiredChannels"; - - // Snapshot of available channels for the endpoint at time of request (DistributionSummary) - public final static String AvailableChannels = "req.rntbd.stats.endpoint.availableChannels"; - - // Snapshot of number of inflight requests for the endpoint at time of request (DistributionSummary) - public final static String InflightRequests = "req.rntbd.stats.endpoint.inflightRequests"; - } - } -} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/TagName.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/TagName.java index 1b1ccbbb58955..691c0991ec128 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/TagName.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/TagName.java @@ -2,6 +2,7 @@ // Licensed under the MIT License. package com.azure.cosmos.implementation.clienttelemetry; +import java.util.EnumSet; import java.util.Locale; public enum TagName { @@ -41,5 +42,41 @@ public String toLowerCase() { public int value() { return this.value; } + + public static final EnumSet DEFAULT_TAGS = EnumSet.of( + TagName.Container, + TagName.Operation, + TagName.OperationStatusCode, + TagName.ClientCorrelationId, + TagName.RequestStatusCode, + TagName.RequestOperationType, + TagName.ServiceAddress, + TagName.RegionName + ); + + public static final EnumSet ALL_TAGS = EnumSet.of( + TagName.Container, + TagName.Operation, + TagName.OperationStatusCode, + TagName.ClientCorrelationId, + TagName.ConsistencyLevel, + TagName.PartitionKeyRangeId, + TagName.RequestStatusCode, + TagName.RequestOperationType, + TagName.RegionName, + TagName.ServiceEndpoint, + TagName.ServiceAddress, + TagName.IsForceRefresh, + TagName.IsForceCollectionRoutingMapRefresh + ); + + public static final EnumSet MINIMUM_TAGS = EnumSet.of( + TagName.Container, + TagName.Operation, + TagName.OperationStatusCode, + TagName.ClientCorrelationId, + TagName.RequestStatusCode, + TagName.RequestOperationType + ); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/RntbdTransportClient.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/RntbdTransportClient.java index 487bfa7152575..48da35c07914c 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/RntbdTransportClient.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/RntbdTransportClient.java @@ -18,6 +18,9 @@ import com.azure.cosmos.implementation.clienttelemetry.MetricCategory; import com.azure.cosmos.implementation.directconnectivity.rntbd.*; import com.azure.cosmos.implementation.guava25.base.Strings; +import com.azure.cosmos.models.CosmosClientTelemetryConfig; +import com.azure.cosmos.models.CosmosMeterName; +import com.azure.cosmos.models.CosmosMeterOptions; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; @@ -93,7 +96,7 @@ public class RntbdTransportClient extends TransportClient { private final Tag tag; private boolean channelAcquisitionContextEnabled; private final GlobalEndpointManager globalEndpointManager; - private final EnumSet metricCategories; + private final CosmosClientTelemetryConfig metricConfig; // endregion @@ -130,7 +133,7 @@ public RntbdTransportClient( this.id = instanceCount.incrementAndGet(); this.tag = RntbdTransportClient.tag(this.id); this.globalEndpointManager = null; - this.metricCategories = MetricCategory.DEFAULT_CATEGORIES; + this.metricConfig = null; } RntbdTransportClient( @@ -154,12 +157,9 @@ public RntbdTransportClient( if (clientTelemetry != null && clientTelemetry.getClientTelemetryConfig() != null) { - this.metricCategories = ImplementationBridgeHelpers - .CosmosClientTelemetryConfigHelper - .getCosmosClientTelemetryConfigAccessor() - .getMetricCategories(clientTelemetry.getClientTelemetryConfig()); + this.metricConfig = clientTelemetry.getClientTelemetryConfig(); } else { - this.metricCategories = MetricCategory.DEFAULT_CATEGORIES; + this.metricConfig = null; } } @@ -371,7 +371,23 @@ private void throwIfClosed() { } public EnumSet getMetricCategories() { - return this.metricCategories; + return this.metricConfig != null ? + ImplementationBridgeHelpers + .CosmosClientTelemetryConfigHelper + .getCosmosClientTelemetryConfigAccessor() + .getMetricCategories(this.metricConfig) : MetricCategory.DEFAULT_CATEGORIES; + } + + public CosmosMeterOptions getMeterOptions(CosmosMeterName name) { + return this.metricConfig != null ? + ImplementationBridgeHelpers + .CosmosClientTelemetryConfigHelper + .getCosmosClientTelemetryConfigAccessor() + .getMeterOptions(this.metricConfig, name) : + ImplementationBridgeHelpers + .CosmosClientTelemetryConfigHelper + .getCosmosClientTelemetryConfigAccessor() + .createDisabledMeterOptions(name); } // endregion diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdMetrics.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdMetrics.java index db9df787ee817..6f4ddb2ce8468 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdMetrics.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdMetrics.java @@ -4,9 +4,9 @@ package com.azure.cosmos.implementation.directconnectivity.rntbd; import com.azure.cosmos.implementation.ConsoleLoggingRegistryFactory; -import com.azure.cosmos.implementation.clienttelemetry.CosmosMetricNames; import com.azure.cosmos.implementation.directconnectivity.RntbdTransportClient; import com.azure.cosmos.implementation.guava25.net.PercentEscaper; +import com.azure.cosmos.models.CosmosMeterName; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import io.micrometer.core.instrument.DistributionSummary; @@ -263,7 +263,7 @@ static String escape(String value) { } private static String nameOf(final String member) { - return CosmosMetricNames.DisabledByDefaultLegacy.LegacyDirectTcpMetricsPrefix + member; + return "azure.cosmos.directTcp." + member; } // endregion diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java index 557c384d410d3..7c84e0c1a0e0f 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java @@ -38,16 +38,7 @@ public final class CosmosClientTelemetryConfig { private static final Duration DEFAULT_NETWORK_REQUEST_TIMEOUT = Duration.ofSeconds(60); private static final Duration DEFAULT_IDLE_CONNECTION_TIMEOUT = Duration.ofSeconds(60); private static final int DEFAULT_MAX_CONNECTION_POOL_SIZE = 1000; - private static EnumSet DEFAULT_TAGS = EnumSet.of( - TagName.Container, - TagName.Operation, - TagName.OperationStatusCode, - TagName.ClientCorrelationId, - TagName.RequestStatusCode, - TagName.RequestOperationType, - TagName.ServiceAddress, - TagName.RegionName - ); + private Boolean clientTelemetryEnabled; private final Duration httpNetworkRequestTimeout; @@ -55,11 +46,10 @@ public final class CosmosClientTelemetryConfig { private final Duration idleHttpConnectionTimeout; private final ProxyOptions proxy; private String clientCorrelationId = null; - private EnumSet metricTagNames = DEFAULT_TAGS; - private EnumSet metricCategories = MetricCategory.DEFAULT_CATEGORIES.clone(); - private MeterRegistry clientMetricRegistry = null; + private EnumSet metricTagNamesOverride = null; private boolean isClientMetricsEnabled = false; private Boolean effectiveIsClientTelemetryEnabled = null; + private CosmosMicrometerMetricsOptions micrometerMetricsOptions = null; /** * Instantiates a new Cosmos client telemetry configuration. @@ -112,16 +102,31 @@ public CosmosClientTelemetryConfig metricsOptions(MetricsOptions clientMetricsOp "Currently only MetricsOptions of type CosmosMicrometerMetricsOptions are supported"); } - CosmosMicrometerMetricsOptions micrometerMetricsOptions = (CosmosMicrometerMetricsOptions)clientMetricsOptions; + CosmosMicrometerMetricsOptions candidate = (CosmosMicrometerMetricsOptions)clientMetricsOptions; + if (this.metricTagNamesOverride != null && + !this.metricTagNamesOverride.equals(candidate.getDefaultTagNames())) { + + if (TagName.DEFAULT_TAGS.equals(candidate.getDefaultTagNames())) { + candidate.setDefaultTagNames(this.metricTagNamesOverride); + } else { + throw new IllegalArgumentException( + "Tags for meters cannot be specified via the deprecated CosmosClientTelemetryConfig " + + "when they are also specified in CosmosMicrometerMetricOptions."); + } + } - this.clientMetricRegistry = micrometerMetricsOptions.getClientMetricRegistry(); + this.micrometerMetricsOptions = candidate; this.isClientMetricsEnabled = micrometerMetricsOptions.isEnabled(); return this; } MeterRegistry getClientMetricRegistry() { - return this.clientMetricRegistry; + if (this.micrometerMetricsOptions == null) { + return null; + } + + return this.micrometerMetricsOptions.getClientMetricRegistry(); } /** @@ -151,10 +156,14 @@ String getClientCorrelationId() { * * @param tagNames - a comma-separated list of tag names that should be considered * @return current CosmosClientTelemetryConfig + * + * @deprecated Use {@link CosmosMicrometerMetricsOptions#defaultTagNames(CosmosMeterTagName...)} or + * {@link CosmosMeterOptions#tagNames(CosmosMeterTagName...)} instead. */ + @Deprecated public CosmosClientTelemetryConfig metricTagNames(String... tagNames) { if (tagNames == null || tagNames.length == 0) { - this.metricTagNames = DEFAULT_TAGS; + this.metricTagNamesOverride = TagName.DEFAULT_TAGS.clone(); } Map tagNameMap = new HashMap<>(); @@ -189,15 +198,11 @@ public CosmosClientTelemetryConfig metricTagNames(String... tagNames) { EnumSet newTagNames = EnumSet.noneOf(TagName.class); tagNameStream.forEach(tagName -> newTagNames.add(tagName)); - this.metricTagNames = newTagNames; + this.metricTagNamesOverride = newTagNames; return this; } - EnumSet getMetricTagNames() { - return this.metricTagNames; - } - private CosmosClientTelemetryConfig setEffectiveIsClientTelemetryEnabled( boolean effectiveIsClientTelemetryEnabled) { @@ -205,102 +210,7 @@ private CosmosClientTelemetryConfig setEffectiveIsClientTelemetryEnabled( return this; } - /** - * Sets the categories of metrics that should be emitted. By default the following categories will be enabled: - * OperationSummary (required), RequestSummary, DirectChannels, DirectRequests, System (required) - * (the System and OperationSummary metrics are always collected and can't be disabled when enabling Cosmos metrics) - * For most use-cases that should be sufficient. An overview of the different metric categories can be found here: - * https://aka.ms/azure-cosmos-metrics - * NOTE: metric categories are mutable. You can safely modify the categories on the CosmosClientTelemetryConfig - * instance passed into the CosmosClientBuilder after the CosmosClient was created - and changes to the config - * instance will be reflected at runtime by the client. - * - * @param categories - a comma-separated list of metric categories that should be emitted - * @return current CosmosClientTelemetryConfig - */ - public CosmosClientTelemetryConfig setMetricCategories(CosmosMetricCategory... categories) { - if (categories == null || categories.length == 0) { - this.metricCategories = MetricCategory.DEFAULT_CATEGORIES.clone(); - } else { - EnumSet newMetricCategories = MetricCategory.MINIMAL_CATEGORIES.clone(); - for (CosmosMetricCategory c: categories) { - for (MetricCategory metricCategory: c.getCategories()) { - newMetricCategories.add(metricCategory); - } - } - - this.metricCategories = newMetricCategories; - } - - return this; - } - - /** - * Adds categories of metrics that should be emitted. By default the following categories will be enabled: - * OperationSummary (required), RequestSummary, DirectChannels, DirectRequests, System (required) - * (the System and OperationSummary metrics are always collected and can't be disabled when enabling Cosmos metrics) - * An overview of the different metric categories can be found here: - * https://aka.ms/azure-cosmos-metrics - * NOTE: metric categories are mutable. You can safely modify the categories on the CosmosClientTelemetryConfig - * instance passed into the CosmosClientBuilder after the CosmosClient was created - and changes to the config - * instance will be reflected at runtime by the client. - * - * @param categories - a comma-separated list of metric categories that should be emitted - * @return current CosmosClientTelemetryConfig - */ - public CosmosClientTelemetryConfig addMetricCategories(CosmosMetricCategory... categories) { - if (categories == null || categories.length == 0) { - return this; - } - EnumSet newMetricCategories = this.metricCategories.clone(); - for (CosmosMetricCategory c: categories) { - for (MetricCategory metricCategory: c.getCategories()) { - newMetricCategories.add(metricCategory); - } - } - - this.metricCategories = newMetricCategories; - return this; - } - - /** - * Removes categories of metrics that should be emitted. By default the following categories will be enabled: - * OperationSummary (required), RequestSummary, DirectChannels, DirectRequests, System (required) - * (the System and OperationSummary metrics are always collected and can't be disabled when enabling Cosmos metrics) - * An overview of the different metric categories can be found here: - * https://aka.ms/azure-cosmos-metrics - * NOTE: metric categories are mutable. You can safely modify the categories on the CosmosClientTelemetryConfig - * instance passed into the CosmosClientBuilder after the CosmosClient was created - and changes to the config - * instance will be reflected at runtime by the client. - * - * @param categories - a comma-separated list of metric categories that should be emitted - * @return current CosmosClientTelemetryConfig - */ - public CosmosClientTelemetryConfig removeMetricCategories(CosmosMetricCategory... categories) { - if (categories == null || categories.length == 0) { - return this; - } - - EnumSet newMetricCategories = this.metricCategories.clone(); - for (CosmosMetricCategory c: categories) { - for (MetricCategory metricCategory: c.getCategories()) { - newMetricCategories.remove(metricCategory); - } - } - - for (MetricCategory metricCategory: CosmosMetricCategory.MINIMUM.getCategories()) { - newMetricCategories.add(metricCategory); - } - - this.metricCategories = newMetricCategories; - - return this; - } - - EnumSet getMetricCategories() { - return this.metricCategories; - } Duration getHttpNetworkRequestTimeout() { return this.httpNetworkRequestTimeout; @@ -413,12 +323,24 @@ public ProxyOptions getProxy(CosmosClientTelemetryConfig config) { @Override public EnumSet getMetricCategories(CosmosClientTelemetryConfig config) { - return config.getMetricCategories(); + return config.micrometerMetricsOptions.getMetricCategories(); } @Override public EnumSet getMetricTagNames(CosmosClientTelemetryConfig config) { - return config.getMetricTagNames(); + return config.micrometerMetricsOptions.getDefaultTagNames(); + } + + @Override + public CosmosMeterOptions getMeterOptions( + CosmosClientTelemetryConfig config, + CosmosMeterName name) { + return config.micrometerMetricsOptions.getMeterOptions(name); + } + + @Override + public CosmosMeterOptions createDisabledMeterOptions(CosmosMeterName name) { + return new CosmosMeterOptions(name, false, null).setEnabled(false); } @Override diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterCategory.java similarity index 65% rename from sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java rename to sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterCategory.java index 05e60c17d411f..bdd286c14ab4b 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterCategory.java @@ -3,7 +3,6 @@ package com.azure.cosmos.models; -import com.azure.core.models.GeoObjectType; import com.azure.core.util.ExpandableStringEnum; import com.azure.cosmos.implementation.clienttelemetry.MetricCategory; @@ -16,33 +15,33 @@ /** * Categories for Cosmos DB client-side metrics */ -public class CosmosMetricCategory extends ExpandableStringEnum { +public final class CosmosMeterCategory extends ExpandableStringEnum { private EnumSet metricCategories; /** - * Creates a new instance of {@link GeoObjectType} without a {@link #toString()} value. + * Creates a new instance of {@link CosmosMeterCategory} without a {@link #toString()} value. *

- * This constructor shouldn't be called as it will produce a {@link GeoObjectType} which doesn't + * This constructor shouldn't be called as it will produce a {@link CosmosMeterCategory} which doesn't * have a String enum value. * * @deprecated Use one of the constants or the {@link #fromString(String)} factory method. */ @Deprecated - CosmosMetricCategory() { + CosmosMeterCategory() { } /** * All metrics enabled */ - public static final CosmosMetricCategory ALL = fromString("All", CosmosMetricCategory.class) + public static final CosmosMeterCategory ALL = fromString("All", CosmosMeterCategory.class) .setCategories(MetricCategory.ALL_CATEGORIES); /** * Default metrics (categories OperationSummary, RequestSummary, System, DirectChannels and DirectRequests) enabled. * These metrics provide good overview of end-to-end telemetry and help with triaging for most common issues */ - public static final CosmosMetricCategory DEFAULT = fromString("Default", CosmosMetricCategory.class) + public static final CosmosMeterCategory DEFAULT = fromString("Default", CosmosMeterCategory.class) .setCategories(MetricCategory.DEFAULT_CATEGORIES); /** @@ -50,7 +49,7 @@ public class CosmosMetricCategory extends ExpandableStringEnum metricCategories) { + private CosmosMeterCategory setCategories(EnumSet metricCategories) { this.metricCategories = metricCategories; return this; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterName.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterName.java new file mode 100644 index 0000000000000..3d3900e93318c --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterName.java @@ -0,0 +1,392 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.models; + +import com.azure.core.util.ExpandableStringEnum; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.StringJoiner; + +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; + +public final class CosmosMeterName extends ExpandableStringEnum { + + private final static Map meters = createMeterNameMap(); + + private CosmosMeterCategory meterCategory; + + /** + * Creates a new instance of {@link CosmosMeterName} without a {@link #toString()} value. + *

+ * This constructor shouldn't be called as it will produce a {@link CosmosMeterName} which doesn't + * have a String enum value. + * + * @deprecated Use one of the constants or the {@link #fromString(String)} factory method. + */ + @Deprecated + CosmosMeterName() { + } + + + /** + * Number of operation calls (Counter) + */ + public static final CosmosMeterName OPERATION_SUMMARY_CALLS = + fromString(nameOf("op.calls"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.OPERATION_SUMMARY); + + /** + * Total latency (across requests including retries) of the operation (Timer) + */ + public static final CosmosMeterName OPERATION_SUMMARY_LATENCY = + fromString(nameOf("op.latency"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.OPERATION_SUMMARY); + + /** + * Request charge for the operation (DistributionSummary) + */ + public static final CosmosMeterName OPERATION_SUMMARY_REQUEST_CHARGE = + fromString(nameOf("op.RUs"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.OPERATION_SUMMARY); + + /** + * Number of regions contacted for processing the operation (DistributionSummary) + */ + public static final CosmosMeterName OPERATION_DETAILS_REGIONS_CONTACTED = + fromString(nameOf("op.regionsContacted"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.OPERATION_DETAILS); + + /** + * Actual item count - relevant for non-point-operations - indicating the actual number of + * docs returned in the response (DistributionSummary) + * NOTE: No percentiles or histogram supported + */ + public static final CosmosMeterName OPERATION_DETAILS_ACTUAL_ITEM_COUNT = + fromString(nameOf("op.actualItemCount"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.OPERATION_DETAILS); + + /** + * Max. item count - relevant for non-point-operations - indicating the requested max. number of + * docs returned in a single response (DistributionSummary) + * NOTE: No percentiles or histogram supported + */ + public static final CosmosMeterName OPERATION_DETAILS_MAX_ITEM_COUNT = + fromString(nameOf("op.maxItemCount"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.OPERATION_DETAILS); + + /** + * Number of requests (Counter) + * NOTE: No percentiles or histogram supported + */ + public static final CosmosMeterName REQUEST_SUMMARY_DIRECT_REQUESTS = + fromString(nameOf("req.rntbd.requests"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.REQUEST_SUMMARY); + + /** + * Latency of the request (Timer) + */ + public static final CosmosMeterName REQUEST_SUMMARY_DIRECT_LATENCY = + fromString(nameOf("req.rntbd.latency"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.REQUEST_SUMMARY); + + /** + * Backend-latency of the request (DistributionSummary) + */ + public static final CosmosMeterName REQUEST_SUMMARY_DIRECT_BACKEND_LATENCY = + fromString(nameOf("req.rntbd.backendLatency"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.REQUEST_SUMMARY); + + /** + * Request charge for a request (DistributionSummary) + */ + public static final CosmosMeterName REQUEST_SUMMARY_DIRECT_REQUEST_CHARGE = + fromString(nameOf("req.rntbd.RUs"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.REQUEST_SUMMARY); + + /** + * Number of requests (Counter) + * NOTE: No percentiles or histogram supported + */ + public static final CosmosMeterName REQUEST_SUMMARY_GATEWAY_REQUESTS = + fromString(nameOf("req.gw.requests"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.REQUEST_SUMMARY); + + /** + * Latency of the request (Timer) + */ + public static final CosmosMeterName REQUEST_SUMMARY_GATEWAY_LATENCY = + fromString(nameOf("req.gw.latency"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.REQUEST_SUMMARY); + + /** + * Request charge for a request (DistributionSummary) + */ + public static final CosmosMeterName REQUEST_SUMMARY_GATEWAY_REQUEST_CHARGE = + fromString(nameOf("req.gw.RUs"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.REQUEST_SUMMARY); + + /** + * Size of the request payload (DistributionSummary) + * NOTE: No percentiles or histogram supported + */ + public static final CosmosMeterName REQUEST_SUMMARY_SIZE_REQUEST = + fromString(nameOf("req.reqPayloadSize"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.REQUEST_SUMMARY); + + /** + * Size of the response payload (DistributionSummary) + * NOTE: No percentiles or histogram supported + */ + public static final CosmosMeterName REQUEST_SUMMARY_SIZE_RESPONSE = + fromString(nameOf("req.rspPayloadSize"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.REQUEST_SUMMARY); + + /** + * Latency in different steps of the request pipeline (Timer) + */ + public static final CosmosMeterName REQUEST_DETAILS_DIRECT_TIMELINE = + fromString(nameOf("req.rntbd.timeline"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.REQUEST_DETAILS); + + /** + * Latency in different steps of the request pipeline (Timer) + */ + public static final CosmosMeterName REQUEST_DETAILS_GATEWAY_TIMELINE = + fromString(nameOf("req.gw.timeline"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.REQUEST_DETAILS); + + /** + * Number of acquired channels (new connections) for this endpoint (FunctionCounter) + */ + public static final CosmosMeterName DIRECT_CHANNELS_ACQUIRED_COUNT = + fromString(nameOf("rntbd.channels.acquired.count"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.DIRECT_CHANNELS); + + /** + * Number of closed channels / connections for this endpoint (FunctionCounter) + */ + public static final CosmosMeterName DIRECT_CHANNELS_CLOSED_COUNT = + fromString(nameOf("rntbd.channels.closed.count"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.DIRECT_CHANNELS); + + /** + * Snapshot of the number of available channels (active connections) for this endpoint (Gauge) + */ + public static final CosmosMeterName DIRECT_CHANNELS_AVAILABLE_COUNT = + fromString(nameOf("rntbd.channels.available.count"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.DIRECT_CHANNELS); + + /** + * Snapshot of the number of endpoints (Gauge) + */ + public static final CosmosMeterName DIRECT_ENDPOINTS_COUNT = + fromString(nameOf("rntbd.endpoints.count"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.DIRECT_ENDPOINTS); + + /** + * Number of evicted/closed endpoints (FunctionCounter) + */ + public static final CosmosMeterName DIRECT_ENDPOINTS_EVICTED = + fromString(nameOf("rntbd.endpoints.evicted"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.DIRECT_ENDPOINTS); + + /** + * Number of RNTBD address resolution requests (Counter) + */ + public static final CosmosMeterName DIRECT_ADDRESS_RESOLUTION_REQUESTS = + fromString(nameOf("rntbd.addressResolution.requests"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.DIRECT_ADDRESS_RESOLUTIONS); + + /** + * Latency of the RNTBD address resolution request (Timer) + */ + public static final CosmosMeterName DIRECT_ADDRESS_RESOLUTION_LATENCY = + fromString(nameOf("rntbd.addressResolution.latency"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.DIRECT_ADDRESS_RESOLUTIONS); + + /** + * Latency of RNTBD requests for this endpoint (Timer) + */ + public static final CosmosMeterName DIRECT_REQUEST_LATENCY = + fromString(nameOf("rntbd.requests.latency"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.DIRECT_REQUESTS); + + /** + * Latency of failed RNTBD requests for this endpoint (Timer) + */ + public static final CosmosMeterName DIRECT_REQUEST_LATENCY_FAILED = + fromString(nameOf("rntbd.requests.failed.latency"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.DIRECT_REQUESTS); + + /** + * Latency of successful RNTBD requests for this endpoint (Timer) + */ + public static final CosmosMeterName DIRECT_REQUEST_LATENCY_SUCCESS = + fromString(nameOf("rntbd.requests.successful.latency"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.DIRECT_REQUESTS); + + /** + * Snapshot of number of concurrent RNTBD requests for this endpoint (Gauge) + */ + public static final CosmosMeterName DIRECT_REQUEST_CONCURRENT_COUNT = + fromString(nameOf("rntbd.requests.concurrent.count"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.DIRECT_REQUESTS); + + /** + * Snapshot of number of queued RNTBD requests for this endpoint (Gauge) + */ + public static final CosmosMeterName DIRECT_REQUEST_QUEUED_COUNT = + fromString(nameOf("rntbd.requests.queued.count"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.DIRECT_REQUESTS); + + /** + * Size of the request payload (DistributionSummary) + */ + public static final CosmosMeterName DIRECT_REQUEST_SIZE_REQUEST = + fromString(nameOf("rntbd.req.reqSize"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.DIRECT_REQUESTS); + + /** + * Size of the response payload (DistributionSummary) + */ + public static final CosmosMeterName DIRECT_REQUEST_SIZE_RESPONSE = + fromString(nameOf("rntbd.req.rspSize"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.DIRECT_REQUESTS); + + /** + * Avg. system-wide CPU load (DistributionSummary) + */ + public static final CosmosMeterName SYSTEM_CPU = + fromString(nameOf("system.avgCpuLoad"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.SYSTEM); + + /** + * JVM's Free available memory (DistributionSummary) + */ + public static final CosmosMeterName SYSTEM_MEMORY_FREE = + fromString(nameOf("system.freeMemoryAvailable"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.SYSTEM); + + /** + * Distribution summary over snapshot of acquired channels for the endpoint at time + * of a request (DistributionSummary) + */ + public static final CosmosMeterName LEGACY_DIRECT_ENDPOINT_STATISTICS_ACQUIRED = + fromString(nameOf("req.rntbd.stats.endpoint.acquiredChannels"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.LEGACY); + + /** + * Distribution summary over snapshot of available channels for the endpoint at time + * of a request (DistributionSummary) + */ + public static final CosmosMeterName LEGACY_DIRECT_ENDPOINT_STATISTICS_AVAILABLE = + fromString(nameOf("req.rntbd.stats.endpoint.availableChannels"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.LEGACY); + + /** + * Distribution summary over snapshot of inflight channels for the endpoint at time + * of a request (DistributionSummary) + */ + public static final CosmosMeterName LEGACY_DIRECT_ENDPOINT_STATISTICS_INFLIGHT = + fromString(nameOf("req.rntbd.stats.endpoint.inflightRequests"), CosmosMeterName.class) + .setCategory(CosmosMeterCategory.LEGACY); + + /** + * Gets the corresponding metric category state from its string representation. + * + * @param name The name of the Cosmos metric category to convert. + * + * @return The corresponding Cosmos metric category. + */ + public static CosmosMeterName fromString(String name) { + checkNotNull(name, "Argument 'name' must not be null."); + + String normalizedName = name.trim().toLowerCase(Locale.ROOT); + CosmosMeterName meterName = meters.getOrDefault(normalizedName, null); + + if (meterName == null) { + String errorMessage = String.format( + "Argument 'name' has invalid value '%s' - valid values are: %s", + name, + getValidValues()); + + throw new IllegalArgumentException(errorMessage); + } + + return meterName; + } + + private static Map createMeterNameMap() { + Map map = new HashMap<>(); + map.put(nameOf("op.latency"), CosmosMeterName.OPERATION_SUMMARY_LATENCY); + map.put(nameOf("op.calls"), CosmosMeterName.OPERATION_SUMMARY_CALLS); + map.put(nameOf("op.rus"), CosmosMeterName.OPERATION_SUMMARY_REQUEST_CHARGE); + map.put(nameOf("op.maxitemcount"), CosmosMeterName.OPERATION_DETAILS_MAX_ITEM_COUNT); + map.put(nameOf("op.actualitemcount"), CosmosMeterName.OPERATION_DETAILS_ACTUAL_ITEM_COUNT); + map.put(nameOf("op.regionscontacted"), CosmosMeterName.OPERATION_DETAILS_REGIONS_CONTACTED); + map.put(nameOf("req.rntbd.requests"), CosmosMeterName.REQUEST_SUMMARY_DIRECT_REQUESTS); + map.put(nameOf("req.rntbd.latency"), CosmosMeterName.REQUEST_SUMMARY_DIRECT_LATENCY); + map.put(nameOf("req.rntbd.backendlatency"), CosmosMeterName.REQUEST_SUMMARY_DIRECT_BACKEND_LATENCY); + map.put(nameOf("req.rntbd.rus"), CosmosMeterName.REQUEST_SUMMARY_DIRECT_REQUEST_CHARGE); + map.put(nameOf("req.gw.requests"), CosmosMeterName.REQUEST_SUMMARY_GATEWAY_REQUESTS); + map.put(nameOf("req.gw.latency"), CosmosMeterName.REQUEST_SUMMARY_GATEWAY_LATENCY); + map.put(nameOf("req.gw.rus"), CosmosMeterName.REQUEST_SUMMARY_GATEWAY_REQUEST_CHARGE); + map.put(nameOf("req.reqPayloadSize"), CosmosMeterName.REQUEST_SUMMARY_SIZE_REQUEST); + map.put(nameOf("req.rspPayloadSize"), CosmosMeterName.REQUEST_SUMMARY_SIZE_RESPONSE); + map.put(nameOf("req.rntbd.timeline"), CosmosMeterName.REQUEST_DETAILS_DIRECT_TIMELINE); + map.put(nameOf("req.gw.timeline"), CosmosMeterName.REQUEST_DETAILS_GATEWAY_TIMELINE); + map.put(nameOf("rntbd.channels.acquired.count"), CosmosMeterName.DIRECT_CHANNELS_ACQUIRED_COUNT); + map.put(nameOf("rntbd.channels.available.count"), CosmosMeterName.DIRECT_CHANNELS_AVAILABLE_COUNT); + map.put(nameOf("rntbd.channels.closed.count"), CosmosMeterName.DIRECT_CHANNELS_CLOSED_COUNT); + map.put(nameOf("rntbd.endpoints.count"), CosmosMeterName.DIRECT_ENDPOINTS_COUNT); + map.put(nameOf("rntbd.endpoints.evicted"), CosmosMeterName.DIRECT_ENDPOINTS_EVICTED); + map.put(nameOf("rntbd.addressresolution.requests"), CosmosMeterName.DIRECT_ADDRESS_RESOLUTION_REQUESTS); + map.put(nameOf("rntbd.addressresolution.latency"), CosmosMeterName.DIRECT_ADDRESS_RESOLUTION_LATENCY); + map.put(nameOf("rntbd.requests.latency"), CosmosMeterName.DIRECT_REQUEST_LATENCY); + map.put(nameOf("rntbd.requests.failed.latency"), CosmosMeterName.DIRECT_REQUEST_LATENCY_FAILED); + map.put(nameOf("rntbd.requests.successful.latency"), CosmosMeterName.DIRECT_REQUEST_LATENCY_SUCCESS); + map.put(nameOf("rntbd.requests.concurrent.count"), CosmosMeterName.DIRECT_REQUEST_CONCURRENT_COUNT); + map.put(nameOf("rntbd.requests.queued.count"), CosmosMeterName.DIRECT_REQUEST_QUEUED_COUNT); + map.put(nameOf("rntbd.req.reqsize"), CosmosMeterName.DIRECT_REQUEST_SIZE_REQUEST); + map.put(nameOf("rntbd.req.rspsize"), CosmosMeterName.DIRECT_REQUEST_SIZE_RESPONSE); + map.put(nameOf("system.freememoryavailable"), CosmosMeterName.SYSTEM_MEMORY_FREE); + map.put(nameOf("system.avgcpuload"), CosmosMeterName.SYSTEM_CPU); + map.put( + nameOf("req.rntbd.stats.endpoint.acquiredchannels"), + CosmosMeterName.LEGACY_DIRECT_ENDPOINT_STATISTICS_ACQUIRED); + map.put( + nameOf("req.rntbd.stats.endpoint.availablechannels"), + CosmosMeterName.LEGACY_DIRECT_ENDPOINT_STATISTICS_AVAILABLE); + map.put( + nameOf("req.rntbd.stats.endpoint.inflightrequests"), + CosmosMeterName.LEGACY_DIRECT_ENDPOINT_STATISTICS_INFLIGHT); + + return Collections.unmodifiableMap(map); + } + + private static String getValidValues() { + StringJoiner sj = new StringJoiner(", "); + for (CosmosMeterName c: CosmosMeterName.values(CosmosMeterName.class)) { + sj.add(c.toString()); + } + + return sj.toString(); + } + + private CosmosMeterName setCategory(CosmosMeterCategory metricCategory) { + this.meterCategory = meterCategory; + return this; + } + + public CosmosMeterCategory getCategory() { + return this.meterCategory; + } + + private static String nameOf(final String member) { + return "cosmos.client." + member; + } +} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterOptions.java new file mode 100644 index 0000000000000..5e849a5186d5e --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterOptions.java @@ -0,0 +1,121 @@ +package com.azure.cosmos.models; + +import com.azure.core.util.MetricsOptions; +import com.azure.cosmos.implementation.ImplementationBridgeHelpers; +import com.azure.cosmos.implementation.clienttelemetry.TagName; + +import java.util.EnumSet; + +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; + +public final class CosmosMeterOptions extends MetricsOptions { + + private final CosmosMeterName meterName; + private boolean isHistogramPublishingEnabled; + private double[] percentiles; + private EnumSet suppressedTagNames; + + /** + * Instantiates new options for a specific Cosmos DB meter + */ + CosmosMeterOptions( + CosmosMeterName meterName, + boolean isHistogramPublishingEnabled, + double[] percentiles) { + + checkNotNull(meterName, "Argument 'meterName' must not be null."); + + this.meterName = meterName; + this.isHistogramPublishingEnabled = isHistogramPublishingEnabled; + this.percentiles = percentiles; + this.suppressedTagNames = EnumSet.noneOf(TagName.class); + } + + public CosmosMeterName getMeterName() { + return this.meterName; + } + + /** + * Sets the tags that should be used for this meter (when applicable) + * + * @param tags - the tags to be used (when applicable) for this meter + * @return current CosmosMeterOptions instance + */ + public CosmosMeterOptions suppressTagNames(CosmosMeterTagName... tags) { + EnumSet newTagNames = EnumSet.noneOf(TagName.class); + if (tags != null && tags.length > 0) { + for (CosmosMeterTagName t: tags) { + for (TagName tagName: t.getTagNames()) { + if (!TagName.MINIMUM_TAGS.contains(tagName)) { + newTagNames.add(tagName); + } + } + } + } + + this.suppressedTagNames = newTagNames; + + return this; + } + + /** + * Sets the tags that should be used for this meter (when applicable) + * + * @param isEnabled - a flag indicating whether histogram publishing is enabled for this meter + * @return current CosmosMeterOptions instance + */ + public CosmosMeterOptions histogramPublishingEnabled(boolean isEnabled) { + this.isHistogramPublishingEnabled = isEnabled; + + return this; + } + + /** + * Sets the percentiles that should be captured for this meter (when applicable) + * + * @param percentiles - a flag indicating whether histogram publishing is enabled for this meter + * @return current CosmosMeterOptions instance + */ + public CosmosMeterOptions percentiles(double... percentiles) { + if (percentiles == null || percentiles.length == 0) { + this.percentiles = null; + } else { + this.percentiles = percentiles.clone(); + } + + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public CosmosMeterOptions setEnabled(boolean enabled) { + super.setEnabled(enabled); + return this; + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // the following helper/accessor only helps to access this class outside of this package.// + /////////////////////////////////////////////////////////////////////////////////////////// + static void initialize() { + ImplementationBridgeHelpers.CosmosMeterOptionsHelper.setCosmosMeterOptionsAccessor( + new ImplementationBridgeHelpers.CosmosMeterOptionsHelper.CosmosMeterOptionsAccessor() { + @Override + public EnumSet getSuppressedTagNames(CosmosMeterOptions options) { + return options.suppressedTagNames; + } + + @Override + public boolean isHistogramPublishingEnabled(CosmosMeterOptions options) { + return options.isHistogramPublishingEnabled; + } + + @Override + public double[] getPercentiles(CosmosMeterOptions options) { + return options.percentiles; + } + } + ); + } +} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterTagName.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterTagName.java new file mode 100644 index 0000000000000..275c735a77917 --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterTagName.java @@ -0,0 +1,212 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.azure.cosmos.implementation.clienttelemetry.TagName; + +import java.util.EnumSet; +import java.util.Locale; +import java.util.StringJoiner; + +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; + +public final class CosmosMeterTagName extends ExpandableStringEnum { + + private EnumSet tagNames; + + /** + * Creates a new instance of {@link CosmosMeterTagName} without a {@link #toString()} value. + *

+ * This constructor shouldn't be called as it will produce a {@link CosmosMeterTagName} which doesn't + * have a String enum value. + * + * @deprecated Use one of the constants or the {@link #fromString(String)} factory method. + */ + @Deprecated + CosmosMeterTagName() { + } + + /** + * All possible tags + */ + public static final CosmosMeterTagName ALL = fromString("All", CosmosMeterTagName.class) + .setTagNames(TagName.ALL_TAGS); + + /** + * Default tags + */ + public static final CosmosMeterTagName DEFAULT = fromString("Default", CosmosMeterTagName.class) + .setTagNames(TagName.DEFAULT_TAGS); + + /** + * Minimum tags that are required and cannot be disabled + */ + public static final CosmosMeterTagName MINIMUM = fromString("Minimum", CosmosMeterTagName.class) + .setTagNames(TagName.MINIMUM_TAGS); + + /** + * Effective Consistency model + * Applicable to operations and requests + */ + public static final CosmosMeterTagName CONSISTENCY_LEVEL = + fromString("ConsistencyLevel", CosmosMeterTagName.class) + .setTagNames(EnumSet.of(TagName.ConsistencyLevel)); + + /** + * Container identifier + * applicable to operations and requests + */ + public static final CosmosMeterTagName CONTAINER = + fromString("Container", CosmosMeterTagName.class) + .setTagNames(EnumSet.of(TagName.Container)); + + /** + * The service endpoint (hostname + port) + * Applicable to requests, direct channel, direct endpoint and direct requests + */ + public static final CosmosMeterTagName SERVICE_ENDPOINT = + fromString("ServiceEndpoint", CosmosMeterTagName.class) + .setTagNames(EnumSet.of(TagName.ServiceEndpoint)); + + /** + * The service endpoint (hostname + port, partitionId, replicaId) + * Applicable to requests + */ + public static final CosmosMeterTagName SERVICE_ADDRESS= + fromString("ServiceAddress", CosmosMeterTagName.class) + .setTagNames(EnumSet.of(TagName.ServiceAddress)); + + /** + * The region names of the regions handling the operation/request + * Applicable to requests and operations + */ + public static final CosmosMeterTagName REGION_NAME = + fromString("RegionName", CosmosMeterTagName.class) + .setTagNames(EnumSet.of(TagName.RegionName)); + + /** + * Operation status code. + * Applicable to operations + */ + public static final CosmosMeterTagName OPERATION_STATUS_CODE = + fromString("OperationStatusCode", CosmosMeterTagName.class) + .setTagNames(EnumSet.of(TagName.OperationStatusCode)); + + /** + * Operation type + * Applicable to operations + */ + public static final CosmosMeterTagName OPERATION = + fromString("Operation", CosmosMeterTagName.class) + .setTagNames(EnumSet.of(TagName.Operation)); + + + /** + * Request status code + * Applicable to requests + */ + public static final CosmosMeterTagName REQUEST_STATUS_CODE = + fromString("RequestStatusCode", CosmosMeterTagName.class) + .setTagNames(EnumSet.of(TagName.RequestStatusCode)); + + /** + * Request operation type + * Applicable to requests + */ + public static final CosmosMeterTagName REQUEST_OPERATION_TYPE = + fromString("RequestOperationType", CosmosMeterTagName.class) + .setTagNames(EnumSet.of(TagName.RequestOperationType)); + + /** + * An identifier for the instance of the Cosmos client + * Applicable to all meters + */ + public static final CosmosMeterTagName CLIENT_CORRELATION_ID = + fromString("ClientCorrelationId", CosmosMeterTagName.class) + .setTagNames(EnumSet.of(TagName.ClientCorrelationId)); + + /** + * An indicator whether an address resolution refresh requested a cache refresh + * Applicable to address resolutions + */ + public static final CosmosMeterTagName ADDRESS_RESOLUTION_FORCED_REFRESH = + fromString("IsForceRefresh", CosmosMeterTagName.class) + .setTagNames(EnumSet.of(TagName.IsForceRefresh)); + + /** + * An indicator whether an address resolution refresh requested a collection routing map + * cache refresh + * Applicable to address resolutions + */ + public static final CosmosMeterTagName ADDRESS_RESOLUTION_COLLECTION_MAP_REFRESH = + fromString("IsForceCollectionRoutingMapRefresh", CosmosMeterTagName.class) + .setTagNames(EnumSet.of(TagName.IsForceCollectionRoutingMapRefresh)); + + /** + * A numeric identifier for a physical partition + * Applicable to operations and requests + */ + public static final CosmosMeterTagName PARTITION_KEY_RANGE_ID = + fromString("PartitionKeyRangeId", CosmosMeterTagName.class) + .setTagNames(EnumSet.of(TagName.PartitionKeyRangeId)); + + /** + * Gets the corresponding metric category state from its string representation. + * + * @param name The name of the Cosmos metric category to convert. + * + * @return The corresponding Cosmos metric category. + */ + public static CosmosMeterTagName fromString(String name) { + checkNotNull(name, "Argument 'name' must not be null."); + + String normalizedName = name.trim().toLowerCase(Locale.ROOT); + switch (normalizedName) { + case "all": return CosmosMeterTagName.ALL; + case "default": return CosmosMeterTagName.DEFAULT; + case "minimum": return CosmosMeterTagName.MINIMUM; + case "consistencylevel": return CosmosMeterTagName.CONSISTENCY_LEVEL; + case "container": return CosmosMeterTagName.CONTAINER; + case "serviceaddress": return CosmosMeterTagName.SERVICE_ADDRESS; + case "serviceendpoint": return CosmosMeterTagName.SERVICE_ENDPOINT; + case "regionname": return CosmosMeterTagName.REGION_NAME; + case "operationstatuscode": return CosmosMeterTagName.OPERATION_STATUS_CODE; + case "operation": return CosmosMeterTagName.OPERATION; + case "requeststatuscode": return CosmosMeterTagName.REQUEST_STATUS_CODE; + case "requestoperationtype": return CosmosMeterTagName.REQUEST_OPERATION_TYPE; + case "clientcorrelationid": return CosmosMeterTagName.CLIENT_CORRELATION_ID; + case "isforcerefresh": return CosmosMeterTagName.ADDRESS_RESOLUTION_FORCED_REFRESH; + case "isforcecollectionroutingmaprefresh": + return CosmosMeterTagName.ADDRESS_RESOLUTION_COLLECTION_MAP_REFRESH; + case "partitionkeyrangeid": return CosmosMeterTagName.PARTITION_KEY_RANGE_ID; + + default: + String errorMessage = String.format( + "Argument 'name' has invalid value '%s' - valid values are: %s", + name, + getValidValues()); + + throw new IllegalArgumentException(errorMessage); + } + } + + private static String getValidValues() { + StringJoiner sj = new StringJoiner(", "); + for (CosmosMeterTagName t: CosmosMeterTagName.values(CosmosMeterTagName.class)) { + sj.add(t.toString()); + } + + return sj.toString(); + } + + private CosmosMeterTagName setTagNames(EnumSet tagNames) { + this.tagNames = tagNames; + return this; + } + + EnumSet getTagNames() { + return this.tagNames; + } +} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMicrometerMetricsOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMicrometerMetricsOptions.java index b1e7b588d0a73..df0991fc2b514 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMicrometerMetricsOptions.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMicrometerMetricsOptions.java @@ -3,14 +3,28 @@ package com.azure.cosmos.models; import com.azure.core.util.MetricsOptions; +import com.azure.cosmos.implementation.clienttelemetry.MetricCategory; +import com.azure.cosmos.implementation.clienttelemetry.TagName; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Metrics; +import io.micrometer.core.instrument.Tag; + +import java.lang.reflect.Array; +import java.util.EnumSet; +import java.util.concurrent.ConcurrentHashMap; + +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; /** * Micrometer-specific Azure Cosmos DB SDK metrics options */ public final class CosmosMicrometerMetricsOptions extends MetricsOptions { private MeterRegistry clientMetricRegistry = Metrics.globalRegistry; + private EnumSet metricCategories = MetricCategory.DEFAULT_CATEGORIES.clone(); + private EnumSet defaultTagNames = TagName.DEFAULT_TAGS.clone(); + private double[] defaultPercentiles = { 0.95, 0.99 }; + private boolean defaultShouldPublishHistograms = true; + private final ConcurrentHashMap effectiveOptions = new ConcurrentHashMap<>(); /** * Instantiates new Micrometer-specific Azure Cosmos DB SDK metrics options @@ -38,6 +52,78 @@ public CosmosMicrometerMetricsOptions meterRegistry(MeterRegistry clientMetricMe return this; } + /** + * Sets the default tags that should be used for metrics (where applicable) unless overridden for a specific + * meter in its {@link CosmosMeterOptions} + * By default all applicable tags are added for each metric. Adding tags/dimensions especially with high + * cardinality has some overhead - so, this method allows modifying the set of tags to be applied when some are + * not relevant in a certain use case. + * + * @param tags - the default tags to be used (when they are applicable to a specific meter and there is no + * override in {@link CosmosMeterOptions} for that meter. + * @return current CosmosMicrometerMetricsOptions instance + */ + public CosmosMicrometerMetricsOptions defaultTagNames(CosmosMeterTagName... tags) { + if (tags == null || tags.length == 0) { + this.defaultTagNames = TagName.DEFAULT_TAGS.clone(); + } else { + EnumSet newTagNames = TagName.MINIMUM_TAGS.clone(); + for (CosmosMeterTagName t: tags) { + for (TagName tagName: t.getTagNames()) { + newTagNames.add(tagName); + } + } + + this.defaultTagNames = newTagNames; + } + + return this; + } + + /** + * Sets the default percentiles that should be captured for metrics (where applicable) unless overridden for a + * specific meter in its {@link CosmosMeterOptions} + * By default percentiles 0.95 and 0.99 are captured. If percentiles is null or empty no percentiles will be + * captured. + * + * @param percentiles - the default percentiles to be captured (when they are applicable to a specific meter and + * there is no override in {@link CosmosMeterOptions} for that meter. + * @return current CosmosMicrometerMetricsOptions instance + */ + public CosmosMicrometerMetricsOptions defaultPercentiles(double... percentiles) { + if (percentiles == null || percentiles.length == 0) { + this.defaultPercentiles = null; + } else { + for (double p: percentiles) { + if (p < 0 || p > 1) { + throw new IllegalArgumentException( + String.format("Percentile '%d' is outside of valid range.", p)); + } + } + + this.defaultPercentiles = percentiles.clone(); + } + + return this; + } + + /** + * Sets a flag indicating whether by default histograms should be published for metrics (where applicable) unless + * overridden for a specific meter in its {@link CosmosMeterOptions} + * By default histograms are published. Publishing histograms has its overhead - so, this method allows disabling + * histograms by default. + * + * @param publishHistograms - a flag indicating whether by default histograms should be published for metrics + * (when they are applicable to a specific meter and there is no override in {@link CosmosMeterOptions} for + * that meter. + * @return current CosmosMicrometerMetricsOptions instance + */ + public CosmosMicrometerMetricsOptions defaultEnableHistograms(boolean publishHistograms) { + this.defaultShouldPublishHistograms = publishHistograms; + + return this; + } + /** * {@inheritDoc} */ @@ -46,4 +132,127 @@ public CosmosMicrometerMetricsOptions setEnabled(boolean enabled) { super.setEnabled(enabled); return this; } + + /** + * Sets the categories of metrics that should be emitted. By default the following categories will be enabled: + * OperationSummary (required), RequestSummary, DirectChannels, DirectRequests, System (required) + * (the System and OperationSummary metrics are always collected and can't be disabled when enabling Cosmos metrics) + * For most use-cases that should be sufficient. An overview of the different metric categories can be found here: + * https://aka.ms/azure-cosmos-metrics + * NOTE: metric categories are mutable. You can safely modify the categories on the CosmosClientTelemetryConfig + * instance passed into the CosmosClientBuilder after the CosmosClient was created - and changes to the config + * instance will be reflected at runtime by the client. + * + * @param categories - a comma-separated list of metric categories that should be emitted + * @return current CosmosClientTelemetryConfig + */ + public CosmosMicrometerMetricsOptions setMetricCategories(CosmosMeterCategory... categories) { + if (categories == null || categories.length == 0) { + this.metricCategories = MetricCategory.DEFAULT_CATEGORIES.clone(); + } else { + EnumSet newMetricCategories = MetricCategory.MINIMAL_CATEGORIES.clone(); + for (CosmosMeterCategory c: categories) { + for (MetricCategory metricCategory: c.getCategories()) { + newMetricCategories.add(metricCategory); + } + } + + this.metricCategories = newMetricCategories; + } + + return this; + } + + /** + * Adds categories of metrics that should be emitted. By default the following categories will be enabled: + * OperationSummary (required), RequestSummary, DirectChannels, DirectRequests, System (required) + * (the System and OperationSummary metrics are always collected and can't be disabled when enabling Cosmos metrics) + * An overview of the different metric categories can be found here: + * https://aka.ms/azure-cosmos-metrics + * NOTE: metric categories are mutable. You can safely modify the categories on the CosmosClientTelemetryConfig + * instance passed into the CosmosClientBuilder after the CosmosClient was created - and changes to the config + * instance will be reflected at runtime by the client. + * + * @param categories - a comma-separated list of metric categories that should be emitted + * @return current CosmosClientTelemetryConfig + */ + public CosmosMicrometerMetricsOptions addMetricCategories(CosmosMeterCategory... categories) { + if (categories == null || categories.length == 0) { + return this; + } + + EnumSet newMetricCategories = this.metricCategories.clone(); + for (CosmosMeterCategory c: categories) { + for (MetricCategory metricCategory: c.getCategories()) { + newMetricCategories.add(metricCategory); + } + } + + this.metricCategories = newMetricCategories; + return this; + } + + /** + * Removes categories of metrics that should be emitted. By default the following categories will be enabled: + * OperationSummary (required), RequestSummary, DirectChannels, DirectRequests, System (required) + * (the System and OperationSummary metrics are always collected and can't be disabled when enabling Cosmos metrics) + * An overview of the different metric categories can be found here: + * https://aka.ms/azure-cosmos-metrics + * NOTE: metric categories are mutable. You can safely modify the categories on the CosmosClientTelemetryConfig + * instance passed into the CosmosClientBuilder after the CosmosClient was created - and changes to the config + * instance will be reflected at runtime by the client. + * + * @param categories - a comma-separated list of metric categories that should be emitted + * @return current CosmosClientTelemetryConfig + */ + public CosmosMicrometerMetricsOptions removeMetricCategories(CosmosMeterCategory... categories) { + if (categories == null || categories.length == 0) { + return this; + } + + EnumSet newMetricCategories = this.metricCategories.clone(); + for (CosmosMeterCategory c: categories) { + for (MetricCategory metricCategory: c.getCategories()) { + newMetricCategories.remove(metricCategory); + } + } + + for (MetricCategory metricCategory: CosmosMeterCategory.MINIMUM.getCategories()) { + newMetricCategories.add(metricCategory); + } + + this.metricCategories = newMetricCategories; + + return this; + } + + /** + * Gets the meter options for a certain meter. The returned meter options can be used to modify the settings for + * this meter. Changes can be applied even after building the Cosmos Client instance at runtime. + * @param meterName - the meter name + * @return the current meter options + */ + public CosmosMeterOptions getMeterOptions(CosmosMeterName meterName) { + checkNotNull(meterName, "Argument 'meterName' must not be null."); + + return this + .effectiveOptions + .computeIfAbsent(meterName, name -> new CosmosMeterOptions( + name, + this.defaultShouldPublishHistograms, + this.defaultPercentiles + )); + } + + EnumSet getMetricCategories() { + return this.metricCategories; + } + + EnumSet getDefaultTagNames() { + return this.defaultTagNames; + } + + void setDefaultTagNames(EnumSet newTagNames) { + this.defaultTagNames = newTagNames; + } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ModelBridgeInternal.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ModelBridgeInternal.java index 07001414a92a7..8f12ffaf7960c 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ModelBridgeInternal.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ModelBridgeInternal.java @@ -964,5 +964,6 @@ public static void initializeAllAccessors() { PartitionKey.initialize(); CosmosClientTelemetryConfig.initialize(); CosmosContainerIdentity.initialize(); + CosmosMeterOptions.initialize(); } } diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java index 45df28262a28c..b8d8afdb1b6bc 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java @@ -25,7 +25,7 @@ import com.azure.cosmos.models.CosmosItemOperation; import com.azure.cosmos.models.CosmosItemRequestOptions; import com.azure.cosmos.models.CosmosItemResponse; -import com.azure.cosmos.models.CosmosMetricCategory; +import com.azure.cosmos.models.CosmosMeterCategory; import com.azure.cosmos.models.CosmosMicrometerMetricsOptions; import com.azure.cosmos.models.CosmosPatchItemRequestOptions; import com.azure.cosmos.models.CosmosQueryRequestOptions; @@ -66,6 +66,7 @@ public class ClientMetricsTest extends BatchTestBase { private MeterRegistry meterRegistry; private String preferredRegion; private CosmosClientTelemetryConfig inputClientTelemetryConfig; + private CosmosMicrometerMetricsOptions inputMetricsOptions; @Factory(dataProvider = "clientBuildersWithDirectTcpSession") public ClientMetricsTest(CosmosClientBuilder clientBuilder) { @@ -80,15 +81,17 @@ private EnumSet getEffectiveMetricCategories() { .getMetricCategories(this.inputClientTelemetryConfig); } - public void beforeTest(CosmosMetricCategory... metricCategories) { + public void beforeTest(CosmosMeterCategory... metricCategories) { assertThat(this.client).isNull(); assertThat(this.meterRegistry).isNull(); this.meterRegistry = ConsoleLoggingRegistryFactory.create(1); - this.inputClientTelemetryConfig = new CosmosClientTelemetryConfig() - .metricsOptions(new CosmosMicrometerMetricsOptions().meterRegistry(this.meterRegistry)) + this.inputMetricsOptions = new CosmosMicrometerMetricsOptions() + .meterRegistry(this.meterRegistry) .setMetricCategories(metricCategories); + this.inputClientTelemetryConfig = new CosmosClientTelemetryConfig() + .metricsOptions(this.inputMetricsOptions); this.client = getClientBuilder() .clientTelemetryConfig(inputClientTelemetryConfig) @@ -139,7 +142,7 @@ public void maxValueExceedingDefinedLimitStillWorksWithoutException() throws Exc // Expected behavior is that higher values than the expected max value can still be recorded // it would only result in getting less accurate "estimates" for percentile histograms - this.beforeTest(CosmosMetricCategory.DEFAULT); + this.beforeTest(CosmosMeterCategory.DEFAULT); try { Tag dummyOperationTag = Tag.of(TagName.Operation.toString(), "TestDummy"); @@ -176,7 +179,7 @@ public void maxValueExceedingDefinedLimitStillWorksWithoutException() throws Exc @Test(groups = { "simple" }, timeOut = TIMEOUT) public void createItem() throws Exception { - this.beforeTest(CosmosMetricCategory.DEFAULT); + this.beforeTest(CosmosMeterCategory.DEFAULT); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); CosmosItemResponse itemResponse = container.createItem(properties); @@ -209,7 +212,7 @@ public void createItem() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void createItemWithAllMetrics() throws Exception { - this.beforeTest(CosmosMetricCategory.ALL); + this.beforeTest(CosmosMeterCategory.ALL); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); CosmosItemResponse itemResponse = container.createItem(properties); @@ -242,7 +245,7 @@ public void createItemWithAllMetrics() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void readItem() throws Exception { - this.beforeTest(CosmosMetricCategory.DEFAULT); + this.beforeTest(CosmosMeterCategory.DEFAULT); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); container.createItem(properties); @@ -278,7 +281,7 @@ public void readItem() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void replaceItem() throws Exception { - this.beforeTest(CosmosMetricCategory.DEFAULT); + this.beforeTest(CosmosMeterCategory.DEFAULT); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); CosmosItemResponse itemResponse = container.createItem(properties); @@ -316,7 +319,7 @@ public void replaceItem() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void deleteItem() throws Exception { - this.beforeTest(CosmosMetricCategory.DEFAULT); + this.beforeTest(CosmosMeterCategory.DEFAULT); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); container.createItem(properties); @@ -348,7 +351,7 @@ public void deleteItem() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void readAllItems() throws Exception { - this.beforeTest(CosmosMetricCategory.DEFAULT); + this.beforeTest(CosmosMeterCategory.DEFAULT); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); container.createItem(properties); @@ -392,9 +395,9 @@ public void readAllItems() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void readAllItemsWithDetailMetrics() throws Exception { this.beforeTest( - CosmosMetricCategory.DEFAULT, - CosmosMetricCategory.OPERATION_DETAILS, - CosmosMetricCategory.REQUEST_DETAILS); + CosmosMeterCategory.DEFAULT, + CosmosMeterCategory.OPERATION_DETAILS, + CosmosMeterCategory.REQUEST_DETAILS); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); container.createItem(properties); @@ -440,7 +443,7 @@ public void readAllItemsWithDetailMetrics() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void queryItems() throws Exception { - this.beforeTest(CosmosMetricCategory.DEFAULT); + this.beforeTest(CosmosMeterCategory.DEFAULT); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); container.createItem(properties); @@ -489,7 +492,7 @@ public void queryItems() throws Exception { @Test(groups = { "emulator" }, timeOut = TIMEOUT * 100) public void itemPatchSuccess() { - this.beforeTest(CosmosMetricCategory.DEFAULT); + this.beforeTest(CosmosMeterCategory.DEFAULT); try { PatchTest.ToDoActivity testItem = PatchTest.ToDoActivity.createRandomItem(this.container); PatchTest.ToDoActivity testItem1 = PatchTest.ToDoActivity.createRandomItem(this.container); @@ -558,7 +561,7 @@ public void itemPatchSuccess() { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void createItem_withBulk() { - this.beforeTest(CosmosMetricCategory.DEFAULT); + this.beforeTest(CosmosMeterCategory.DEFAULT); try { int totalRequest = 5; @@ -612,7 +615,7 @@ public void createItem_withBulk() { @Test(groups = {"simple"}, timeOut = TIMEOUT) public void batchMultipleItemExecution() { - this.beforeTest(CosmosMetricCategory.DEFAULT); + this.beforeTest(CosmosMeterCategory.DEFAULT); try { TestDoc firstDoc = this.populateTestDoc(this.partitionKey1); TestDoc replaceDoc = this.getTestDocCopy(firstDoc); @@ -674,7 +677,7 @@ public void batchMultipleItemExecution() { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void effectiveMetricCategoriesForDefault() { - this.beforeTest(CosmosMetricCategory.DEFAULT); + this.beforeTest(CosmosMeterCategory.DEFAULT); try { assertThat(this.getEffectiveMetricCategories().size()).isEqualTo(5); @@ -697,9 +700,9 @@ public void effectiveMetricCategoriesForDefault() { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void effectiveMetricCategoriesForDefaultPlusDetails() { this.beforeTest( - CosmosMetricCategory.DEFAULT, - CosmosMetricCategory.fromString("RequestDetails"), - CosmosMetricCategory.fromString("OperationDETAILS")); + CosmosMeterCategory.DEFAULT, + CosmosMeterCategory.fromString("RequestDetails"), + CosmosMeterCategory.fromString("OperationDETAILS")); try { assertThat(this.getEffectiveMetricCategories().size()).isEqualTo(7); @@ -726,8 +729,8 @@ public void effectiveMetricCategoriesInvalidCategory() { String badCategoryName = "InvalidCategory"; try { this.beforeTest( - CosmosMetricCategory.DEFAULT, - CosmosMetricCategory.fromString(badCategoryName)); + CosmosMeterCategory.DEFAULT, + CosmosMeterCategory.fromString(badCategoryName)); fail("Should have thrown exception"); } catch (IllegalArgumentException argError) { @@ -739,7 +742,7 @@ public void effectiveMetricCategoriesInvalidCategory() { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void effectiveMetricCategoriesForAll() { - this.beforeTest(CosmosMetricCategory.ALL); + this.beforeTest(CosmosMeterCategory.ALL); try { assertThat(this.getEffectiveMetricCategories().size()).isEqualTo(10); @@ -766,7 +769,7 @@ public void effectiveMetricCategoriesForAll() { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void effectiveMetricCategoriesForAllLatebound() { - this.beforeTest(CosmosMetricCategory.DEFAULT); + this.beforeTest(CosmosMeterCategory.DEFAULT); try { assertThat(this.getEffectiveMetricCategories().size()).isEqualTo(5); @@ -785,7 +788,8 @@ public void effectiveMetricCategoriesForAllLatebound() { // Now change the metricCategories on the config passed into the CosmosClientBuilder // and validate that these changes take effect immediately on the client build via the builder - this.inputClientTelemetryConfig.setMetricCategories(CosmosMetricCategory.ALL); + this.inputMetricsOptions + .setMetricCategories(CosmosMeterCategory.ALL); assertThat(this.getEffectiveMetricCategories().size()).isEqualTo(10); From 7a0a2293e59e28913b8999771fb932842898dd15 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Wed, 15 Feb 2023 11:59:21 +0000 Subject: [PATCH 19/40] Fixing linting violations --- .../clienttelemetry/ClientTelemetryMetrics.java | 6 +++--- .../main/java/com/azure/cosmos/models/CosmosMeterName.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java index 2b0915f4c38e4..93660dcbe4c3e 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java @@ -286,19 +286,19 @@ private static Tags getEffectiveTags(Tags tags, CosmosMeterOptions meterOptions) return tags; } - Tags result = Tags.empty(); HashSet suppressedNames = new HashSet<>(); for (TagName t: suppressedTags) { suppressedNames.add(t.name()); } + List result = new ArrayList<>(); for (Tag t: tags) { if (!suppressedNames.contains(t.getKey())) { - result.and(t); + result.add(t); } } - return result; + return Tags.of(result); } private static class OperationMetricProducer { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterName.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterName.java index 3d3900e93318c..1a2edc6957969 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterName.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterName.java @@ -377,7 +377,7 @@ private static String getValidValues() { return sj.toString(); } - private CosmosMeterName setCategory(CosmosMeterCategory metricCategory) { + private CosmosMeterName setCategory(CosmosMeterCategory meterCategory) { this.meterCategory = meterCategory; return this; } From 4e4fa9fdff2c85129d4ab0bfe1ba6dca8eeb901e Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Wed, 15 Feb 2023 12:12:13 +0000 Subject: [PATCH 20/40] Fixing tests --- .../cosmos/spark/CosmosClientCache.scala | 38 ++++++++++++------- .../spark/SparkE2EChangeFeedITest.scala | 1 + .../cosmos/spark/SparkE2EQueryITestBase.scala | 1 + .../java/com/azure/cosmos/BridgeInternal.java | 1 - 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/CosmosClientCache.scala b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/CosmosClientCache.scala index dbc1725ec729f..8ea15d1bc11de 100644 --- a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/CosmosClientCache.scala +++ b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/CosmosClientCache.scala @@ -6,7 +6,7 @@ import com.azure.core.management.AzureEnvironment import com.azure.core.management.profile.AzureProfile import com.azure.cosmos.implementation.clienttelemetry.TagName import com.azure.cosmos.implementation.{CosmosClientMetadataCachesSnapshot, CosmosDaemonThreadFactory, SparkBridgeImplementationInternal, Strings} -import com.azure.cosmos.models.{CosmosClientTelemetryConfig, CosmosMicrometerMetricsOptions} +import com.azure.cosmos.models.{CosmosClientTelemetryConfig, CosmosMeterCategory, CosmosMeterTagName, CosmosMicrometerMetricsOptions} import com.azure.cosmos.spark.CosmosPredicates.isOnSparkDriver import com.azure.cosmos.spark.catalog.{CosmosCatalogClient, CosmosCatalogCosmosSDKClient, CosmosCatalogManagementSDKClient} import com.azure.cosmos.spark.diagnostics.BasicLoggingTrait @@ -212,20 +212,32 @@ private[spark] object CosmosClientCache extends BasicLoggingTrait { case None => customApplicationNameSuffix } + val metricsOptions = new CosmosMicrometerMetricsOptions() + .meterRegistry(CosmosClientMetrics.meterRegistry.get) + .defaultTagNames( + CosmosMeterTagName.CONTAINER, + CosmosMeterTagName.CLIENT_CORRELATION_ID, + CosmosMeterTagName.OPERATION, + CosmosMeterTagName.OPERATION_STATUS_CODE, + CosmosMeterTagName.PARTITION_KEY_RANGE_ID, + CosmosMeterTagName.SERVICE_ENDPOINT, + CosmosMeterTagName.ADDRESS_RESOLUTION_COLLECTION_MAP_REFRESH, + CosmosMeterTagName.ADDRESS_RESOLUTION_FORCED_REFRESH, + CosmosMeterTagName.REQUEST_STATUS_CODE, + CosmosMeterTagName.REQUEST_OPERATION_TYPE + ) + .setMetricCategories( + CosmosMeterCategory.SYSTEM, + CosmosMeterCategory.OPERATION_SUMMARY, + CosmosMeterCategory.REQUEST_SUMMARY, + CosmosMeterCategory.DIRECT_ADDRESS_RESOLUTIONS, + CosmosMeterCategory.DIRECT_REQUESTS, + CosmosMeterCategory.DIRECT_CHANNELS + ) + val telemetryConfig = new CosmosClientTelemetryConfig() - .metricsOptions( - new CosmosMicrometerMetricsOptions().meterRegistry(CosmosClientMetrics.meterRegistry.get) - ) + .metricsOptions(metricsOptions) .clientCorrelationId(clientCorrelationId) - .metricTagNames( - TagName.Container.toString, - TagName.ClientCorrelationId.toString, - TagName.Operation.toString, - TagName.OperationStatusCode.toString, - TagName.PartitionKeyRangeId.toString, - TagName.ServiceEndpoint.toString, - TagName.ServiceAddress.toString - ) builder.clientTelemetryConfig(telemetryConfig) } diff --git a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/SparkE2EChangeFeedITest.scala b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/SparkE2EChangeFeedITest.scala index 89d550c60f76b..1eaf6ba611d05 100644 --- a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/SparkE2EChangeFeedITest.scala +++ b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/SparkE2EChangeFeedITest.scala @@ -331,6 +331,7 @@ class SparkE2EChangeFeedITest assertMetrics(meterRegistry, "cosmos.client.req.gw", expectedToFind = true) assertMetrics(meterRegistry, "cosmos.client.req.rntbd", expectedToFind = true) assertMetrics(meterRegistry, "cosmos.client.rntbd", expectedToFind = true) + assertMetrics(meterRegistry, "cosmos.client.rntbd.addressResolution", expectedToFind = true) } "spark change feed query (incremental)" can "filter feed ranges" in { diff --git a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/SparkE2EQueryITestBase.scala b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/SparkE2EQueryITestBase.scala index ae7579effe50c..e5141bee2647b 100644 --- a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/SparkE2EQueryITestBase.scala +++ b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/SparkE2EQueryITestBase.scala @@ -80,6 +80,7 @@ abstract class SparkE2EQueryITestBase //assertMetrics(meterRegistry, "cosmos.client.req.gw", expectedToFind = true) assertMetrics(meterRegistry, "cosmos.client.req.rntbd", expectedToFind = true) assertMetrics(meterRegistry, "cosmos.client.rntbd", expectedToFind = true) + assertMetrics(meterRegistry, "cosmos.client.rntbd.addressResolution", expectedToFind = true) } private def insertDummyValue() : Unit = { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/BridgeInternal.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/BridgeInternal.java index 6e0143ba76607..705075aed3755 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/BridgeInternal.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/BridgeInternal.java @@ -40,7 +40,6 @@ import com.azure.cosmos.implementation.query.metrics.ClientSideMetrics; import com.azure.cosmos.implementation.routing.PartitionKeyInternal; import com.azure.cosmos.models.CosmosItemResponse; -import com.azure.cosmos.models.CosmosMeterOptions; import com.azure.cosmos.models.CosmosStoredProcedureProperties; import com.azure.cosmos.models.FeedResponse; import com.azure.cosmos.models.ModelBridgeInternal; From c0aea62c84a865a36270bac8e33069752aed62e6 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Wed, 15 Feb 2023 12:34:11 +0000 Subject: [PATCH 21/40] Making system meters configurable --- .../com/azure/cosmos/CosmosAsyncClient.java | 9 ++- .../ClientTelemetryMetrics.java | 56 ++++++++++++------- 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java index e962aafafe178..13d91847c5a67 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java @@ -190,8 +190,15 @@ public final class CosmosAsyncClient implements Closeable { this.clientMetricRegistrySnapshot = telemetryConfigAccessor .getClientMetricRegistry(effectiveTelemetryConfig); this.clientMetricsEnabled = clientMetricRegistrySnapshot != null; + + CosmosMeterOptions cpuMeterOptions = telemetryConfigAccessor + .getMeterOptions(this.clientTelemetryConfig, CosmosMeterName.SYSTEM_CPU); + CosmosMeterOptions memoryMeterOptions = telemetryConfigAccessor + .getMeterOptions(this.clientTelemetryConfig, CosmosMeterName.SYSTEM_MEMORY_FREE); + + if (clientMetricRegistrySnapshot != null) { - ClientTelemetryMetrics.add(clientMetricRegistrySnapshot); + ClientTelemetryMetrics.add(clientMetricRegistrySnapshot, cpuMeterOptions, memoryMeterOptions); } this.accountTagValue = URI.create(this.serviceEndpoint).getHost().replace( ".documents.azure.com", "" diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java index 93660dcbe4c3e..b9dc24312aa0e 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java @@ -63,6 +63,8 @@ public final class ClientTelemetryMetrics { private static CompositeMeterRegistry compositeRegistry = createFreshRegistry(); private static final ConcurrentHashMap registryRefCount = new ConcurrentHashMap<>(); + private static CosmosMeterOptions cpuOptions; + private static CosmosMeterOptions memoryOptions; private static String convertStackTraceToString(Throwable throwable) { @@ -98,28 +100,32 @@ public static void recordSystemUsage( float averageSystemCpuUsage, float freeMemoryAvailableInMB ) { - if (compositeRegistry.getRegistries().isEmpty()) { + if (compositeRegistry.getRegistries().isEmpty() || cpuOptions == null || memoryOptions == null) { return; } - DistributionSummary averageSystemCpuUsageMeter = DistributionSummary - .builder(CosmosMeterName.SYSTEM_CPU.toString()) - .baseUnit("%") - .description("Avg. System CPU load") - .maximumExpectedValue(100d) - .publishPercentiles(0.95, 0.99) - .publishPercentileHistogram(true) - .register(compositeRegistry); - averageSystemCpuUsageMeter.record(averageSystemCpuUsage); - - DistributionSummary freeMemoryAvailableInMBMeter = DistributionSummary - .builder(CosmosMeterName.SYSTEM_MEMORY_FREE.toString()) - .baseUnit("MB") - .description("Free memory available") - .publishPercentiles() - .publishPercentileHistogram(false) - .register(compositeRegistry); - freeMemoryAvailableInMBMeter.record(freeMemoryAvailableInMB); + if (cpuOptions.isEnabled()) { + DistributionSummary averageSystemCpuUsageMeter = DistributionSummary + .builder(CosmosMeterName.SYSTEM_CPU.toString()) + .baseUnit("%") + .description("Avg. System CPU load") + .maximumExpectedValue(100d) + .publishPercentiles(optionsAccessor.getPercentiles(cpuOptions)) + .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(cpuOptions)) + .register(compositeRegistry); + averageSystemCpuUsageMeter.record(averageSystemCpuUsage); + } + + if (memoryOptions.isEnabled()) { + DistributionSummary freeMemoryAvailableInMBMeter = DistributionSummary + .builder(CosmosMeterName.SYSTEM_MEMORY_FREE.toString()) + .baseUnit("MB") + .description("Free memory available") + .publishPercentiles() + .publishPercentileHistogram(false) + .register(compositeRegistry); + freeMemoryAvailableInMBMeter.record(freeMemoryAvailableInMB); + } } public static void recordOperation( @@ -185,13 +191,23 @@ public static RntbdMetricsCompletionRecorder createRntbdMetrics( return new RntbdMetricsV2(compositeRegistry, client, endpoint); } - public static synchronized void add(MeterRegistry registry) { + public static synchronized void add( + MeterRegistry registry, + CosmosMeterOptions cpuOptions, + CosmosMeterOptions memoryOptions) { if (registryRefCount .computeIfAbsent(registry, (meterRegistry) -> { return new AtomicLong(0); }) .incrementAndGet() == 1L) { ClientTelemetryMetrics .compositeRegistry .add(registry); + + // CPU and Memory signals are scoped system-wide - not for each client + // technically multiple CosmosClients could have different configuration for system meter options + // which isn't possible because it is a global system-wide metric + // so using most intuitive compromise - last meter options wins + cpuOptions = cpuOptions; + memoryOptions = memoryOptions; } } From 80c7680a6094db62e984709cb684b45c3da73bf9 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Wed, 15 Feb 2023 13:01:33 +0000 Subject: [PATCH 22/40] NITs --- .../scala/com/azure/cosmos/spark/CosmosClientCache.scala | 2 +- .../clienttelemetry/ClientTelemetryMetrics.java | 8 ++++---- .../directconnectivity/rntbd/RntbdMetrics.java | 1 - 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/CosmosClientCache.scala b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/CosmosClientCache.scala index 8ea15d1bc11de..bc30818f88861 100644 --- a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/CosmosClientCache.scala +++ b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/CosmosClientCache.scala @@ -220,7 +220,7 @@ private[spark] object CosmosClientCache extends BasicLoggingTrait { CosmosMeterTagName.OPERATION, CosmosMeterTagName.OPERATION_STATUS_CODE, CosmosMeterTagName.PARTITION_KEY_RANGE_ID, - CosmosMeterTagName.SERVICE_ENDPOINT, + CosmosMeterTagName.SERVICE_ADDRESS, CosmosMeterTagName.ADDRESS_RESOLUTION_COLLECTION_MAP_REFRESH, CosmosMeterTagName.ADDRESS_RESOLUTION_FORCED_REFRESH, CosmosMeterTagName.REQUEST_STATUS_CODE, diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java index b9dc24312aa0e..fa5f95dff8f1c 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java @@ -206,8 +206,8 @@ public static synchronized void add( // technically multiple CosmosClients could have different configuration for system meter options // which isn't possible because it is a global system-wide metric // so using most intuitive compromise - last meter options wins - cpuOptions = cpuOptions; - memoryOptions = memoryOptions; + ClientTelemetryMetrics.cpuOptions = cpuOptions; + ClientTelemetryMetrics.memoryOptions = memoryOptions; } } @@ -377,8 +377,8 @@ public void recordOperation( .baseUnit("Regions contacted") .description("Operation - regions contacted") .maximumExpectedValue(100d) - .publishPercentiles(optionsAccessor.getPercentiles(regionsOptions)) - .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(regionsOptions)) + .publishPercentiles() + .publishPercentileHistogram(false) .tags(getEffectiveTags(operationTags, regionsOptions)) .register(compositeRegistry); if (contactedRegions != null && contactedRegions.size() > 0) { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdMetrics.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdMetrics.java index 6f4ddb2ce8468..32355df37aa84 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdMetrics.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdMetrics.java @@ -6,7 +6,6 @@ import com.azure.cosmos.implementation.ConsoleLoggingRegistryFactory; import com.azure.cosmos.implementation.directconnectivity.RntbdTransportClient; import com.azure.cosmos.implementation.guava25.net.PercentEscaper; -import com.azure.cosmos.models.CosmosMeterName; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import io.micrometer.core.instrument.DistributionSummary; From 5c731bc5391e19c4ca1a206a67473ffd50125f0b Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Wed, 15 Feb 2023 13:02:51 +0000 Subject: [PATCH 23/40] Update CosmosMeterOptions.java --- .../main/java/com/azure/cosmos/models/CosmosMeterOptions.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterOptions.java index 5e849a5186d5e..1a13d01c08044 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterOptions.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterOptions.java @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + package com.azure.cosmos.models; import com.azure.core.util.MetricsOptions; From b30a4de8067a118014bd5bf6480cd9f24bee4bdf Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Wed, 15 Feb 2023 13:09:49 +0000 Subject: [PATCH 24/40] Test fix --- .../src/main/java/com/azure/cosmos/CosmosAsyncClient.java | 4 ++-- .../azure/cosmos/models/CosmosClientTelemetryConfig.java | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java index 13d91847c5a67..2f10fdbe74ec2 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java @@ -192,9 +192,9 @@ public final class CosmosAsyncClient implements Closeable { this.clientMetricsEnabled = clientMetricRegistrySnapshot != null; CosmosMeterOptions cpuMeterOptions = telemetryConfigAccessor - .getMeterOptions(this.clientTelemetryConfig, CosmosMeterName.SYSTEM_CPU); + .getMeterOptions(effectiveTelemetryConfig, CosmosMeterName.SYSTEM_CPU); CosmosMeterOptions memoryMeterOptions = telemetryConfigAccessor - .getMeterOptions(this.clientTelemetryConfig, CosmosMeterName.SYSTEM_MEMORY_FREE); + .getMeterOptions(effectiveTelemetryConfig, CosmosMeterName.SYSTEM_MEMORY_FREE); if (clientMetricRegistrySnapshot != null) { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java index 7c84e0c1a0e0f..481c4754f2db2 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java @@ -335,7 +335,13 @@ public EnumSet getMetricTagNames(CosmosClientTelemetryConfig config) { public CosmosMeterOptions getMeterOptions( CosmosClientTelemetryConfig config, CosmosMeterName name) { - return config.micrometerMetricsOptions.getMeterOptions(name); + if (config != null && + config.micrometerMetricsOptions != null) { + + return config.micrometerMetricsOptions.getMeterOptions(name); + } + + return createDisabledMeterOptions(name); } @Override From 17c04ba7fa21132139fb2d4e5aa9bcf6d68bd9f4 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Wed, 15 Feb 2023 14:52:48 +0000 Subject: [PATCH 25/40] Adding few more tests and fixing javadoc violations --- .../models/CosmosClientTelemetryConfig.java | 2 +- .../azure/cosmos/models/CosmosMeterName.java | 20 +- .../cosmos/models/CosmosMeterOptions.java | 8 + .../cosmos/models/CosmosMeterTagName.java | 5 + .../com/azure/cosmos/ClientMetricsTest.java | 365 +++++++++++++----- 5 files changed, 303 insertions(+), 97 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java index 481c4754f2db2..90d41fde3698f 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java @@ -158,7 +158,7 @@ String getClientCorrelationId() { * @return current CosmosClientTelemetryConfig * * @deprecated Use {@link CosmosMicrometerMetricsOptions#defaultTagNames(CosmosMeterTagName...)} or - * {@link CosmosMeterOptions#tagNames(CosmosMeterTagName...)} instead. + * {@link CosmosMeterOptions#suppressTagNames(CosmosMeterTagName...)} instead. */ @Deprecated public CosmosClientTelemetryConfig metricTagNames(String... tagNames) { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterName.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterName.java index 1a2edc6957969..111c55081de9b 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterName.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterName.java @@ -13,10 +13,10 @@ import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; +/** + * Names of Cosmos DB client-side meters + */ public final class CosmosMeterName extends ExpandableStringEnum { - - private final static Map meters = createMeterNameMap(); - private CosmosMeterCategory meterCategory; /** @@ -295,6 +295,8 @@ public final class CosmosMeterName extends ExpandableStringEnum fromString(nameOf("req.rntbd.stats.endpoint.inflightRequests"), CosmosMeterName.class) .setCategory(CosmosMeterCategory.LEGACY); + private final static Map meters = createMeterNameMap(); + /** * Gets the corresponding metric category state from its string representation. * @@ -320,6 +322,14 @@ public static CosmosMeterName fromString(String name) { return meterName; } + /** + * Gets the meter category of the meter + * @return the category of the meter + */ + public CosmosMeterCategory getCategory() { + return this.meterCategory; + } + private static Map createMeterNameMap() { Map map = new HashMap<>(); map.put(nameOf("op.latency"), CosmosMeterName.OPERATION_SUMMARY_LATENCY); @@ -382,10 +392,6 @@ private CosmosMeterName setCategory(CosmosMeterCategory meterCategory) { return this; } - public CosmosMeterCategory getCategory() { - return this.meterCategory; - } - private static String nameOf(final String member) { return "cosmos.client." + member; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterOptions.java index 1a13d01c08044..678c5695d457c 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterOptions.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterOptions.java @@ -11,6 +11,10 @@ import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; +/** + * Options of a Cosmos client-side meter that can be used to enable/disable it, change the percentile and histogram + * capturing (if percentiles are applicable for the meter) and allows suppressing tags that are not desired. + */ public final class CosmosMeterOptions extends MetricsOptions { private final CosmosMeterName meterName; @@ -34,6 +38,10 @@ public final class CosmosMeterOptions extends MetricsOptions { this.suppressedTagNames = EnumSet.noneOf(TagName.class); } + /** + * Gets the name of the meter these options are applicable for + * @return the meter name for these options + */ public CosmosMeterName getMeterName() { return this.meterName; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterTagName.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterTagName.java index 275c735a77917..cdf6a8616929b 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterTagName.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterTagName.java @@ -12,6 +12,11 @@ import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; +/** + * The tag names that can be used for Cosmos client-side meters. Not all tag names are applicable for all meters, but + * this identifier can be used to tune which tags to use for individual meters or also define the default tags that + * should be used when no meter-specific suppression exists. + */ public final class CosmosMeterTagName extends ExpandableStringEnum { private EnumSet tagNames; diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java index b8d8afdb1b6bc..78bd82df172a6 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java @@ -26,6 +26,8 @@ import com.azure.cosmos.models.CosmosItemRequestOptions; import com.azure.cosmos.models.CosmosItemResponse; import com.azure.cosmos.models.CosmosMeterCategory; +import com.azure.cosmos.models.CosmosMeterName; +import com.azure.cosmos.models.CosmosMeterTagName; import com.azure.cosmos.models.CosmosMicrometerMetricsOptions; import com.azure.cosmos.models.CosmosPatchItemRequestOptions; import com.azure.cosmos.models.CosmosQueryRequestOptions; @@ -49,6 +51,7 @@ import java.util.Collections; import java.util.EnumSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -179,67 +182,121 @@ public void maxValueExceedingDefinedLimitStillWorksWithoutException() throws Exc @Test(groups = { "simple" }, timeOut = TIMEOUT) public void createItem() throws Exception { - this.beforeTest(CosmosMeterCategory.DEFAULT); - try { - InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); - CosmosItemResponse itemResponse = container.createItem(properties); - assertThat(itemResponse.getRequestCharge()).isGreaterThan(0); - validateItemResponse(properties, itemResponse); + boolean[] disableLatencyMeterTestCases = { false, true }; - properties = getDocumentDefinition(UUID.randomUUID().toString()); - CosmosItemResponse itemResponse1 = container.createItem(properties, new CosmosItemRequestOptions()); - validateItemResponse(properties, itemResponse1); + for (boolean disableLatencyMeter: disableLatencyMeterTestCases) { - this.validateMetrics( - Tag.of(TagName.OperationStatusCode.toString(), "201"), - Tag.of(TagName.RequestStatusCode.toString(), "201/0"), - 1, - 100 - ); + this.beforeTest(CosmosMeterCategory.DEFAULT); - this.validateMetrics( - Tag.of( - TagName.Operation.toString(), "Document/Create"), - Tag.of(TagName.RequestOperationType.toString(), "Document/Create"), - 1, - 100 - ); + if (disableLatencyMeter) { + this.inputMetricsOptions + .getMeterOptions( + CosmosMeterName.fromString( + CosmosMeterName.OPERATION_SUMMARY_LATENCY.toString().toUpperCase(Locale.ROOT))) + .setEnabled(false); + } - } finally { - this.afterTest(); + try { + InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); + CosmosItemResponse itemResponse = container.createItem(properties); + assertThat(itemResponse.getRequestCharge()).isGreaterThan(0); + validateItemResponse(properties, itemResponse); + + properties = getDocumentDefinition(UUID.randomUUID().toString()); + CosmosItemResponse itemResponse1 = container.createItem(properties, new CosmosItemRequestOptions()); + validateItemResponse(properties, itemResponse1); + + Tag expectedOperationTag = Tag.of(TagName.OperationStatusCode.toString(), "201"); + // Latency meter can be disabled + this.assertMetrics("cosmos.client.op.latency", !disableLatencyMeter, expectedOperationTag); + + // Calls meter is never disabled - should always show up + this.assertMetrics("cosmos.client.op.calls", true, expectedOperationTag); + + if (!disableLatencyMeter) { + this.validateMetrics( + expectedOperationTag, + Tag.of(TagName.RequestStatusCode.toString(), "201/0"), + 1, + 100 + ); + + this.validateMetrics( + Tag.of( + TagName.Operation.toString(), "Document/Create"), + Tag.of(TagName.RequestOperationType.toString(), "Document/Create"), + 1, + 100 + ); + } + + } finally { + this.afterTest(); + } } } @Test(groups = { "simple" }, timeOut = TIMEOUT) public void createItemWithAllMetrics() throws Exception { - this.beforeTest(CosmosMeterCategory.ALL); - try { - InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); - CosmosItemResponse itemResponse = container.createItem(properties); - assertThat(itemResponse.getRequestCharge()).isGreaterThan(0); - validateItemResponse(properties, itemResponse); - properties = getDocumentDefinition(UUID.randomUUID().toString()); - CosmosItemResponse itemResponse1 = container.createItem(properties, new CosmosItemRequestOptions()); - validateItemResponse(properties, itemResponse1); + boolean[] suppressConsistencyLevelTagTestCases = { false, true }; - this.validateMetrics( - Tag.of(TagName.OperationStatusCode.toString(), "201"), - Tag.of(TagName.RequestStatusCode.toString(), "201/0"), - 1, - 100 - ); + for (boolean suppressConsistencyLevelTag: suppressConsistencyLevelTagTestCases) { - this.validateMetrics( - Tag.of( - TagName.Operation.toString(), "Document/Create"), - Tag.of(TagName.RequestOperationType.toString(), "Document/Create"), - 1, - 100 - ); + this.beforeTest(CosmosMeterCategory.ALL); + this + .inputMetricsOptions + .defaultTagNames(CosmosMeterTagName.ALL); - } finally { - this.afterTest(); + if (suppressConsistencyLevelTag) { + this + .inputMetricsOptions + .getMeterOptions(CosmosMeterName.OPERATION_SUMMARY_LATENCY) + .suppressTagNames(CosmosMeterTagName.fromString("ConsistencyLevel")) + .histogramPublishingEnabled(false) + .percentiles(0.99, 0.999) + ; + } + + try { + InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); + CosmosItemResponse itemResponse = container.createItem(properties); + assertThat(itemResponse.getRequestCharge()).isGreaterThan(0); + validateItemResponse(properties, itemResponse); + + properties = getDocumentDefinition(UUID.randomUUID().toString()); + CosmosItemResponse itemResponse1 = container.createItem(properties, new CosmosItemRequestOptions()); + validateItemResponse(properties, itemResponse1); + + this.validateMetrics( + Tag.of(TagName.OperationStatusCode.toString(), "201"), + Tag.of(TagName.RequestStatusCode.toString(), "201/0"), + 1, + 100 + ); + + this.validateMetrics( + Tag.of( + TagName.Operation.toString(), "Document/Create"), + Tag.of(TagName.RequestOperationType.toString(), "Document/Create"), + 1, + 100 + ); + + Tag expectedConsistencyTag = Tag.of(TagName.ConsistencyLevel.toString(), "Session"); + this.assertMetrics( + "cosmos.client.op.latency", + !suppressConsistencyLevelTag, + expectedConsistencyTag); + + this.assertMetrics( + "cosmos.client.op.calls", + true, + expectedConsistencyTag); + + } finally { + this.afterTest(); + } } } @@ -677,7 +734,7 @@ public void batchMultipleItemExecution() { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void effectiveMetricCategoriesForDefault() { - this.beforeTest(CosmosMeterCategory.DEFAULT); + this.beforeTest(CosmosMeterCategory.fromString("DeFAult")); try { assertThat(this.getEffectiveMetricCategories().size()).isEqualTo(5); @@ -789,7 +846,12 @@ public void effectiveMetricCategoriesForAllLatebound() { // Now change the metricCategories on the config passed into the CosmosClientBuilder // and validate that these changes take effect immediately on the client build via the builder this.inputMetricsOptions - .setMetricCategories(CosmosMeterCategory.ALL); + .setMetricCategories(CosmosMeterCategory.ALL) + .removeMetricCategories(CosmosMeterCategory.OPERATION_DETAILS) + .addMetricCategories(CosmosMeterCategory.OPERATION_DETAILS, CosmosMeterCategory.REQUEST_DETAILS) + .defaultPercentiles(0.9) + .defaultEnableHistograms(false) + .setEnabled(true); assertThat(this.getEffectiveMetricCategories().size()).isEqualTo(10); @@ -803,6 +865,170 @@ public void effectiveMetricCategoriesForAllLatebound() { } } + @Test(groups = {"simple"}, timeOut = TIMEOUT) + public void invalidMeterNameThrows() { + try { + CosmosMeterName.fromString("InvalidMeterName"); + fail("Should have thrown"); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage()).contains("InvalidMeterName"); + } + } + + @Test(groups = {"simple"}, timeOut = TIMEOUT) + public void invalidMeterCategoryThrows() { + try { + CosmosMeterCategory.fromString("InvalidMeterCategory"); + fail("Should have thrown"); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage()).contains("InvalidMeterCategory"); + } + } + + @Test(groups = {"simple"}, timeOut = TIMEOUT) + public void invalidMeterTagNameThrows() { + try { + CosmosMeterTagName.fromString("InvalidMeterTagName"); + fail("Should have thrown"); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage()).contains("InvalidMeterTagName"); + } + } + + @Test(groups = {"simple"}, timeOut = TIMEOUT) + public void meterTagNameFromStringConversion() { + assertThat(CosmosMeterTagName.fromString("aLl ")) + .isSameAs(CosmosMeterTagName.ALL); + assertThat(CosmosMeterTagName.fromString("Default")) + .isSameAs(CosmosMeterTagName.DEFAULT); + assertThat(CosmosMeterTagName.fromString("minimum")) + .isSameAs(CosmosMeterTagName.MINIMUM); + assertThat(CosmosMeterTagName.fromString("IsForceCollectionRoutingMapRefresh")) + .isSameAs(CosmosMeterTagName.ADDRESS_RESOLUTION_COLLECTION_MAP_REFRESH); + assertThat(CosmosMeterTagName.fromString("isForcerefresh")) + .isSameAs(CosmosMeterTagName.ADDRESS_RESOLUTION_FORCED_REFRESH); + assertThat(CosmosMeterTagName.fromString("ClientCorrelationID")) + .isSameAs(CosmosMeterTagName.CLIENT_CORRELATION_ID); + assertThat(CosmosMeterTagName.fromString("container")) + .isSameAs(CosmosMeterTagName.CONTAINER); + assertThat(CosmosMeterTagName.fromString(" ConsistencyLevel")) + .isSameAs(CosmosMeterTagName.CONSISTENCY_LEVEL); + assertThat(CosmosMeterTagName.fromString("operation")) + .isSameAs(CosmosMeterTagName.OPERATION); + assertThat(CosmosMeterTagName.fromString("OperationStatusCode")) + .isSameAs(CosmosMeterTagName.OPERATION_STATUS_CODE); + assertThat(CosmosMeterTagName.fromString("PartitionKeyRangeId")) + .isSameAs(CosmosMeterTagName.PARTITION_KEY_RANGE_ID); + assertThat(CosmosMeterTagName.fromString("regionname")) + .isSameAs(CosmosMeterTagName.REGION_NAME); + assertThat(CosmosMeterTagName.fromString("RequestOperationType")) + .isSameAs(CosmosMeterTagName.REQUEST_OPERATION_TYPE); + assertThat(CosmosMeterTagName.fromString("requestStatusCode")) + .isSameAs(CosmosMeterTagName.REQUEST_STATUS_CODE); + assertThat(CosmosMeterTagName.fromString("serviceaddress")) + .isSameAs(CosmosMeterTagName.SERVICE_ADDRESS); + assertThat(CosmosMeterTagName.fromString("serviceEndpoint")) + .isSameAs(CosmosMeterTagName.SERVICE_ENDPOINT); + } + + @Test(groups = {"simple"}, timeOut = TIMEOUT) + public void meterCategoryFromStringConversion() { + assertThat(CosmosMeterCategory.fromString("aLl ")) + .isSameAs(CosmosMeterCategory.ALL); + assertThat(CosmosMeterCategory.fromString("Default")) + .isSameAs(CosmosMeterCategory.DEFAULT); + assertThat(CosmosMeterCategory.fromString("minimum")) + .isSameAs(CosmosMeterCategory.MINIMUM); + assertThat(CosmosMeterCategory.fromString("operationsummary ")) + .isSameAs(CosmosMeterCategory.OPERATION_SUMMARY); + assertThat(CosmosMeterCategory.fromString("operationDetails")) + .isSameAs(CosmosMeterCategory.OPERATION_DETAILS); + assertThat(CosmosMeterCategory.fromString("RequestSummary")) + .isSameAs(CosmosMeterCategory.REQUEST_SUMMARY); + assertThat(CosmosMeterCategory.fromString("RequestDetails")) + .isSameAs(CosmosMeterCategory.REQUEST_DETAILS); + assertThat(CosmosMeterCategory.fromString("DirectChannels")) + .isSameAs(CosmosMeterCategory.DIRECT_CHANNELS); + assertThat(CosmosMeterCategory.fromString("DirectRequests")) + .isSameAs(CosmosMeterCategory.DIRECT_REQUESTS); + assertThat(CosmosMeterCategory.fromString("DirectEndpoints")) + .isSameAs(CosmosMeterCategory.DIRECT_ENDPOINTS); + assertThat(CosmosMeterCategory.fromString("DirectAddressResolutions")) + .isSameAs(CosmosMeterCategory.DIRECT_ADDRESS_RESOLUTIONS); + assertThat(CosmosMeterCategory.fromString("system")) + .isSameAs(CosmosMeterCategory.SYSTEM); + assertThat(CosmosMeterCategory.fromString("Legacy")) + .isSameAs(CosmosMeterCategory.LEGACY); + } + + @Test(groups = {"simple"}, timeOut = TIMEOUT) + public void meterNameFromStringConversion() { + assertThat(CosmosMeterName.fromString("cosmos.client.op.laTency")) + .isSameAs(CosmosMeterName.OPERATION_SUMMARY_LATENCY); + assertThat(CosmosMeterName.fromString("cosmos.client.op.cAlls")) + .isSameAs(CosmosMeterName.OPERATION_SUMMARY_CALLS); + assertThat(CosmosMeterName.fromString("cosmos.client.op.rus")) + .isSameAs(CosmosMeterName.OPERATION_SUMMARY_REQUEST_CHARGE); + assertThat(CosmosMeterName.fromString("cosmos.client.OP.actualItemCount")) + .isSameAs(CosmosMeterName.OPERATION_DETAILS_ACTUAL_ITEM_COUNT); + assertThat(CosmosMeterName.fromString("cosmos.client.op.MAXItemCount")) + .isSameAs(CosmosMeterName.OPERATION_DETAILS_MAX_ITEM_COUNT); + assertThat(CosmosMeterName.fromString("cosmos.client.op.REGIONScontacted")) + .isSameAs(CosmosMeterName.OPERATION_DETAILS_REGIONS_CONTACTED); + + assertThat(CosmosMeterName.fromString("cosmos.CLIENT.req.rntbd.backendLatency")) + .isSameAs(CosmosMeterName.REQUEST_SUMMARY_DIRECT_BACKEND_LATENCY); + assertThat(CosmosMeterName.fromString("cosmos.CLIENT.req.rntbd.LAtency")) + .isSameAs(CosmosMeterName.REQUEST_SUMMARY_DIRECT_LATENCY); + assertThat(CosmosMeterName.fromString("cosmos.CLIENT.req.rntbd.RUS")) + .isSameAs(CosmosMeterName.REQUEST_SUMMARY_DIRECT_REQUEST_CHARGE); + assertThat(CosmosMeterName.fromString("cosmos.CLIENT.req.rntbd.ReQUEsts")) + .isSameAs(CosmosMeterName.REQUEST_SUMMARY_DIRECT_REQUESTS); + assertThat(CosmosMeterName.fromString("cosmos.client.req.rntbd.TIMEline")) + .isSameAs(CosmosMeterName.REQUEST_DETAILS_DIRECT_TIMELINE); + + assertThat(CosmosMeterName.fromString("cosmos.CLIENT.req.gw.LAtency")) + .isSameAs(CosmosMeterName.REQUEST_SUMMARY_GATEWAY_LATENCY); + assertThat(CosmosMeterName.fromString("cosmos.CLIENT.req.gw.RUS")) + .isSameAs(CosmosMeterName.REQUEST_SUMMARY_GATEWAY_REQUEST_CHARGE); + assertThat(CosmosMeterName.fromString("cosmos.CLIENT.req.gw.ReQUEsts")) + .isSameAs(CosmosMeterName.REQUEST_SUMMARY_GATEWAY_REQUESTS); + assertThat(CosmosMeterName.fromString("cosmos.client.req.gw.tiMELine")) + .isSameAs(CosmosMeterName.REQUEST_DETAILS_GATEWAY_TIMELINE); + + assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.addressResolution.latency")) + .isSameAs(CosmosMeterName.DIRECT_ADDRESS_RESOLUTION_LATENCY); + assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.addressResolution.requests")) + .isSameAs(CosmosMeterName.DIRECT_ADDRESS_RESOLUTION_REQUESTS); + + assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.channels.acquired.COUNT")) + .isSameAs(CosmosMeterName.DIRECT_CHANNELS_ACQUIRED_COUNT); + assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.channels.available.COUNT")) + .isSameAs(CosmosMeterName.DIRECT_CHANNELS_AVAILABLE_COUNT); + assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.channels.closed.COUNT")) + .isSameAs(CosmosMeterName.DIRECT_CHANNELS_CLOSED_COUNT); + + assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.endpoints.COUNT")) + .isSameAs(CosmosMeterName.DIRECT_ENDPOINTS_COUNT); + assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.endpoints.evicted")) + .isSameAs(CosmosMeterName.DIRECT_ENDPOINTS_EVICTED); + + assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.requests.concurrent.count")) + .isSameAs(CosmosMeterName.DIRECT_REQUEST_CONCURRENT_COUNT); + assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.requests.LAtency")) + .isSameAs(CosmosMeterName.DIRECT_REQUEST_LATENCY); + assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.requests.FAIled.latency")) + .isSameAs(CosmosMeterName.DIRECT_REQUEST_LATENCY_FAILED); + assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.requests.successful.latency")) + .isSameAs(CosmosMeterName.DIRECT_REQUEST_LATENCY_SUCCESS); + assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.requests.queued.count")) + .isSameAs(CosmosMeterName.DIRECT_REQUEST_QUEUED_COUNT); + assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.req.RSPsize")) + .isSameAs(CosmosMeterName.DIRECT_REQUEST_SIZE_RESPONSE); + assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.req.reqsize")) + .isSameAs(CosmosMeterName.DIRECT_REQUEST_SIZE_REQUEST); + } + private InternalObjectNode getDocumentDefinition(String documentId) { final String uuid = UUID.randomUUID().toString(); return @@ -823,45 +1049,6 @@ private void validateItemResponse(InternalObjectNode containerProperties, .isEqualTo(containerProperties.getId()); } - private void validateMetrics(int minRu, int maxRu) { - this.assertMetrics("cosmos.client.op.latency", true); - this.assertMetrics("cosmos.client.op.calls", true); - Meter reportedOpRequestCharge = this.assertMetrics("cosmos.client.op.RUs", true); - validateReasonableRUs(reportedOpRequestCharge, minRu, maxRu); - this.assertMetrics("cosmos.client.op.regionsContacted", true); - this.assertMetrics( - "cosmos.client.op.regionsContacted", - true, - Tag.of(TagName.RegionName.toString(), this.preferredRegion)); - - if (this.client.asyncClient().getConnectionPolicy().getConnectionMode() == ConnectionMode.DIRECT) { - this.assertMetrics("cosmos.client.req.rntbd.latency", true); - this.assertMetrics( - "cosmos.client.req.rntbd.latency", - true, - Tag.of(TagName.RegionName.toString(), this.preferredRegion)); - this.assertMetrics("cosmos.client.req.rntbd.backendLatency", true); - this.assertMetrics("cosmos.client.req.rntbd.requests", true); - Meter reportedRntbdRequestCharge = - this.assertMetrics("cosmos.client.req.rntbd.RUs", true); - validateReasonableRUs(reportedRntbdRequestCharge, minRu, maxRu); - this.assertMetrics("cosmos.client.req.rntbd.timeline", true); - } else { - this.assertMetrics("cosmos.client.req.gw.latency", true); - this.assertMetrics( - "cosmos.client.req.gw.latency", - true, - Tag.of(TagName.RegionName.toString(), this.preferredRegion)); - this.assertMetrics("cosmos.client.req.gw.backendLatency", false); - this.assertMetrics("cosmos.client.req.gw.requests", true); - Meter reportedGatewayRequestCharge = - this.assertMetrics("cosmos.client.req.gw.RUs", true); - validateReasonableRUs(reportedGatewayRequestCharge, minRu, maxRu); - this.assertMetrics("cosmos.client.req.gw.timeline", true); - this.assertMetrics("cosmos.client.req.rntbd", false); - } - } - private void validateItemCountMetrics(Tag expectedOperationTag) { if (this.getEffectiveMetricCategories().contains(MetricCategory.OperationDetails)) { this.assertMetrics("cosmos.client.op.maxItemCount", true, expectedOperationTag); From 2ae7bb66720fb1f566e105af53ca881e21c9521c Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Wed, 15 Feb 2023 17:43:25 +0000 Subject: [PATCH 26/40] Reacting to Code review feedback --- .../clienttelemetry/ClientTelemetryMetrics.java | 10 ++++++++-- .../clienttelemetry/MetricCategory.java | 13 +------------ .../implementation/clienttelemetry/TagName.java | 16 +--------------- .../rntbd/RntbdRequestArgs.java | 12 +++++++++--- 4 files changed, 19 insertions(+), 32 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java index fa5f95dff8f1c..4ff7b263ac17b 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java @@ -1192,8 +1192,14 @@ public void markComplete(RntbdRequestRecord requestRecord) { requestRecord.stop(this.requests, requestRecord.isCompletedExceptionally() ? this.responseErrors : this.responseSuccesses); - this.requestSize.record(requestRecord.requestLength()); - this.responseSize.record(requestRecord.responseLength()); + + if (this.requestSize != null) { + this.requestSize.record(requestRecord.requestLength()); + } + + if (this.responseSize != null) { + this.responseSize.record(requestRecord.responseLength()); + } } else { requestRecord.stop(); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/MetricCategory.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/MetricCategory.java index c760cbd6be01a..e71e32c122977 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/MetricCategory.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/MetricCategory.java @@ -40,18 +40,7 @@ public int value() { return this.value; } - public static final EnumSet ALL_CATEGORIES = EnumSet.of( - MetricCategory.OperationSummary, - MetricCategory.OperationDetails, - MetricCategory.RequestSummary, - MetricCategory.RequestDetails, - MetricCategory.AddressResolutions, - MetricCategory.DirectChannels, - MetricCategory.DirectEndpoints, - MetricCategory.DirectRequests, - MetricCategory.System, - MetricCategory.Legacy - ); + public static final EnumSet ALL_CATEGORIES = EnumSet.allOf(MetricCategory.class); public static final EnumSet DEFAULT_CATEGORIES = EnumSet.of( MetricCategory.OperationSummary, diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/TagName.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/TagName.java index 691c0991ec128..0324e1237c343 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/TagName.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/TagName.java @@ -54,21 +54,7 @@ public int value() { TagName.RegionName ); - public static final EnumSet ALL_TAGS = EnumSet.of( - TagName.Container, - TagName.Operation, - TagName.OperationStatusCode, - TagName.ClientCorrelationId, - TagName.ConsistencyLevel, - TagName.PartitionKeyRangeId, - TagName.RequestStatusCode, - TagName.RequestOperationType, - TagName.RegionName, - TagName.ServiceEndpoint, - TagName.ServiceAddress, - TagName.IsForceRefresh, - TagName.IsForceCollectionRoutingMapRefresh - ); + public static final EnumSet ALL_TAGS = EnumSet.allOf(TagName.class); public static final EnumSet MINIMUM_TAGS = EnumSet.of( TagName.Container, diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdRequestArgs.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdRequestArgs.java index 3c1daecb2333f..32869a5f6460a 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdRequestArgs.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdRequestArgs.java @@ -111,10 +111,16 @@ public void stop() { this.lifetime.stop(); } - public long stop(Timer requests, Timer responses) { + public void stop(Timer requests, Timer responses) { this.lifetime.stop(); - this.sample.stop(requests); - return this.sample.stop(responses); + + if (requests != null) { + this.sample.stop(requests); + } + + if (responses != null) { + this.sample.stop(responses); + } } @Override From f95d1663a9c5d3876b1541c4424a82323efa125e Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Wed, 15 Feb 2023 20:46:15 +0000 Subject: [PATCH 27/40] Reacting to API review feedback --- .../cosmos/spark/CosmosClientCache.scala | 34 +- .../com/azure/cosmos/CosmosAsyncClient.java | 14 +- .../ImplementationBridgeHelpers.java | 16 +- .../ClientTelemetryMetrics.java | 319 +++++++------- .../RntbdTransportClient.java | 6 +- .../models/CosmosClientTelemetryConfig.java | 13 +- .../azure/cosmos/models/CosmosMeterName.java | 398 ------------------ ...ategory.java => CosmosMetricCategory.java} | 86 ++-- .../azure/cosmos/models/CosmosMetricName.java | 398 ++++++++++++++++++ ...rTagName.java => CosmosMetricTagName.java} | 104 ++--- ...java => CosmosMicrometerMeterOptions.java} | 46 +- .../CosmosMicrometerMetricsOptions.java | 38 +- .../cosmos/models/ModelBridgeInternal.java | 2 +- .../com/azure/cosmos/ClientMetricsTest.java | 318 +++++++------- 14 files changed, 892 insertions(+), 900 deletions(-) delete mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterName.java rename sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/{CosmosMeterCategory.java => CosmosMetricCategory.java} (68%) create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricName.java rename sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/{CosmosMeterTagName.java => CosmosMetricTagName.java} (56%) rename sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/{CosmosMeterOptions.java => CosmosMicrometerMeterOptions.java} (75%) diff --git a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/CosmosClientCache.scala b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/CosmosClientCache.scala index bc30818f88861..ebb6ef44b7aa8 100644 --- a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/CosmosClientCache.scala +++ b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/CosmosClientCache.scala @@ -6,7 +6,7 @@ import com.azure.core.management.AzureEnvironment import com.azure.core.management.profile.AzureProfile import com.azure.cosmos.implementation.clienttelemetry.TagName import com.azure.cosmos.implementation.{CosmosClientMetadataCachesSnapshot, CosmosDaemonThreadFactory, SparkBridgeImplementationInternal, Strings} -import com.azure.cosmos.models.{CosmosClientTelemetryConfig, CosmosMeterCategory, CosmosMeterTagName, CosmosMicrometerMetricsOptions} +import com.azure.cosmos.models.{CosmosClientTelemetryConfig, CosmosMetricCategory, CosmosMetricTagName, CosmosMicrometerMetricsOptions} import com.azure.cosmos.spark.CosmosPredicates.isOnSparkDriver import com.azure.cosmos.spark.catalog.{CosmosCatalogClient, CosmosCatalogCosmosSDKClient, CosmosCatalogManagementSDKClient} import com.azure.cosmos.spark.diagnostics.BasicLoggingTrait @@ -215,24 +215,24 @@ private[spark] object CosmosClientCache extends BasicLoggingTrait { val metricsOptions = new CosmosMicrometerMetricsOptions() .meterRegistry(CosmosClientMetrics.meterRegistry.get) .defaultTagNames( - CosmosMeterTagName.CONTAINER, - CosmosMeterTagName.CLIENT_CORRELATION_ID, - CosmosMeterTagName.OPERATION, - CosmosMeterTagName.OPERATION_STATUS_CODE, - CosmosMeterTagName.PARTITION_KEY_RANGE_ID, - CosmosMeterTagName.SERVICE_ADDRESS, - CosmosMeterTagName.ADDRESS_RESOLUTION_COLLECTION_MAP_REFRESH, - CosmosMeterTagName.ADDRESS_RESOLUTION_FORCED_REFRESH, - CosmosMeterTagName.REQUEST_STATUS_CODE, - CosmosMeterTagName.REQUEST_OPERATION_TYPE + CosmosMetricTagName.CONTAINER, + CosmosMetricTagName.CLIENT_CORRELATION_ID, + CosmosMetricTagName.OPERATION, + CosmosMetricTagName.OPERATION_STATUS_CODE, + CosmosMetricTagName.PARTITION_KEY_RANGE_ID, + CosmosMetricTagName.SERVICE_ADDRESS, + CosmosMetricTagName.ADDRESS_RESOLUTION_COLLECTION_MAP_REFRESH, + CosmosMetricTagName.ADDRESS_RESOLUTION_FORCED_REFRESH, + CosmosMetricTagName.REQUEST_STATUS_CODE, + CosmosMetricTagName.REQUEST_OPERATION_TYPE ) .setMetricCategories( - CosmosMeterCategory.SYSTEM, - CosmosMeterCategory.OPERATION_SUMMARY, - CosmosMeterCategory.REQUEST_SUMMARY, - CosmosMeterCategory.DIRECT_ADDRESS_RESOLUTIONS, - CosmosMeterCategory.DIRECT_REQUESTS, - CosmosMeterCategory.DIRECT_CHANNELS + CosmosMetricCategory.SYSTEM, + CosmosMetricCategory.OPERATION_SUMMARY, + CosmosMetricCategory.REQUEST_SUMMARY, + CosmosMetricCategory.DIRECT_ADDRESS_RESOLUTIONS, + CosmosMetricCategory.DIRECT_REQUESTS, + CosmosMetricCategory.DIRECT_CHANNELS ) val telemetryConfig = new CosmosClientTelemetryConfig() diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java index 2f10fdbe74ec2..2c4205cceaf1b 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java @@ -28,8 +28,8 @@ import com.azure.cosmos.models.CosmosDatabaseProperties; import com.azure.cosmos.models.CosmosDatabaseRequestOptions; import com.azure.cosmos.models.CosmosDatabaseResponse; -import com.azure.cosmos.models.CosmosMeterName; -import com.azure.cosmos.models.CosmosMeterOptions; +import com.azure.cosmos.models.CosmosMetricName; +import com.azure.cosmos.models.CosmosMicrometerMeterOptions; import com.azure.cosmos.models.CosmosPermissionProperties; import com.azure.cosmos.models.CosmosQueryRequestOptions; import com.azure.cosmos.models.ModelBridgeInternal; @@ -191,10 +191,10 @@ public final class CosmosAsyncClient implements Closeable { .getClientMetricRegistry(effectiveTelemetryConfig); this.clientMetricsEnabled = clientMetricRegistrySnapshot != null; - CosmosMeterOptions cpuMeterOptions = telemetryConfigAccessor - .getMeterOptions(effectiveTelemetryConfig, CosmosMeterName.SYSTEM_CPU); - CosmosMeterOptions memoryMeterOptions = telemetryConfigAccessor - .getMeterOptions(effectiveTelemetryConfig, CosmosMeterName.SYSTEM_MEMORY_FREE); + CosmosMicrometerMeterOptions cpuMeterOptions = telemetryConfigAccessor + .getMeterOptions(effectiveTelemetryConfig, CosmosMetricName.SYSTEM_CPU); + CosmosMicrometerMeterOptions memoryMeterOptions = telemetryConfigAccessor + .getMeterOptions(effectiveTelemetryConfig, CosmosMetricName.SYSTEM_MEMORY_FREE); if (clientMetricRegistrySnapshot != null) { @@ -763,7 +763,7 @@ public boolean isEndpointDiscoveryEnabled(CosmosAsyncClient client) { } @Override - public CosmosMeterOptions getMeterOptions(CosmosAsyncClient client, CosmosMeterName name) { + public CosmosMicrometerMeterOptions getMeterOptions(CosmosAsyncClient client, CosmosMetricName name) { return telemetryConfigAccessor .getMeterOptions(client.clientTelemetryConfig, name); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ImplementationBridgeHelpers.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ImplementationBridgeHelpers.java index c36a14e8a3745..bf68f8423e4ce 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ImplementationBridgeHelpers.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ImplementationBridgeHelpers.java @@ -38,8 +38,8 @@ import com.azure.cosmos.models.CosmosContainerProperties; import com.azure.cosmos.models.CosmosItemRequestOptions; import com.azure.cosmos.models.CosmosItemResponse; -import com.azure.cosmos.models.CosmosMeterName; -import com.azure.cosmos.models.CosmosMeterOptions; +import com.azure.cosmos.models.CosmosMetricName; +import com.azure.cosmos.models.CosmosMicrometerMeterOptions; import com.azure.cosmos.models.CosmosPatchOperations; import com.azure.cosmos.models.CosmosQueryRequestOptions; import com.azure.cosmos.models.FeedResponse; @@ -1048,7 +1048,7 @@ public interface CosmosAsyncClientAccessor { boolean isSendClientTelemetryToServiceEnabled(CosmosAsyncClient client); List getPreferredRegions(CosmosAsyncClient client); boolean isEndpointDiscoveryEnabled(CosmosAsyncClient client); - CosmosMeterOptions getMeterOptions(CosmosAsyncClient client, CosmosMeterName name); + CosmosMicrometerMeterOptions getMeterOptions(CosmosAsyncClient client, CosmosMetricName name); } } @@ -1083,9 +1083,9 @@ public static CosmosMeterOptionsAccessor getCosmosMeterOptionsAccessor() { } public interface CosmosMeterOptionsAccessor { - EnumSet getSuppressedTagNames(CosmosMeterOptions options); - boolean isHistogramPublishingEnabled(CosmosMeterOptions options); - double[] getPercentiles(CosmosMeterOptions options); + EnumSet getSuppressedTagNames(CosmosMicrometerMeterOptions options); + boolean isHistogramPublishingEnabled(CosmosMicrometerMeterOptions options); + double[] getPercentiles(CosmosMicrometerMeterOptions options); } } @@ -1173,8 +1173,8 @@ public interface CosmosClientTelemetryConfigAccessor { Boolean isSendClientTelemetryToServiceEnabled(CosmosClientTelemetryConfig config); boolean isClientMetricsEnabled(CosmosClientTelemetryConfig config); void resetIsSendClientTelemetryToServiceEnabled(CosmosClientTelemetryConfig config); - CosmosMeterOptions getMeterOptions(CosmosClientTelemetryConfig config, CosmosMeterName name); - CosmosMeterOptions createDisabledMeterOptions(CosmosMeterName name); + CosmosMicrometerMeterOptions getMeterOptions(CosmosClientTelemetryConfig config, CosmosMetricName name); + CosmosMicrometerMeterOptions createDisabledMeterOptions(CosmosMetricName name); CosmosClientTelemetryConfig createSnapshot( CosmosClientTelemetryConfig config, boolean effectiveIsClientTelemetryEnabled); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java index 4ff7b263ac17b..834b2fd557783 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java @@ -22,8 +22,8 @@ import com.azure.cosmos.implementation.directconnectivity.rntbd.RntbdRequestRecord; import com.azure.cosmos.implementation.guava25.net.PercentEscaper; import com.azure.cosmos.implementation.query.QueryInfo; -import com.azure.cosmos.models.CosmosMeterName; -import com.azure.cosmos.models.CosmosMeterOptions; +import com.azure.cosmos.models.CosmosMetricName; +import com.azure.cosmos.models.CosmosMicrometerMeterOptions; import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.DistributionSummary; import io.micrometer.core.instrument.FunctionCounter; @@ -63,8 +63,8 @@ public final class ClientTelemetryMetrics { private static CompositeMeterRegistry compositeRegistry = createFreshRegistry(); private static final ConcurrentHashMap registryRefCount = new ConcurrentHashMap<>(); - private static CosmosMeterOptions cpuOptions; - private static CosmosMeterOptions memoryOptions; + private static CosmosMicrometerMeterOptions cpuOptions; + private static CosmosMicrometerMeterOptions memoryOptions; private static String convertStackTraceToString(Throwable throwable) { @@ -106,7 +106,7 @@ public static void recordSystemUsage( if (cpuOptions.isEnabled()) { DistributionSummary averageSystemCpuUsageMeter = DistributionSummary - .builder(CosmosMeterName.SYSTEM_CPU.toString()) + .builder(CosmosMetricName.SYSTEM_CPU.toString()) .baseUnit("%") .description("Avg. System CPU load") .maximumExpectedValue(100d) @@ -118,7 +118,7 @@ public static void recordSystemUsage( if (memoryOptions.isEnabled()) { DistributionSummary freeMemoryAvailableInMBMeter = DistributionSummary - .builder(CosmosMeterName.SYSTEM_MEMORY_FREE.toString()) + .builder(CosmosMetricName.SYSTEM_MEMORY_FREE.toString()) .baseUnit("MB") .description("Free memory available") .publishPercentiles() @@ -193,8 +193,8 @@ public static RntbdMetricsCompletionRecorder createRntbdMetrics( public static synchronized void add( MeterRegistry registry, - CosmosMeterOptions cpuOptions, - CosmosMeterOptions memoryOptions) { + CosmosMicrometerMeterOptions cpuOptions, + CosmosMicrometerMeterOptions memoryOptions) { if (registryRefCount .computeIfAbsent(registry, (meterRegistry) -> { return new AtomicLong(0); }) .incrementAndGet() == 1L) { @@ -296,7 +296,7 @@ private static Tags createOperationTags( return Tags.of(effectiveTags); } - private static Tags getEffectiveTags(Tags tags, CosmosMeterOptions meterOptions) { + private static Tags getEffectiveTags(Tags tags, CosmosMicrometerMeterOptions meterOptions) { EnumSet suppressedTags = optionsAccessor.getSuppressedTagNames(meterOptions); if (suppressedTags == null || suppressedTags.isEmpty()) { return tags; @@ -337,9 +337,9 @@ public void recordOperation( CosmosDiagnostics diagnostics, Set contactedRegions) { - CosmosMeterOptions callsOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions callsOptions = clientAccessor.getMeterOptions( cosmosAsyncClient, - CosmosMeterName.OPERATION_SUMMARY_CALLS); + CosmosMetricName.OPERATION_SUMMARY_CALLS); if (callsOptions.isEnabled()) { Counter operationsCounter = Counter @@ -351,9 +351,9 @@ public void recordOperation( operationsCounter.increment(); } - CosmosMeterOptions requestChargeOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions requestChargeOptions = clientAccessor.getMeterOptions( cosmosAsyncClient, - CosmosMeterName.OPERATION_SUMMARY_REQUEST_CHARGE); + CosmosMetricName.OPERATION_SUMMARY_REQUEST_CHARGE); if (requestChargeOptions.isEnabled()) { DistributionSummary requestChargeMeter = DistributionSummary .builder(requestChargeOptions.getMeterName().toString()) @@ -368,9 +368,9 @@ public void recordOperation( } if (this.metricCategories.contains(MetricCategory.OperationDetails)) { - CosmosMeterOptions regionsOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions regionsOptions = clientAccessor.getMeterOptions( cosmosAsyncClient, - CosmosMeterName.OPERATION_DETAILS_REGIONS_CONTACTED); + CosmosMetricName.OPERATION_DETAILS_REGIONS_CONTACTED); if (regionsOptions.isEnabled()) { DistributionSummary regionsContactedMeter = DistributionSummary .builder(regionsOptions.getMeterName().toString()) @@ -389,9 +389,9 @@ public void recordOperation( this.recordItemCounts(cosmosAsyncClient, maxItemCount, actualItemCount); } - CosmosMeterOptions latencyOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions latencyOptions = clientAccessor.getMeterOptions( cosmosAsyncClient, - CosmosMeterName.OPERATION_SUMMARY_LATENCY); + CosmosMetricName.OPERATION_SUMMARY_LATENCY); if (latencyOptions.isEnabled()) { Timer latencyMeter = Timer .builder(latencyOptions.getMeterName().toString()) @@ -450,9 +450,9 @@ private void recordQueryPlanDiagnostics( createQueryPlanTags(metricTagNames) ); - CosmosMeterOptions requestsOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions requestsOptions = clientAccessor.getMeterOptions( cosmosAsyncClient, - CosmosMeterName.REQUEST_SUMMARY_GATEWAY_REQUESTS); + CosmosMetricName.REQUEST_SUMMARY_GATEWAY_REQUESTS); if (requestsOptions.isEnabled()) { Counter requestCounter = Counter .builder(requestsOptions.getMeterName().toString()) @@ -466,9 +466,9 @@ private void recordQueryPlanDiagnostics( Duration latency = queryPlanDiagnostics.getDuration(); if (latency != null) { - CosmosMeterOptions latencyOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions latencyOptions = clientAccessor.getMeterOptions( cosmosAsyncClient, - CosmosMeterName.REQUEST_SUMMARY_GATEWAY_LATENCY); + CosmosMetricName.REQUEST_SUMMARY_GATEWAY_LATENCY); if (latencyOptions.isEnabled()) { Timer requestLatencyMeter = Timer .builder(latencyOptions.getMeterName().toString()) @@ -484,7 +484,7 @@ private void recordQueryPlanDiagnostics( recordRequestTimeline( cosmosAsyncClient, - CosmosMeterName.REQUEST_DETAILS_GATEWAY_TIMELINE, + CosmosMetricName.REQUEST_DETAILS_GATEWAY_TIMELINE, queryPlanDiagnostics.getRequestTimeline(), requestTags); } @@ -493,9 +493,9 @@ private void recordRequestPayloadSizes( int requestPayloadSizeInBytes, int responsePayloadSizeInBytes ) { - CosmosMeterOptions reqSizeOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions reqSizeOptions = clientAccessor.getMeterOptions( client, - CosmosMeterName.REQUEST_SUMMARY_SIZE_REQUEST); + CosmosMetricName.REQUEST_SUMMARY_SIZE_REQUEST); if (reqSizeOptions.isEnabled()) { DistributionSummary requestPayloadSizeMeter = DistributionSummary .builder(reqSizeOptions.getMeterName().toString()) @@ -509,9 +509,9 @@ private void recordRequestPayloadSizes( requestPayloadSizeMeter.record(requestPayloadSizeInBytes); } - CosmosMeterOptions rspSizeOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions rspSizeOptions = clientAccessor.getMeterOptions( client, - CosmosMeterName.REQUEST_SUMMARY_SIZE_RESPONSE); + CosmosMetricName.REQUEST_SUMMARY_SIZE_RESPONSE); if (rspSizeOptions.isEnabled()) { DistributionSummary responsePayloadSizeMeter = DistributionSummary .builder(rspSizeOptions.getMeterName().toString()) @@ -533,9 +533,9 @@ private void recordItemCounts( ) { if (maxItemCount > 0 && this.metricCategories.contains(MetricCategory.OperationDetails)) { - CosmosMeterOptions maxItemCountOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions maxItemCountOptions = clientAccessor.getMeterOptions( client, - CosmosMeterName.OPERATION_DETAILS_MAX_ITEM_COUNT); + CosmosMetricName.OPERATION_DETAILS_MAX_ITEM_COUNT); if (maxItemCountOptions.isEnabled()) { DistributionSummary maxItemCountMeter = DistributionSummary .builder(maxItemCountOptions.getMeterName().toString()) @@ -549,9 +549,9 @@ private void recordItemCounts( maxItemCountMeter.record(Math.max(0, Math.min(maxItemCount, 100_000d))); } - CosmosMeterOptions actualItemCountOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions actualItemCountOptions = clientAccessor.getMeterOptions( client, - CosmosMeterName.OPERATION_DETAILS_ACTUAL_ITEM_COUNT); + CosmosMetricName.OPERATION_DETAILS_ACTUAL_ITEM_COUNT); if (actualItemCountOptions.isEnabled()) { DistributionSummary actualItemCountMeter = DistributionSummary .builder(actualItemCountOptions.getMeterName().toString()) @@ -671,9 +671,9 @@ private void recordRntbdEndpointStatistics( return; } - CosmosMeterOptions acquiredOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions acquiredOptions = clientAccessor.getMeterOptions( client, - CosmosMeterName.LEGACY_DIRECT_ENDPOINT_STATISTICS_ACQUIRED); + CosmosMetricName.LEGACY_DIRECT_ENDPOINT_STATISTICS_ACQUIRED); if (acquiredOptions.isEnabled()) { DistributionSummary acquiredChannelsMeter = DistributionSummary .builder(acquiredOptions.getMeterName().toString()) @@ -688,9 +688,9 @@ private void recordRntbdEndpointStatistics( acquiredChannelsMeter.record(endpointStatistics.getAcquiredChannels()); } - CosmosMeterOptions availableOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions availableOptions = clientAccessor.getMeterOptions( client, - CosmosMeterName.LEGACY_DIRECT_ENDPOINT_STATISTICS_AVAILABLE); + CosmosMetricName.LEGACY_DIRECT_ENDPOINT_STATISTICS_AVAILABLE); if (availableOptions.isEnabled()) { DistributionSummary availableChannelsMeter = DistributionSummary .builder(availableOptions.getMeterName().toString()) @@ -704,9 +704,9 @@ private void recordRntbdEndpointStatistics( availableChannelsMeter.record(endpointStatistics.getAvailableChannels()); } - CosmosMeterOptions inflightOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions inflightOptions = clientAccessor.getMeterOptions( client, - CosmosMeterName.LEGACY_DIRECT_ENDPOINT_STATISTICS_INFLIGHT); + CosmosMetricName.LEGACY_DIRECT_ENDPOINT_STATISTICS_INFLIGHT); if (inflightOptions.isEnabled()) { DistributionSummary inflightRequestsMeter = DistributionSummary .builder(inflightOptions.getMeterName().toString()) @@ -723,7 +723,7 @@ private void recordRntbdEndpointStatistics( private void recordRequestTimeline( CosmosAsyncClient client, - CosmosMeterName name, + CosmosMetricName name, RequestTimeline requestTimeline, Tags requestTags) { @@ -731,7 +731,7 @@ private void recordRequestTimeline( return; } - CosmosMeterOptions timelineOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions timelineOptions = clientAccessor.getMeterOptions( client, name); if (!timelineOptions.isEnabled()) { @@ -785,9 +785,9 @@ private void recordStoreResponseStatistics( if (backendLatency != null) { - CosmosMeterOptions beLatencyOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions beLatencyOptions = clientAccessor.getMeterOptions( client, - CosmosMeterName.REQUEST_SUMMARY_DIRECT_BACKEND_LATENCY); + CosmosMetricName.REQUEST_SUMMARY_DIRECT_BACKEND_LATENCY); if (beLatencyOptions.isEnabled()) { DistributionSummary backendRequestLatencyMeter = DistributionSummary .builder(beLatencyOptions.getMeterName().toString()) @@ -802,9 +802,9 @@ private void recordStoreResponseStatistics( } } - CosmosMeterOptions ruOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions ruOptions = clientAccessor.getMeterOptions( client, - CosmosMeterName.REQUEST_SUMMARY_DIRECT_REQUEST_CHARGE); + CosmosMetricName.REQUEST_SUMMARY_DIRECT_REQUEST_CHARGE); if (ruOptions.isEnabled()) { double requestCharge = storeResponseDiagnostics.getRequestCharge(); DistributionSummary requestChargeMeter = DistributionSummary @@ -819,9 +819,9 @@ private void recordStoreResponseStatistics( requestChargeMeter.record(Math.min(requestCharge, 100_000d)); } - CosmosMeterOptions latencyOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions latencyOptions = clientAccessor.getMeterOptions( client, - CosmosMeterName.REQUEST_SUMMARY_DIRECT_LATENCY); + CosmosMetricName.REQUEST_SUMMARY_DIRECT_LATENCY); if (latencyOptions.isEnabled()) { Duration latency = responseStatistics.getDuration(); if (latency != null) { @@ -837,9 +837,9 @@ private void recordStoreResponseStatistics( } } - CosmosMeterOptions reqOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions reqOptions = clientAccessor.getMeterOptions( client, - CosmosMeterName.REQUEST_SUMMARY_DIRECT_REQUESTS); + CosmosMetricName.REQUEST_SUMMARY_DIRECT_REQUESTS); if (reqOptions.isEnabled()) { Counter requestCounter = Counter .builder(reqOptions.getMeterName().toString()) @@ -853,7 +853,7 @@ private void recordStoreResponseStatistics( if (this.metricCategories.contains(MetricCategory.RequestDetails)) { recordRequestTimeline( client, - CosmosMeterName.REQUEST_DETAILS_DIRECT_TIMELINE, + CosmosMetricName.REQUEST_DETAILS_DIRECT_TIMELINE, storeResponseDiagnostics.getRequestTimeline(), requestTags); } @@ -897,9 +897,9 @@ private void recordGatewayStatistics( null) ); - CosmosMeterOptions reqOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions reqOptions = clientAccessor.getMeterOptions( client, - CosmosMeterName.REQUEST_SUMMARY_GATEWAY_REQUESTS); + CosmosMetricName.REQUEST_SUMMARY_GATEWAY_REQUESTS); if (reqOptions.isEnabled()) { Counter requestCounter = Counter .builder(reqOptions.getMeterName().toString()) @@ -910,9 +910,9 @@ private void recordGatewayStatistics( requestCounter.increment(); } - CosmosMeterOptions ruOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions ruOptions = clientAccessor.getMeterOptions( client, - CosmosMeterName.REQUEST_SUMMARY_GATEWAY_REQUEST_CHARGE); + CosmosMetricName.REQUEST_SUMMARY_GATEWAY_REQUEST_CHARGE); if (ruOptions.isEnabled()) { double requestCharge = gatewayStatistics.getRequestCharge(); DistributionSummary requestChargeMeter = DistributionSummary @@ -928,9 +928,9 @@ private void recordGatewayStatistics( } if (latency != null) { - CosmosMeterOptions latencyOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions latencyOptions = clientAccessor.getMeterOptions( client, - CosmosMeterName.REQUEST_SUMMARY_GATEWAY_LATENCY); + CosmosMetricName.REQUEST_SUMMARY_GATEWAY_LATENCY); if (latencyOptions.isEnabled()) { Timer requestLatencyMeter = Timer .builder(latencyOptions.getMeterName().toString()) @@ -946,7 +946,7 @@ private void recordGatewayStatistics( recordRequestTimeline( client, - CosmosMeterName.REQUEST_DETAILS_GATEWAY_TIMELINE, + CosmosMetricName.REQUEST_DETAILS_GATEWAY_TIMELINE, gatewayStatistics.getRequestTimeline(), requestTags); } @@ -986,9 +986,9 @@ private void recordAddressResolutionStatistics( addressResolutionStatistics.getStartTimeUTC(), addressResolutionStatistics.getEndTimeUTC()); - CosmosMeterOptions latencyOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions latencyOptions = clientAccessor.getMeterOptions( client, - CosmosMeterName.DIRECT_ADDRESS_RESOLUTION_LATENCY); + CosmosMetricName.DIRECT_ADDRESS_RESOLUTION_LATENCY); if (latencyOptions.isEnabled()) { Timer addressResolutionLatencyMeter = Timer .builder(latencyOptions.getMeterName().toString()) @@ -1001,9 +1001,9 @@ private void recordAddressResolutionStatistics( addressResolutionLatencyMeter.record(latency); } - CosmosMeterOptions reqOptions = clientAccessor.getMeterOptions( + CosmosMicrometerMeterOptions reqOptions = clientAccessor.getMeterOptions( client, - CosmosMeterName.DIRECT_ADDRESS_RESOLUTION_REQUESTS); + CosmosMetricName.DIRECT_ADDRESS_RESOLUTION_REQUESTS); if (reqOptions.isEnabled()) { Counter requestCounter = Counter .builder(reqOptions.getMeterName().toString()) @@ -1018,65 +1018,18 @@ private void recordAddressResolutionStatistics( } private static class RntbdMetricsV2 implements RntbdMetricsCompletionRecorder { - private final DistributionSummary requestSize; - private final Timer requests; - private final Timer responseErrors; - private final DistributionSummary responseSize; - private final Timer responseSuccesses; - private final EnumSet metricCategories; + private final RntbdTransportClient client; + private final Tags tags; + private final MeterRegistry registry; private RntbdMetricsV2(MeterRegistry registry, RntbdTransportClient client, RntbdEndpoint endpoint) { - Tags tags = Tags.of(endpoint.clientMetricTag()); - this.metricCategories = client.getMetricCategories(); - if (metricCategories.contains(MetricCategory.DirectRequests)) { - - CosmosMeterOptions options = client - .getMeterOptions(CosmosMeterName.DIRECT_REQUEST_LATENCY); - if (options.isEnabled()) { - this.requests = Timer - .builder(options.getMeterName().toString()) - .description("RNTBD request latency") - .maximumExpectedValue(Duration.ofSeconds(300)) - .publishPercentiles(optionsAccessor.getPercentiles(options)) - .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(options)) - .tags(getEffectiveTags(tags, options)) - .register(registry); - } else { - this.requests = null; - } - - options = client - .getMeterOptions(CosmosMeterName.DIRECT_REQUEST_LATENCY_FAILED); - if (options.isEnabled()) { - this.responseErrors = Timer - .builder(options.getMeterName().toString()) - .description("RNTBD failed request latency") - .maximumExpectedValue(Duration.ofSeconds(300)) - .publishPercentiles(optionsAccessor.getPercentiles(options)) - .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(options)) - .tags(getEffectiveTags(tags, options)) - .register(registry); - } else { - this.responseErrors = null; - } + this.tags = Tags.of(endpoint.clientMetricTag(), endpoint.tag()); + this.client = client; + this.registry = registry; + if (this.client.getMetricCategories().contains(MetricCategory.DirectRequests)) { - options = client - .getMeterOptions(CosmosMeterName.DIRECT_REQUEST_LATENCY_SUCCESS); - if (options.isEnabled()) { - this.responseSuccesses = Timer - .builder(options.getMeterName().toString()) - .description("RNTBD successful request latency") - .maximumExpectedValue(Duration.ofSeconds(300)) - .publishPercentiles(optionsAccessor.getPercentiles(options)) - .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(options)) - .tags(getEffectiveTags(tags, options)) - .register(registry); - } else { - this.responseSuccesses = null; - } - - options = client - .getMeterOptions(CosmosMeterName.DIRECT_REQUEST_CONCURRENT_COUNT); + CosmosMicrometerMeterOptions options = client + .getMeterOptions(CosmosMetricName.DIRECT_REQUEST_CONCURRENT_COUNT); if (options.isEnabled()) { Gauge.builder(options.getMeterName().toString(), endpoint, RntbdEndpoint::concurrentRequests) .description("RNTBD concurrent requests (executing or queued request count)") @@ -1085,54 +1038,18 @@ private RntbdMetricsV2(MeterRegistry registry, RntbdTransportClient client, Rntb } options = client - .getMeterOptions(CosmosMeterName.DIRECT_REQUEST_QUEUED_COUNT); + .getMeterOptions(CosmosMetricName.DIRECT_REQUEST_QUEUED_COUNT); if (options.isEnabled()) { Gauge.builder(options.getMeterName().toString(), endpoint, RntbdEndpoint::requestQueueLength) .description("RNTBD queued request count") .tags(getEffectiveTags(tags, options)) .register(registry); } - - options = client - .getMeterOptions(CosmosMeterName.DIRECT_REQUEST_SIZE_REQUEST); - if (options.isEnabled()) { - this.requestSize = DistributionSummary.builder(options.getMeterName().toString()) - .description("RNTBD request size (bytes)") - .baseUnit("bytes") - .tags(getEffectiveTags(tags, options)) - .maximumExpectedValue(16_000_000d) - .publishPercentileHistogram(false) - .publishPercentiles() - .register(registry); - } else { - this.requestSize = null; - } - - options = client - .getMeterOptions(CosmosMeterName.DIRECT_REQUEST_SIZE_RESPONSE); - if (options.isEnabled()) { - this.responseSize = DistributionSummary.builder(options.getMeterName().toString()) - .description("RNTBD response size (bytes)") - .baseUnit("bytes") - .tags(getEffectiveTags(tags, options)) - .maximumExpectedValue(16_000_000d) - .publishPercentileHistogram(false) - .publishPercentiles() - .register(registry); - } else { - this.responseSize = null; - } - } else { - this.requests = null; - this.responseErrors = null; - this.responseSuccesses = null; - this.requestSize = null; - this.responseSize= null; } - if (metricCategories.contains(MetricCategory.DirectEndpoints)) { - CosmosMeterOptions options = client - .getMeterOptions(CosmosMeterName.DIRECT_ENDPOINTS_COUNT); + if (this.client.getMetricCategories().contains(MetricCategory.DirectEndpoints)) { + CosmosMicrometerMeterOptions options = client + .getMeterOptions(CosmosMetricName.DIRECT_ENDPOINTS_COUNT); if (options.isEnabled()) { Gauge.builder(options.getMeterName().toString(), client, RntbdTransportClient::endpointCount) .description("RNTBD endpoint count") @@ -1140,7 +1057,7 @@ private RntbdMetricsV2(MeterRegistry registry, RntbdTransportClient client, Rntb } options = client - .getMeterOptions(CosmosMeterName.DIRECT_ENDPOINTS_EVICTED); + .getMeterOptions(CosmosMetricName.DIRECT_ENDPOINTS_EVICTED); if (options.isEnabled()) { FunctionCounter.builder( options.getMeterName().toString(), @@ -1151,9 +1068,9 @@ private RntbdMetricsV2(MeterRegistry registry, RntbdTransportClient client, Rntb } } - if (metricCategories.contains(MetricCategory.DirectChannels)) { - CosmosMeterOptions options = client - .getMeterOptions(CosmosMeterName.DIRECT_CHANNELS_ACQUIRED_COUNT); + if (this.client.getMetricCategories().contains(MetricCategory.DirectChannels)) { + CosmosMicrometerMeterOptions options = client + .getMeterOptions(CosmosMetricName.DIRECT_CHANNELS_ACQUIRED_COUNT); if (options.isEnabled()) { FunctionCounter.builder( options.getMeterName().toString(), @@ -1165,7 +1082,7 @@ private RntbdMetricsV2(MeterRegistry registry, RntbdTransportClient client, Rntb } options = client - .getMeterOptions(CosmosMeterName.DIRECT_CHANNELS_CLOSED_COUNT); + .getMeterOptions(CosmosMetricName.DIRECT_CHANNELS_CLOSED_COUNT); if (options.isEnabled()) { FunctionCounter.builder( options.getMeterName().toString(), @@ -1177,7 +1094,7 @@ private RntbdMetricsV2(MeterRegistry registry, RntbdTransportClient client, Rntb } options = client - .getMeterOptions(CosmosMeterName.DIRECT_CHANNELS_AVAILABLE_COUNT); + .getMeterOptions(CosmosMetricName.DIRECT_CHANNELS_AVAILABLE_COUNT); if (options.isEnabled()) { Gauge.builder(options.getMeterName().toString(), endpoint, RntbdEndpoint::channelsAvailableMetric) .description("RNTBD available channel count") @@ -1188,17 +1105,83 @@ private RntbdMetricsV2(MeterRegistry registry, RntbdTransportClient client, Rntb } public void markComplete(RntbdRequestRecord requestRecord) { - if (this.metricCategories.contains(MetricCategory.DirectRequests)) { - requestRecord.stop(this.requests, requestRecord.isCompletedExceptionally() - ? this.responseErrors - : this.responseSuccesses); + if (this.client.getMetricCategories().contains(MetricCategory.DirectRequests)) { + + Timer requests = null; + Timer requestsSuccess = null; + Timer requestsFailed = null; + + CosmosMicrometerMeterOptions options = this.client + .getMeterOptions(CosmosMetricName.DIRECT_REQUEST_LATENCY); + + if (options.isEnabled()) { + requests = Timer + .builder(options.getMeterName().toString()) + .description("RNTBD request latency") + .maximumExpectedValue(Duration.ofSeconds(300)) + .publishPercentiles(optionsAccessor.getPercentiles(options)) + .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(options)) + .tags(getEffectiveTags(this.tags, options)) + .register(this.registry); + } + + options = client + .getMeterOptions(CosmosMetricName.DIRECT_REQUEST_LATENCY_FAILED); + if (options.isEnabled()) { + requestsFailed = Timer + .builder(options.getMeterName().toString()) + .description("RNTBD failed request latency") + .maximumExpectedValue(Duration.ofSeconds(300)) + .publishPercentiles(optionsAccessor.getPercentiles(options)) + .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(options)) + .tags(getEffectiveTags(tags, options)) + .register(registry); + } + + options = client + .getMeterOptions(CosmosMetricName.DIRECT_REQUEST_LATENCY_SUCCESS); + if (options.isEnabled()) { + requestsSuccess = Timer + .builder(options.getMeterName().toString()) + .description("RNTBD successful request latency") + .maximumExpectedValue(Duration.ofSeconds(300)) + .publishPercentiles(optionsAccessor.getPercentiles(options)) + .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(options)) + .tags(getEffectiveTags(tags, options)) + .register(registry); + } - if (this.requestSize != null) { - this.requestSize.record(requestRecord.requestLength()); + requestRecord.stop( + requests, + requestRecord.isCompletedExceptionally() ? requestsFailed : requestsSuccess); + + options = client + .getMeterOptions(CosmosMetricName.DIRECT_REQUEST_SIZE_REQUEST); + if (options.isEnabled()) { + DistributionSummary requestSize = DistributionSummary.builder(options.getMeterName().toString()) + .description("RNTBD request size (bytes)") + .baseUnit("bytes") + .tags(getEffectiveTags(tags, options)) + .maximumExpectedValue(16_000_000d) + .publishPercentileHistogram(false) + .publishPercentiles() + .register(registry); + requestSize.record(requestRecord.requestLength()); } - if (this.responseSize != null) { - this.responseSize.record(requestRecord.responseLength()); + options = client + .getMeterOptions(CosmosMetricName.DIRECT_REQUEST_SIZE_RESPONSE); + if (options.isEnabled()) { + DistributionSummary responseSize = DistributionSummary.builder(options.getMeterName().toString()) + .description("RNTBD response size (bytes)") + .baseUnit("bytes") + .tags(getEffectiveTags(tags, options)) + .maximumExpectedValue(16_000_000d) + .publishPercentileHistogram(false) + .publishPercentiles() + .register(registry); + + responseSize.record(requestRecord.responseLength()); } } else { requestRecord.stop(); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/RntbdTransportClient.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/RntbdTransportClient.java index 48da35c07914c..e8acb194e9063 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/RntbdTransportClient.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/RntbdTransportClient.java @@ -19,8 +19,8 @@ import com.azure.cosmos.implementation.directconnectivity.rntbd.*; import com.azure.cosmos.implementation.guava25.base.Strings; import com.azure.cosmos.models.CosmosClientTelemetryConfig; -import com.azure.cosmos.models.CosmosMeterName; -import com.azure.cosmos.models.CosmosMeterOptions; +import com.azure.cosmos.models.CosmosMetricName; +import com.azure.cosmos.models.CosmosMicrometerMeterOptions; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; @@ -378,7 +378,7 @@ public EnumSet getMetricCategories() { .getMetricCategories(this.metricConfig) : MetricCategory.DEFAULT_CATEGORIES; } - public CosmosMeterOptions getMeterOptions(CosmosMeterName name) { + public CosmosMicrometerMeterOptions getMeterOptions(CosmosMetricName name) { return this.metricConfig != null ? ImplementationBridgeHelpers .CosmosClientTelemetryConfigHelper diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java index 90d41fde3698f..c58c2a218c61d 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java @@ -23,7 +23,6 @@ import java.util.Arrays; import java.util.EnumSet; import java.util.HashMap; -import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.stream.Stream; @@ -157,8 +156,8 @@ String getClientCorrelationId() { * @param tagNames - a comma-separated list of tag names that should be considered * @return current CosmosClientTelemetryConfig * - * @deprecated Use {@link CosmosMicrometerMetricsOptions#defaultTagNames(CosmosMeterTagName...)} or - * {@link CosmosMeterOptions#suppressTagNames(CosmosMeterTagName...)} instead. + * @deprecated Use {@link CosmosMicrometerMetricsOptions#defaultTagNames(CosmosMetricTagName...)} or + * {@link CosmosMicrometerMeterOptions#suppressTagNames(CosmosMetricTagName...)} instead. */ @Deprecated public CosmosClientTelemetryConfig metricTagNames(String... tagNames) { @@ -332,9 +331,9 @@ public EnumSet getMetricTagNames(CosmosClientTelemetryConfig config) { } @Override - public CosmosMeterOptions getMeterOptions( + public CosmosMicrometerMeterOptions getMeterOptions( CosmosClientTelemetryConfig config, - CosmosMeterName name) { + CosmosMetricName name) { if (config != null && config.micrometerMetricsOptions != null) { @@ -345,8 +344,8 @@ public CosmosMeterOptions getMeterOptions( } @Override - public CosmosMeterOptions createDisabledMeterOptions(CosmosMeterName name) { - return new CosmosMeterOptions(name, false, null).setEnabled(false); + public CosmosMicrometerMeterOptions createDisabledMeterOptions(CosmosMetricName name) { + return new CosmosMicrometerMeterOptions(name, false, null).setEnabled(false); } @Override diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterName.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterName.java deleted file mode 100644 index 111c55081de9b..0000000000000 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterName.java +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.cosmos.models; - -import com.azure.core.util.ExpandableStringEnum; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.StringJoiner; - -import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; - -/** - * Names of Cosmos DB client-side meters - */ -public final class CosmosMeterName extends ExpandableStringEnum { - private CosmosMeterCategory meterCategory; - - /** - * Creates a new instance of {@link CosmosMeterName} without a {@link #toString()} value. - *

- * This constructor shouldn't be called as it will produce a {@link CosmosMeterName} which doesn't - * have a String enum value. - * - * @deprecated Use one of the constants or the {@link #fromString(String)} factory method. - */ - @Deprecated - CosmosMeterName() { - } - - - /** - * Number of operation calls (Counter) - */ - public static final CosmosMeterName OPERATION_SUMMARY_CALLS = - fromString(nameOf("op.calls"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.OPERATION_SUMMARY); - - /** - * Total latency (across requests including retries) of the operation (Timer) - */ - public static final CosmosMeterName OPERATION_SUMMARY_LATENCY = - fromString(nameOf("op.latency"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.OPERATION_SUMMARY); - - /** - * Request charge for the operation (DistributionSummary) - */ - public static final CosmosMeterName OPERATION_SUMMARY_REQUEST_CHARGE = - fromString(nameOf("op.RUs"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.OPERATION_SUMMARY); - - /** - * Number of regions contacted for processing the operation (DistributionSummary) - */ - public static final CosmosMeterName OPERATION_DETAILS_REGIONS_CONTACTED = - fromString(nameOf("op.regionsContacted"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.OPERATION_DETAILS); - - /** - * Actual item count - relevant for non-point-operations - indicating the actual number of - * docs returned in the response (DistributionSummary) - * NOTE: No percentiles or histogram supported - */ - public static final CosmosMeterName OPERATION_DETAILS_ACTUAL_ITEM_COUNT = - fromString(nameOf("op.actualItemCount"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.OPERATION_DETAILS); - - /** - * Max. item count - relevant for non-point-operations - indicating the requested max. number of - * docs returned in a single response (DistributionSummary) - * NOTE: No percentiles or histogram supported - */ - public static final CosmosMeterName OPERATION_DETAILS_MAX_ITEM_COUNT = - fromString(nameOf("op.maxItemCount"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.OPERATION_DETAILS); - - /** - * Number of requests (Counter) - * NOTE: No percentiles or histogram supported - */ - public static final CosmosMeterName REQUEST_SUMMARY_DIRECT_REQUESTS = - fromString(nameOf("req.rntbd.requests"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.REQUEST_SUMMARY); - - /** - * Latency of the request (Timer) - */ - public static final CosmosMeterName REQUEST_SUMMARY_DIRECT_LATENCY = - fromString(nameOf("req.rntbd.latency"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.REQUEST_SUMMARY); - - /** - * Backend-latency of the request (DistributionSummary) - */ - public static final CosmosMeterName REQUEST_SUMMARY_DIRECT_BACKEND_LATENCY = - fromString(nameOf("req.rntbd.backendLatency"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.REQUEST_SUMMARY); - - /** - * Request charge for a request (DistributionSummary) - */ - public static final CosmosMeterName REQUEST_SUMMARY_DIRECT_REQUEST_CHARGE = - fromString(nameOf("req.rntbd.RUs"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.REQUEST_SUMMARY); - - /** - * Number of requests (Counter) - * NOTE: No percentiles or histogram supported - */ - public static final CosmosMeterName REQUEST_SUMMARY_GATEWAY_REQUESTS = - fromString(nameOf("req.gw.requests"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.REQUEST_SUMMARY); - - /** - * Latency of the request (Timer) - */ - public static final CosmosMeterName REQUEST_SUMMARY_GATEWAY_LATENCY = - fromString(nameOf("req.gw.latency"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.REQUEST_SUMMARY); - - /** - * Request charge for a request (DistributionSummary) - */ - public static final CosmosMeterName REQUEST_SUMMARY_GATEWAY_REQUEST_CHARGE = - fromString(nameOf("req.gw.RUs"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.REQUEST_SUMMARY); - - /** - * Size of the request payload (DistributionSummary) - * NOTE: No percentiles or histogram supported - */ - public static final CosmosMeterName REQUEST_SUMMARY_SIZE_REQUEST = - fromString(nameOf("req.reqPayloadSize"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.REQUEST_SUMMARY); - - /** - * Size of the response payload (DistributionSummary) - * NOTE: No percentiles or histogram supported - */ - public static final CosmosMeterName REQUEST_SUMMARY_SIZE_RESPONSE = - fromString(nameOf("req.rspPayloadSize"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.REQUEST_SUMMARY); - - /** - * Latency in different steps of the request pipeline (Timer) - */ - public static final CosmosMeterName REQUEST_DETAILS_DIRECT_TIMELINE = - fromString(nameOf("req.rntbd.timeline"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.REQUEST_DETAILS); - - /** - * Latency in different steps of the request pipeline (Timer) - */ - public static final CosmosMeterName REQUEST_DETAILS_GATEWAY_TIMELINE = - fromString(nameOf("req.gw.timeline"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.REQUEST_DETAILS); - - /** - * Number of acquired channels (new connections) for this endpoint (FunctionCounter) - */ - public static final CosmosMeterName DIRECT_CHANNELS_ACQUIRED_COUNT = - fromString(nameOf("rntbd.channels.acquired.count"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.DIRECT_CHANNELS); - - /** - * Number of closed channels / connections for this endpoint (FunctionCounter) - */ - public static final CosmosMeterName DIRECT_CHANNELS_CLOSED_COUNT = - fromString(nameOf("rntbd.channels.closed.count"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.DIRECT_CHANNELS); - - /** - * Snapshot of the number of available channels (active connections) for this endpoint (Gauge) - */ - public static final CosmosMeterName DIRECT_CHANNELS_AVAILABLE_COUNT = - fromString(nameOf("rntbd.channels.available.count"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.DIRECT_CHANNELS); - - /** - * Snapshot of the number of endpoints (Gauge) - */ - public static final CosmosMeterName DIRECT_ENDPOINTS_COUNT = - fromString(nameOf("rntbd.endpoints.count"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.DIRECT_ENDPOINTS); - - /** - * Number of evicted/closed endpoints (FunctionCounter) - */ - public static final CosmosMeterName DIRECT_ENDPOINTS_EVICTED = - fromString(nameOf("rntbd.endpoints.evicted"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.DIRECT_ENDPOINTS); - - /** - * Number of RNTBD address resolution requests (Counter) - */ - public static final CosmosMeterName DIRECT_ADDRESS_RESOLUTION_REQUESTS = - fromString(nameOf("rntbd.addressResolution.requests"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.DIRECT_ADDRESS_RESOLUTIONS); - - /** - * Latency of the RNTBD address resolution request (Timer) - */ - public static final CosmosMeterName DIRECT_ADDRESS_RESOLUTION_LATENCY = - fromString(nameOf("rntbd.addressResolution.latency"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.DIRECT_ADDRESS_RESOLUTIONS); - - /** - * Latency of RNTBD requests for this endpoint (Timer) - */ - public static final CosmosMeterName DIRECT_REQUEST_LATENCY = - fromString(nameOf("rntbd.requests.latency"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.DIRECT_REQUESTS); - - /** - * Latency of failed RNTBD requests for this endpoint (Timer) - */ - public static final CosmosMeterName DIRECT_REQUEST_LATENCY_FAILED = - fromString(nameOf("rntbd.requests.failed.latency"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.DIRECT_REQUESTS); - - /** - * Latency of successful RNTBD requests for this endpoint (Timer) - */ - public static final CosmosMeterName DIRECT_REQUEST_LATENCY_SUCCESS = - fromString(nameOf("rntbd.requests.successful.latency"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.DIRECT_REQUESTS); - - /** - * Snapshot of number of concurrent RNTBD requests for this endpoint (Gauge) - */ - public static final CosmosMeterName DIRECT_REQUEST_CONCURRENT_COUNT = - fromString(nameOf("rntbd.requests.concurrent.count"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.DIRECT_REQUESTS); - - /** - * Snapshot of number of queued RNTBD requests for this endpoint (Gauge) - */ - public static final CosmosMeterName DIRECT_REQUEST_QUEUED_COUNT = - fromString(nameOf("rntbd.requests.queued.count"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.DIRECT_REQUESTS); - - /** - * Size of the request payload (DistributionSummary) - */ - public static final CosmosMeterName DIRECT_REQUEST_SIZE_REQUEST = - fromString(nameOf("rntbd.req.reqSize"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.DIRECT_REQUESTS); - - /** - * Size of the response payload (DistributionSummary) - */ - public static final CosmosMeterName DIRECT_REQUEST_SIZE_RESPONSE = - fromString(nameOf("rntbd.req.rspSize"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.DIRECT_REQUESTS); - - /** - * Avg. system-wide CPU load (DistributionSummary) - */ - public static final CosmosMeterName SYSTEM_CPU = - fromString(nameOf("system.avgCpuLoad"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.SYSTEM); - - /** - * JVM's Free available memory (DistributionSummary) - */ - public static final CosmosMeterName SYSTEM_MEMORY_FREE = - fromString(nameOf("system.freeMemoryAvailable"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.SYSTEM); - - /** - * Distribution summary over snapshot of acquired channels for the endpoint at time - * of a request (DistributionSummary) - */ - public static final CosmosMeterName LEGACY_DIRECT_ENDPOINT_STATISTICS_ACQUIRED = - fromString(nameOf("req.rntbd.stats.endpoint.acquiredChannels"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.LEGACY); - - /** - * Distribution summary over snapshot of available channels for the endpoint at time - * of a request (DistributionSummary) - */ - public static final CosmosMeterName LEGACY_DIRECT_ENDPOINT_STATISTICS_AVAILABLE = - fromString(nameOf("req.rntbd.stats.endpoint.availableChannels"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.LEGACY); - - /** - * Distribution summary over snapshot of inflight channels for the endpoint at time - * of a request (DistributionSummary) - */ - public static final CosmosMeterName LEGACY_DIRECT_ENDPOINT_STATISTICS_INFLIGHT = - fromString(nameOf("req.rntbd.stats.endpoint.inflightRequests"), CosmosMeterName.class) - .setCategory(CosmosMeterCategory.LEGACY); - - private final static Map meters = createMeterNameMap(); - - /** - * Gets the corresponding metric category state from its string representation. - * - * @param name The name of the Cosmos metric category to convert. - * - * @return The corresponding Cosmos metric category. - */ - public static CosmosMeterName fromString(String name) { - checkNotNull(name, "Argument 'name' must not be null."); - - String normalizedName = name.trim().toLowerCase(Locale.ROOT); - CosmosMeterName meterName = meters.getOrDefault(normalizedName, null); - - if (meterName == null) { - String errorMessage = String.format( - "Argument 'name' has invalid value '%s' - valid values are: %s", - name, - getValidValues()); - - throw new IllegalArgumentException(errorMessage); - } - - return meterName; - } - - /** - * Gets the meter category of the meter - * @return the category of the meter - */ - public CosmosMeterCategory getCategory() { - return this.meterCategory; - } - - private static Map createMeterNameMap() { - Map map = new HashMap<>(); - map.put(nameOf("op.latency"), CosmosMeterName.OPERATION_SUMMARY_LATENCY); - map.put(nameOf("op.calls"), CosmosMeterName.OPERATION_SUMMARY_CALLS); - map.put(nameOf("op.rus"), CosmosMeterName.OPERATION_SUMMARY_REQUEST_CHARGE); - map.put(nameOf("op.maxitemcount"), CosmosMeterName.OPERATION_DETAILS_MAX_ITEM_COUNT); - map.put(nameOf("op.actualitemcount"), CosmosMeterName.OPERATION_DETAILS_ACTUAL_ITEM_COUNT); - map.put(nameOf("op.regionscontacted"), CosmosMeterName.OPERATION_DETAILS_REGIONS_CONTACTED); - map.put(nameOf("req.rntbd.requests"), CosmosMeterName.REQUEST_SUMMARY_DIRECT_REQUESTS); - map.put(nameOf("req.rntbd.latency"), CosmosMeterName.REQUEST_SUMMARY_DIRECT_LATENCY); - map.put(nameOf("req.rntbd.backendlatency"), CosmosMeterName.REQUEST_SUMMARY_DIRECT_BACKEND_LATENCY); - map.put(nameOf("req.rntbd.rus"), CosmosMeterName.REQUEST_SUMMARY_DIRECT_REQUEST_CHARGE); - map.put(nameOf("req.gw.requests"), CosmosMeterName.REQUEST_SUMMARY_GATEWAY_REQUESTS); - map.put(nameOf("req.gw.latency"), CosmosMeterName.REQUEST_SUMMARY_GATEWAY_LATENCY); - map.put(nameOf("req.gw.rus"), CosmosMeterName.REQUEST_SUMMARY_GATEWAY_REQUEST_CHARGE); - map.put(nameOf("req.reqPayloadSize"), CosmosMeterName.REQUEST_SUMMARY_SIZE_REQUEST); - map.put(nameOf("req.rspPayloadSize"), CosmosMeterName.REQUEST_SUMMARY_SIZE_RESPONSE); - map.put(nameOf("req.rntbd.timeline"), CosmosMeterName.REQUEST_DETAILS_DIRECT_TIMELINE); - map.put(nameOf("req.gw.timeline"), CosmosMeterName.REQUEST_DETAILS_GATEWAY_TIMELINE); - map.put(nameOf("rntbd.channels.acquired.count"), CosmosMeterName.DIRECT_CHANNELS_ACQUIRED_COUNT); - map.put(nameOf("rntbd.channels.available.count"), CosmosMeterName.DIRECT_CHANNELS_AVAILABLE_COUNT); - map.put(nameOf("rntbd.channels.closed.count"), CosmosMeterName.DIRECT_CHANNELS_CLOSED_COUNT); - map.put(nameOf("rntbd.endpoints.count"), CosmosMeterName.DIRECT_ENDPOINTS_COUNT); - map.put(nameOf("rntbd.endpoints.evicted"), CosmosMeterName.DIRECT_ENDPOINTS_EVICTED); - map.put(nameOf("rntbd.addressresolution.requests"), CosmosMeterName.DIRECT_ADDRESS_RESOLUTION_REQUESTS); - map.put(nameOf("rntbd.addressresolution.latency"), CosmosMeterName.DIRECT_ADDRESS_RESOLUTION_LATENCY); - map.put(nameOf("rntbd.requests.latency"), CosmosMeterName.DIRECT_REQUEST_LATENCY); - map.put(nameOf("rntbd.requests.failed.latency"), CosmosMeterName.DIRECT_REQUEST_LATENCY_FAILED); - map.put(nameOf("rntbd.requests.successful.latency"), CosmosMeterName.DIRECT_REQUEST_LATENCY_SUCCESS); - map.put(nameOf("rntbd.requests.concurrent.count"), CosmosMeterName.DIRECT_REQUEST_CONCURRENT_COUNT); - map.put(nameOf("rntbd.requests.queued.count"), CosmosMeterName.DIRECT_REQUEST_QUEUED_COUNT); - map.put(nameOf("rntbd.req.reqsize"), CosmosMeterName.DIRECT_REQUEST_SIZE_REQUEST); - map.put(nameOf("rntbd.req.rspsize"), CosmosMeterName.DIRECT_REQUEST_SIZE_RESPONSE); - map.put(nameOf("system.freememoryavailable"), CosmosMeterName.SYSTEM_MEMORY_FREE); - map.put(nameOf("system.avgcpuload"), CosmosMeterName.SYSTEM_CPU); - map.put( - nameOf("req.rntbd.stats.endpoint.acquiredchannels"), - CosmosMeterName.LEGACY_DIRECT_ENDPOINT_STATISTICS_ACQUIRED); - map.put( - nameOf("req.rntbd.stats.endpoint.availablechannels"), - CosmosMeterName.LEGACY_DIRECT_ENDPOINT_STATISTICS_AVAILABLE); - map.put( - nameOf("req.rntbd.stats.endpoint.inflightrequests"), - CosmosMeterName.LEGACY_DIRECT_ENDPOINT_STATISTICS_INFLIGHT); - - return Collections.unmodifiableMap(map); - } - - private static String getValidValues() { - StringJoiner sj = new StringJoiner(", "); - for (CosmosMeterName c: CosmosMeterName.values(CosmosMeterName.class)) { - sj.add(c.toString()); - } - - return sj.toString(); - } - - private CosmosMeterName setCategory(CosmosMeterCategory meterCategory) { - this.meterCategory = meterCategory; - return this; - } - - private static String nameOf(final String member) { - return "cosmos.client." + member; - } -} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterCategory.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java similarity index 68% rename from sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterCategory.java rename to sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java index bdd286c14ab4b..f1be773e8a144 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterCategory.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java @@ -15,33 +15,33 @@ /** * Categories for Cosmos DB client-side metrics */ -public final class CosmosMeterCategory extends ExpandableStringEnum { +public final class CosmosMetricCategory extends ExpandableStringEnum { private EnumSet metricCategories; /** - * Creates a new instance of {@link CosmosMeterCategory} without a {@link #toString()} value. + * Creates a new instance of {@link CosmosMetricCategory} without a {@link #toString()} value. *

- * This constructor shouldn't be called as it will produce a {@link CosmosMeterCategory} which doesn't + * This constructor shouldn't be called as it will produce a {@link CosmosMetricCategory} which doesn't * have a String enum value. * * @deprecated Use one of the constants or the {@link #fromString(String)} factory method. */ @Deprecated - CosmosMeterCategory() { + CosmosMetricCategory() { } /** * All metrics enabled */ - public static final CosmosMeterCategory ALL = fromString("All", CosmosMeterCategory.class) + public static final CosmosMetricCategory ALL = fromString("All", CosmosMetricCategory.class) .setCategories(MetricCategory.ALL_CATEGORIES); /** * Default metrics (categories OperationSummary, RequestSummary, System, DirectChannels and DirectRequests) enabled. * These metrics provide good overview of end-to-end telemetry and help with triaging for most common issues */ - public static final CosmosMeterCategory DEFAULT = fromString("Default", CosmosMeterCategory.class) + public static final CosmosMetricCategory DEFAULT = fromString("Default", CosmosMetricCategory.class) .setCategories(MetricCategory.DEFAULT_CATEGORIES); /** @@ -49,7 +49,7 @@ public final class CosmosMeterCategory extends ExpandableStringEnum metricCategories) { + private CosmosMetricCategory setCategories(EnumSet metricCategories) { this.metricCategories = metricCategories; return this; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricName.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricName.java new file mode 100644 index 0000000000000..bcf720e88417c --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricName.java @@ -0,0 +1,398 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.models; + +import com.azure.core.util.ExpandableStringEnum; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.StringJoiner; + +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; + +/** + * Names of Cosmos DB client-side meters + */ +public final class CosmosMetricName extends ExpandableStringEnum { + private CosmosMetricCategory meterCategory; + + /** + * Creates a new instance of {@link CosmosMetricName} without a {@link #toString()} value. + *

+ * This constructor shouldn't be called as it will produce a {@link CosmosMetricName} which doesn't + * have a String enum value. + * + * @deprecated Use one of the constants or the {@link #fromString(String)} factory method. + */ + @Deprecated + CosmosMetricName() { + } + + + /** + * Number of operation calls (Counter) + */ + public static final CosmosMetricName OPERATION_SUMMARY_CALLS = + fromString(nameOf("op.calls"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.OPERATION_SUMMARY); + + /** + * Total latency (across requests including retries) of the operation (Timer) + */ + public static final CosmosMetricName OPERATION_SUMMARY_LATENCY = + fromString(nameOf("op.latency"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.OPERATION_SUMMARY); + + /** + * Request charge for the operation (DistributionSummary) + */ + public static final CosmosMetricName OPERATION_SUMMARY_REQUEST_CHARGE = + fromString(nameOf("op.RUs"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.OPERATION_SUMMARY); + + /** + * Number of regions contacted for processing the operation (DistributionSummary) + */ + public static final CosmosMetricName OPERATION_DETAILS_REGIONS_CONTACTED = + fromString(nameOf("op.regionsContacted"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.OPERATION_DETAILS); + + /** + * Actual item count - relevant for non-point-operations - indicating the actual number of + * docs returned in the response (DistributionSummary) + * NOTE: No percentiles or histogram supported + */ + public static final CosmosMetricName OPERATION_DETAILS_ACTUAL_ITEM_COUNT = + fromString(nameOf("op.actualItemCount"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.OPERATION_DETAILS); + + /** + * Max. item count - relevant for non-point-operations - indicating the requested max. number of + * docs returned in a single response (DistributionSummary) + * NOTE: No percentiles or histogram supported + */ + public static final CosmosMetricName OPERATION_DETAILS_MAX_ITEM_COUNT = + fromString(nameOf("op.maxItemCount"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.OPERATION_DETAILS); + + /** + * Number of requests (Counter) + * NOTE: No percentiles or histogram supported + */ + public static final CosmosMetricName REQUEST_SUMMARY_DIRECT_REQUESTS = + fromString(nameOf("req.rntbd.requests"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.REQUEST_SUMMARY); + + /** + * Latency of the request (Timer) + */ + public static final CosmosMetricName REQUEST_SUMMARY_DIRECT_LATENCY = + fromString(nameOf("req.rntbd.latency"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.REQUEST_SUMMARY); + + /** + * Backend-latency of the request (DistributionSummary) + */ + public static final CosmosMetricName REQUEST_SUMMARY_DIRECT_BACKEND_LATENCY = + fromString(nameOf("req.rntbd.backendLatency"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.REQUEST_SUMMARY); + + /** + * Request charge for a request (DistributionSummary) + */ + public static final CosmosMetricName REQUEST_SUMMARY_DIRECT_REQUEST_CHARGE = + fromString(nameOf("req.rntbd.RUs"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.REQUEST_SUMMARY); + + /** + * Number of requests (Counter) + * NOTE: No percentiles or histogram supported + */ + public static final CosmosMetricName REQUEST_SUMMARY_GATEWAY_REQUESTS = + fromString(nameOf("req.gw.requests"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.REQUEST_SUMMARY); + + /** + * Latency of the request (Timer) + */ + public static final CosmosMetricName REQUEST_SUMMARY_GATEWAY_LATENCY = + fromString(nameOf("req.gw.latency"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.REQUEST_SUMMARY); + + /** + * Request charge for a request (DistributionSummary) + */ + public static final CosmosMetricName REQUEST_SUMMARY_GATEWAY_REQUEST_CHARGE = + fromString(nameOf("req.gw.RUs"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.REQUEST_SUMMARY); + + /** + * Size of the request payload (DistributionSummary) + * NOTE: No percentiles or histogram supported + */ + public static final CosmosMetricName REQUEST_SUMMARY_SIZE_REQUEST = + fromString(nameOf("req.reqPayloadSize"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.REQUEST_SUMMARY); + + /** + * Size of the response payload (DistributionSummary) + * NOTE: No percentiles or histogram supported + */ + public static final CosmosMetricName REQUEST_SUMMARY_SIZE_RESPONSE = + fromString(nameOf("req.rspPayloadSize"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.REQUEST_SUMMARY); + + /** + * Latency in different steps of the request pipeline (Timer) + */ + public static final CosmosMetricName REQUEST_DETAILS_DIRECT_TIMELINE = + fromString(nameOf("req.rntbd.timeline"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.REQUEST_DETAILS); + + /** + * Latency in different steps of the request pipeline (Timer) + */ + public static final CosmosMetricName REQUEST_DETAILS_GATEWAY_TIMELINE = + fromString(nameOf("req.gw.timeline"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.REQUEST_DETAILS); + + /** + * Number of acquired channels (new connections) for this endpoint (FunctionCounter) + */ + public static final CosmosMetricName DIRECT_CHANNELS_ACQUIRED_COUNT = + fromString(nameOf("rntbd.channels.acquired.count"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.DIRECT_CHANNELS); + + /** + * Number of closed channels / connections for this endpoint (FunctionCounter) + */ + public static final CosmosMetricName DIRECT_CHANNELS_CLOSED_COUNT = + fromString(nameOf("rntbd.channels.closed.count"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.DIRECT_CHANNELS); + + /** + * Snapshot of the number of available channels (active connections) for this endpoint (Gauge) + */ + public static final CosmosMetricName DIRECT_CHANNELS_AVAILABLE_COUNT = + fromString(nameOf("rntbd.channels.available.count"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.DIRECT_CHANNELS); + + /** + * Snapshot of the number of endpoints (Gauge) + */ + public static final CosmosMetricName DIRECT_ENDPOINTS_COUNT = + fromString(nameOf("rntbd.endpoints.count"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.DIRECT_ENDPOINTS); + + /** + * Number of evicted/closed endpoints (FunctionCounter) + */ + public static final CosmosMetricName DIRECT_ENDPOINTS_EVICTED = + fromString(nameOf("rntbd.endpoints.evicted"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.DIRECT_ENDPOINTS); + + /** + * Number of RNTBD address resolution requests (Counter) + */ + public static final CosmosMetricName DIRECT_ADDRESS_RESOLUTION_REQUESTS = + fromString(nameOf("rntbd.addressResolution.requests"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.DIRECT_ADDRESS_RESOLUTIONS); + + /** + * Latency of the RNTBD address resolution request (Timer) + */ + public static final CosmosMetricName DIRECT_ADDRESS_RESOLUTION_LATENCY = + fromString(nameOf("rntbd.addressResolution.latency"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.DIRECT_ADDRESS_RESOLUTIONS); + + /** + * Latency of RNTBD requests for this endpoint (Timer) + */ + public static final CosmosMetricName DIRECT_REQUEST_LATENCY = + fromString(nameOf("rntbd.requests.latency"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.DIRECT_REQUESTS); + + /** + * Latency of failed RNTBD requests for this endpoint (Timer) + */ + public static final CosmosMetricName DIRECT_REQUEST_LATENCY_FAILED = + fromString(nameOf("rntbd.requests.failed.latency"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.DIRECT_REQUESTS); + + /** + * Latency of successful RNTBD requests for this endpoint (Timer) + */ + public static final CosmosMetricName DIRECT_REQUEST_LATENCY_SUCCESS = + fromString(nameOf("rntbd.requests.successful.latency"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.DIRECT_REQUESTS); + + /** + * Snapshot of number of concurrent RNTBD requests for this endpoint (Gauge) + */ + public static final CosmosMetricName DIRECT_REQUEST_CONCURRENT_COUNT = + fromString(nameOf("rntbd.requests.concurrent.count"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.DIRECT_REQUESTS); + + /** + * Snapshot of number of queued RNTBD requests for this endpoint (Gauge) + */ + public static final CosmosMetricName DIRECT_REQUEST_QUEUED_COUNT = + fromString(nameOf("rntbd.requests.queued.count"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.DIRECT_REQUESTS); + + /** + * Size of the request payload (DistributionSummary) + */ + public static final CosmosMetricName DIRECT_REQUEST_SIZE_REQUEST = + fromString(nameOf("rntbd.req.reqSize"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.DIRECT_REQUESTS); + + /** + * Size of the response payload (DistributionSummary) + */ + public static final CosmosMetricName DIRECT_REQUEST_SIZE_RESPONSE = + fromString(nameOf("rntbd.req.rspSize"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.DIRECT_REQUESTS); + + /** + * Avg. system-wide CPU load (DistributionSummary) + */ + public static final CosmosMetricName SYSTEM_CPU = + fromString(nameOf("system.avgCpuLoad"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.SYSTEM); + + /** + * JVM's Free available memory (DistributionSummary) + */ + public static final CosmosMetricName SYSTEM_MEMORY_FREE = + fromString(nameOf("system.freeMemoryAvailable"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.SYSTEM); + + /** + * Distribution summary over snapshot of acquired channels for the endpoint at time + * of a request (DistributionSummary) + */ + public static final CosmosMetricName LEGACY_DIRECT_ENDPOINT_STATISTICS_ACQUIRED = + fromString(nameOf("req.rntbd.stats.endpoint.acquiredChannels"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.LEGACY); + + /** + * Distribution summary over snapshot of available channels for the endpoint at time + * of a request (DistributionSummary) + */ + public static final CosmosMetricName LEGACY_DIRECT_ENDPOINT_STATISTICS_AVAILABLE = + fromString(nameOf("req.rntbd.stats.endpoint.availableChannels"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.LEGACY); + + /** + * Distribution summary over snapshot of inflight channels for the endpoint at time + * of a request (DistributionSummary) + */ + public static final CosmosMetricName LEGACY_DIRECT_ENDPOINT_STATISTICS_INFLIGHT = + fromString(nameOf("req.rntbd.stats.endpoint.inflightRequests"), CosmosMetricName.class) + .setCategory(CosmosMetricCategory.LEGACY); + + private final static Map meters = createMeterNameMap(); + + /** + * Gets the corresponding metric category state from its string representation. + * + * @param name The name of the Cosmos metric category to convert. + * + * @return The corresponding Cosmos metric category. + */ + public static CosmosMetricName fromString(String name) { + checkNotNull(name, "Argument 'name' must not be null."); + + String normalizedName = name.trim().toLowerCase(Locale.ROOT); + CosmosMetricName meterName = meters.getOrDefault(normalizedName, null); + + if (meterName == null) { + String errorMessage = String.format( + "Argument 'name' has invalid value '%s' - valid values are: %s", + name, + getValidValues()); + + throw new IllegalArgumentException(errorMessage); + } + + return meterName; + } + + /** + * Gets the meter category of the meter + * @return the category of the meter + */ + public CosmosMetricCategory getCategory() { + return this.meterCategory; + } + + private static Map createMeterNameMap() { + Map map = new HashMap<>(); + map.put(nameOf("op.latency"), CosmosMetricName.OPERATION_SUMMARY_LATENCY); + map.put(nameOf("op.calls"), CosmosMetricName.OPERATION_SUMMARY_CALLS); + map.put(nameOf("op.rus"), CosmosMetricName.OPERATION_SUMMARY_REQUEST_CHARGE); + map.put(nameOf("op.maxitemcount"), CosmosMetricName.OPERATION_DETAILS_MAX_ITEM_COUNT); + map.put(nameOf("op.actualitemcount"), CosmosMetricName.OPERATION_DETAILS_ACTUAL_ITEM_COUNT); + map.put(nameOf("op.regionscontacted"), CosmosMetricName.OPERATION_DETAILS_REGIONS_CONTACTED); + map.put(nameOf("req.rntbd.requests"), CosmosMetricName.REQUEST_SUMMARY_DIRECT_REQUESTS); + map.put(nameOf("req.rntbd.latency"), CosmosMetricName.REQUEST_SUMMARY_DIRECT_LATENCY); + map.put(nameOf("req.rntbd.backendlatency"), CosmosMetricName.REQUEST_SUMMARY_DIRECT_BACKEND_LATENCY); + map.put(nameOf("req.rntbd.rus"), CosmosMetricName.REQUEST_SUMMARY_DIRECT_REQUEST_CHARGE); + map.put(nameOf("req.gw.requests"), CosmosMetricName.REQUEST_SUMMARY_GATEWAY_REQUESTS); + map.put(nameOf("req.gw.latency"), CosmosMetricName.REQUEST_SUMMARY_GATEWAY_LATENCY); + map.put(nameOf("req.gw.rus"), CosmosMetricName.REQUEST_SUMMARY_GATEWAY_REQUEST_CHARGE); + map.put(nameOf("req.reqPayloadSize"), CosmosMetricName.REQUEST_SUMMARY_SIZE_REQUEST); + map.put(nameOf("req.rspPayloadSize"), CosmosMetricName.REQUEST_SUMMARY_SIZE_RESPONSE); + map.put(nameOf("req.rntbd.timeline"), CosmosMetricName.REQUEST_DETAILS_DIRECT_TIMELINE); + map.put(nameOf("req.gw.timeline"), CosmosMetricName.REQUEST_DETAILS_GATEWAY_TIMELINE); + map.put(nameOf("rntbd.channels.acquired.count"), CosmosMetricName.DIRECT_CHANNELS_ACQUIRED_COUNT); + map.put(nameOf("rntbd.channels.available.count"), CosmosMetricName.DIRECT_CHANNELS_AVAILABLE_COUNT); + map.put(nameOf("rntbd.channels.closed.count"), CosmosMetricName.DIRECT_CHANNELS_CLOSED_COUNT); + map.put(nameOf("rntbd.endpoints.count"), CosmosMetricName.DIRECT_ENDPOINTS_COUNT); + map.put(nameOf("rntbd.endpoints.evicted"), CosmosMetricName.DIRECT_ENDPOINTS_EVICTED); + map.put(nameOf("rntbd.addressresolution.requests"), CosmosMetricName.DIRECT_ADDRESS_RESOLUTION_REQUESTS); + map.put(nameOf("rntbd.addressresolution.latency"), CosmosMetricName.DIRECT_ADDRESS_RESOLUTION_LATENCY); + map.put(nameOf("rntbd.requests.latency"), CosmosMetricName.DIRECT_REQUEST_LATENCY); + map.put(nameOf("rntbd.requests.failed.latency"), CosmosMetricName.DIRECT_REQUEST_LATENCY_FAILED); + map.put(nameOf("rntbd.requests.successful.latency"), CosmosMetricName.DIRECT_REQUEST_LATENCY_SUCCESS); + map.put(nameOf("rntbd.requests.concurrent.count"), CosmosMetricName.DIRECT_REQUEST_CONCURRENT_COUNT); + map.put(nameOf("rntbd.requests.queued.count"), CosmosMetricName.DIRECT_REQUEST_QUEUED_COUNT); + map.put(nameOf("rntbd.req.reqsize"), CosmosMetricName.DIRECT_REQUEST_SIZE_REQUEST); + map.put(nameOf("rntbd.req.rspsize"), CosmosMetricName.DIRECT_REQUEST_SIZE_RESPONSE); + map.put(nameOf("system.freememoryavailable"), CosmosMetricName.SYSTEM_MEMORY_FREE); + map.put(nameOf("system.avgcpuload"), CosmosMetricName.SYSTEM_CPU); + map.put( + nameOf("req.rntbd.stats.endpoint.acquiredchannels"), + CosmosMetricName.LEGACY_DIRECT_ENDPOINT_STATISTICS_ACQUIRED); + map.put( + nameOf("req.rntbd.stats.endpoint.availablechannels"), + CosmosMetricName.LEGACY_DIRECT_ENDPOINT_STATISTICS_AVAILABLE); + map.put( + nameOf("req.rntbd.stats.endpoint.inflightrequests"), + CosmosMetricName.LEGACY_DIRECT_ENDPOINT_STATISTICS_INFLIGHT); + + return Collections.unmodifiableMap(map); + } + + private static String getValidValues() { + StringJoiner sj = new StringJoiner(", "); + for (CosmosMetricName c: CosmosMetricName.values(CosmosMetricName.class)) { + sj.add(c.toString()); + } + + return sj.toString(); + } + + private CosmosMetricName setCategory(CosmosMetricCategory meterCategory) { + this.meterCategory = meterCategory; + return this; + } + + private static String nameOf(final String member) { + return "cosmos.client." + member; + } +} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterTagName.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricTagName.java similarity index 56% rename from sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterTagName.java rename to sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricTagName.java index cdf6a8616929b..2712454ff0f66 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterTagName.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricTagName.java @@ -17,94 +17,94 @@ * this identifier can be used to tune which tags to use for individual meters or also define the default tags that * should be used when no meter-specific suppression exists. */ -public final class CosmosMeterTagName extends ExpandableStringEnum { +public final class CosmosMetricTagName extends ExpandableStringEnum { private EnumSet tagNames; /** - * Creates a new instance of {@link CosmosMeterTagName} without a {@link #toString()} value. + * Creates a new instance of {@link CosmosMetricTagName} without a {@link #toString()} value. *

- * This constructor shouldn't be called as it will produce a {@link CosmosMeterTagName} which doesn't + * This constructor shouldn't be called as it will produce a {@link CosmosMetricTagName} which doesn't * have a String enum value. * * @deprecated Use one of the constants or the {@link #fromString(String)} factory method. */ @Deprecated - CosmosMeterTagName() { + CosmosMetricTagName() { } /** * All possible tags */ - public static final CosmosMeterTagName ALL = fromString("All", CosmosMeterTagName.class) + public static final CosmosMetricTagName ALL = fromString("All", CosmosMetricTagName.class) .setTagNames(TagName.ALL_TAGS); /** * Default tags */ - public static final CosmosMeterTagName DEFAULT = fromString("Default", CosmosMeterTagName.class) + public static final CosmosMetricTagName DEFAULT = fromString("Default", CosmosMetricTagName.class) .setTagNames(TagName.DEFAULT_TAGS); /** * Minimum tags that are required and cannot be disabled */ - public static final CosmosMeterTagName MINIMUM = fromString("Minimum", CosmosMeterTagName.class) + public static final CosmosMetricTagName MINIMUM = fromString("Minimum", CosmosMetricTagName.class) .setTagNames(TagName.MINIMUM_TAGS); /** * Effective Consistency model * Applicable to operations and requests */ - public static final CosmosMeterTagName CONSISTENCY_LEVEL = - fromString("ConsistencyLevel", CosmosMeterTagName.class) + public static final CosmosMetricTagName CONSISTENCY_LEVEL = + fromString("ConsistencyLevel", CosmosMetricTagName.class) .setTagNames(EnumSet.of(TagName.ConsistencyLevel)); /** * Container identifier * applicable to operations and requests */ - public static final CosmosMeterTagName CONTAINER = - fromString("Container", CosmosMeterTagName.class) + public static final CosmosMetricTagName CONTAINER = + fromString("Container", CosmosMetricTagName.class) .setTagNames(EnumSet.of(TagName.Container)); /** * The service endpoint (hostname + port) * Applicable to requests, direct channel, direct endpoint and direct requests */ - public static final CosmosMeterTagName SERVICE_ENDPOINT = - fromString("ServiceEndpoint", CosmosMeterTagName.class) + public static final CosmosMetricTagName SERVICE_ENDPOINT = + fromString("ServiceEndpoint", CosmosMetricTagName.class) .setTagNames(EnumSet.of(TagName.ServiceEndpoint)); /** * The service endpoint (hostname + port, partitionId, replicaId) * Applicable to requests */ - public static final CosmosMeterTagName SERVICE_ADDRESS= - fromString("ServiceAddress", CosmosMeterTagName.class) + public static final CosmosMetricTagName SERVICE_ADDRESS= + fromString("ServiceAddress", CosmosMetricTagName.class) .setTagNames(EnumSet.of(TagName.ServiceAddress)); /** * The region names of the regions handling the operation/request * Applicable to requests and operations */ - public static final CosmosMeterTagName REGION_NAME = - fromString("RegionName", CosmosMeterTagName.class) + public static final CosmosMetricTagName REGION_NAME = + fromString("RegionName", CosmosMetricTagName.class) .setTagNames(EnumSet.of(TagName.RegionName)); /** * Operation status code. * Applicable to operations */ - public static final CosmosMeterTagName OPERATION_STATUS_CODE = - fromString("OperationStatusCode", CosmosMeterTagName.class) + public static final CosmosMetricTagName OPERATION_STATUS_CODE = + fromString("OperationStatusCode", CosmosMetricTagName.class) .setTagNames(EnumSet.of(TagName.OperationStatusCode)); /** * Operation type * Applicable to operations */ - public static final CosmosMeterTagName OPERATION = - fromString("Operation", CosmosMeterTagName.class) + public static final CosmosMetricTagName OPERATION = + fromString("Operation", CosmosMetricTagName.class) .setTagNames(EnumSet.of(TagName.Operation)); @@ -112,32 +112,32 @@ public final class CosmosMeterTagName extends ExpandableStringEnum tagNames) { + private CosmosMetricTagName setTagNames(EnumSet tagNames) { this.tagNames = tagNames; return this; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMicrometerMeterOptions.java similarity index 75% rename from sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterOptions.java rename to sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMicrometerMeterOptions.java index 678c5695d457c..03bacadd9660a 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMeterOptions.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMicrometerMeterOptions.java @@ -3,7 +3,6 @@ package com.azure.cosmos.models; -import com.azure.core.util.MetricsOptions; import com.azure.cosmos.implementation.ImplementationBridgeHelpers; import com.azure.cosmos.implementation.clienttelemetry.TagName; @@ -15,18 +14,19 @@ * Options of a Cosmos client-side meter that can be used to enable/disable it, change the percentile and histogram * capturing (if percentiles are applicable for the meter) and allows suppressing tags that are not desired. */ -public final class CosmosMeterOptions extends MetricsOptions { +public final class CosmosMicrometerMeterOptions { - private final CosmosMeterName meterName; + private final CosmosMetricName meterName; private boolean isHistogramPublishingEnabled; private double[] percentiles; private EnumSet suppressedTagNames; + private boolean isEnabled; /** * Instantiates new options for a specific Cosmos DB meter */ - CosmosMeterOptions( - CosmosMeterName meterName, + CosmosMicrometerMeterOptions( + CosmosMetricName meterName, boolean isHistogramPublishingEnabled, double[] percentiles) { @@ -36,13 +36,14 @@ public final class CosmosMeterOptions extends MetricsOptions { this.isHistogramPublishingEnabled = isHistogramPublishingEnabled; this.percentiles = percentiles; this.suppressedTagNames = EnumSet.noneOf(TagName.class); + this.isEnabled = true; } /** * Gets the name of the meter these options are applicable for * @return the meter name for these options */ - public CosmosMeterName getMeterName() { + public CosmosMetricName getMeterName() { return this.meterName; } @@ -52,10 +53,10 @@ public CosmosMeterName getMeterName() { * @param tags - the tags to be used (when applicable) for this meter * @return current CosmosMeterOptions instance */ - public CosmosMeterOptions suppressTagNames(CosmosMeterTagName... tags) { + public CosmosMicrometerMeterOptions suppressTagNames(CosmosMetricTagName... tags) { EnumSet newTagNames = EnumSet.noneOf(TagName.class); if (tags != null && tags.length > 0) { - for (CosmosMeterTagName t: tags) { + for (CosmosMetricTagName t: tags) { for (TagName tagName: t.getTagNames()) { if (!TagName.MINIMUM_TAGS.contains(tagName)) { newTagNames.add(tagName); @@ -75,7 +76,7 @@ public CosmosMeterOptions suppressTagNames(CosmosMeterTagName... tags) { * @param isEnabled - a flag indicating whether histogram publishing is enabled for this meter * @return current CosmosMeterOptions instance */ - public CosmosMeterOptions histogramPublishingEnabled(boolean isEnabled) { + public CosmosMicrometerMeterOptions histogramPublishingEnabled(boolean isEnabled) { this.isHistogramPublishingEnabled = isEnabled; return this; @@ -87,7 +88,7 @@ public CosmosMeterOptions histogramPublishingEnabled(boolean isEnabled) { * @param percentiles - a flag indicating whether histogram publishing is enabled for this meter * @return current CosmosMeterOptions instance */ - public CosmosMeterOptions percentiles(double... percentiles) { + public CosmosMicrometerMeterOptions percentiles(double... percentiles) { if (percentiles == null || percentiles.length == 0) { this.percentiles = null; } else { @@ -97,15 +98,26 @@ public CosmosMeterOptions percentiles(double... percentiles) { return this; } + /** - * {@inheritDoc} + * Enables or disables this meter. By default, meters are enabled. + * + * @param enabled pass {@code true} to enable the meter. + * @return the updated {@code MetricsOptions} object. */ - @Override - public CosmosMeterOptions setEnabled(boolean enabled) { - super.setEnabled(enabled); + public CosmosMicrometerMeterOptions setEnabled(boolean enabled) { + this.isEnabled = enabled; return this; } + /** + * Flag indicating if this meter is currently enabled. + * @return {@code true} if meter is currently enabled, {@code false} otherwise. + */ + public boolean isEnabled() { + return this.isEnabled; + } + /////////////////////////////////////////////////////////////////////////////////////////// // the following helper/accessor only helps to access this class outside of this package.// /////////////////////////////////////////////////////////////////////////////////////////// @@ -113,17 +125,17 @@ static void initialize() { ImplementationBridgeHelpers.CosmosMeterOptionsHelper.setCosmosMeterOptionsAccessor( new ImplementationBridgeHelpers.CosmosMeterOptionsHelper.CosmosMeterOptionsAccessor() { @Override - public EnumSet getSuppressedTagNames(CosmosMeterOptions options) { + public EnumSet getSuppressedTagNames(CosmosMicrometerMeterOptions options) { return options.suppressedTagNames; } @Override - public boolean isHistogramPublishingEnabled(CosmosMeterOptions options) { + public boolean isHistogramPublishingEnabled(CosmosMicrometerMeterOptions options) { return options.isHistogramPublishingEnabled; } @Override - public double[] getPercentiles(CosmosMeterOptions options) { + public double[] getPercentiles(CosmosMicrometerMeterOptions options) { return options.percentiles; } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMicrometerMetricsOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMicrometerMetricsOptions.java index df0991fc2b514..4b83348fc24cc 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMicrometerMetricsOptions.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMicrometerMetricsOptions.java @@ -7,9 +7,7 @@ import com.azure.cosmos.implementation.clienttelemetry.TagName; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Metrics; -import io.micrometer.core.instrument.Tag; -import java.lang.reflect.Array; import java.util.EnumSet; import java.util.concurrent.ConcurrentHashMap; @@ -24,7 +22,7 @@ public final class CosmosMicrometerMetricsOptions extends MetricsOptions { private EnumSet defaultTagNames = TagName.DEFAULT_TAGS.clone(); private double[] defaultPercentiles = { 0.95, 0.99 }; private boolean defaultShouldPublishHistograms = true; - private final ConcurrentHashMap effectiveOptions = new ConcurrentHashMap<>(); + private final ConcurrentHashMap effectiveOptions = new ConcurrentHashMap<>(); /** * Instantiates new Micrometer-specific Azure Cosmos DB SDK metrics options @@ -54,21 +52,21 @@ public CosmosMicrometerMetricsOptions meterRegistry(MeterRegistry clientMetricMe /** * Sets the default tags that should be used for metrics (where applicable) unless overridden for a specific - * meter in its {@link CosmosMeterOptions} + * meter in its {@link CosmosMicrometerMeterOptions} * By default all applicable tags are added for each metric. Adding tags/dimensions especially with high * cardinality has some overhead - so, this method allows modifying the set of tags to be applied when some are * not relevant in a certain use case. * * @param tags - the default tags to be used (when they are applicable to a specific meter and there is no - * override in {@link CosmosMeterOptions} for that meter. + * override in {@link CosmosMicrometerMeterOptions} for that meter. * @return current CosmosMicrometerMetricsOptions instance */ - public CosmosMicrometerMetricsOptions defaultTagNames(CosmosMeterTagName... tags) { + public CosmosMicrometerMetricsOptions defaultTagNames(CosmosMetricTagName... tags) { if (tags == null || tags.length == 0) { this.defaultTagNames = TagName.DEFAULT_TAGS.clone(); } else { EnumSet newTagNames = TagName.MINIMUM_TAGS.clone(); - for (CosmosMeterTagName t: tags) { + for (CosmosMetricTagName t: tags) { for (TagName tagName: t.getTagNames()) { newTagNames.add(tagName); } @@ -82,12 +80,12 @@ public CosmosMicrometerMetricsOptions defaultTagNames(CosmosMeterTagName... tags /** * Sets the default percentiles that should be captured for metrics (where applicable) unless overridden for a - * specific meter in its {@link CosmosMeterOptions} + * specific meter in its {@link CosmosMicrometerMeterOptions} * By default percentiles 0.95 and 0.99 are captured. If percentiles is null or empty no percentiles will be * captured. * * @param percentiles - the default percentiles to be captured (when they are applicable to a specific meter and - * there is no override in {@link CosmosMeterOptions} for that meter. + * there is no override in {@link CosmosMicrometerMeterOptions} for that meter. * @return current CosmosMicrometerMetricsOptions instance */ public CosmosMicrometerMetricsOptions defaultPercentiles(double... percentiles) { @@ -109,12 +107,12 @@ public CosmosMicrometerMetricsOptions defaultPercentiles(double... percentiles) /** * Sets a flag indicating whether by default histograms should be published for metrics (where applicable) unless - * overridden for a specific meter in its {@link CosmosMeterOptions} + * overridden for a specific meter in its {@link CosmosMicrometerMeterOptions} * By default histograms are published. Publishing histograms has its overhead - so, this method allows disabling * histograms by default. * * @param publishHistograms - a flag indicating whether by default histograms should be published for metrics - * (when they are applicable to a specific meter and there is no override in {@link CosmosMeterOptions} for + * (when they are applicable to a specific meter and there is no override in {@link CosmosMicrometerMeterOptions} for * that meter. * @return current CosmosMicrometerMetricsOptions instance */ @@ -146,12 +144,12 @@ public CosmosMicrometerMetricsOptions setEnabled(boolean enabled) { * @param categories - a comma-separated list of metric categories that should be emitted * @return current CosmosClientTelemetryConfig */ - public CosmosMicrometerMetricsOptions setMetricCategories(CosmosMeterCategory... categories) { + public CosmosMicrometerMetricsOptions setMetricCategories(CosmosMetricCategory... categories) { if (categories == null || categories.length == 0) { this.metricCategories = MetricCategory.DEFAULT_CATEGORIES.clone(); } else { EnumSet newMetricCategories = MetricCategory.MINIMAL_CATEGORIES.clone(); - for (CosmosMeterCategory c: categories) { + for (CosmosMetricCategory c: categories) { for (MetricCategory metricCategory: c.getCategories()) { newMetricCategories.add(metricCategory); } @@ -176,13 +174,13 @@ public CosmosMicrometerMetricsOptions setMetricCategories(CosmosMeterCategory... * @param categories - a comma-separated list of metric categories that should be emitted * @return current CosmosClientTelemetryConfig */ - public CosmosMicrometerMetricsOptions addMetricCategories(CosmosMeterCategory... categories) { + public CosmosMicrometerMetricsOptions addMetricCategories(CosmosMetricCategory... categories) { if (categories == null || categories.length == 0) { return this; } EnumSet newMetricCategories = this.metricCategories.clone(); - for (CosmosMeterCategory c: categories) { + for (CosmosMetricCategory c: categories) { for (MetricCategory metricCategory: c.getCategories()) { newMetricCategories.add(metricCategory); } @@ -205,19 +203,19 @@ public CosmosMicrometerMetricsOptions addMetricCategories(CosmosMeterCategory... * @param categories - a comma-separated list of metric categories that should be emitted * @return current CosmosClientTelemetryConfig */ - public CosmosMicrometerMetricsOptions removeMetricCategories(CosmosMeterCategory... categories) { + public CosmosMicrometerMetricsOptions removeMetricCategories(CosmosMetricCategory... categories) { if (categories == null || categories.length == 0) { return this; } EnumSet newMetricCategories = this.metricCategories.clone(); - for (CosmosMeterCategory c: categories) { + for (CosmosMetricCategory c: categories) { for (MetricCategory metricCategory: c.getCategories()) { newMetricCategories.remove(metricCategory); } } - for (MetricCategory metricCategory: CosmosMeterCategory.MINIMUM.getCategories()) { + for (MetricCategory metricCategory: CosmosMetricCategory.MINIMUM.getCategories()) { newMetricCategories.add(metricCategory); } @@ -232,12 +230,12 @@ public CosmosMicrometerMetricsOptions removeMetricCategories(CosmosMeterCategory * @param meterName - the meter name * @return the current meter options */ - public CosmosMeterOptions getMeterOptions(CosmosMeterName meterName) { + public CosmosMicrometerMeterOptions getMeterOptions(CosmosMetricName meterName) { checkNotNull(meterName, "Argument 'meterName' must not be null."); return this .effectiveOptions - .computeIfAbsent(meterName, name -> new CosmosMeterOptions( + .computeIfAbsent(meterName, name -> new CosmosMicrometerMeterOptions( name, this.defaultShouldPublishHistograms, this.defaultPercentiles diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ModelBridgeInternal.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ModelBridgeInternal.java index 8f12ffaf7960c..10aec4c1decab 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ModelBridgeInternal.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ModelBridgeInternal.java @@ -964,6 +964,6 @@ public static void initializeAllAccessors() { PartitionKey.initialize(); CosmosClientTelemetryConfig.initialize(); CosmosContainerIdentity.initialize(); - CosmosMeterOptions.initialize(); + CosmosMicrometerMeterOptions.initialize(); } } diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java index 78bd82df172a6..8cc44d664498f 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java @@ -25,9 +25,9 @@ import com.azure.cosmos.models.CosmosItemOperation; import com.azure.cosmos.models.CosmosItemRequestOptions; import com.azure.cosmos.models.CosmosItemResponse; -import com.azure.cosmos.models.CosmosMeterCategory; -import com.azure.cosmos.models.CosmosMeterName; -import com.azure.cosmos.models.CosmosMeterTagName; +import com.azure.cosmos.models.CosmosMetricCategory; +import com.azure.cosmos.models.CosmosMetricName; +import com.azure.cosmos.models.CosmosMetricTagName; import com.azure.cosmos.models.CosmosMicrometerMetricsOptions; import com.azure.cosmos.models.CosmosPatchItemRequestOptions; import com.azure.cosmos.models.CosmosQueryRequestOptions; @@ -84,7 +84,7 @@ private EnumSet getEffectiveMetricCategories() { .getMetricCategories(this.inputClientTelemetryConfig); } - public void beforeTest(CosmosMeterCategory... metricCategories) { + public void beforeTest(CosmosMetricCategory... metricCategories) { assertThat(this.client).isNull(); assertThat(this.meterRegistry).isNull(); @@ -145,7 +145,7 @@ public void maxValueExceedingDefinedLimitStillWorksWithoutException() throws Exc // Expected behavior is that higher values than the expected max value can still be recorded // it would only result in getting less accurate "estimates" for percentile histograms - this.beforeTest(CosmosMeterCategory.DEFAULT); + this.beforeTest(CosmosMetricCategory.DEFAULT); try { Tag dummyOperationTag = Tag.of(TagName.Operation.toString(), "TestDummy"); @@ -186,13 +186,13 @@ public void createItem() throws Exception { for (boolean disableLatencyMeter: disableLatencyMeterTestCases) { - this.beforeTest(CosmosMeterCategory.DEFAULT); + this.beforeTest(CosmosMetricCategory.DEFAULT); if (disableLatencyMeter) { this.inputMetricsOptions .getMeterOptions( - CosmosMeterName.fromString( - CosmosMeterName.OPERATION_SUMMARY_LATENCY.toString().toUpperCase(Locale.ROOT))) + CosmosMetricName.fromString( + CosmosMetricName.OPERATION_SUMMARY_LATENCY.toString().toUpperCase(Locale.ROOT))) .setEnabled(false); } @@ -243,16 +243,16 @@ public void createItemWithAllMetrics() throws Exception { for (boolean suppressConsistencyLevelTag: suppressConsistencyLevelTagTestCases) { - this.beforeTest(CosmosMeterCategory.ALL); + this.beforeTest(CosmosMetricCategory.ALL); this .inputMetricsOptions - .defaultTagNames(CosmosMeterTagName.ALL); + .defaultTagNames(CosmosMetricTagName.ALL); if (suppressConsistencyLevelTag) { this .inputMetricsOptions - .getMeterOptions(CosmosMeterName.OPERATION_SUMMARY_LATENCY) - .suppressTagNames(CosmosMeterTagName.fromString("ConsistencyLevel")) + .getMeterOptions(CosmosMetricName.OPERATION_SUMMARY_LATENCY) + .suppressTagNames(CosmosMetricTagName.fromString("ConsistencyLevel")) .histogramPublishingEnabled(false) .percentiles(0.99, 0.999) ; @@ -302,7 +302,7 @@ public void createItemWithAllMetrics() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void readItem() throws Exception { - this.beforeTest(CosmosMeterCategory.DEFAULT); + this.beforeTest(CosmosMetricCategory.DEFAULT); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); container.createItem(properties); @@ -338,7 +338,7 @@ public void readItem() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void replaceItem() throws Exception { - this.beforeTest(CosmosMeterCategory.DEFAULT); + this.beforeTest(CosmosMetricCategory.DEFAULT); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); CosmosItemResponse itemResponse = container.createItem(properties); @@ -376,7 +376,7 @@ public void replaceItem() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void deleteItem() throws Exception { - this.beforeTest(CosmosMeterCategory.DEFAULT); + this.beforeTest(CosmosMetricCategory.DEFAULT); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); container.createItem(properties); @@ -408,7 +408,7 @@ public void deleteItem() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void readAllItems() throws Exception { - this.beforeTest(CosmosMeterCategory.DEFAULT); + this.beforeTest(CosmosMetricCategory.DEFAULT); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); container.createItem(properties); @@ -452,9 +452,9 @@ public void readAllItems() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void readAllItemsWithDetailMetrics() throws Exception { this.beforeTest( - CosmosMeterCategory.DEFAULT, - CosmosMeterCategory.OPERATION_DETAILS, - CosmosMeterCategory.REQUEST_DETAILS); + CosmosMetricCategory.DEFAULT, + CosmosMetricCategory.OPERATION_DETAILS, + CosmosMetricCategory.REQUEST_DETAILS); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); container.createItem(properties); @@ -500,7 +500,7 @@ public void readAllItemsWithDetailMetrics() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void queryItems() throws Exception { - this.beforeTest(CosmosMeterCategory.DEFAULT); + this.beforeTest(CosmosMetricCategory.DEFAULT); try { InternalObjectNode properties = getDocumentDefinition(UUID.randomUUID().toString()); container.createItem(properties); @@ -549,7 +549,7 @@ public void queryItems() throws Exception { @Test(groups = { "emulator" }, timeOut = TIMEOUT * 100) public void itemPatchSuccess() { - this.beforeTest(CosmosMeterCategory.DEFAULT); + this.beforeTest(CosmosMetricCategory.DEFAULT); try { PatchTest.ToDoActivity testItem = PatchTest.ToDoActivity.createRandomItem(this.container); PatchTest.ToDoActivity testItem1 = PatchTest.ToDoActivity.createRandomItem(this.container); @@ -618,7 +618,7 @@ public void itemPatchSuccess() { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void createItem_withBulk() { - this.beforeTest(CosmosMeterCategory.DEFAULT); + this.beforeTest(CosmosMetricCategory.DEFAULT); try { int totalRequest = 5; @@ -672,7 +672,7 @@ public void createItem_withBulk() { @Test(groups = {"simple"}, timeOut = TIMEOUT) public void batchMultipleItemExecution() { - this.beforeTest(CosmosMeterCategory.DEFAULT); + this.beforeTest(CosmosMetricCategory.DEFAULT); try { TestDoc firstDoc = this.populateTestDoc(this.partitionKey1); TestDoc replaceDoc = this.getTestDocCopy(firstDoc); @@ -734,7 +734,7 @@ public void batchMultipleItemExecution() { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void effectiveMetricCategoriesForDefault() { - this.beforeTest(CosmosMeterCategory.fromString("DeFAult")); + this.beforeTest(CosmosMetricCategory.fromString("DeFAult")); try { assertThat(this.getEffectiveMetricCategories().size()).isEqualTo(5); @@ -757,9 +757,9 @@ public void effectiveMetricCategoriesForDefault() { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void effectiveMetricCategoriesForDefaultPlusDetails() { this.beforeTest( - CosmosMeterCategory.DEFAULT, - CosmosMeterCategory.fromString("RequestDetails"), - CosmosMeterCategory.fromString("OperationDETAILS")); + CosmosMetricCategory.DEFAULT, + CosmosMetricCategory.fromString("RequestDetails"), + CosmosMetricCategory.fromString("OperationDETAILS")); try { assertThat(this.getEffectiveMetricCategories().size()).isEqualTo(7); @@ -786,8 +786,8 @@ public void effectiveMetricCategoriesInvalidCategory() { String badCategoryName = "InvalidCategory"; try { this.beforeTest( - CosmosMeterCategory.DEFAULT, - CosmosMeterCategory.fromString(badCategoryName)); + CosmosMetricCategory.DEFAULT, + CosmosMetricCategory.fromString(badCategoryName)); fail("Should have thrown exception"); } catch (IllegalArgumentException argError) { @@ -799,7 +799,7 @@ public void effectiveMetricCategoriesInvalidCategory() { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void effectiveMetricCategoriesForAll() { - this.beforeTest(CosmosMeterCategory.ALL); + this.beforeTest(CosmosMetricCategory.ALL); try { assertThat(this.getEffectiveMetricCategories().size()).isEqualTo(10); @@ -826,7 +826,7 @@ public void effectiveMetricCategoriesForAll() { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void effectiveMetricCategoriesForAllLatebound() { - this.beforeTest(CosmosMeterCategory.DEFAULT); + this.beforeTest(CosmosMetricCategory.DEFAULT); try { assertThat(this.getEffectiveMetricCategories().size()).isEqualTo(5); @@ -846,9 +846,9 @@ public void effectiveMetricCategoriesForAllLatebound() { // Now change the metricCategories on the config passed into the CosmosClientBuilder // and validate that these changes take effect immediately on the client build via the builder this.inputMetricsOptions - .setMetricCategories(CosmosMeterCategory.ALL) - .removeMetricCategories(CosmosMeterCategory.OPERATION_DETAILS) - .addMetricCategories(CosmosMeterCategory.OPERATION_DETAILS, CosmosMeterCategory.REQUEST_DETAILS) + .setMetricCategories(CosmosMetricCategory.ALL) + .removeMetricCategories(CosmosMetricCategory.OPERATION_DETAILS) + .addMetricCategories(CosmosMetricCategory.OPERATION_DETAILS, CosmosMetricCategory.REQUEST_DETAILS) .defaultPercentiles(0.9) .defaultEnableHistograms(false) .setEnabled(true); @@ -868,7 +868,7 @@ public void effectiveMetricCategoriesForAllLatebound() { @Test(groups = {"simple"}, timeOut = TIMEOUT) public void invalidMeterNameThrows() { try { - CosmosMeterName.fromString("InvalidMeterName"); + CosmosMetricName.fromString("InvalidMeterName"); fail("Should have thrown"); } catch (IllegalArgumentException e) { assertThat(e.getMessage()).contains("InvalidMeterName"); @@ -878,7 +878,7 @@ public void invalidMeterNameThrows() { @Test(groups = {"simple"}, timeOut = TIMEOUT) public void invalidMeterCategoryThrows() { try { - CosmosMeterCategory.fromString("InvalidMeterCategory"); + CosmosMetricCategory.fromString("InvalidMeterCategory"); fail("Should have thrown"); } catch (IllegalArgumentException e) { assertThat(e.getMessage()).contains("InvalidMeterCategory"); @@ -888,7 +888,7 @@ public void invalidMeterCategoryThrows() { @Test(groups = {"simple"}, timeOut = TIMEOUT) public void invalidMeterTagNameThrows() { try { - CosmosMeterTagName.fromString("InvalidMeterTagName"); + CosmosMetricTagName.fromString("InvalidMeterTagName"); fail("Should have thrown"); } catch (IllegalArgumentException e) { assertThat(e.getMessage()).contains("InvalidMeterTagName"); @@ -897,136 +897,136 @@ public void invalidMeterTagNameThrows() { @Test(groups = {"simple"}, timeOut = TIMEOUT) public void meterTagNameFromStringConversion() { - assertThat(CosmosMeterTagName.fromString("aLl ")) - .isSameAs(CosmosMeterTagName.ALL); - assertThat(CosmosMeterTagName.fromString("Default")) - .isSameAs(CosmosMeterTagName.DEFAULT); - assertThat(CosmosMeterTagName.fromString("minimum")) - .isSameAs(CosmosMeterTagName.MINIMUM); - assertThat(CosmosMeterTagName.fromString("IsForceCollectionRoutingMapRefresh")) - .isSameAs(CosmosMeterTagName.ADDRESS_RESOLUTION_COLLECTION_MAP_REFRESH); - assertThat(CosmosMeterTagName.fromString("isForcerefresh")) - .isSameAs(CosmosMeterTagName.ADDRESS_RESOLUTION_FORCED_REFRESH); - assertThat(CosmosMeterTagName.fromString("ClientCorrelationID")) - .isSameAs(CosmosMeterTagName.CLIENT_CORRELATION_ID); - assertThat(CosmosMeterTagName.fromString("container")) - .isSameAs(CosmosMeterTagName.CONTAINER); - assertThat(CosmosMeterTagName.fromString(" ConsistencyLevel")) - .isSameAs(CosmosMeterTagName.CONSISTENCY_LEVEL); - assertThat(CosmosMeterTagName.fromString("operation")) - .isSameAs(CosmosMeterTagName.OPERATION); - assertThat(CosmosMeterTagName.fromString("OperationStatusCode")) - .isSameAs(CosmosMeterTagName.OPERATION_STATUS_CODE); - assertThat(CosmosMeterTagName.fromString("PartitionKeyRangeId")) - .isSameAs(CosmosMeterTagName.PARTITION_KEY_RANGE_ID); - assertThat(CosmosMeterTagName.fromString("regionname")) - .isSameAs(CosmosMeterTagName.REGION_NAME); - assertThat(CosmosMeterTagName.fromString("RequestOperationType")) - .isSameAs(CosmosMeterTagName.REQUEST_OPERATION_TYPE); - assertThat(CosmosMeterTagName.fromString("requestStatusCode")) - .isSameAs(CosmosMeterTagName.REQUEST_STATUS_CODE); - assertThat(CosmosMeterTagName.fromString("serviceaddress")) - .isSameAs(CosmosMeterTagName.SERVICE_ADDRESS); - assertThat(CosmosMeterTagName.fromString("serviceEndpoint")) - .isSameAs(CosmosMeterTagName.SERVICE_ENDPOINT); + assertThat(CosmosMetricTagName.fromString("aLl ")) + .isSameAs(CosmosMetricTagName.ALL); + assertThat(CosmosMetricTagName.fromString("Default")) + .isSameAs(CosmosMetricTagName.DEFAULT); + assertThat(CosmosMetricTagName.fromString("minimum")) + .isSameAs(CosmosMetricTagName.MINIMUM); + assertThat(CosmosMetricTagName.fromString("IsForceCollectionRoutingMapRefresh")) + .isSameAs(CosmosMetricTagName.ADDRESS_RESOLUTION_COLLECTION_MAP_REFRESH); + assertThat(CosmosMetricTagName.fromString("isForcerefresh")) + .isSameAs(CosmosMetricTagName.ADDRESS_RESOLUTION_FORCED_REFRESH); + assertThat(CosmosMetricTagName.fromString("ClientCorrelationID")) + .isSameAs(CosmosMetricTagName.CLIENT_CORRELATION_ID); + assertThat(CosmosMetricTagName.fromString("container")) + .isSameAs(CosmosMetricTagName.CONTAINER); + assertThat(CosmosMetricTagName.fromString(" ConsistencyLevel")) + .isSameAs(CosmosMetricTagName.CONSISTENCY_LEVEL); + assertThat(CosmosMetricTagName.fromString("operation")) + .isSameAs(CosmosMetricTagName.OPERATION); + assertThat(CosmosMetricTagName.fromString("OperationStatusCode")) + .isSameAs(CosmosMetricTagName.OPERATION_STATUS_CODE); + assertThat(CosmosMetricTagName.fromString("PartitionKeyRangeId")) + .isSameAs(CosmosMetricTagName.PARTITION_KEY_RANGE_ID); + assertThat(CosmosMetricTagName.fromString("regionname")) + .isSameAs(CosmosMetricTagName.REGION_NAME); + assertThat(CosmosMetricTagName.fromString("RequestOperationType")) + .isSameAs(CosmosMetricTagName.REQUEST_OPERATION_TYPE); + assertThat(CosmosMetricTagName.fromString("requestStatusCode")) + .isSameAs(CosmosMetricTagName.REQUEST_STATUS_CODE); + assertThat(CosmosMetricTagName.fromString("serviceaddress")) + .isSameAs(CosmosMetricTagName.SERVICE_ADDRESS); + assertThat(CosmosMetricTagName.fromString("serviceEndpoint")) + .isSameAs(CosmosMetricTagName.SERVICE_ENDPOINT); } @Test(groups = {"simple"}, timeOut = TIMEOUT) public void meterCategoryFromStringConversion() { - assertThat(CosmosMeterCategory.fromString("aLl ")) - .isSameAs(CosmosMeterCategory.ALL); - assertThat(CosmosMeterCategory.fromString("Default")) - .isSameAs(CosmosMeterCategory.DEFAULT); - assertThat(CosmosMeterCategory.fromString("minimum")) - .isSameAs(CosmosMeterCategory.MINIMUM); - assertThat(CosmosMeterCategory.fromString("operationsummary ")) - .isSameAs(CosmosMeterCategory.OPERATION_SUMMARY); - assertThat(CosmosMeterCategory.fromString("operationDetails")) - .isSameAs(CosmosMeterCategory.OPERATION_DETAILS); - assertThat(CosmosMeterCategory.fromString("RequestSummary")) - .isSameAs(CosmosMeterCategory.REQUEST_SUMMARY); - assertThat(CosmosMeterCategory.fromString("RequestDetails")) - .isSameAs(CosmosMeterCategory.REQUEST_DETAILS); - assertThat(CosmosMeterCategory.fromString("DirectChannels")) - .isSameAs(CosmosMeterCategory.DIRECT_CHANNELS); - assertThat(CosmosMeterCategory.fromString("DirectRequests")) - .isSameAs(CosmosMeterCategory.DIRECT_REQUESTS); - assertThat(CosmosMeterCategory.fromString("DirectEndpoints")) - .isSameAs(CosmosMeterCategory.DIRECT_ENDPOINTS); - assertThat(CosmosMeterCategory.fromString("DirectAddressResolutions")) - .isSameAs(CosmosMeterCategory.DIRECT_ADDRESS_RESOLUTIONS); - assertThat(CosmosMeterCategory.fromString("system")) - .isSameAs(CosmosMeterCategory.SYSTEM); - assertThat(CosmosMeterCategory.fromString("Legacy")) - .isSameAs(CosmosMeterCategory.LEGACY); + assertThat(CosmosMetricCategory.fromString("aLl ")) + .isSameAs(CosmosMetricCategory.ALL); + assertThat(CosmosMetricCategory.fromString("Default")) + .isSameAs(CosmosMetricCategory.DEFAULT); + assertThat(CosmosMetricCategory.fromString("minimum")) + .isSameAs(CosmosMetricCategory.MINIMUM); + assertThat(CosmosMetricCategory.fromString("operationsummary ")) + .isSameAs(CosmosMetricCategory.OPERATION_SUMMARY); + assertThat(CosmosMetricCategory.fromString("operationDetails")) + .isSameAs(CosmosMetricCategory.OPERATION_DETAILS); + assertThat(CosmosMetricCategory.fromString("RequestSummary")) + .isSameAs(CosmosMetricCategory.REQUEST_SUMMARY); + assertThat(CosmosMetricCategory.fromString("RequestDetails")) + .isSameAs(CosmosMetricCategory.REQUEST_DETAILS); + assertThat(CosmosMetricCategory.fromString("DirectChannels")) + .isSameAs(CosmosMetricCategory.DIRECT_CHANNELS); + assertThat(CosmosMetricCategory.fromString("DirectRequests")) + .isSameAs(CosmosMetricCategory.DIRECT_REQUESTS); + assertThat(CosmosMetricCategory.fromString("DirectEndpoints")) + .isSameAs(CosmosMetricCategory.DIRECT_ENDPOINTS); + assertThat(CosmosMetricCategory.fromString("DirectAddressResolutions")) + .isSameAs(CosmosMetricCategory.DIRECT_ADDRESS_RESOLUTIONS); + assertThat(CosmosMetricCategory.fromString("system")) + .isSameAs(CosmosMetricCategory.SYSTEM); + assertThat(CosmosMetricCategory.fromString("Legacy")) + .isSameAs(CosmosMetricCategory.LEGACY); } @Test(groups = {"simple"}, timeOut = TIMEOUT) public void meterNameFromStringConversion() { - assertThat(CosmosMeterName.fromString("cosmos.client.op.laTency")) - .isSameAs(CosmosMeterName.OPERATION_SUMMARY_LATENCY); - assertThat(CosmosMeterName.fromString("cosmos.client.op.cAlls")) - .isSameAs(CosmosMeterName.OPERATION_SUMMARY_CALLS); - assertThat(CosmosMeterName.fromString("cosmos.client.op.rus")) - .isSameAs(CosmosMeterName.OPERATION_SUMMARY_REQUEST_CHARGE); - assertThat(CosmosMeterName.fromString("cosmos.client.OP.actualItemCount")) - .isSameAs(CosmosMeterName.OPERATION_DETAILS_ACTUAL_ITEM_COUNT); - assertThat(CosmosMeterName.fromString("cosmos.client.op.MAXItemCount")) - .isSameAs(CosmosMeterName.OPERATION_DETAILS_MAX_ITEM_COUNT); - assertThat(CosmosMeterName.fromString("cosmos.client.op.REGIONScontacted")) - .isSameAs(CosmosMeterName.OPERATION_DETAILS_REGIONS_CONTACTED); - - assertThat(CosmosMeterName.fromString("cosmos.CLIENT.req.rntbd.backendLatency")) - .isSameAs(CosmosMeterName.REQUEST_SUMMARY_DIRECT_BACKEND_LATENCY); - assertThat(CosmosMeterName.fromString("cosmos.CLIENT.req.rntbd.LAtency")) - .isSameAs(CosmosMeterName.REQUEST_SUMMARY_DIRECT_LATENCY); - assertThat(CosmosMeterName.fromString("cosmos.CLIENT.req.rntbd.RUS")) - .isSameAs(CosmosMeterName.REQUEST_SUMMARY_DIRECT_REQUEST_CHARGE); - assertThat(CosmosMeterName.fromString("cosmos.CLIENT.req.rntbd.ReQUEsts")) - .isSameAs(CosmosMeterName.REQUEST_SUMMARY_DIRECT_REQUESTS); - assertThat(CosmosMeterName.fromString("cosmos.client.req.rntbd.TIMEline")) - .isSameAs(CosmosMeterName.REQUEST_DETAILS_DIRECT_TIMELINE); - - assertThat(CosmosMeterName.fromString("cosmos.CLIENT.req.gw.LAtency")) - .isSameAs(CosmosMeterName.REQUEST_SUMMARY_GATEWAY_LATENCY); - assertThat(CosmosMeterName.fromString("cosmos.CLIENT.req.gw.RUS")) - .isSameAs(CosmosMeterName.REQUEST_SUMMARY_GATEWAY_REQUEST_CHARGE); - assertThat(CosmosMeterName.fromString("cosmos.CLIENT.req.gw.ReQUEsts")) - .isSameAs(CosmosMeterName.REQUEST_SUMMARY_GATEWAY_REQUESTS); - assertThat(CosmosMeterName.fromString("cosmos.client.req.gw.tiMELine")) - .isSameAs(CosmosMeterName.REQUEST_DETAILS_GATEWAY_TIMELINE); - - assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.addressResolution.latency")) - .isSameAs(CosmosMeterName.DIRECT_ADDRESS_RESOLUTION_LATENCY); - assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.addressResolution.requests")) - .isSameAs(CosmosMeterName.DIRECT_ADDRESS_RESOLUTION_REQUESTS); - - assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.channels.acquired.COUNT")) - .isSameAs(CosmosMeterName.DIRECT_CHANNELS_ACQUIRED_COUNT); - assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.channels.available.COUNT")) - .isSameAs(CosmosMeterName.DIRECT_CHANNELS_AVAILABLE_COUNT); - assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.channels.closed.COUNT")) - .isSameAs(CosmosMeterName.DIRECT_CHANNELS_CLOSED_COUNT); - - assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.endpoints.COUNT")) - .isSameAs(CosmosMeterName.DIRECT_ENDPOINTS_COUNT); - assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.endpoints.evicted")) - .isSameAs(CosmosMeterName.DIRECT_ENDPOINTS_EVICTED); - - assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.requests.concurrent.count")) - .isSameAs(CosmosMeterName.DIRECT_REQUEST_CONCURRENT_COUNT); - assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.requests.LAtency")) - .isSameAs(CosmosMeterName.DIRECT_REQUEST_LATENCY); - assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.requests.FAIled.latency")) - .isSameAs(CosmosMeterName.DIRECT_REQUEST_LATENCY_FAILED); - assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.requests.successful.latency")) - .isSameAs(CosmosMeterName.DIRECT_REQUEST_LATENCY_SUCCESS); - assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.requests.queued.count")) - .isSameAs(CosmosMeterName.DIRECT_REQUEST_QUEUED_COUNT); - assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.req.RSPsize")) - .isSameAs(CosmosMeterName.DIRECT_REQUEST_SIZE_RESPONSE); - assertThat(CosmosMeterName.fromString("cosmos.client.RNTBD.req.reqsize")) - .isSameAs(CosmosMeterName.DIRECT_REQUEST_SIZE_REQUEST); + assertThat(CosmosMetricName.fromString("cosmos.client.op.laTency")) + .isSameAs(CosmosMetricName.OPERATION_SUMMARY_LATENCY); + assertThat(CosmosMetricName.fromString("cosmos.client.op.cAlls")) + .isSameAs(CosmosMetricName.OPERATION_SUMMARY_CALLS); + assertThat(CosmosMetricName.fromString("cosmos.client.op.rus")) + .isSameAs(CosmosMetricName.OPERATION_SUMMARY_REQUEST_CHARGE); + assertThat(CosmosMetricName.fromString("cosmos.client.OP.actualItemCount")) + .isSameAs(CosmosMetricName.OPERATION_DETAILS_ACTUAL_ITEM_COUNT); + assertThat(CosmosMetricName.fromString("cosmos.client.op.MAXItemCount")) + .isSameAs(CosmosMetricName.OPERATION_DETAILS_MAX_ITEM_COUNT); + assertThat(CosmosMetricName.fromString("cosmos.client.op.REGIONScontacted")) + .isSameAs(CosmosMetricName.OPERATION_DETAILS_REGIONS_CONTACTED); + + assertThat(CosmosMetricName.fromString("cosmos.CLIENT.req.rntbd.backendLatency")) + .isSameAs(CosmosMetricName.REQUEST_SUMMARY_DIRECT_BACKEND_LATENCY); + assertThat(CosmosMetricName.fromString("cosmos.CLIENT.req.rntbd.LAtency")) + .isSameAs(CosmosMetricName.REQUEST_SUMMARY_DIRECT_LATENCY); + assertThat(CosmosMetricName.fromString("cosmos.CLIENT.req.rntbd.RUS")) + .isSameAs(CosmosMetricName.REQUEST_SUMMARY_DIRECT_REQUEST_CHARGE); + assertThat(CosmosMetricName.fromString("cosmos.CLIENT.req.rntbd.ReQUEsts")) + .isSameAs(CosmosMetricName.REQUEST_SUMMARY_DIRECT_REQUESTS); + assertThat(CosmosMetricName.fromString("cosmos.client.req.rntbd.TIMEline")) + .isSameAs(CosmosMetricName.REQUEST_DETAILS_DIRECT_TIMELINE); + + assertThat(CosmosMetricName.fromString("cosmos.CLIENT.req.gw.LAtency")) + .isSameAs(CosmosMetricName.REQUEST_SUMMARY_GATEWAY_LATENCY); + assertThat(CosmosMetricName.fromString("cosmos.CLIENT.req.gw.RUS")) + .isSameAs(CosmosMetricName.REQUEST_SUMMARY_GATEWAY_REQUEST_CHARGE); + assertThat(CosmosMetricName.fromString("cosmos.CLIENT.req.gw.ReQUEsts")) + .isSameAs(CosmosMetricName.REQUEST_SUMMARY_GATEWAY_REQUESTS); + assertThat(CosmosMetricName.fromString("cosmos.client.req.gw.tiMELine")) + .isSameAs(CosmosMetricName.REQUEST_DETAILS_GATEWAY_TIMELINE); + + assertThat(CosmosMetricName.fromString("cosmos.client.RNTBD.addressResolution.latency")) + .isSameAs(CosmosMetricName.DIRECT_ADDRESS_RESOLUTION_LATENCY); + assertThat(CosmosMetricName.fromString("cosmos.client.RNTBD.addressResolution.requests")) + .isSameAs(CosmosMetricName.DIRECT_ADDRESS_RESOLUTION_REQUESTS); + + assertThat(CosmosMetricName.fromString("cosmos.client.RNTBD.channels.acquired.COUNT")) + .isSameAs(CosmosMetricName.DIRECT_CHANNELS_ACQUIRED_COUNT); + assertThat(CosmosMetricName.fromString("cosmos.client.RNTBD.channels.available.COUNT")) + .isSameAs(CosmosMetricName.DIRECT_CHANNELS_AVAILABLE_COUNT); + assertThat(CosmosMetricName.fromString("cosmos.client.RNTBD.channels.closed.COUNT")) + .isSameAs(CosmosMetricName.DIRECT_CHANNELS_CLOSED_COUNT); + + assertThat(CosmosMetricName.fromString("cosmos.client.RNTBD.endpoints.COUNT")) + .isSameAs(CosmosMetricName.DIRECT_ENDPOINTS_COUNT); + assertThat(CosmosMetricName.fromString("cosmos.client.RNTBD.endpoints.evicted")) + .isSameAs(CosmosMetricName.DIRECT_ENDPOINTS_EVICTED); + + assertThat(CosmosMetricName.fromString("cosmos.client.RNTBD.requests.concurrent.count")) + .isSameAs(CosmosMetricName.DIRECT_REQUEST_CONCURRENT_COUNT); + assertThat(CosmosMetricName.fromString("cosmos.client.RNTBD.requests.LAtency")) + .isSameAs(CosmosMetricName.DIRECT_REQUEST_LATENCY); + assertThat(CosmosMetricName.fromString("cosmos.client.RNTBD.requests.FAIled.latency")) + .isSameAs(CosmosMetricName.DIRECT_REQUEST_LATENCY_FAILED); + assertThat(CosmosMetricName.fromString("cosmos.client.RNTBD.requests.successful.latency")) + .isSameAs(CosmosMetricName.DIRECT_REQUEST_LATENCY_SUCCESS); + assertThat(CosmosMetricName.fromString("cosmos.client.RNTBD.requests.queued.count")) + .isSameAs(CosmosMetricName.DIRECT_REQUEST_QUEUED_COUNT); + assertThat(CosmosMetricName.fromString("cosmos.client.RNTBD.req.RSPsize")) + .isSameAs(CosmosMetricName.DIRECT_REQUEST_SIZE_RESPONSE); + assertThat(CosmosMetricName.fromString("cosmos.client.RNTBD.req.reqsize")) + .isSameAs(CosmosMetricName.DIRECT_REQUEST_SIZE_REQUEST); } private InternalObjectNode getDocumentDefinition(String documentId) { From 69be95430db90bd30afcd115cbbc8e27a16f3668 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Wed, 15 Feb 2023 23:14:59 +0000 Subject: [PATCH 28/40] Refactoring based on API review --- sdk/cosmos/azure-cosmos/pom.xml | 2 +- .../com/azure/cosmos/CosmosAsyncClient.java | 7 +- .../ImplementationBridgeHelpers.java | 44 +----- .../ClientTelemetryMetrics.java | 128 +++++++++--------- .../clienttelemetry/CosmosMeterOptions.java | 52 +++++++ .../RntbdTransportClient.java | 3 +- .../models/CosmosClientTelemetryConfig.java | 12 +- .../models/CosmosMicrometerMeterOptions.java | 72 +++------- .../CosmosMicrometerMetricsOptions.java | 67 ++++++++- .../cosmos/models/ModelBridgeInternal.java | 1 - .../com/azure/cosmos/ClientMetricsTest.java | 19 +-- 11 files changed, 223 insertions(+), 184 deletions(-) create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMeterOptions.java diff --git a/sdk/cosmos/azure-cosmos/pom.xml b/sdk/cosmos/azure-cosmos/pom.xml index cc5aca57d3efc..62b5edace6f5b 100644 --- a/sdk/cosmos/azure-cosmos/pom.xml +++ b/sdk/cosmos/azure-cosmos/pom.xml @@ -13,7 +13,7 @@ Licensed under the MIT License. com.azure azure-cosmos - 4.41.0-beta.1 + 4.41.0-beta.2 Microsoft Azure SDK for SQL API of Azure Cosmos DB Service This Package contains Microsoft Azure Cosmos SDK (with Reactive Extension Reactor support) for Azure Cosmos DB SQL API jar diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java index 2c4205cceaf1b..09e7176d95cdb 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java @@ -19,6 +19,7 @@ import com.azure.cosmos.implementation.TracerProvider; import com.azure.cosmos.implementation.clienttelemetry.ClientTelemetry; import com.azure.cosmos.implementation.clienttelemetry.ClientTelemetryMetrics; +import com.azure.cosmos.implementation.clienttelemetry.CosmosMeterOptions; import com.azure.cosmos.implementation.clienttelemetry.MetricCategory; import com.azure.cosmos.implementation.clienttelemetry.TagName; import com.azure.cosmos.implementation.directconnectivity.rntbd.RntbdMetrics; @@ -191,9 +192,9 @@ public final class CosmosAsyncClient implements Closeable { .getClientMetricRegistry(effectiveTelemetryConfig); this.clientMetricsEnabled = clientMetricRegistrySnapshot != null; - CosmosMicrometerMeterOptions cpuMeterOptions = telemetryConfigAccessor + CosmosMeterOptions cpuMeterOptions = telemetryConfigAccessor .getMeterOptions(effectiveTelemetryConfig, CosmosMetricName.SYSTEM_CPU); - CosmosMicrometerMeterOptions memoryMeterOptions = telemetryConfigAccessor + CosmosMeterOptions memoryMeterOptions = telemetryConfigAccessor .getMeterOptions(effectiveTelemetryConfig, CosmosMetricName.SYSTEM_MEMORY_FREE); @@ -763,7 +764,7 @@ public boolean isEndpointDiscoveryEnabled(CosmosAsyncClient client) { } @Override - public CosmosMicrometerMeterOptions getMeterOptions(CosmosAsyncClient client, CosmosMetricName name) { + public CosmosMeterOptions getMeterOptions(CosmosAsyncClient client, CosmosMetricName name) { return telemetryConfigAccessor .getMeterOptions(client.clientTelemetryConfig, name); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ImplementationBridgeHelpers.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ImplementationBridgeHelpers.java index bf68f8423e4ce..d268e33e77c53 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ImplementationBridgeHelpers.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ImplementationBridgeHelpers.java @@ -19,6 +19,7 @@ import com.azure.cosmos.ThroughputControlGroupConfig; import com.azure.cosmos.implementation.batch.ItemBatchOperation; import com.azure.cosmos.implementation.batch.PartitionScopeThresholds; +import com.azure.cosmos.implementation.clienttelemetry.CosmosMeterOptions; import com.azure.cosmos.implementation.clienttelemetry.MetricCategory; import com.azure.cosmos.implementation.clienttelemetry.TagName; import com.azure.cosmos.implementation.patch.PatchOperation; @@ -1048,44 +1049,7 @@ public interface CosmosAsyncClientAccessor { boolean isSendClientTelemetryToServiceEnabled(CosmosAsyncClient client); List getPreferredRegions(CosmosAsyncClient client); boolean isEndpointDiscoveryEnabled(CosmosAsyncClient client); - CosmosMicrometerMeterOptions getMeterOptions(CosmosAsyncClient client, CosmosMetricName name); - } - } - - public static final class CosmosMeterOptionsHelper { - private static final AtomicReference accessor = new AtomicReference<>(); - private static final AtomicBoolean cosmosMeterOptionsClassLoaded = new AtomicBoolean(false); - - private CosmosMeterOptionsHelper() {} - - public static void setCosmosMeterOptionsAccessor(final CosmosMeterOptionsAccessor newAccessor) { - if (!accessor.compareAndSet(null, newAccessor)) { - logger.debug("CosmosMeterOptionsAccessor already initialized!"); - } else { - logger.debug("Setting CosmosMeterOptionsAccessor..."); - cosmosMeterOptionsClassLoaded.set(true); - } - } - - public static CosmosMeterOptionsAccessor getCosmosMeterOptionsAccessor() { - if (!cosmosMeterOptionsClassLoaded.get()) { - logger.debug("Initializing CosmosMeterOptionsAccessor..."); - initializeAllAccessors(); - } - - CosmosMeterOptionsHelper.CosmosMeterOptionsAccessor snapshot = accessor.get(); - if (snapshot == null) { - logger.error("CosmosMeterOptionsAccessor is not initialized yet!"); - System.exit(9726); // Using a unique status code here to help debug the issue. - } - - return snapshot; - } - - public interface CosmosMeterOptionsAccessor { - EnumSet getSuppressedTagNames(CosmosMicrometerMeterOptions options); - boolean isHistogramPublishingEnabled(CosmosMicrometerMeterOptions options); - double[] getPercentiles(CosmosMicrometerMeterOptions options); + CosmosMeterOptions getMeterOptions(CosmosAsyncClient client, CosmosMetricName name); } } @@ -1173,8 +1137,8 @@ public interface CosmosClientTelemetryConfigAccessor { Boolean isSendClientTelemetryToServiceEnabled(CosmosClientTelemetryConfig config); boolean isClientMetricsEnabled(CosmosClientTelemetryConfig config); void resetIsSendClientTelemetryToServiceEnabled(CosmosClientTelemetryConfig config); - CosmosMicrometerMeterOptions getMeterOptions(CosmosClientTelemetryConfig config, CosmosMetricName name); - CosmosMicrometerMeterOptions createDisabledMeterOptions(CosmosMetricName name); + CosmosMeterOptions getMeterOptions(CosmosClientTelemetryConfig config, CosmosMetricName name); + CosmosMeterOptions createDisabledMeterOptions(CosmosMetricName name); CosmosClientTelemetryConfig createSnapshot( CosmosClientTelemetryConfig config, boolean effectiveIsClientTelemetryEnabled); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java index 834b2fd557783..868ec95b704d1 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetryMetrics.java @@ -54,8 +54,6 @@ public final class ClientTelemetryMetrics { private static final Logger logger = LoggerFactory.getLogger(ClientTelemetryMetrics.class); private static final ImplementationBridgeHelpers.CosmosAsyncClientHelper.CosmosAsyncClientAccessor clientAccessor = ImplementationBridgeHelpers.CosmosAsyncClientHelper.getCosmosAsyncClientAccessor(); - private static final ImplementationBridgeHelpers.CosmosMeterOptionsHelper.CosmosMeterOptionsAccessor optionsAccessor = - ImplementationBridgeHelpers.CosmosMeterOptionsHelper.getCosmosMeterOptionsAccessor(); private static final ImplementationBridgeHelpers.CosmosDiagnosticsHelper.CosmosDiagnosticsAccessor diagnosticsAccessor = ImplementationBridgeHelpers.CosmosDiagnosticsHelper.getCosmosDiagnosticsAccessor(); @@ -63,8 +61,8 @@ public final class ClientTelemetryMetrics { private static CompositeMeterRegistry compositeRegistry = createFreshRegistry(); private static final ConcurrentHashMap registryRefCount = new ConcurrentHashMap<>(); - private static CosmosMicrometerMeterOptions cpuOptions; - private static CosmosMicrometerMeterOptions memoryOptions; + private static CosmosMeterOptions cpuOptions; + private static CosmosMeterOptions memoryOptions; private static String convertStackTraceToString(Throwable throwable) { @@ -110,8 +108,8 @@ public static void recordSystemUsage( .baseUnit("%") .description("Avg. System CPU load") .maximumExpectedValue(100d) - .publishPercentiles(optionsAccessor.getPercentiles(cpuOptions)) - .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(cpuOptions)) + .publishPercentiles(cpuOptions.getPercentiles()) + .publishPercentileHistogram(cpuOptions.isHistogramPublishingEnabled()) .register(compositeRegistry); averageSystemCpuUsageMeter.record(averageSystemCpuUsage); } @@ -193,8 +191,8 @@ public static RntbdMetricsCompletionRecorder createRntbdMetrics( public static synchronized void add( MeterRegistry registry, - CosmosMicrometerMeterOptions cpuOptions, - CosmosMicrometerMeterOptions memoryOptions) { + CosmosMeterOptions cpuOptions, + CosmosMeterOptions memoryOptions) { if (registryRefCount .computeIfAbsent(registry, (meterRegistry) -> { return new AtomicLong(0); }) .incrementAndGet() == 1L) { @@ -296,8 +294,8 @@ private static Tags createOperationTags( return Tags.of(effectiveTags); } - private static Tags getEffectiveTags(Tags tags, CosmosMicrometerMeterOptions meterOptions) { - EnumSet suppressedTags = optionsAccessor.getSuppressedTagNames(meterOptions); + private static Tags getEffectiveTags(Tags tags, CosmosMeterOptions meterOptions) { + EnumSet suppressedTags = meterOptions.getSuppressedTagNames(); if (suppressedTags == null || suppressedTags.isEmpty()) { return tags; } @@ -337,7 +335,7 @@ public void recordOperation( CosmosDiagnostics diagnostics, Set contactedRegions) { - CosmosMicrometerMeterOptions callsOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions callsOptions = clientAccessor.getMeterOptions( cosmosAsyncClient, CosmosMetricName.OPERATION_SUMMARY_CALLS); @@ -351,7 +349,7 @@ public void recordOperation( operationsCounter.increment(); } - CosmosMicrometerMeterOptions requestChargeOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions requestChargeOptions = clientAccessor.getMeterOptions( cosmosAsyncClient, CosmosMetricName.OPERATION_SUMMARY_REQUEST_CHARGE); if (requestChargeOptions.isEnabled()) { @@ -360,15 +358,15 @@ public void recordOperation( .baseUnit("RU (request unit)") .description("Operation RU charge") .maximumExpectedValue(100_000d) - .publishPercentiles(optionsAccessor.getPercentiles(requestChargeOptions)) - .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(requestChargeOptions)) + .publishPercentiles(requestChargeOptions.getPercentiles()) + .publishPercentileHistogram(requestChargeOptions.isHistogramPublishingEnabled()) .tags(getEffectiveTags(operationTags, requestChargeOptions)) .register(compositeRegistry); requestChargeMeter.record(Math.min(requestCharge, 100_000d)); } if (this.metricCategories.contains(MetricCategory.OperationDetails)) { - CosmosMicrometerMeterOptions regionsOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions regionsOptions = clientAccessor.getMeterOptions( cosmosAsyncClient, CosmosMetricName.OPERATION_DETAILS_REGIONS_CONTACTED); if (regionsOptions.isEnabled()) { @@ -389,7 +387,7 @@ public void recordOperation( this.recordItemCounts(cosmosAsyncClient, maxItemCount, actualItemCount); } - CosmosMicrometerMeterOptions latencyOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions latencyOptions = clientAccessor.getMeterOptions( cosmosAsyncClient, CosmosMetricName.OPERATION_SUMMARY_LATENCY); if (latencyOptions.isEnabled()) { @@ -397,8 +395,8 @@ public void recordOperation( .builder(latencyOptions.getMeterName().toString()) .description("Operation latency") .maximumExpectedValue(Duration.ofSeconds(300)) - .publishPercentiles(optionsAccessor.getPercentiles(latencyOptions)) - .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(latencyOptions)) + .publishPercentiles(latencyOptions.getPercentiles()) + .publishPercentileHistogram(latencyOptions.isHistogramPublishingEnabled()) .tags(getEffectiveTags(operationTags, latencyOptions)) .register(compositeRegistry); latencyMeter.record(latency); @@ -450,7 +448,7 @@ private void recordQueryPlanDiagnostics( createQueryPlanTags(metricTagNames) ); - CosmosMicrometerMeterOptions requestsOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions requestsOptions = clientAccessor.getMeterOptions( cosmosAsyncClient, CosmosMetricName.REQUEST_SUMMARY_GATEWAY_REQUESTS); if (requestsOptions.isEnabled()) { @@ -466,7 +464,7 @@ private void recordQueryPlanDiagnostics( Duration latency = queryPlanDiagnostics.getDuration(); if (latency != null) { - CosmosMicrometerMeterOptions latencyOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions latencyOptions = clientAccessor.getMeterOptions( cosmosAsyncClient, CosmosMetricName.REQUEST_SUMMARY_GATEWAY_LATENCY); if (latencyOptions.isEnabled()) { @@ -474,8 +472,8 @@ private void recordQueryPlanDiagnostics( .builder(latencyOptions.getMeterName().toString()) .description("Gateway Request latency") .maximumExpectedValue(Duration.ofSeconds(300)) - .publishPercentiles(optionsAccessor.getPercentiles(latencyOptions)) - .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(latencyOptions)) + .publishPercentiles(latencyOptions.getPercentiles()) + .publishPercentileHistogram(latencyOptions.isHistogramPublishingEnabled()) .tags(getEffectiveTags(requestTags, latencyOptions)) .register(compositeRegistry); requestLatencyMeter.record(latency); @@ -493,7 +491,7 @@ private void recordRequestPayloadSizes( int requestPayloadSizeInBytes, int responsePayloadSizeInBytes ) { - CosmosMicrometerMeterOptions reqSizeOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions reqSizeOptions = clientAccessor.getMeterOptions( client, CosmosMetricName.REQUEST_SUMMARY_SIZE_REQUEST); if (reqSizeOptions.isEnabled()) { @@ -509,7 +507,7 @@ private void recordRequestPayloadSizes( requestPayloadSizeMeter.record(requestPayloadSizeInBytes); } - CosmosMicrometerMeterOptions rspSizeOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions rspSizeOptions = clientAccessor.getMeterOptions( client, CosmosMetricName.REQUEST_SUMMARY_SIZE_RESPONSE); if (rspSizeOptions.isEnabled()) { @@ -533,7 +531,7 @@ private void recordItemCounts( ) { if (maxItemCount > 0 && this.metricCategories.contains(MetricCategory.OperationDetails)) { - CosmosMicrometerMeterOptions maxItemCountOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions maxItemCountOptions = clientAccessor.getMeterOptions( client, CosmosMetricName.OPERATION_DETAILS_MAX_ITEM_COUNT); if (maxItemCountOptions.isEnabled()) { @@ -549,7 +547,7 @@ private void recordItemCounts( maxItemCountMeter.record(Math.max(0, Math.min(maxItemCount, 100_000d))); } - CosmosMicrometerMeterOptions actualItemCountOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions actualItemCountOptions = clientAccessor.getMeterOptions( client, CosmosMetricName.OPERATION_DETAILS_ACTUAL_ITEM_COUNT); if (actualItemCountOptions.isEnabled()) { @@ -671,7 +669,7 @@ private void recordRntbdEndpointStatistics( return; } - CosmosMicrometerMeterOptions acquiredOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions acquiredOptions = clientAccessor.getMeterOptions( client, CosmosMetricName.LEGACY_DIRECT_ENDPOINT_STATISTICS_ACQUIRED); if (acquiredOptions.isEnabled()) { @@ -688,7 +686,7 @@ private void recordRntbdEndpointStatistics( acquiredChannelsMeter.record(endpointStatistics.getAcquiredChannels()); } - CosmosMicrometerMeterOptions availableOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions availableOptions = clientAccessor.getMeterOptions( client, CosmosMetricName.LEGACY_DIRECT_ENDPOINT_STATISTICS_AVAILABLE); if (availableOptions.isEnabled()) { @@ -704,7 +702,7 @@ private void recordRntbdEndpointStatistics( availableChannelsMeter.record(endpointStatistics.getAvailableChannels()); } - CosmosMicrometerMeterOptions inflightOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions inflightOptions = clientAccessor.getMeterOptions( client, CosmosMetricName.LEGACY_DIRECT_ENDPOINT_STATISTICS_INFLIGHT); if (inflightOptions.isEnabled()) { @@ -714,8 +712,8 @@ private void recordRntbdEndpointStatistics( .description("Endpoint statistics(inflight requests)") .tags(getEffectiveTags(requestTags, inflightOptions)) .maximumExpectedValue(1_000_000d) - .publishPercentiles(optionsAccessor.getPercentiles(inflightOptions)) - .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(inflightOptions)) + .publishPercentiles(inflightOptions.getPercentiles()) + .publishPercentileHistogram(inflightOptions.isHistogramPublishingEnabled()) .register(compositeRegistry); inflightRequestsMeter.record(endpointStatistics.getInflightRequests()); } @@ -731,7 +729,7 @@ private void recordRequestTimeline( return; } - CosmosMicrometerMeterOptions timelineOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions timelineOptions = clientAccessor.getMeterOptions( client, name); if (!timelineOptions.isEnabled()) { @@ -747,8 +745,8 @@ private void recordRequestTimeline( .builder(timelineOptions.getMeterName().toString() + "." + escape(event.getName())) .description(String.format("Request timeline (%s)", event.getName())) .maximumExpectedValue(Duration.ofSeconds(300)) - .publishPercentiles(optionsAccessor.getPercentiles(timelineOptions)) - .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(timelineOptions)) + .publishPercentiles(timelineOptions.getPercentiles()) + .publishPercentileHistogram(timelineOptions.isHistogramPublishingEnabled()) .tags(getEffectiveTags(requestTags, timelineOptions)) .register(compositeRegistry); eventMeter.record(duration); @@ -785,7 +783,7 @@ private void recordStoreResponseStatistics( if (backendLatency != null) { - CosmosMicrometerMeterOptions beLatencyOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions beLatencyOptions = clientAccessor.getMeterOptions( client, CosmosMetricName.REQUEST_SUMMARY_DIRECT_BACKEND_LATENCY); if (beLatencyOptions.isEnabled()) { @@ -794,15 +792,15 @@ private void recordStoreResponseStatistics( .baseUnit("ms") .description("Backend service latency") .maximumExpectedValue(6_000d) - .publishPercentiles(optionsAccessor.getPercentiles(beLatencyOptions)) - .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(beLatencyOptions)) + .publishPercentiles(beLatencyOptions.getPercentiles()) + .publishPercentileHistogram(beLatencyOptions.isHistogramPublishingEnabled()) .tags(getEffectiveTags(requestTags, beLatencyOptions)) .register(compositeRegistry); backendRequestLatencyMeter.record(storeResultDiagnostics.getBackendLatencyInMs()); } } - CosmosMicrometerMeterOptions ruOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions ruOptions = clientAccessor.getMeterOptions( client, CosmosMetricName.REQUEST_SUMMARY_DIRECT_REQUEST_CHARGE); if (ruOptions.isEnabled()) { @@ -812,14 +810,14 @@ private void recordStoreResponseStatistics( .baseUnit("RU (request unit)") .description("RNTBD Request RU charge") .maximumExpectedValue(100_000d) - .publishPercentiles(optionsAccessor.getPercentiles(ruOptions)) - .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(ruOptions)) + .publishPercentiles(ruOptions.getPercentiles()) + .publishPercentileHistogram(ruOptions.isHistogramPublishingEnabled()) .tags(getEffectiveTags(requestTags, ruOptions)) .register(compositeRegistry); requestChargeMeter.record(Math.min(requestCharge, 100_000d)); } - CosmosMicrometerMeterOptions latencyOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions latencyOptions = clientAccessor.getMeterOptions( client, CosmosMetricName.REQUEST_SUMMARY_DIRECT_LATENCY); if (latencyOptions.isEnabled()) { @@ -829,15 +827,15 @@ private void recordStoreResponseStatistics( .builder(latencyOptions.getMeterName().toString()) .description("RNTBD Request latency") .maximumExpectedValue(Duration.ofSeconds(6)) - .publishPercentiles(optionsAccessor.getPercentiles(latencyOptions)) - .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(latencyOptions)) + .publishPercentiles(latencyOptions.getPercentiles()) + .publishPercentileHistogram(latencyOptions.isHistogramPublishingEnabled()) .tags(getEffectiveTags(requestTags, latencyOptions)) .register(compositeRegistry); requestLatencyMeter.record(latency); } } - CosmosMicrometerMeterOptions reqOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions reqOptions = clientAccessor.getMeterOptions( client, CosmosMetricName.REQUEST_SUMMARY_DIRECT_REQUESTS); if (reqOptions.isEnabled()) { @@ -897,7 +895,7 @@ private void recordGatewayStatistics( null) ); - CosmosMicrometerMeterOptions reqOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions reqOptions = clientAccessor.getMeterOptions( client, CosmosMetricName.REQUEST_SUMMARY_GATEWAY_REQUESTS); if (reqOptions.isEnabled()) { @@ -910,7 +908,7 @@ private void recordGatewayStatistics( requestCounter.increment(); } - CosmosMicrometerMeterOptions ruOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions ruOptions = clientAccessor.getMeterOptions( client, CosmosMetricName.REQUEST_SUMMARY_GATEWAY_REQUEST_CHARGE); if (ruOptions.isEnabled()) { @@ -920,15 +918,15 @@ private void recordGatewayStatistics( .baseUnit("RU (request unit)") .description("Gateway Request RU charge") .maximumExpectedValue(100_000d) - .publishPercentiles(optionsAccessor.getPercentiles(ruOptions)) - .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(ruOptions)) + .publishPercentiles(ruOptions.getPercentiles()) + .publishPercentileHistogram(ruOptions.isHistogramPublishingEnabled()) .tags(getEffectiveTags(requestTags, ruOptions)) .register(compositeRegistry); requestChargeMeter.record(Math.min(requestCharge, 100_000d)); } if (latency != null) { - CosmosMicrometerMeterOptions latencyOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions latencyOptions = clientAccessor.getMeterOptions( client, CosmosMetricName.REQUEST_SUMMARY_GATEWAY_LATENCY); if (latencyOptions.isEnabled()) { @@ -936,8 +934,8 @@ private void recordGatewayStatistics( .builder(latencyOptions.getMeterName().toString()) .description("Gateway Request latency") .maximumExpectedValue(Duration.ofSeconds(300)) - .publishPercentiles(optionsAccessor.getPercentiles(latencyOptions)) - .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(latencyOptions)) + .publishPercentiles(latencyOptions.getPercentiles()) + .publishPercentileHistogram(latencyOptions.isHistogramPublishingEnabled()) .tags(getEffectiveTags(requestTags, latencyOptions)) .register(compositeRegistry); requestLatencyMeter.record(latency); @@ -986,7 +984,7 @@ private void recordAddressResolutionStatistics( addressResolutionStatistics.getStartTimeUTC(), addressResolutionStatistics.getEndTimeUTC()); - CosmosMicrometerMeterOptions latencyOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions latencyOptions = clientAccessor.getMeterOptions( client, CosmosMetricName.DIRECT_ADDRESS_RESOLUTION_LATENCY); if (latencyOptions.isEnabled()) { @@ -994,14 +992,14 @@ private void recordAddressResolutionStatistics( .builder(latencyOptions.getMeterName().toString()) .description("Address resolution latency") .maximumExpectedValue(Duration.ofSeconds(6)) - .publishPercentiles(optionsAccessor.getPercentiles(latencyOptions)) - .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(latencyOptions)) + .publishPercentiles(latencyOptions.getPercentiles()) + .publishPercentileHistogram(latencyOptions.isHistogramPublishingEnabled()) .tags(getEffectiveTags(addressResolutionTags, latencyOptions)) .register(compositeRegistry); addressResolutionLatencyMeter.record(latency); } - CosmosMicrometerMeterOptions reqOptions = clientAccessor.getMeterOptions( + CosmosMeterOptions reqOptions = clientAccessor.getMeterOptions( client, CosmosMetricName.DIRECT_ADDRESS_RESOLUTION_REQUESTS); if (reqOptions.isEnabled()) { @@ -1028,7 +1026,7 @@ private RntbdMetricsV2(MeterRegistry registry, RntbdTransportClient client, Rntb this.registry = registry; if (this.client.getMetricCategories().contains(MetricCategory.DirectRequests)) { - CosmosMicrometerMeterOptions options = client + CosmosMeterOptions options = client .getMeterOptions(CosmosMetricName.DIRECT_REQUEST_CONCURRENT_COUNT); if (options.isEnabled()) { Gauge.builder(options.getMeterName().toString(), endpoint, RntbdEndpoint::concurrentRequests) @@ -1048,7 +1046,7 @@ private RntbdMetricsV2(MeterRegistry registry, RntbdTransportClient client, Rntb } if (this.client.getMetricCategories().contains(MetricCategory.DirectEndpoints)) { - CosmosMicrometerMeterOptions options = client + CosmosMeterOptions options = client .getMeterOptions(CosmosMetricName.DIRECT_ENDPOINTS_COUNT); if (options.isEnabled()) { Gauge.builder(options.getMeterName().toString(), client, RntbdTransportClient::endpointCount) @@ -1069,7 +1067,7 @@ private RntbdMetricsV2(MeterRegistry registry, RntbdTransportClient client, Rntb } if (this.client.getMetricCategories().contains(MetricCategory.DirectChannels)) { - CosmosMicrometerMeterOptions options = client + CosmosMeterOptions options = client .getMeterOptions(CosmosMetricName.DIRECT_CHANNELS_ACQUIRED_COUNT); if (options.isEnabled()) { FunctionCounter.builder( @@ -1111,7 +1109,7 @@ public void markComplete(RntbdRequestRecord requestRecord) { Timer requestsSuccess = null; Timer requestsFailed = null; - CosmosMicrometerMeterOptions options = this.client + CosmosMeterOptions options = this.client .getMeterOptions(CosmosMetricName.DIRECT_REQUEST_LATENCY); if (options.isEnabled()) { @@ -1119,8 +1117,8 @@ public void markComplete(RntbdRequestRecord requestRecord) { .builder(options.getMeterName().toString()) .description("RNTBD request latency") .maximumExpectedValue(Duration.ofSeconds(300)) - .publishPercentiles(optionsAccessor.getPercentiles(options)) - .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(options)) + .publishPercentiles(options.getPercentiles()) + .publishPercentileHistogram(options.isHistogramPublishingEnabled()) .tags(getEffectiveTags(this.tags, options)) .register(this.registry); } @@ -1132,8 +1130,8 @@ public void markComplete(RntbdRequestRecord requestRecord) { .builder(options.getMeterName().toString()) .description("RNTBD failed request latency") .maximumExpectedValue(Duration.ofSeconds(300)) - .publishPercentiles(optionsAccessor.getPercentiles(options)) - .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(options)) + .publishPercentiles(options.getPercentiles()) + .publishPercentileHistogram(options.isHistogramPublishingEnabled()) .tags(getEffectiveTags(tags, options)) .register(registry); } @@ -1145,8 +1143,8 @@ public void markComplete(RntbdRequestRecord requestRecord) { .builder(options.getMeterName().toString()) .description("RNTBD successful request latency") .maximumExpectedValue(Duration.ofSeconds(300)) - .publishPercentiles(optionsAccessor.getPercentiles(options)) - .publishPercentileHistogram(optionsAccessor.isHistogramPublishingEnabled(options)) + .publishPercentiles(options.getPercentiles()) + .publishPercentileHistogram(options.isHistogramPublishingEnabled()) .tags(getEffectiveTags(tags, options)) .register(registry); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMeterOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMeterOptions.java new file mode 100644 index 0000000000000..f1ff5c56dda27 --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMeterOptions.java @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.implementation.clienttelemetry; + +import com.azure.cosmos.models.CosmosMetricName; +import com.azure.cosmos.models.CosmosMicrometerMeterOptions; + +import java.util.EnumSet; + +public final class CosmosMeterOptions { + + private final CosmosMetricName name; + private final boolean isEnabled; + private final double[] percentiles; + private final boolean isHistogramPublishingEnabled; + private final EnumSet suppressedTagNames; + + public CosmosMeterOptions( + CosmosMetricName name, + boolean isEnabled, + double[] percentiles, + boolean isHistogramPublishingEnabled, + EnumSet suppressedTagNames) { + + this.name = name; + this.isEnabled = isEnabled; + this.percentiles = percentiles; + this.isHistogramPublishingEnabled = isHistogramPublishingEnabled; + this.suppressedTagNames = suppressedTagNames; + } + + public CosmosMetricName getMeterName() { + return this.name; + } + + public EnumSet getSuppressedTagNames() { + return this.suppressedTagNames; + } + + public boolean isHistogramPublishingEnabled() { + return this.isHistogramPublishingEnabled; + } + + public double[] getPercentiles() { + return this.percentiles; + } + + public boolean isEnabled() { + return this.isEnabled; + } +} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/RntbdTransportClient.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/RntbdTransportClient.java index e8acb194e9063..df3ce14222d4c 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/RntbdTransportClient.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/RntbdTransportClient.java @@ -15,6 +15,7 @@ import com.azure.cosmos.implementation.RxDocumentServiceRequest; import com.azure.cosmos.implementation.UserAgentContainer; import com.azure.cosmos.implementation.clienttelemetry.ClientTelemetry; +import com.azure.cosmos.implementation.clienttelemetry.CosmosMeterOptions; import com.azure.cosmos.implementation.clienttelemetry.MetricCategory; import com.azure.cosmos.implementation.directconnectivity.rntbd.*; import com.azure.cosmos.implementation.guava25.base.Strings; @@ -378,7 +379,7 @@ public EnumSet getMetricCategories() { .getMetricCategories(this.metricConfig) : MetricCategory.DEFAULT_CATEGORIES; } - public CosmosMicrometerMeterOptions getMeterOptions(CosmosMetricName name) { + public CosmosMeterOptions getMeterOptions(CosmosMetricName name) { return this.metricConfig != null ? ImplementationBridgeHelpers .CosmosClientTelemetryConfigHelper diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java index c58c2a218c61d..0f876a0806906 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosClientTelemetryConfig.java @@ -10,6 +10,7 @@ import com.azure.cosmos.implementation.Strings; import com.azure.cosmos.implementation.Utils; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; +import com.azure.cosmos.implementation.clienttelemetry.CosmosMeterOptions; import com.azure.cosmos.implementation.clienttelemetry.MetricCategory; import com.azure.cosmos.implementation.clienttelemetry.TagName; import com.fasterxml.jackson.annotation.JsonProperty; @@ -331,7 +332,7 @@ public EnumSet getMetricTagNames(CosmosClientTelemetryConfig config) { } @Override - public CosmosMicrometerMeterOptions getMeterOptions( + public CosmosMeterOptions getMeterOptions( CosmosClientTelemetryConfig config, CosmosMetricName name) { if (config != null && @@ -344,8 +345,13 @@ public CosmosMicrometerMeterOptions getMeterOptions( } @Override - public CosmosMicrometerMeterOptions createDisabledMeterOptions(CosmosMetricName name) { - return new CosmosMicrometerMeterOptions(name, false, null).setEnabled(false); + public CosmosMeterOptions createDisabledMeterOptions(CosmosMetricName name) { + return new CosmosMeterOptions( + name, + false, + new double[0], + false, + EnumSet.noneOf(TagName.class)); } @Override diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMicrometerMeterOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMicrometerMeterOptions.java index 03bacadd9660a..37aed0dd2b1bf 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMicrometerMeterOptions.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMicrometerMeterOptions.java @@ -3,48 +3,29 @@ package com.azure.cosmos.models; -import com.azure.cosmos.implementation.ImplementationBridgeHelpers; import com.azure.cosmos.implementation.clienttelemetry.TagName; import java.util.EnumSet; -import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; - /** * Options of a Cosmos client-side meter that can be used to enable/disable it, change the percentile and histogram * capturing (if percentiles are applicable for the meter) and allows suppressing tags that are not desired. */ public final class CosmosMicrometerMeterOptions { - private final CosmosMetricName meterName; - private boolean isHistogramPublishingEnabled; + private Boolean isHistogramPublishingEnabled; private double[] percentiles; private EnumSet suppressedTagNames; - private boolean isEnabled; + private Boolean isEnabled; /** * Instantiates new options for a specific Cosmos DB meter */ - CosmosMicrometerMeterOptions( - CosmosMetricName meterName, - boolean isHistogramPublishingEnabled, - double[] percentiles) { - - checkNotNull(meterName, "Argument 'meterName' must not be null."); - - this.meterName = meterName; - this.isHistogramPublishingEnabled = isHistogramPublishingEnabled; - this.percentiles = percentiles; - this.suppressedTagNames = EnumSet.noneOf(TagName.class); - this.isEnabled = true; - } - - /** - * Gets the name of the meter these options are applicable for - * @return the meter name for these options - */ - public CosmosMetricName getMeterName() { - return this.meterName; + public CosmosMicrometerMeterOptions() { + this.isHistogramPublishingEnabled = null; + this.percentiles = null; + this.suppressedTagNames = null; + this.isEnabled = null; } /** @@ -90,7 +71,7 @@ public CosmosMicrometerMeterOptions histogramPublishingEnabled(boolean isEnabled */ public CosmosMicrometerMeterOptions percentiles(double... percentiles) { if (percentiles == null || percentiles.length == 0) { - this.percentiles = null; + this.percentiles = new double[0]; } else { this.percentiles = percentiles.clone(); } @@ -98,7 +79,6 @@ public CosmosMicrometerMeterOptions percentiles(double... percentiles) { return this; } - /** * Enables or disables this meter. By default, meters are enabled. * @@ -110,35 +90,19 @@ public CosmosMicrometerMeterOptions setEnabled(boolean enabled) { return this; } - /** - * Flag indicating if this meter is currently enabled. - * @return {@code true} if meter is currently enabled, {@code false} otherwise. - */ - public boolean isEnabled() { - return this.isEnabled; + EnumSet getSuppressedTagNames() { + return this.suppressedTagNames; } - /////////////////////////////////////////////////////////////////////////////////////////// - // the following helper/accessor only helps to access this class outside of this package.// - /////////////////////////////////////////////////////////////////////////////////////////// - static void initialize() { - ImplementationBridgeHelpers.CosmosMeterOptionsHelper.setCosmosMeterOptionsAccessor( - new ImplementationBridgeHelpers.CosmosMeterOptionsHelper.CosmosMeterOptionsAccessor() { - @Override - public EnumSet getSuppressedTagNames(CosmosMicrometerMeterOptions options) { - return options.suppressedTagNames; - } + Boolean getIsHistogramPublishingEnabled() { + return this.isHistogramPublishingEnabled; + } - @Override - public boolean isHistogramPublishingEnabled(CosmosMicrometerMeterOptions options) { - return options.isHistogramPublishingEnabled; - } + Boolean getIsEnabled() { + return this.isEnabled; + } - @Override - public double[] getPercentiles(CosmosMicrometerMeterOptions options) { - return options.percentiles; - } - } - ); + double[] getPercentiles() { + return this.percentiles; } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMicrometerMetricsOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMicrometerMetricsOptions.java index 4b83348fc24cc..8b435fac469b6 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMicrometerMetricsOptions.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMicrometerMetricsOptions.java @@ -3,6 +3,7 @@ package com.azure.cosmos.models; import com.azure.core.util.MetricsOptions; +import com.azure.cosmos.implementation.clienttelemetry.CosmosMeterOptions; import com.azure.cosmos.implementation.clienttelemetry.MetricCategory; import com.azure.cosmos.implementation.clienttelemetry.TagName; import io.micrometer.core.instrument.MeterRegistry; @@ -22,7 +23,7 @@ public final class CosmosMicrometerMetricsOptions extends MetricsOptions { private EnumSet defaultTagNames = TagName.DEFAULT_TAGS.clone(); private double[] defaultPercentiles = { 0.95, 0.99 }; private boolean defaultShouldPublishHistograms = true; - private final ConcurrentHashMap effectiveOptions = new ConcurrentHashMap<>(); + private final ConcurrentHashMap effectiveOptions = new ConcurrentHashMap<>(); /** * Instantiates new Micrometer-specific Azure Cosmos DB SDK metrics options @@ -142,7 +143,7 @@ public CosmosMicrometerMetricsOptions setEnabled(boolean enabled) { * instance will be reflected at runtime by the client. * * @param categories - a comma-separated list of metric categories that should be emitted - * @return current CosmosClientTelemetryConfig + * @return current CosmosMicrometerMetricsOptions instance */ public CosmosMicrometerMetricsOptions setMetricCategories(CosmosMetricCategory... categories) { if (categories == null || categories.length == 0) { @@ -172,7 +173,7 @@ public CosmosMicrometerMetricsOptions setMetricCategories(CosmosMetricCategory.. * instance will be reflected at runtime by the client. * * @param categories - a comma-separated list of metric categories that should be emitted - * @return current CosmosClientTelemetryConfig + * @return current CosmosMicrometerMetricsOptions instance */ public CosmosMicrometerMetricsOptions addMetricCategories(CosmosMetricCategory... categories) { if (categories == null || categories.length == 0) { @@ -201,7 +202,7 @@ public CosmosMicrometerMetricsOptions addMetricCategories(CosmosMetricCategory.. * instance will be reflected at runtime by the client. * * @param categories - a comma-separated list of metric categories that should be emitted - * @return current CosmosClientTelemetryConfig + * @return current CosmosMicrometerMetricsOptions instance */ public CosmosMicrometerMetricsOptions removeMetricCategories(CosmosMetricCategory... categories) { if (categories == null || categories.length == 0) { @@ -224,21 +225,73 @@ public CosmosMicrometerMetricsOptions removeMetricCategories(CosmosMetricCategor return this; } + + /** + * Allows overriding meter-specific options. + * @param meterName the meter name + * @param options the options to be overridden + * @return current CosmosMicrometerMetricsOptions instance + */ + public CosmosMicrometerMetricsOptions configureMeter( + CosmosMetricName meterName, + CosmosMicrometerMeterOptions options) { + + this + .effectiveOptions + .compute( + meterName, + (name, valueBeforeUpdate) -> { + if (valueBeforeUpdate == null) { + return new CosmosMeterOptions( + name, + options.getIsEnabled() != null ? options.getIsEnabled().booleanValue() : true, + options.getPercentiles() != null ? options.getPercentiles() : this.defaultPercentiles, + options.getIsHistogramPublishingEnabled() != null ? + options.getIsHistogramPublishingEnabled().booleanValue() : + this.defaultShouldPublishHistograms, + options.getSuppressedTagNames() != null ? + options.getSuppressedTagNames() : + EnumSet.noneOf(TagName.class) + ); + } + + return new CosmosMeterOptions( + name, + options.getIsEnabled() != null ? + options.getIsEnabled().booleanValue() : + valueBeforeUpdate.isEnabled(), + options.getPercentiles() != null ? + options.getPercentiles() : + valueBeforeUpdate.getPercentiles(), + options.getIsHistogramPublishingEnabled() != null ? + options.getIsHistogramPublishingEnabled().booleanValue() : + valueBeforeUpdate.isHistogramPublishingEnabled(), + options.getSuppressedTagNames() != null ? + options.getSuppressedTagNames() : + valueBeforeUpdate.getSuppressedTagNames() + ); + }); + + return this; + } + /** * Gets the meter options for a certain meter. The returned meter options can be used to modify the settings for * this meter. Changes can be applied even after building the Cosmos Client instance at runtime. * @param meterName - the meter name * @return the current meter options */ - public CosmosMicrometerMeterOptions getMeterOptions(CosmosMetricName meterName) { + CosmosMeterOptions getMeterOptions(CosmosMetricName meterName) { checkNotNull(meterName, "Argument 'meterName' must not be null."); return this .effectiveOptions - .computeIfAbsent(meterName, name -> new CosmosMicrometerMeterOptions( + .computeIfAbsent(meterName, name -> new CosmosMeterOptions( name, + true, + this.defaultPercentiles, this.defaultShouldPublishHistograms, - this.defaultPercentiles + EnumSet.noneOf(TagName.class) )); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ModelBridgeInternal.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ModelBridgeInternal.java index 10aec4c1decab..07001414a92a7 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ModelBridgeInternal.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ModelBridgeInternal.java @@ -964,6 +964,5 @@ public static void initializeAllAccessors() { PartitionKey.initialize(); CosmosClientTelemetryConfig.initialize(); CosmosContainerIdentity.initialize(); - CosmosMicrometerMeterOptions.initialize(); } } diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java index 8cc44d664498f..1bbc198ff54a4 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java @@ -28,6 +28,7 @@ import com.azure.cosmos.models.CosmosMetricCategory; import com.azure.cosmos.models.CosmosMetricName; import com.azure.cosmos.models.CosmosMetricTagName; +import com.azure.cosmos.models.CosmosMicrometerMeterOptions; import com.azure.cosmos.models.CosmosMicrometerMetricsOptions; import com.azure.cosmos.models.CosmosPatchItemRequestOptions; import com.azure.cosmos.models.CosmosQueryRequestOptions; @@ -190,10 +191,9 @@ public void createItem() throws Exception { if (disableLatencyMeter) { this.inputMetricsOptions - .getMeterOptions( - CosmosMetricName.fromString( - CosmosMetricName.OPERATION_SUMMARY_LATENCY.toString().toUpperCase(Locale.ROOT))) - .setEnabled(false); + .configureMeter( + CosmosMetricName.fromString(CosmosMetricName.OPERATION_SUMMARY_LATENCY.toString().toUpperCase(Locale.ROOT)), + new CosmosMicrometerMeterOptions().setEnabled(false)); } try { @@ -251,11 +251,12 @@ public void createItemWithAllMetrics() throws Exception { if (suppressConsistencyLevelTag) { this .inputMetricsOptions - .getMeterOptions(CosmosMetricName.OPERATION_SUMMARY_LATENCY) - .suppressTagNames(CosmosMetricTagName.fromString("ConsistencyLevel")) - .histogramPublishingEnabled(false) - .percentiles(0.99, 0.999) - ; + .configureMeter( + CosmosMetricName.OPERATION_SUMMARY_LATENCY, + new CosmosMicrometerMeterOptions() + .suppressTagNames(CosmosMetricTagName.fromString("ConsistencyLevel")) + .histogramPublishingEnabled(false) + .percentiles(0.99, 0.999)); } try { From eb71343d42b94d2b93161e8992947ee58ed717f9 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Wed, 15 Feb 2023 23:16:56 +0000 Subject: [PATCH 29/40] Update pom.xml --- sdk/cosmos/azure-cosmos/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/cosmos/azure-cosmos/pom.xml b/sdk/cosmos/azure-cosmos/pom.xml index 62b5edace6f5b..cc5aca57d3efc 100644 --- a/sdk/cosmos/azure-cosmos/pom.xml +++ b/sdk/cosmos/azure-cosmos/pom.xml @@ -13,7 +13,7 @@ Licensed under the MIT License. com.azure azure-cosmos - 4.41.0-beta.2 + 4.41.0-beta.1 Microsoft Azure SDK for SQL API of Azure Cosmos DB Service This Package contains Microsoft Azure Cosmos SDK (with Reactive Extension Reactor support) for Azure Cosmos DB SQL API jar From 85ccd3b5d0724dcc79b31ee17604249ad8e77bf8 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Wed, 15 Feb 2023 23:55:32 +0000 Subject: [PATCH 30/40] Update CosmosMeterOptions.java --- .../implementation/clienttelemetry/CosmosMeterOptions.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMeterOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMeterOptions.java index f1ff5c56dda27..31d9b8fdb8a03 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMeterOptions.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMeterOptions.java @@ -4,7 +4,6 @@ package com.azure.cosmos.implementation.clienttelemetry; import com.azure.cosmos.models.CosmosMetricName; -import com.azure.cosmos.models.CosmosMicrometerMeterOptions; import java.util.EnumSet; @@ -43,7 +42,7 @@ public boolean isHistogramPublishingEnabled() { } public double[] getPercentiles() { - return this.percentiles; + return this.percentiles.clone(); } public boolean isEnabled() { From ad1c43d9e492d6c176d94710dbbd670b34126782 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Thu, 16 Feb 2023 00:16:10 +0000 Subject: [PATCH 31/40] Update CosmosMeterOptions.java --- .../implementation/clienttelemetry/CosmosMeterOptions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMeterOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMeterOptions.java index 31d9b8fdb8a03..4eee05fb2f292 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMeterOptions.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMeterOptions.java @@ -24,7 +24,7 @@ public CosmosMeterOptions( this.name = name; this.isEnabled = isEnabled; - this.percentiles = percentiles; + this.percentiles = percentiles != null ? percentiles.clone() : null; this.isHistogramPublishingEnabled = isHistogramPublishingEnabled; this.suppressedTagNames = suppressedTagNames; } From aa09a880578c5e56900b04e695676d866b562e3a Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Thu, 16 Feb 2023 00:16:45 +0000 Subject: [PATCH 32/40] Update CosmosMeterOptions.java --- .../implementation/clienttelemetry/CosmosMeterOptions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMeterOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMeterOptions.java index 4eee05fb2f292..c1c4b0333966d 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMeterOptions.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMeterOptions.java @@ -42,7 +42,7 @@ public boolean isHistogramPublishingEnabled() { } public double[] getPercentiles() { - return this.percentiles.clone(); + return this.percentiles != null ? this.percentiles.clone() : null; } public boolean isEnabled() { From ba04d1b44ab74309a096bc9c6e0dac668920e084 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Thu, 16 Feb 2023 00:36:05 +0000 Subject: [PATCH 33/40] Update CosmosMeterOptions.java --- .../implementation/clienttelemetry/CosmosMeterOptions.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMeterOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMeterOptions.java index c1c4b0333966d..4f49215ab480d 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMeterOptions.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/CosmosMeterOptions.java @@ -24,7 +24,7 @@ public CosmosMeterOptions( this.name = name; this.isEnabled = isEnabled; - this.percentiles = percentiles != null ? percentiles.clone() : null; + this.percentiles = percentiles != null ? percentiles.clone() : new double[0]; this.isHistogramPublishingEnabled = isHistogramPublishingEnabled; this.suppressedTagNames = suppressedTagNames; } @@ -42,7 +42,7 @@ public boolean isHistogramPublishingEnabled() { } public double[] getPercentiles() { - return this.percentiles != null ? this.percentiles.clone() : null; + return this.percentiles.clone(); } public boolean isEnabled() { From d9af6e814f3d8ad6c17d8921cf86470bc14d8191 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Thu, 16 Feb 2023 01:11:11 +0000 Subject: [PATCH 34/40] Update pom.xml --- sdk/cosmos/azure-cosmos/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/cosmos/azure-cosmos/pom.xml b/sdk/cosmos/azure-cosmos/pom.xml index cc5aca57d3efc..79f029cbb03e6 100644 --- a/sdk/cosmos/azure-cosmos/pom.xml +++ b/sdk/cosmos/azure-cosmos/pom.xml @@ -13,7 +13,7 @@ Licensed under the MIT License. com.azure azure-cosmos - 4.41.0-beta.1 + 4.41.0-beta.3 Microsoft Azure SDK for SQL API of Azure Cosmos DB Service This Package contains Microsoft Azure Cosmos SDK (with Reactive Extension Reactor support) for Azure Cosmos DB SQL API jar From 48aacab59b73dcdc0971b6cdd56042dc61e43d68 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Thu, 16 Feb 2023 01:11:23 +0000 Subject: [PATCH 35/40] Update pom.xml --- sdk/cosmos/azure-cosmos/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/cosmos/azure-cosmos/pom.xml b/sdk/cosmos/azure-cosmos/pom.xml index 79f029cbb03e6..cc5aca57d3efc 100644 --- a/sdk/cosmos/azure-cosmos/pom.xml +++ b/sdk/cosmos/azure-cosmos/pom.xml @@ -13,7 +13,7 @@ Licensed under the MIT License. com.azure azure-cosmos - 4.41.0-beta.3 + 4.41.0-beta.1 Microsoft Azure SDK for SQL API of Azure Cosmos DB Service This Package contains Microsoft Azure Cosmos SDK (with Reactive Extension Reactor support) for Azure Cosmos DB SQL API jar From 2eebb6ad19e185009d375cc024759d364d8356dc Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Thu, 16 Feb 2023 11:14:41 +0000 Subject: [PATCH 36/40] Update ClientMetricsTest.java --- .../com/azure/cosmos/ClientMetricsTest.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java index 1bbc198ff54a4..4b383430369a4 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java @@ -218,7 +218,7 @@ public void createItem() throws Exception { expectedOperationTag, Tag.of(TagName.RequestStatusCode.toString(), "201/0"), 1, - 100 + 300 ); this.validateMetrics( @@ -226,7 +226,7 @@ public void createItem() throws Exception { TagName.Operation.toString(), "Document/Create"), Tag.of(TagName.RequestOperationType.toString(), "Document/Create"), 1, - 100 + 300 ); } @@ -273,7 +273,7 @@ public void createItemWithAllMetrics() throws Exception { Tag.of(TagName.OperationStatusCode.toString(), "201"), Tag.of(TagName.RequestStatusCode.toString(), "201/0"), 1, - 100 + 300 ); this.validateMetrics( @@ -281,7 +281,7 @@ public void createItemWithAllMetrics() throws Exception { TagName.Operation.toString(), "Document/Create"), Tag.of(TagName.RequestOperationType.toString(), "Document/Create"), 1, - 100 + 300 ); Tag expectedConsistencyTag = Tag.of(TagName.ConsistencyLevel.toString(), "Session"); @@ -424,7 +424,7 @@ public void readAllItems() throws Exception { Tag.of(TagName.OperationStatusCode.toString(), "200"), Tag.of(TagName.RequestStatusCode.toString(), "200/0"), 1, - 100 + 300 ); this.validateMetrics( @@ -470,7 +470,7 @@ public void readAllItemsWithDetailMetrics() throws Exception { Tag.of(TagName.OperationStatusCode.toString(), "200"), Tag.of(TagName.RequestStatusCode.toString(), "200/0"), 1, - 100 + 1000 ); this.validateMetrics( @@ -602,7 +602,7 @@ public void itemPatchSuccess() { Tag.of(TagName.OperationStatusCode.toString(), "200"), Tag.of(TagName.RequestStatusCode.toString(), "200/0"), 1, - 100 + 300 ); this.validateMetrics( @@ -610,7 +610,7 @@ public void itemPatchSuccess() { TagName.Operation.toString(), "Document/Patch"), Tag.of(TagName.RequestOperationType.toString(), "Document/Patch"), 1, - 100 + 300 ); } finally { this.afterTest(); @@ -718,7 +718,7 @@ public void batchMultipleItemExecution() { Tag.of(TagName.OperationStatusCode.toString(), "200"), Tag.of(TagName.RequestStatusCode.toString(), "200/0"), 1, - 100 + 300 ); this.validateMetrics( @@ -726,7 +726,7 @@ public void batchMultipleItemExecution() { TagName.Operation.toString(), "Document/Batch"), Tag.of(TagName.RequestOperationType.toString(), "Document/Batch"), 1, - 100 + 300 ); } finally { this.afterTest(); From ecc3fc76829fc46c22f1831a964439bc34a18dc9 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Fri, 17 Feb 2023 00:35:19 +0000 Subject: [PATCH 37/40] Refactoring to avoid dependency on ExtendableStringEnum --- .../cosmos/models/CosmosMetricCategory.java | 123 ++++----- .../azure/cosmos/models/CosmosMetricName.java | 253 +++++++++--------- .../cosmos/models/CosmosMetricTagName.java | 144 +++++----- .../src/main/java/module-info.java | 2 +- 4 files changed, 260 insertions(+), 262 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java index f1be773e8a144..8af6a5dcc816a 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java @@ -3,7 +3,6 @@ package com.azure.cosmos.models; -import com.azure.core.util.ExpandableStringEnum; import com.azure.cosmos.implementation.clienttelemetry.MetricCategory; import java.util.EnumSet; @@ -15,59 +14,59 @@ /** * Categories for Cosmos DB client-side metrics */ -public final class CosmosMetricCategory extends ExpandableStringEnum { +public final class CosmosMetricCategory { - private EnumSet metricCategories; + private final String name; + private final EnumSet metricCategories; - /** - * Creates a new instance of {@link CosmosMetricCategory} without a {@link #toString()} value. - *

- * This constructor shouldn't be called as it will produce a {@link CosmosMetricCategory} which doesn't - * have a String enum value. - * - * @deprecated Use one of the constants or the {@link #fromString(String)} factory method. - */ - @Deprecated - CosmosMetricCategory() { + private CosmosMetricCategory(String name, EnumSet metricCategories) { + checkNotNull(name, "Argument 'name' must not be null."); + checkNotNull(metricCategories, "Argument 'metricCategories' must not be null."); + + this.name = name; + this.metricCategories = metricCategories; } /** * All metrics enabled */ - public static final CosmosMetricCategory ALL = fromString("All", CosmosMetricCategory.class) - .setCategories(MetricCategory.ALL_CATEGORIES); + public static final CosmosMetricCategory ALL = new CosmosMetricCategory( + "All", + MetricCategory.ALL_CATEGORIES); /** * Default metrics (categories OperationSummary, RequestSummary, System, DirectChannels and DirectRequests) enabled. * These metrics provide good overview of end-to-end telemetry and help with triaging for most common issues */ - public static final CosmosMetricCategory DEFAULT = fromString("Default", CosmosMetricCategory.class) - .setCategories(MetricCategory.DEFAULT_CATEGORIES); + public static final CosmosMetricCategory DEFAULT = new CosmosMetricCategory( + "Default", + MetricCategory.DEFAULT_CATEGORIES); /** * Minimum set of metrics (categories OperationSummary and System) enabled. * These metrics provide a basic overview of end-to-end telemetry but won't be sufficient for triaging * most issues */ - public static final CosmosMetricCategory MINIMUM = fromString("Minimum", CosmosMetricCategory.class) - .setCategories(EnumSet.of(MetricCategory.OperationSummary, MetricCategory.System)); + public static final CosmosMetricCategory MINIMUM = new CosmosMetricCategory( + "Minimum", + EnumSet.of(MetricCategory.OperationSummary, MetricCategory.System)); /** * The metrics in the OperationSummary category emit most important end-to-end metrics (like latency, request rate, * request charge, request- and response-payload size etc.) for SDK operations * These metrics are intended to visualize health state and impact - but alone not sufficient for triaging issues. */ - public static final CosmosMetricCategory OPERATION_SUMMARY = - fromString("OperationSummary", CosmosMetricCategory.class) - .setCategories(EnumSet.of(MetricCategory.OperationSummary)); + public static final CosmosMetricCategory OPERATION_SUMMARY = new CosmosMetricCategory( + "OperationSummary", + EnumSet.of(MetricCategory.OperationSummary)); /** * The metrics in the OperationDetails category emit additional end-to-end metrics (like item count) for SDK * operations. */ - public static final CosmosMetricCategory OPERATION_DETAILS = - fromString("OperationDetails", CosmosMetricCategory.class) - .setCategories(EnumSet.of(MetricCategory.OperationDetails)); + public static final CosmosMetricCategory OPERATION_DETAILS = new CosmosMetricCategory( + "OperationDetails", + EnumSet.of(MetricCategory.OperationDetails)); /** * The metrics in the RequestSummary category emit most important end-to-end metrics (like latency, request rate, @@ -76,9 +75,9 @@ public final class CosmosMetricCategory extends ExpandableStringEnum metricCategories) { - this.metricCategories = metricCategories; - return this; + return new StringJoiner(", ") + .add(CosmosMetricCategory.ALL.name) + .add(CosmosMetricCategory.DEFAULT.name) + .add(CosmosMetricCategory.MINIMUM.name) + .add(CosmosMetricCategory.OPERATION_SUMMARY.name) + .add(CosmosMetricCategory.OPERATION_DETAILS.name) + .add(CosmosMetricCategory.REQUEST_SUMMARY.name) + .add(CosmosMetricCategory.REQUEST_DETAILS.name) + .add(CosmosMetricCategory.DIRECT_ADDRESS_RESOLUTIONS.name) + .add(CosmosMetricCategory.DIRECT_CHANNELS.name) + .add(CosmosMetricCategory.DIRECT_ENDPOINTS.name) + .add(CosmosMetricCategory.DIRECT_REQUESTS.name) + .add(CosmosMetricCategory.LEGACY.name) + .add(CosmosMetricCategory.SYSTEM.name) + .toString(); } EnumSet getCategories() { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricName.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricName.java index bcf720e88417c..15e6bbaf24a23 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricName.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricName.java @@ -3,8 +3,6 @@ package com.azure.cosmos.models; -import com.azure.core.util.ExpandableStringEnum; - import java.util.Collections; import java.util.HashMap; import java.util.Locale; @@ -16,286 +14,282 @@ /** * Names of Cosmos DB client-side meters */ -public final class CosmosMetricName extends ExpandableStringEnum { - private CosmosMetricCategory meterCategory; +public final class CosmosMetricName { + private final static Map meters = createMeterNameMap(); + private final String name; + private final CosmosMetricCategory metricCategory; - /** - * Creates a new instance of {@link CosmosMetricName} without a {@link #toString()} value. - *

- * This constructor shouldn't be called as it will produce a {@link CosmosMetricName} which doesn't - * have a String enum value. - * - * @deprecated Use one of the constants or the {@link #fromString(String)} factory method. - */ - @Deprecated - CosmosMetricName() { + private CosmosMetricName(String name, CosmosMetricCategory metricCategory) { + checkNotNull(name, "Argument 'name' must not be null."); + checkNotNull(metricCategory, "Argument 'meterCategory' must not be null."); + + this.name = name; + this.metricCategory = metricCategory; } /** * Number of operation calls (Counter) */ - public static final CosmosMetricName OPERATION_SUMMARY_CALLS = - fromString(nameOf("op.calls"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.OPERATION_SUMMARY); + public static final CosmosMetricName OPERATION_SUMMARY_CALLS = new CosmosMetricName( + nameOf("op.calls"), + CosmosMetricCategory.OPERATION_SUMMARY); /** * Total latency (across requests including retries) of the operation (Timer) */ - public static final CosmosMetricName OPERATION_SUMMARY_LATENCY = - fromString(nameOf("op.latency"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.OPERATION_SUMMARY); + public static final CosmosMetricName OPERATION_SUMMARY_LATENCY = new CosmosMetricName( + nameOf("op.latency"), + CosmosMetricCategory.OPERATION_SUMMARY); /** * Request charge for the operation (DistributionSummary) */ - public static final CosmosMetricName OPERATION_SUMMARY_REQUEST_CHARGE = - fromString(nameOf("op.RUs"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.OPERATION_SUMMARY); + public static final CosmosMetricName OPERATION_SUMMARY_REQUEST_CHARGE = new CosmosMetricName( + nameOf("op.RUs"), + CosmosMetricCategory.OPERATION_SUMMARY); /** * Number of regions contacted for processing the operation (DistributionSummary) */ - public static final CosmosMetricName OPERATION_DETAILS_REGIONS_CONTACTED = - fromString(nameOf("op.regionsContacted"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.OPERATION_DETAILS); + public static final CosmosMetricName OPERATION_DETAILS_REGIONS_CONTACTED = new CosmosMetricName( + nameOf("op.regionsContacted"), + CosmosMetricCategory.OPERATION_DETAILS); /** * Actual item count - relevant for non-point-operations - indicating the actual number of * docs returned in the response (DistributionSummary) * NOTE: No percentiles or histogram supported */ - public static final CosmosMetricName OPERATION_DETAILS_ACTUAL_ITEM_COUNT = - fromString(nameOf("op.actualItemCount"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.OPERATION_DETAILS); + public static final CosmosMetricName OPERATION_DETAILS_ACTUAL_ITEM_COUNT = new CosmosMetricName( + nameOf("op.actualItemCount"), + CosmosMetricCategory.OPERATION_DETAILS); /** * Max. item count - relevant for non-point-operations - indicating the requested max. number of * docs returned in a single response (DistributionSummary) * NOTE: No percentiles or histogram supported */ - public static final CosmosMetricName OPERATION_DETAILS_MAX_ITEM_COUNT = - fromString(nameOf("op.maxItemCount"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.OPERATION_DETAILS); + public static final CosmosMetricName OPERATION_DETAILS_MAX_ITEM_COUNT = new CosmosMetricName( + nameOf("op.maxItemCount"), + CosmosMetricCategory.OPERATION_DETAILS); /** * Number of requests (Counter) * NOTE: No percentiles or histogram supported */ - public static final CosmosMetricName REQUEST_SUMMARY_DIRECT_REQUESTS = - fromString(nameOf("req.rntbd.requests"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.REQUEST_SUMMARY); + public static final CosmosMetricName REQUEST_SUMMARY_DIRECT_REQUESTS = new CosmosMetricName( + nameOf("req.rntbd.requests"), + CosmosMetricCategory.REQUEST_SUMMARY); /** * Latency of the request (Timer) */ - public static final CosmosMetricName REQUEST_SUMMARY_DIRECT_LATENCY = - fromString(nameOf("req.rntbd.latency"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.REQUEST_SUMMARY); + public static final CosmosMetricName REQUEST_SUMMARY_DIRECT_LATENCY = new CosmosMetricName( + nameOf("req.rntbd.latency"), + CosmosMetricCategory.REQUEST_SUMMARY); /** * Backend-latency of the request (DistributionSummary) */ - public static final CosmosMetricName REQUEST_SUMMARY_DIRECT_BACKEND_LATENCY = - fromString(nameOf("req.rntbd.backendLatency"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.REQUEST_SUMMARY); + public static final CosmosMetricName REQUEST_SUMMARY_DIRECT_BACKEND_LATENCY = new CosmosMetricName( + nameOf("req.rntbd.backendLatency"), + CosmosMetricCategory.REQUEST_SUMMARY); /** * Request charge for a request (DistributionSummary) */ - public static final CosmosMetricName REQUEST_SUMMARY_DIRECT_REQUEST_CHARGE = - fromString(nameOf("req.rntbd.RUs"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.REQUEST_SUMMARY); + public static final CosmosMetricName REQUEST_SUMMARY_DIRECT_REQUEST_CHARGE = new CosmosMetricName( + nameOf("req.rntbd.RUs"), + CosmosMetricCategory.REQUEST_SUMMARY); /** * Number of requests (Counter) * NOTE: No percentiles or histogram supported */ - public static final CosmosMetricName REQUEST_SUMMARY_GATEWAY_REQUESTS = - fromString(nameOf("req.gw.requests"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.REQUEST_SUMMARY); + public static final CosmosMetricName REQUEST_SUMMARY_GATEWAY_REQUESTS = new CosmosMetricName( + nameOf("req.gw.requests"), + CosmosMetricCategory.REQUEST_SUMMARY); /** * Latency of the request (Timer) */ - public static final CosmosMetricName REQUEST_SUMMARY_GATEWAY_LATENCY = - fromString(nameOf("req.gw.latency"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.REQUEST_SUMMARY); + public static final CosmosMetricName REQUEST_SUMMARY_GATEWAY_LATENCY = new CosmosMetricName( + nameOf("req.gw.latency"), + CosmosMetricCategory.REQUEST_SUMMARY); /** * Request charge for a request (DistributionSummary) */ - public static final CosmosMetricName REQUEST_SUMMARY_GATEWAY_REQUEST_CHARGE = - fromString(nameOf("req.gw.RUs"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.REQUEST_SUMMARY); + public static final CosmosMetricName REQUEST_SUMMARY_GATEWAY_REQUEST_CHARGE = new CosmosMetricName( + nameOf("req.gw.RUs"), + CosmosMetricCategory.REQUEST_SUMMARY); /** * Size of the request payload (DistributionSummary) * NOTE: No percentiles or histogram supported */ - public static final CosmosMetricName REQUEST_SUMMARY_SIZE_REQUEST = - fromString(nameOf("req.reqPayloadSize"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.REQUEST_SUMMARY); + public static final CosmosMetricName REQUEST_SUMMARY_SIZE_REQUEST = new CosmosMetricName( + nameOf("req.reqPayloadSize"), + CosmosMetricCategory.REQUEST_SUMMARY); /** * Size of the response payload (DistributionSummary) * NOTE: No percentiles or histogram supported */ - public static final CosmosMetricName REQUEST_SUMMARY_SIZE_RESPONSE = - fromString(nameOf("req.rspPayloadSize"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.REQUEST_SUMMARY); + public static final CosmosMetricName REQUEST_SUMMARY_SIZE_RESPONSE = new CosmosMetricName( + nameOf("req.rspPayloadSize"), + CosmosMetricCategory.REQUEST_SUMMARY); /** * Latency in different steps of the request pipeline (Timer) */ - public static final CosmosMetricName REQUEST_DETAILS_DIRECT_TIMELINE = - fromString(nameOf("req.rntbd.timeline"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.REQUEST_DETAILS); + public static final CosmosMetricName REQUEST_DETAILS_DIRECT_TIMELINE = new CosmosMetricName( + nameOf("req.rntbd.timeline"), + CosmosMetricCategory.REQUEST_DETAILS); /** * Latency in different steps of the request pipeline (Timer) */ - public static final CosmosMetricName REQUEST_DETAILS_GATEWAY_TIMELINE = - fromString(nameOf("req.gw.timeline"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.REQUEST_DETAILS); + public static final CosmosMetricName REQUEST_DETAILS_GATEWAY_TIMELINE = new CosmosMetricName( + nameOf("req.gw.timeline"), + CosmosMetricCategory.REQUEST_DETAILS); /** * Number of acquired channels (new connections) for this endpoint (FunctionCounter) */ - public static final CosmosMetricName DIRECT_CHANNELS_ACQUIRED_COUNT = - fromString(nameOf("rntbd.channels.acquired.count"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.DIRECT_CHANNELS); + public static final CosmosMetricName DIRECT_CHANNELS_ACQUIRED_COUNT = new CosmosMetricName( + nameOf("rntbd.channels.acquired.count"), + CosmosMetricCategory.DIRECT_CHANNELS); /** * Number of closed channels / connections for this endpoint (FunctionCounter) */ - public static final CosmosMetricName DIRECT_CHANNELS_CLOSED_COUNT = - fromString(nameOf("rntbd.channels.closed.count"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.DIRECT_CHANNELS); + public static final CosmosMetricName DIRECT_CHANNELS_CLOSED_COUNT = new CosmosMetricName( + nameOf("rntbd.channels.closed.count"), + CosmosMetricCategory.DIRECT_CHANNELS); /** * Snapshot of the number of available channels (active connections) for this endpoint (Gauge) */ - public static final CosmosMetricName DIRECT_CHANNELS_AVAILABLE_COUNT = - fromString(nameOf("rntbd.channels.available.count"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.DIRECT_CHANNELS); + public static final CosmosMetricName DIRECT_CHANNELS_AVAILABLE_COUNT = new CosmosMetricName( + nameOf("rntbd.channels.available.count"), + CosmosMetricCategory.DIRECT_CHANNELS); /** * Snapshot of the number of endpoints (Gauge) */ - public static final CosmosMetricName DIRECT_ENDPOINTS_COUNT = - fromString(nameOf("rntbd.endpoints.count"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.DIRECT_ENDPOINTS); + public static final CosmosMetricName DIRECT_ENDPOINTS_COUNT = new CosmosMetricName( + nameOf("rntbd.endpoints.count"), + CosmosMetricCategory.DIRECT_ENDPOINTS); /** * Number of evicted/closed endpoints (FunctionCounter) */ - public static final CosmosMetricName DIRECT_ENDPOINTS_EVICTED = - fromString(nameOf("rntbd.endpoints.evicted"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.DIRECT_ENDPOINTS); + public static final CosmosMetricName DIRECT_ENDPOINTS_EVICTED = new CosmosMetricName( + nameOf("rntbd.endpoints.evicted"), + CosmosMetricCategory.DIRECT_ENDPOINTS); /** * Number of RNTBD address resolution requests (Counter) */ - public static final CosmosMetricName DIRECT_ADDRESS_RESOLUTION_REQUESTS = - fromString(nameOf("rntbd.addressResolution.requests"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.DIRECT_ADDRESS_RESOLUTIONS); + public static final CosmosMetricName DIRECT_ADDRESS_RESOLUTION_REQUESTS = new CosmosMetricName( + nameOf("rntbd.addressResolution.requests"), + CosmosMetricCategory.DIRECT_ADDRESS_RESOLUTIONS); /** * Latency of the RNTBD address resolution request (Timer) */ - public static final CosmosMetricName DIRECT_ADDRESS_RESOLUTION_LATENCY = - fromString(nameOf("rntbd.addressResolution.latency"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.DIRECT_ADDRESS_RESOLUTIONS); + public static final CosmosMetricName DIRECT_ADDRESS_RESOLUTION_LATENCY = new CosmosMetricName( + nameOf("rntbd.addressResolution.latency"), + CosmosMetricCategory.DIRECT_ADDRESS_RESOLUTIONS); /** * Latency of RNTBD requests for this endpoint (Timer) */ - public static final CosmosMetricName DIRECT_REQUEST_LATENCY = - fromString(nameOf("rntbd.requests.latency"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.DIRECT_REQUESTS); + public static final CosmosMetricName DIRECT_REQUEST_LATENCY = new CosmosMetricName( + nameOf("rntbd.requests.latency"), + CosmosMetricCategory.DIRECT_REQUESTS); /** * Latency of failed RNTBD requests for this endpoint (Timer) */ - public static final CosmosMetricName DIRECT_REQUEST_LATENCY_FAILED = - fromString(nameOf("rntbd.requests.failed.latency"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.DIRECT_REQUESTS); + public static final CosmosMetricName DIRECT_REQUEST_LATENCY_FAILED = new CosmosMetricName( + nameOf("rntbd.requests.failed.latency"), + CosmosMetricCategory.DIRECT_REQUESTS); /** * Latency of successful RNTBD requests for this endpoint (Timer) */ - public static final CosmosMetricName DIRECT_REQUEST_LATENCY_SUCCESS = - fromString(nameOf("rntbd.requests.successful.latency"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.DIRECT_REQUESTS); + public static final CosmosMetricName DIRECT_REQUEST_LATENCY_SUCCESS = new CosmosMetricName( + nameOf("rntbd.requests.successful.latency"), + CosmosMetricCategory.DIRECT_REQUESTS); /** * Snapshot of number of concurrent RNTBD requests for this endpoint (Gauge) */ - public static final CosmosMetricName DIRECT_REQUEST_CONCURRENT_COUNT = - fromString(nameOf("rntbd.requests.concurrent.count"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.DIRECT_REQUESTS); + public static final CosmosMetricName DIRECT_REQUEST_CONCURRENT_COUNT = new CosmosMetricName( + nameOf("rntbd.requests.concurrent.count"), + CosmosMetricCategory.DIRECT_REQUESTS); /** * Snapshot of number of queued RNTBD requests for this endpoint (Gauge) */ - public static final CosmosMetricName DIRECT_REQUEST_QUEUED_COUNT = - fromString(nameOf("rntbd.requests.queued.count"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.DIRECT_REQUESTS); + public static final CosmosMetricName DIRECT_REQUEST_QUEUED_COUNT = new CosmosMetricName( + nameOf("rntbd.requests.queued.count"), + CosmosMetricCategory.DIRECT_REQUESTS); /** * Size of the request payload (DistributionSummary) */ - public static final CosmosMetricName DIRECT_REQUEST_SIZE_REQUEST = - fromString(nameOf("rntbd.req.reqSize"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.DIRECT_REQUESTS); + public static final CosmosMetricName DIRECT_REQUEST_SIZE_REQUEST = new CosmosMetricName( + nameOf("rntbd.req.reqSize"), + CosmosMetricCategory.DIRECT_REQUESTS); /** * Size of the response payload (DistributionSummary) */ - public static final CosmosMetricName DIRECT_REQUEST_SIZE_RESPONSE = - fromString(nameOf("rntbd.req.rspSize"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.DIRECT_REQUESTS); + public static final CosmosMetricName DIRECT_REQUEST_SIZE_RESPONSE = new CosmosMetricName( + nameOf("rntbd.req.rspSize"), + CosmosMetricCategory.DIRECT_REQUESTS); /** * Avg. system-wide CPU load (DistributionSummary) */ - public static final CosmosMetricName SYSTEM_CPU = - fromString(nameOf("system.avgCpuLoad"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.SYSTEM); + public static final CosmosMetricName SYSTEM_CPU = new CosmosMetricName( + nameOf("system.avgCpuLoad"), + CosmosMetricCategory.SYSTEM); /** * JVM's Free available memory (DistributionSummary) */ - public static final CosmosMetricName SYSTEM_MEMORY_FREE = - fromString(nameOf("system.freeMemoryAvailable"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.SYSTEM); + public static final CosmosMetricName SYSTEM_MEMORY_FREE = new CosmosMetricName( + nameOf("system.freeMemoryAvailable"), + CosmosMetricCategory.SYSTEM); /** * Distribution summary over snapshot of acquired channels for the endpoint at time * of a request (DistributionSummary) */ - public static final CosmosMetricName LEGACY_DIRECT_ENDPOINT_STATISTICS_ACQUIRED = - fromString(nameOf("req.rntbd.stats.endpoint.acquiredChannels"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.LEGACY); + public static final CosmosMetricName LEGACY_DIRECT_ENDPOINT_STATISTICS_ACQUIRED = new CosmosMetricName( + nameOf("req.rntbd.stats.endpoint.acquiredChannels"), + CosmosMetricCategory.LEGACY); /** * Distribution summary over snapshot of available channels for the endpoint at time * of a request (DistributionSummary) */ - public static final CosmosMetricName LEGACY_DIRECT_ENDPOINT_STATISTICS_AVAILABLE = - fromString(nameOf("req.rntbd.stats.endpoint.availableChannels"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.LEGACY); + public static final CosmosMetricName LEGACY_DIRECT_ENDPOINT_STATISTICS_AVAILABLE = new CosmosMetricName( + nameOf("req.rntbd.stats.endpoint.availableChannels"), + CosmosMetricCategory.LEGACY); /** * Distribution summary over snapshot of inflight channels for the endpoint at time * of a request (DistributionSummary) */ - public static final CosmosMetricName LEGACY_DIRECT_ENDPOINT_STATISTICS_INFLIGHT = - fromString(nameOf("req.rntbd.stats.endpoint.inflightRequests"), CosmosMetricName.class) - .setCategory(CosmosMetricCategory.LEGACY); - - private final static Map meters = createMeterNameMap(); + public static final CosmosMetricName LEGACY_DIRECT_ENDPOINT_STATISTICS_INFLIGHT = new CosmosMetricName( + nameOf("req.rntbd.stats.endpoint.inflightRequests"), + CosmosMetricCategory.LEGACY); /** * Gets the corresponding metric category state from its string representation. @@ -327,7 +321,7 @@ public static CosmosMetricName fromString(String name) { * @return the category of the meter */ public CosmosMetricCategory getCategory() { - return this.meterCategory; + return this.metricCategory; } private static Map createMeterNameMap() { @@ -380,18 +374,13 @@ private static Map createMeterNameMap() { private static String getValidValues() { StringJoiner sj = new StringJoiner(", "); - for (CosmosMetricName c: CosmosMetricName.values(CosmosMetricName.class)) { - sj.add(c.toString()); + for (CosmosMetricName metric: meters.values()) { + sj.add(metric.name); } return sj.toString(); } - private CosmosMetricName setCategory(CosmosMetricCategory meterCategory) { - this.meterCategory = meterCategory; - return this; - } - private static String nameOf(final String member) { return "cosmos.client." + member; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricTagName.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricTagName.java index 2712454ff0f66..69532e7191e22 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricTagName.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricTagName.java @@ -3,7 +3,6 @@ package com.azure.cosmos.models; -import com.azure.core.util.ExpandableStringEnum; import com.azure.cosmos.implementation.clienttelemetry.TagName; import java.util.EnumSet; @@ -17,145 +16,145 @@ * this identifier can be used to tune which tags to use for individual meters or also define the default tags that * should be used when no meter-specific suppression exists. */ -public final class CosmosMetricTagName extends ExpandableStringEnum { +public final class CosmosMetricTagName { - private EnumSet tagNames; + private final String name; + private final EnumSet tagNames; - /** - * Creates a new instance of {@link CosmosMetricTagName} without a {@link #toString()} value. - *

- * This constructor shouldn't be called as it will produce a {@link CosmosMetricTagName} which doesn't - * have a String enum value. - * - * @deprecated Use one of the constants or the {@link #fromString(String)} factory method. - */ - @Deprecated - CosmosMetricTagName() { + private CosmosMetricTagName(String name, EnumSet tagNames) { + checkNotNull(name, "Argument 'name' must not be null."); + checkNotNull(tagNames, "Argument 'tagNames' must not be null."); + + this.name = name; + this.tagNames = tagNames; } /** * All possible tags */ - public static final CosmosMetricTagName ALL = fromString("All", CosmosMetricTagName.class) - .setTagNames(TagName.ALL_TAGS); + public static final CosmosMetricTagName ALL = new CosmosMetricTagName( + "All", + TagName.ALL_TAGS); /** * Default tags */ - public static final CosmosMetricTagName DEFAULT = fromString("Default", CosmosMetricTagName.class) - .setTagNames(TagName.DEFAULT_TAGS); + public static final CosmosMetricTagName DEFAULT = new CosmosMetricTagName( + "Default", + TagName.DEFAULT_TAGS); /** * Minimum tags that are required and cannot be disabled */ - public static final CosmosMetricTagName MINIMUM = fromString("Minimum", CosmosMetricTagName.class) - .setTagNames(TagName.MINIMUM_TAGS); + public static final CosmosMetricTagName MINIMUM = new CosmosMetricTagName( + "Minimum", + TagName.MINIMUM_TAGS); /** * Effective Consistency model * Applicable to operations and requests */ - public static final CosmosMetricTagName CONSISTENCY_LEVEL = - fromString("ConsistencyLevel", CosmosMetricTagName.class) - .setTagNames(EnumSet.of(TagName.ConsistencyLevel)); + public static final CosmosMetricTagName CONSISTENCY_LEVEL =new CosmosMetricTagName( + "ConsistencyLevel", + EnumSet.of(TagName.ConsistencyLevel)); /** * Container identifier * applicable to operations and requests */ - public static final CosmosMetricTagName CONTAINER = - fromString("Container", CosmosMetricTagName.class) - .setTagNames(EnumSet.of(TagName.Container)); + public static final CosmosMetricTagName CONTAINER =new CosmosMetricTagName( + "Container", + EnumSet.of(TagName.Container)); /** * The service endpoint (hostname + port) * Applicable to requests, direct channel, direct endpoint and direct requests */ - public static final CosmosMetricTagName SERVICE_ENDPOINT = - fromString("ServiceEndpoint", CosmosMetricTagName.class) - .setTagNames(EnumSet.of(TagName.ServiceEndpoint)); + public static final CosmosMetricTagName SERVICE_ENDPOINT = new CosmosMetricTagName( + "ServiceEndpoint", + EnumSet.of(TagName.ServiceEndpoint)); /** * The service endpoint (hostname + port, partitionId, replicaId) * Applicable to requests */ - public static final CosmosMetricTagName SERVICE_ADDRESS= - fromString("ServiceAddress", CosmosMetricTagName.class) - .setTagNames(EnumSet.of(TagName.ServiceAddress)); + public static final CosmosMetricTagName SERVICE_ADDRESS = new CosmosMetricTagName( + "ServiceAddress", + EnumSet.of(TagName.ServiceAddress)); /** * The region names of the regions handling the operation/request * Applicable to requests and operations */ - public static final CosmosMetricTagName REGION_NAME = - fromString("RegionName", CosmosMetricTagName.class) - .setTagNames(EnumSet.of(TagName.RegionName)); + public static final CosmosMetricTagName REGION_NAME = new CosmosMetricTagName( + "RegionName", + EnumSet.of(TagName.RegionName)); /** * Operation status code. * Applicable to operations */ - public static final CosmosMetricTagName OPERATION_STATUS_CODE = - fromString("OperationStatusCode", CosmosMetricTagName.class) - .setTagNames(EnumSet.of(TagName.OperationStatusCode)); + public static final CosmosMetricTagName OPERATION_STATUS_CODE = new CosmosMetricTagName( + "OperationStatusCode", + EnumSet.of(TagName.OperationStatusCode)); /** * Operation type * Applicable to operations */ - public static final CosmosMetricTagName OPERATION = - fromString("Operation", CosmosMetricTagName.class) - .setTagNames(EnumSet.of(TagName.Operation)); + public static final CosmosMetricTagName OPERATION = new CosmosMetricTagName( + "Operation", + EnumSet.of(TagName.Operation)); /** * Request status code * Applicable to requests */ - public static final CosmosMetricTagName REQUEST_STATUS_CODE = - fromString("RequestStatusCode", CosmosMetricTagName.class) - .setTagNames(EnumSet.of(TagName.RequestStatusCode)); + public static final CosmosMetricTagName REQUEST_STATUS_CODE = new CosmosMetricTagName( + "RequestStatusCode", + EnumSet.of(TagName.RequestStatusCode)); /** * Request operation type * Applicable to requests */ - public static final CosmosMetricTagName REQUEST_OPERATION_TYPE = - fromString("RequestOperationType", CosmosMetricTagName.class) - .setTagNames(EnumSet.of(TagName.RequestOperationType)); + public static final CosmosMetricTagName REQUEST_OPERATION_TYPE = new CosmosMetricTagName( + "RequestOperationType", + EnumSet.of(TagName.RequestOperationType)); /** * An identifier for the instance of the Cosmos client * Applicable to all meters */ - public static final CosmosMetricTagName CLIENT_CORRELATION_ID = - fromString("ClientCorrelationId", CosmosMetricTagName.class) - .setTagNames(EnumSet.of(TagName.ClientCorrelationId)); + public static final CosmosMetricTagName CLIENT_CORRELATION_ID = new CosmosMetricTagName( + "ClientCorrelationId", + EnumSet.of(TagName.ClientCorrelationId)); /** * An indicator whether an address resolution refresh requested a cache refresh * Applicable to address resolutions */ - public static final CosmosMetricTagName ADDRESS_RESOLUTION_FORCED_REFRESH = - fromString("IsForceRefresh", CosmosMetricTagName.class) - .setTagNames(EnumSet.of(TagName.IsForceRefresh)); + public static final CosmosMetricTagName ADDRESS_RESOLUTION_FORCED_REFRESH = new CosmosMetricTagName( + "IsForceRefresh", + EnumSet.of(TagName.IsForceRefresh)); /** * An indicator whether an address resolution refresh requested a collection routing map * cache refresh * Applicable to address resolutions */ - public static final CosmosMetricTagName ADDRESS_RESOLUTION_COLLECTION_MAP_REFRESH = - fromString("IsForceCollectionRoutingMapRefresh", CosmosMetricTagName.class) - .setTagNames(EnumSet.of(TagName.IsForceCollectionRoutingMapRefresh)); + public static final CosmosMetricTagName ADDRESS_RESOLUTION_COLLECTION_MAP_REFRESH = new CosmosMetricTagName( + "IsForceCollectionRoutingMapRefresh", + EnumSet.of(TagName.IsForceCollectionRoutingMapRefresh)); /** * A numeric identifier for a physical partition * Applicable to operations and requests */ - public static final CosmosMetricTagName PARTITION_KEY_RANGE_ID = - fromString("PartitionKeyRangeId", CosmosMetricTagName.class) - .setTagNames(EnumSet.of(TagName.PartitionKeyRangeId)); + public static final CosmosMetricTagName PARTITION_KEY_RANGE_ID = new CosmosMetricTagName( + "PartitionKeyRangeId", + EnumSet.of(TagName.PartitionKeyRangeId)); /** * Gets the corresponding metric category state from its string representation. @@ -198,17 +197,24 @@ public static CosmosMetricTagName fromString(String name) { } private static String getValidValues() { - StringJoiner sj = new StringJoiner(", "); - for (CosmosMetricTagName t: CosmosMetricTagName.values(CosmosMetricTagName.class)) { - sj.add(t.toString()); - } - - return sj.toString(); - } - - private CosmosMetricTagName setTagNames(EnumSet tagNames) { - this.tagNames = tagNames; - return this; + return new StringJoiner(", ") + .add(CosmosMetricTagName.ALL.name) + .add(CosmosMetricTagName.DEFAULT.name) + .add(CosmosMetricTagName.MINIMUM.name) + .add(CosmosMetricTagName.CONSISTENCY_LEVEL.name) + .add(CosmosMetricTagName.CONTAINER.name) + .add(CosmosMetricTagName.SERVICE_ADDRESS.name) + .add(CosmosMetricTagName.SERVICE_ENDPOINT.name) + .add(CosmosMetricTagName.REGION_NAME.name) + .add(CosmosMetricTagName.OPERATION_STATUS_CODE.name) + .add(CosmosMetricTagName.OPERATION.name) + .add(CosmosMetricTagName.REQUEST_STATUS_CODE.name) + .add(CosmosMetricTagName.REQUEST_OPERATION_TYPE.name) + .add(CosmosMetricTagName.CLIENT_CORRELATION_ID.name) + .add(CosmosMetricTagName.ADDRESS_RESOLUTION_FORCED_REFRESH.name) + .add(CosmosMetricTagName.ADDRESS_RESOLUTION_COLLECTION_MAP_REFRESH.name) + .add(CosmosMetricTagName.PARTITION_KEY_RANGE_ID.name) + .toString(); } EnumSet getTagNames() { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/module-info.java b/sdk/cosmos/azure-cosmos/src/main/java/module-info.java index dd8b1048b62e1..352bf1c37ac6b 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/module-info.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/module-info.java @@ -70,7 +70,7 @@ opens com.azure.cosmos.util to com.fasterxml.jackson.databind; opens com.azure.cosmos.implementation.throughputControl to com.fasterxml.jackson.databind; opens com.azure.cosmos.implementation.throughputControl.controller.group.global to com.fasterxml.jackson.databind; - opens com.azure.cosmos.models to com.fasterxml.jackson.databind, com.fasterxml.jackson.module.afterburner, java.logging, com.azure.core; + opens com.azure.cosmos.models to com.fasterxml.jackson.databind, com.fasterxml.jackson.module.afterburner, java.logging; uses com.azure.cosmos.implementation.guava25.base.PatternCompiler; uses com.azure.core.util.tracing.Tracer; From 50c5d8046f0f5cb3f80f4d59b9ffc01932cda53e Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Fri, 17 Feb 2023 01:53:21 +0000 Subject: [PATCH 38/40] Fixing regression from removing ExpandableStringENum --- .../cosmos/models/CosmosMetricCategory.java | 29 +++++++++++++ .../azure/cosmos/models/CosmosMetricName.java | 42 ++++++++++++++++++- .../cosmos/models/CosmosMetricTagName.java | 29 +++++++++++++ 3 files changed, 99 insertions(+), 1 deletion(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java index 8af6a5dcc816a..85c0df54edf1d 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricCategory.java @@ -4,9 +4,11 @@ package com.azure.cosmos.models; import com.azure.cosmos.implementation.clienttelemetry.MetricCategory; +import com.fasterxml.jackson.annotation.JsonValue; import java.util.EnumSet; import java.util.Locale; +import java.util.Objects; import java.util.StringJoiner; import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; @@ -180,6 +182,33 @@ public static CosmosMetricCategory fromString(String name) { } } + @Override + @JsonValue + public String toString() { + return this.name; + } + + @Override + public int hashCode() { + return Objects.hash(CosmosMetricCategory.class, this.name); + } + + @SuppressWarnings("unchecked") + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } else if (!CosmosMetricCategory.class.isAssignableFrom(obj.getClass())) { + return false; + } else if (obj == this) { + return true; + } else if (this.name == null) { + return ((CosmosMetricCategory) obj).name == null; + } else { + return this.name.equals(((CosmosMetricCategory) obj).name); + } + } + private static String getValidValues() { return new StringJoiner(", ") .add(CosmosMetricCategory.ALL.name) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricName.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricName.java index 15e6bbaf24a23..1eb84056477c8 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricName.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricName.java @@ -3,10 +3,14 @@ package com.azure.cosmos.models; +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonValue; + import java.util.Collections; import java.util.HashMap; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.StringJoiner; import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; @@ -15,7 +19,8 @@ * Names of Cosmos DB client-side meters */ public final class CosmosMetricName { - private final static Map meters = createMeterNameMap(); + private static Object lockObject = new Object(); + private static Map meters = null; private final String name; private final CosmosMetricCategory metricCategory; @@ -301,6 +306,14 @@ private CosmosMetricName(String name, CosmosMetricCategory metricCategory) { public static CosmosMetricName fromString(String name) { checkNotNull(name, "Argument 'name' must not be null."); + if (meters == null) { + synchronized (lockObject) { + if (meters == null) { + meters = createMeterNameMap(); + } + } + } + String normalizedName = name.trim().toLowerCase(Locale.ROOT); CosmosMetricName meterName = meters.getOrDefault(normalizedName, null); @@ -324,6 +337,33 @@ public CosmosMetricCategory getCategory() { return this.metricCategory; } + @Override + @JsonValue + public String toString() { + return this.name; + } + + @Override + public int hashCode() { + return Objects.hash(CosmosMetricName.class, this.name); + } + + @SuppressWarnings("unchecked") + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } else if (!CosmosMetricName.class.isAssignableFrom(obj.getClass())) { + return false; + } else if (obj == this) { + return true; + } else if (this.name == null) { + return ((CosmosMetricName) obj).name == null; + } else { + return this.name.equals(((CosmosMetricName) obj).name); + } + } + private static Map createMeterNameMap() { Map map = new HashMap<>(); map.put(nameOf("op.latency"), CosmosMetricName.OPERATION_SUMMARY_LATENCY); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricTagName.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricTagName.java index 69532e7191e22..6391970600b09 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricTagName.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricTagName.java @@ -4,9 +4,11 @@ package com.azure.cosmos.models; import com.azure.cosmos.implementation.clienttelemetry.TagName; +import com.fasterxml.jackson.annotation.JsonValue; import java.util.EnumSet; import java.util.Locale; +import java.util.Objects; import java.util.StringJoiner; import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; @@ -196,6 +198,33 @@ public static CosmosMetricTagName fromString(String name) { } } + @Override + @JsonValue + public String toString() { + return this.name; + } + + @Override + public int hashCode() { + return Objects.hash(CosmosMetricTagName.class, this.name); + } + + @SuppressWarnings("unchecked") + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } else if (!CosmosMetricTagName.class.isAssignableFrom(obj.getClass())) { + return false; + } else if (obj == this) { + return true; + } else if (this.name == null) { + return ((CosmosMetricTagName) obj).name == null; + } else { + return this.name.equals(((CosmosMetricTagName) obj).name); + } + } + private static String getValidValues() { return new StringJoiner(", ") .add(CosmosMetricTagName.ALL.name) From 1f84f5985cebe5b72036fd89d97c93da0aa2369e Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Fri, 17 Feb 2023 02:46:03 +0000 Subject: [PATCH 39/40] Update CosmosMetricName.java --- .../com/azure/cosmos/models/CosmosMetricName.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricName.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricName.java index 1eb84056477c8..7f3f1e4861425 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricName.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosMetricName.java @@ -19,8 +19,6 @@ * Names of Cosmos DB client-side meters */ public final class CosmosMetricName { - private static Object lockObject = new Object(); - private static Map meters = null; private final String name; private final CosmosMetricCategory metricCategory; @@ -296,6 +294,11 @@ private CosmosMetricName(String name, CosmosMetricCategory metricCategory) { nameOf("req.rntbd.stats.endpoint.inflightRequests"), CosmosMetricCategory.LEGACY); + // NOTE - it is important to declare this field after all the Factory properties above + // In java static fields are first set to default value - then in the order of the + // declarations the assignment/initialization is executed. + private final static Map meters = createMeterNameMap(); + /** * Gets the corresponding metric category state from its string representation. * @@ -306,14 +309,6 @@ private CosmosMetricName(String name, CosmosMetricCategory metricCategory) { public static CosmosMetricName fromString(String name) { checkNotNull(name, "Argument 'name' must not be null."); - if (meters == null) { - synchronized (lockObject) { - if (meters == null) { - meters = createMeterNameMap(); - } - } - } - String normalizedName = name.trim().toLowerCase(Locale.ROOT); CosmosMetricName meterName = meters.getOrDefault(normalizedName, null); From f4cd11f10a857bdab435c49e04e39b902711b08b Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Fri, 17 Feb 2023 04:06:14 +0000 Subject: [PATCH 40/40] Update ClientMetricsTest.java --- .../com/azure/cosmos/ClientMetricsTest.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java index 4b383430369a4..40d0406e2175b 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/ClientMetricsTest.java @@ -318,7 +318,7 @@ public void readItem() throws Exception { Tag.of(TagName.OperationStatusCode.toString(), "200"), Tag.of(TagName.RequestStatusCode.toString(), "200/0"), 1, - 50 + 500 ); this.validateMetrics( @@ -326,7 +326,7 @@ public void readItem() throws Exception { TagName.Operation.toString(), "Document/Read"), Tag.of(TagName.RequestOperationType.toString(), "Document/Read"), 1, - 50 + 500 ); Tag queryPlanTag = Tag.of(TagName.RequestOperationType.toString(), "DocumentCollection_QueryPlan"); @@ -424,7 +424,7 @@ public void readAllItems() throws Exception { Tag.of(TagName.OperationStatusCode.toString(), "200"), Tag.of(TagName.RequestStatusCode.toString(), "200/0"), 1, - 300 + 3000 ); this.validateMetrics( @@ -432,7 +432,7 @@ public void readAllItems() throws Exception { TagName.Operation.toString(), "Document/ReadFeed/readAllItems." + container.getId()), Tag.of(TagName.RequestOperationType.toString(), "Document/Query"), 1, - 1000 + 10000 ); this.validateItemCountMetrics( @@ -470,7 +470,7 @@ public void readAllItemsWithDetailMetrics() throws Exception { Tag.of(TagName.OperationStatusCode.toString(), "200"), Tag.of(TagName.RequestStatusCode.toString(), "200/0"), 1, - 1000 + 10000 ); this.validateMetrics( @@ -478,7 +478,7 @@ public void readAllItemsWithDetailMetrics() throws Exception { TagName.Operation.toString(), "Document/ReadFeed/readAllItems." + container.getId()), Tag.of(TagName.RequestOperationType.toString(), "Document/Query"), 1, - 1000 + 10000 ); this.validateItemCountMetrics( @@ -524,7 +524,7 @@ public void queryItems() throws Exception { Tag.of(TagName.OperationStatusCode.toString(), "200"), Tag.of(TagName.RequestStatusCode.toString(), "200/0"), 1, - 10000 + 100000 ); this.validateMetrics( @@ -532,7 +532,7 @@ public void queryItems() throws Exception { TagName.Operation.toString(), "Document/Query/queryItems." + container.getId()), Tag.of(TagName.RequestOperationType.toString(), "Document/Query"), 1, - 10000 + 100000 ); this.validateItemCountMetrics( @@ -602,7 +602,7 @@ public void itemPatchSuccess() { Tag.of(TagName.OperationStatusCode.toString(), "200"), Tag.of(TagName.RequestStatusCode.toString(), "200/0"), 1, - 300 + 3000 ); this.validateMetrics( @@ -610,7 +610,7 @@ public void itemPatchSuccess() { TagName.Operation.toString(), "Document/Patch"), Tag.of(TagName.RequestOperationType.toString(), "Document/Patch"), 1, - 300 + 3000 ); } finally { this.afterTest(); @@ -656,7 +656,7 @@ public void createItem_withBulk() { Tag.of(TagName.OperationStatusCode.toString(), "200"), Tag.of(TagName.RequestStatusCode.toString(), "200/0"), 1, - 1000 + 10000 ); this.validateMetrics( @@ -664,7 +664,7 @@ public void createItem_withBulk() { TagName.Operation.toString(), "Document/Batch"), Tag.of(TagName.RequestOperationType.toString(), "Document/Batch"), 1, - 1000 + 10000 ); } finally { this.afterTest(); @@ -718,7 +718,7 @@ public void batchMultipleItemExecution() { Tag.of(TagName.OperationStatusCode.toString(), "200"), Tag.of(TagName.RequestStatusCode.toString(), "200/0"), 1, - 300 + 3000 ); this.validateMetrics( @@ -726,7 +726,7 @@ public void batchMultipleItemExecution() { TagName.Operation.toString(), "Document/Batch"), Tag.of(TagName.RequestOperationType.toString(), "Document/Batch"), 1, - 300 + 3000 ); } finally { this.afterTest();