From 3dc96e39daad46d31b12a994c9b72c4907faa4b5 Mon Sep 17 00:00:00 2001
From: Piotr Karpala <piotrkarpala@microsoft.com>
Date: Wed, 12 Jun 2024 14:34:29 -0400
Subject: [PATCH] logging

Signed-off-by: Piotr Karpala <piotrkarpala@microsoft.com>
---
 .gitignore                                    |  1 +
 .vscode/launch.json                           | 25 +++++++++++++++++++
 src/Scaler.Demo/OrderGenerator/Program.cs     | 11 +++++---
 src/Scaler.Demo/OrderProcessor/Worker.cs      |  4 +--
 .../CosmosDbScalerServiceTests.cs             |  4 ++-
 src/Scaler/Services/CosmosDbMetricProvider.cs | 10 +++++++-
 src/Scaler/Services/CosmosDbScalerService.cs  |  8 +++++-
 7 files changed, 55 insertions(+), 8 deletions(-)

diff --git a/.gitignore b/.gitignore
index 8afdcb6..ae8a90c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -452,3 +452,4 @@ $RECYCLE.BIN/
 !.vscode/tasks.json
 !.vscode/launch.json
 !.vscode/extensions.json
+src/Scaler.Demo/OrderProcessor/appsettings.Development.json
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 1da3396..41d4b7c 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -30,6 +30,31 @@
             "name": ".NET Core Attach",
             "type": "coreclr",
             "request": "attach"
+        },
+        {
+            // Use IntelliSense to find out which attributes exist for C# debugging
+            // Use hover for the description of the existing attributes
+            // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
+            "name": "Order Processor",
+            "type": "coreclr",
+            "request": "launch",
+            "preLaunchTask": "build",
+            // If you have changed target frameworks, make sure to update the program path.
+            "program": "${workspaceFolder}/src/Scaler.Demo/OrderProcessor/bin/Debug/net6.0/Keda.CosmosDb.Scaler.Demo.OrderProcessor.dll",
+            "args": [],
+            "cwd": "${workspaceFolder}/src/Scaler.Demo/OrderProcessor",
+            "stopAtEntry": false,
+            // Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
+            "serverReadyAction": {
+                "action": "openExternally",
+                "pattern": "\\bNow listening on:\\s+(https?://\\S+)"
+            },
+            "env": {
+                "ASPNETCORE_ENVIRONMENT": "Development",
+            },
+            "sourceFileMap": {
+                "/Views": "${workspaceFolder}/Views"
+            }
         }
     ]
 }
