From 6715d249e0ec18c54d1e202462c6b7001d74f239 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Wed, 18 Sep 2024 22:13:04 +0530 Subject: [PATCH] adding test --- .../src/Handler/TelemetryHandler.cs | 2 +- .../OpenTelemetryMetricsCollector.cs | 38 +++++++++++-- .../OpenTelemetry/OpenTelemetryMetrics.cs | 14 ++--- .../Metrics/CustomMetricExporter.cs | 53 +++++++++++++++++++ .../Metrics/OpenTelemetryMetricsTest.cs | 21 ++------ 5 files changed, 101 insertions(+), 27 deletions(-) create mode 100644 Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Metrics/CustomMetricExporter.cs diff --git a/Microsoft.Azure.Cosmos/src/Handler/TelemetryHandler.cs b/Microsoft.Azure.Cosmos/src/Handler/TelemetryHandler.cs index 04e9e92740..7f07ccae59 100644 --- a/Microsoft.Azure.Cosmos/src/Handler/TelemetryHandler.cs +++ b/Microsoft.Azure.Cosmos/src/Handler/TelemetryHandler.cs @@ -46,7 +46,7 @@ public override async Task SendAsync( RequestCharge = response.Headers.RequestCharge, SubStatusCode = response.Headers.SubStatusCode, Trace = response.Trace, - MaxItemCount = Convert.ToString(new Random().Next(100)), + MaxItemCount = request.Headers.PageSize, ActualItemCount = response.Headers.ItemCount, PartitionKeyRangeId = request.Headers.PartitionKeyRangeId })); diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/Collector/OpenTelemetryMetricsCollector.cs b/Microsoft.Azure.Cosmos/src/Telemetry/Collector/OpenTelemetryMetricsCollector.cs index da8809e5dd..8518cb86cb 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/Collector/OpenTelemetryMetricsCollector.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/Collector/OpenTelemetryMetricsCollector.cs @@ -19,7 +19,9 @@ internal class OpenTelemetryMetricsCollector : ITelemetryCollector private readonly string clientId; private readonly string accountName; - private static readonly ConcurrentBag[]>> maxItemCounts = new (); + private static ConcurrentBag[]>> maxItemCounts = null; + private static ConcurrentBag[]>> actualItemCounts = null; + private static ConcurrentBag[]>> regionsContactedCounts = null; /// /// Initializes a new instance of the OpenTelemetryMetricsCollector class. @@ -48,7 +50,9 @@ public void CollectOperationAndNetworkInfo(Func getTelemet KeyValuePair[] dimensions = new[] { - new KeyValuePair("Container", $"{this.accountName}/{telemetryInformation.DatabaseId}/{telemetryInformation.ContainerId}"), + new KeyValuePair("AccountName", this.accountName), + new KeyValuePair("Container", telemetryInformation.ContainerId), + new KeyValuePair("Database", telemetryInformation.DatabaseId), new KeyValuePair("Operation", telemetryInformation.OperationType), new KeyValuePair("OperationStatusCode", telemetryInformation.StatusCode), new KeyValuePair("ClientCorrelationId", this.clientId), @@ -66,8 +70,18 @@ public void CollectOperationAndNetworkInfo(Func getTelemet /// Key-value pairs representing various metadata about the operation (e.g., container, operation type, consistency level). private static void PushOperationLevelMetrics(TelemetryInformation telemetryInformation, KeyValuePair[] dimensions) { + Console.WriteLine("Pushing maxItemCounts " + telemetryInformation.MaxItemCount); + maxItemCounts ??= new ConcurrentBag[]>>(); maxItemCounts.Add(new Tuple[]>(Convert.ToInt32(telemetryInformation.MaxItemCount), dimensions)); + Console.WriteLine("Pushing ActualItemCount " + telemetryInformation.ActualItemCount); + actualItemCounts ??= new ConcurrentBag[]>>(); + actualItemCounts.Add(new Tuple[]>(Convert.ToInt32(telemetryInformation.ActualItemCount), dimensions)); + + Console.WriteLine("Pushing telemetryInformation.RegionsContactedList.Count " + telemetryInformation.RegionsContactedList.Count); + regionsContactedCounts ??= new ConcurrentBag[]>>(); + regionsContactedCounts.Add(new Tuple[]>(telemetryInformation.RegionsContactedList.Count, dimensions)); + OpenTelemetryMetrics.RequestUnitsHistogram.Record(telemetryInformation.RequestCharge, dimensions); OpenTelemetryMetrics.RequestLatencyHistogram.Record(telemetryInformation.RequestLatency.Value.Milliseconds, dimensions); OpenTelemetryMetrics.NumberOfOperationCallCounter.Add(1, dimensions); @@ -77,9 +91,27 @@ public static IEnumerable> GetMaxItemCount() { foreach (Tuple[]> maxItemCount in maxItemCounts) { + Console.WriteLine("Pulling maxItemCounts " + maxItemCount.Item1); yield return new Measurement(maxItemCount.Item1, maxItemCount.Item2); } - } + } + + public static IEnumerable> GetActualItemCount() + { + foreach (Tuple[]> actualItemCount in actualItemCounts) + { + Console.WriteLine("Pulling actualItemCount " + actualItemCount.Item1); + yield return new Measurement(actualItemCount.Item1, actualItemCount.Item2); + } + } + public static IEnumerable> GetRegionContactedCount() + { + foreach (Tuple[]> regionContactedCount in regionsContactedCounts) + { + Console.WriteLine("Pulling regionContactedCount " + regionContactedCount.Item1); + yield return new Measurement(regionContactedCount.Item1, regionContactedCount.Item2); + } + } } } diff --git a/Microsoft.Azure.Cosmos/src/Telemetry/OpenTelemetry/OpenTelemetryMetrics.cs b/Microsoft.Azure.Cosmos/src/Telemetry/OpenTelemetry/OpenTelemetryMetrics.cs index b9e5fe9a79..800c344dad 100644 --- a/Microsoft.Azure.Cosmos/src/Telemetry/OpenTelemetry/OpenTelemetryMetrics.cs +++ b/Microsoft.Azure.Cosmos/src/Telemetry/OpenTelemetry/OpenTelemetryMetrics.cs @@ -34,19 +34,21 @@ internal static class OpenTelemetryMetrics internal static readonly ObservableGauge maxItemGauge = CosmosMeter.CreateObservableGauge(name: "cosmos.client.op.maxItemCount", - observeValue: () => OpenTelemetryMetricsCollector.GetMaxItemCount(), + observeValues: () => OpenTelemetryMetricsCollector.GetMaxItemCount(), unit: "#", description: "For feed operations (query, readAll, readMany, change feed) and batch operations this meter capture the requested maxItemCount per page/request"); - /*internal static readonly ObservableGauge ActualItemCounter = - CosmosMeter.CreateObservableGauge(name: "cosmos.client.op.actualItemCount", + internal static readonly ObservableGauge ActualItemCounter = + CosmosMeter.CreateObservableGauge(name: "cosmos.client.op.actualItemCount", + observeValues: () => OpenTelemetryMetricsCollector.GetActualItemCount(), unit: "#", description: "For feed operations (query, readAll, readMany, change feed) batch operations this meter capture the actual item count in responses from the service"); internal static readonly ObservableGauge RegionsContactedCounter = - CosmosMeter.CreateObservableGauge(name: "cosmos.client.op.regionsContacted", - unit: "#", - description: "Number of regions contacted when executing an operation");*/ + CosmosMeter.CreateObservableGauge(name: "cosmos.client.op.regionsContacted", + observeValues: () => OpenTelemetryMetricsCollector.GetRegionContactedCount(), + unit: "# regions", + description: "Number of regions contacted when executing an operation"); } } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Metrics/CustomMetricExporter.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Metrics/CustomMetricExporter.cs new file mode 100644 index 0000000000..a411905a8e --- /dev/null +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Metrics/CustomMetricExporter.cs @@ -0,0 +1,53 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests.Metrics +{ + using OpenTelemetry.Metrics; + using OpenTelemetry; + using System; + + public class CustomMetricExporter : BaseExporter + { + // This method will be called periodically by OpenTelemetry SDK + public override ExportResult Export(in Batch batch) + { + Console.WriteLine("\n[Custom Exporter] Exporting metrics:"); + + int gaugeCount = 0; + foreach (var metric in batch) + { + Console.WriteLine($"Metric: {metric.Name}, Type: {metric.MetricType}"); + + foreach (var metricPoint in metric.GetMetricPoints()) + { + switch (metric.MetricType) + { + case MetricType.LongSum: + Console.WriteLine($"Value (Counter): {metricPoint.GetSumLong()}"); + break; + case MetricType.LongGauge: + Console.WriteLine($"Value (Gauge): {metricPoint.GetGaugeLastValueLong()}"); + gaugeCount++; + break; + case MetricType.Histogram: + Console.WriteLine($"Value (Histogram): {metricPoint.GetHistogramCount()}"); + + foreach (HistogramBucket bucket in metricPoint.GetHistogramBuckets()) + { + Console.WriteLine($"{bucket.ExplicitBound} : {bucket.BucketCount}"); + } + break; + } + } + + } + + Console.WriteLine($"Total gauge values exported: {gaugeCount}"); + Console.WriteLine(); + + return ExportResult.Success; + } + } +} diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Metrics/OpenTelemetryMetricsTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Metrics/OpenTelemetryMetricsTest.cs index 06086b5a2d..c30a1e365b 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Metrics/OpenTelemetryMetricsTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Metrics/OpenTelemetryMetricsTest.cs @@ -5,18 +5,11 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests.Metrics { using System; - using System.Collections.Concurrent; using System.Collections.Generic; - using System.Linq; using System.Net; using System.Net.Http; - using System.Reflection; using System.Threading.Tasks; - using Microsoft.Azure.Cosmos.Fluent; - using Microsoft.Azure.Documents; using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - using Moq.Protected; using OpenTelemetry.Metrics; using OpenTelemetry; using System.Diagnostics; @@ -61,13 +54,11 @@ public async Task Cleanup() [TestMethod] public async Task OperationLevelMetrics() { - //var histogramBuckets = new double[] { 0, 5, 10, 25, 50, 75, 100, 250, 500 }; MeterProvider meterProvider = Sdk - .CreateMeterProviderBuilder() - .AddMeter("*")/* - .AddView("cosmos.client.op.RUs", new ExplicitBucketHistogramConfiguration { Boundaries = histogramBuckets })*/ - .AddConsoleExporter() - .Build(); + .CreateMeterProviderBuilder() + .AddMeter("*") + .AddReader(new PeriodicExportingMetricReader(new CustomMetricExporter(), exportIntervalMilliseconds: 3000)) + .Build(); int httpCallsMade = 0; HttpClientHandlerHelper httpClientHandlerHelper = new HttpClientHandlerHelper @@ -98,8 +89,6 @@ public async Task OperationLevelMetrics() ContainerInternal container = (ContainerInternal)cosmosClient.GetContainer(this.database.Id, "ClientCreateAndInitializeContainer"); - await Task.Delay(1000); - Stopwatch sw = Stopwatch.StartNew(); sw.Start(); while(true) @@ -112,8 +101,6 @@ public async Task OperationLevelMetrics() } } sw.Stop(); - - await Task.Delay(1000); cosmosClient.Dispose();