\ No newline at end of file
diff --git a/src/Scaler.Demo/OrderGenerator/Program.cs b/src/Scaler.Demo/OrderGenerator/Program.cs
index 77bfac5..d473a7a 100644
--- a/src/Scaler.Demo/OrderGenerator/Program.cs
+++ b/src/Scaler.Demo/OrderGenerator/Program.cs
@@ -132,8 +132,11 @@ private static async Task CreateOrderAsync(Container container, string article)
         private static async Task SetupAsync()
         {
             Console.WriteLine($"Creating database: {_cosmosDbConfig.DatabaseId}");
+            using var cosmosClient = _cosmosDbConfig.Connection.Contains("AccountKey")
+                ? new CosmosClient(_cosmosDbConfig.Connection, new CosmosClientOptions { ConnectionMode = ConnectionMode.Gateway })
+                : new CosmosClient(_cosmosDbConfig.Connection, new DefaultAzureCredential(), new CosmosClientOptions { ConnectionMode = ConnectionMode.Direct });
 
-            Database database = await new CosmosClient(_cosmosDbConfig.Connection)
+            Database database = await cosmosClient
                 .CreateDatabaseIfNotExistsAsync(_cosmosDbConfig.DatabaseId);
 
             Console.WriteLine($"Creating container: {_cosmosDbConfig.ContainerId} with throughput: {_cosmosDbConfig.ContainerThroughput} RU/s");
@@ -147,12 +150,14 @@ await database.CreateContainerIfNotExistsAsync(
 
         private static async Task TeardownAsync()
         {
-            var client = new CosmosClient(_cosmosDbConfig.Connection);
+            using var cosmosClient = _cosmosDbConfig.Connection.Contains("AccountKey")
+                ? new CosmosClient(_cosmosDbConfig.Connection, new CosmosClientOptions { ConnectionMode = ConnectionMode.Gateway })
+                : new CosmosClient(_cosmosDbConfig.Connection, new DefaultAzureCredential(), new CosmosClientOptions { ConnectionMode = ConnectionMode.Direct });
 
             try
             {
                 Console.WriteLine($"Deleting database: {_cosmosDbConfig.DatabaseId}");
-                await client.GetDatabase(_cosmosDbConfig.DatabaseId).DeleteAsync();
+                await cosmosClient.GetDatabase(_cosmosDbConfig.DatabaseId).DeleteAsync();
             }
             catch (CosmosException)
             {
diff --git a/src/Scaler.Demo/OrderProcessor/Worker.cs b/src/Scaler.Demo/OrderProcessor/Worker.cs
index eb2844a..17eec0c 100644
--- a/src/Scaler.Demo/OrderProcessor/Worker.cs
+++ b/src/Scaler.Demo/OrderProcessor/Worker.cs
@@ -30,7 +30,7 @@ public override async Task StartAsync(CancellationToken cancellationToken)
             ? new CosmosClient(_cosmosDbConfig.Connection)
             : new CosmosClient(_cosmosDbConfig.Connection, new DefaultAzureCredential());
 
-            Database leaseDatabase = await new CosmosClient(_cosmosDbConfig.LeaseConnection)
+            Database leaseDatabase = await cosmosClient
                 .CreateDatabaseIfNotExistsAsync(_cosmosDbConfig.LeaseDatabaseId, cancellationToken: cancellationToken);
 
             Container leaseContainer = await leaseDatabase
@@ -42,7 +42,7 @@ public override async Task StartAsync(CancellationToken cancellationToken)
             // Change feed processor instance name should be unique for each container application.
             string instanceName = $"Instance-{Dns.GetHostName()}";
 
-            _processor = new CosmosClient(_cosmosDbConfig.Connection)
+            _processor = cosmosClient
                 .GetContainer(_cosmosDbConfig.DatabaseId, _cosmosDbConfig.ContainerId)
                 .GetChangeFeedProcessorBuilder<Order>(_cosmosDbConfig.ProcessorName, ProcessOrdersAsync)
                 .WithInstanceName(instanceName)
diff --git a/src/Scaler.Tests/CosmosDbScalerServiceTests.cs b/src/Scaler.Tests/CosmosDbScalerServiceTests.cs
index 2156b0e..58ade43 100644
--- a/src/Scaler.Tests/CosmosDbScalerServiceTests.cs
+++ b/src/Scaler.Tests/CosmosDbScalerServiceTests.cs
@@ -1,6 +1,7 @@
 using System;
 using System.Threading.Tasks;
 using Google.Protobuf.Collections;
+using Microsoft.Extensions.Logging;
 using Moq;
 using Newtonsoft.Json;
 using Xunit;
@@ -15,7 +16,8 @@ public class CosmosDbScalerServiceTests
         public CosmosDbScalerServiceTests()
         {
             _metricProviderMock = new Mock<ICosmosDbMetricProvider>();
-            _cosmosDbScalerService = new CosmosDbScalerService(_metricProviderMock.Object);
+            var _loggerMock = new Mock<ILogger<CosmosDbScalerService>>();
+            _cosmosDbScalerService = new CosmosDbScalerService(_metricProviderMock.Object, _loggerMock.Object);
         }
 
         [Theory]
diff --git a/src/Scaler/Services/CosmosDbMetricProvider.cs b/src/Scaler/Services/CosmosDbMetricProvider.cs
index 8ca242b..355110a 100644
--- a/src/Scaler/Services/CosmosDbMetricProvider.cs
+++ b/src/Scaler/Services/CosmosDbMetricProvider.cs
@@ -41,10 +41,18 @@ public async Task<long> GetPartitionCountAsync(ScalerMetadata scalerMetadata)
                     while (iterator.HasMoreResults)
                     {
                         FeedResponse<ChangeFeedProcessorState> states = await iterator.ReadNextAsync();
-                        partitionCount += states.Where(state => state.EstimatedLag > 0).Count();
+
+                        foreach (ChangeFeedProcessorState leaseState in states)
+                        {
+                            string host = leaseState.InstanceName == null ? $"not owned by any host currently" : $"owned by host {leaseState.InstanceName}";
+                            _logger.LogInformation("Lease [{LeaseToken}] {host} reports {EstimatedLag} as estimated lag.", leaseState.LeaseToken, host, leaseState.EstimatedLag);
+
+                            partitionCount += leaseState.EstimatedLag > 0 ? 1 : 0;
+                        }
                     }
                 }
 
+                _logger.LogInformation("Returning active {partitionCount}", partitionCount);
                 return partitionCount;
             }
             catch (CosmosException exception)
diff --git a/src/Scaler/Services/CosmosDbScalerService.cs b/src/Scaler/Services/CosmosDbScalerService.cs
index 0ce6c69..dc7950c 100644
--- a/src/Scaler/Services/CosmosDbScalerService.cs
+++ b/src/Scaler/Services/CosmosDbScalerService.cs
@@ -8,10 +8,12 @@ namespace Keda.CosmosDb.Scaler
     internal sealed class CosmosDbScalerService : ExternalScaler.ExternalScalerBase
     {
         private readonly ICosmosDbMetricProvider _metricProvider;
+        private readonly ILogger<CosmosDbScalerService> _logger;
 
-        public CosmosDbScalerService(ICosmosDbMetricProvider metricProvider)
+        public CosmosDbScalerService(ICosmosDbMetricProvider metricProvider, ILogger<CosmosDbScalerService> logger)
         {
             _metricProvider = metricProvider ?? throw new ArgumentNullException(nameof(metricProvider));
+            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
         }
 
         public override async Task<IsActiveResponse> IsActive(ScaledObjectRef request, ServerCallContext context)
@@ -19,6 +21,8 @@ public override async Task<IsActiveResponse> IsActive(ScaledObjectRef request, S
             var scalerMetadata = ScalerMetadata.Create(request);
 
             bool isActive = (await _metricProvider.GetPartitionCountAsync(scalerMetadata)) > 0L;
+
+            _logger.LogInformation("Scaler is {status}", isActive ? "active" : "inactive");
             return new IsActiveResponse { Result = isActive };
         }
 
@@ -34,6 +38,7 @@ public override async Task<GetMetricsResponse> GetMetrics(GetMetricsRequest requ
                 MetricValue_ = await _metricProvider.GetPartitionCountAsync(scalerMetadata),
             });
 
+            _logger.LogInformation("Returning metric value {value} for metric {metric}", response.MetricValues[0].MetricValue_, response.MetricValues[0].MetricName);
             return response;
         }
 
@@ -49,6 +54,7 @@ public override Task<GetMetricSpecResponse> GetMetricSpec(ScaledObjectRef reques
                 TargetSize = 1L,
             });
 
+            _logger.LogInformation("Returning target size {size} for metric {metric}", response.MetricSpecs[0].TargetSize, response.MetricSpecs[0].MetricName);
             return Task.FromResult(response);
         }
     }