From 9329d76ab627b5c832d4c3bd96b02366d128a6ad Mon Sep 17 00:00:00 2001 From: dsokolovrudakov Date: Thu, 20 Feb 2025 00:05:33 +0200 Subject: [PATCH] Fix returned status codes depending on scenario, provide informative logs Extend logic of encpoints to provide more informative status codes on different scenarios (not found, bad request, etc). Update logging to write structured and informative logs --- .../Services/CommunicationControlService.cs | 90 ++++++++++--------- .../ICommunicationControlService.cs | 1 + .../Services/HiveMindMovingService.cs | 10 +-- .../Services/HiveMindService.cs | 2 + .../Exceptions/HiveNotFoundException.cs | 19 ---- .../Controllers/ClientController.cs | 13 ++- .../Controllers/HiveController.cs | 31 +++++-- .../DevOpsProject/DI/LogicConfiguration.cs | 2 - 8 files changed, 89 insertions(+), 79 deletions(-) delete mode 100644 src/CommunicationControl/DevOpsProject.Shared/Exceptions/HiveNotFoundException.cs diff --git a/src/CommunicationControl/DevOpsProject.CommunicationControl.Logic/Services/CommunicationControlService.cs b/src/CommunicationControl/DevOpsProject.CommunicationControl.Logic/Services/CommunicationControlService.cs index dea50b7..5e0b449 100644 --- a/src/CommunicationControl/DevOpsProject.CommunicationControl.Logic/Services/CommunicationControlService.cs +++ b/src/CommunicationControl/DevOpsProject.CommunicationControl.Logic/Services/CommunicationControlService.cs @@ -37,7 +37,7 @@ namespace DevOpsProject.CommunicationControl.Logic.Services bool isSuccessfullyDisconnected = false; try { - var result = await _redisService.DeleteAsync(hiveId); + var result = await _redisService.DeleteAsync(GetHiveKey(hiveId)); isSuccessfullyDisconnected = result; return result; } @@ -65,9 +65,11 @@ namespace DevOpsProject.CommunicationControl.Logic.Services public async Task ConnectHive(HiveModel model) { + _logger.LogInformation("Trying to connect Hive: {@model}", model); bool result = await _redisService.SetAsync(GetHiveKey(model.HiveID), model); if (result) { + _logger.LogInformation("Successfully connected Hive: {@model}", model); var operationalArea = _spatialService.GetHiveOperationalArea(model); await _messageBus.Publish(new HiveConnectedMessage { @@ -80,46 +82,41 @@ namespace DevOpsProject.CommunicationControl.Logic.Services } else { - await _messageBus.Publish(new HiveConnectedMessage - { - HiveID = model.HiveID, - Hive = model, - IsSuccessfullyConnected = result - }); + _logger.LogError("Failed to connect Hive: {@model}", model); throw new HiveConnectionException($"Failed to connect hive for HiveId: {model.HiveID}"); } } + public async Task IsHiveConnected(string hiveId) + { + string hiveKey = GetHiveKey(hiveId); + return await _redisService.CheckIfKeyExists(hiveKey); + } + public async Task AddTelemetry(HiveTelemetryModel model) { string hiveKey = GetHiveKey(model.HiveID); - bool hiveExists = await _redisService.CheckIfKeyExists(hiveKey); - if (hiveExists) + bool result = await _redisService.UpdateAsync(hiveKey, (HiveModel hive) => { - bool result = await _redisService.UpdateAsync(hiveKey, (HiveModel hive) => - { - hive.Telemetry = model; - }); + hive.Telemetry = model; + }); - await _messageBus.Publish(new TelemetrySentMessage - { - HiveID = model.HiveID, - Telemetry = model, - IsSuccessfullySent = result - }); - return model.Timestamp; + if (result) + { + _logger.LogInformation("Telemetry updated for HiveID: {hiveId}. Updated telemetry timestamp: {timestamp}", model.HiveID, model.Timestamp); } else { - await _messageBus.Publish(new TelemetrySentMessage - { - HiveID = model.HiveID, - Telemetry = model, - IsSuccessfullySent = false - }); - throw new HiveNotFoundException($"Hive not found for id: {model.HiveID}"); + _logger.LogError("Failed to update Telemetry - Redis update issue. HiveID: {hiveId}, Telemetry model: {@telemetry}", model.HiveID, model); } + await _messageBus.Publish(new TelemetrySentMessage + { + HiveID = model.HiveID, + Telemetry = model, + IsSuccessfullySent = result + }); + return model.Timestamp; } public async Task SendHiveControlSignal(string hiveId, Location destination) @@ -127,33 +124,40 @@ namespace DevOpsProject.CommunicationControl.Logic.Services var hive = await GetHiveModel(hiveId); if (hive == null) { - throw new Exception($"Hive control signal error: cannot find hive with id: {hiveId}"); + _logger.LogError("Sending Hive Control signal: Hive not found for HiveID: {hiveId}", hiveId); + return null; } bool isSuccessfullySent = false; - + string hiveMindPath = _communicationControlConfiguration.CurrentValue.HiveMindPath; + var command = new MoveHiveMindCommand + { + CommandType = State.Move, + Location = destination, + Timestamp = DateTime.Now + }; try { - var command = new MoveHiveMindCommand - { - CommandType = State.Move, - Location = destination, - Timestamp = DateTime.Now - }; - - var result = await _hiveHttpClient.SendHiveControlCommandAsync(hive.HiveSchema, hive.HiveIP, hive.HivePort, - _communicationControlConfiguration.CurrentValue.HiveMindPath, command); + var result = await _hiveHttpClient.SendHiveControlCommandAsync(hive.HiveSchema, hive.HiveIP, hive.HivePort, hiveMindPath, command); isSuccessfullySent = true; return result; } finally { - await _messageBus.Publish(new MoveHiveMessage + if (isSuccessfullySent) { - IsSuccessfullySent = isSuccessfullySent, - Destination = destination, - HiveID = hiveId - }); + await _messageBus.Publish(new MoveHiveMessage + { + IsSuccessfullySent = isSuccessfullySent, + Destination = destination, + HiveID = hiveId + }); + } + else + { + _logger.LogError("Failed to send control command for Hive: {@hive}, path: {path}, \n Command: {@command}", hive, hiveMindPath, command); + } + } } diff --git a/src/CommunicationControl/DevOpsProject.CommunicationControl.Logic/Services/Interfaces/ICommunicationControlService.cs b/src/CommunicationControl/DevOpsProject.CommunicationControl.Logic/Services/Interfaces/ICommunicationControlService.cs index 86445cf..6569990 100644 --- a/src/CommunicationControl/DevOpsProject.CommunicationControl.Logic/Services/Interfaces/ICommunicationControlService.cs +++ b/src/CommunicationControl/DevOpsProject.CommunicationControl.Logic/Services/Interfaces/ICommunicationControlService.cs @@ -8,6 +8,7 @@ namespace DevOpsProject.CommunicationControl.Logic.Services.Interfaces Task GetHiveModel(string hiveId); Task> GetAllHives(); Task ConnectHive(HiveModel model); + Task IsHiveConnected(string hiveId); Task AddTelemetry(HiveTelemetryModel model); Task SendHiveControlSignal(string hiveId, Location destination); } diff --git a/src/CommunicationControl/DevOpsProject.HiveMind.Logic/Services/HiveMindMovingService.cs b/src/CommunicationControl/DevOpsProject.HiveMind.Logic/Services/HiveMindMovingService.cs index 5633e8a..553e89b 100644 --- a/src/CommunicationControl/DevOpsProject.HiveMind.Logic/Services/HiveMindMovingService.cs +++ b/src/CommunicationControl/DevOpsProject.HiveMind.Logic/Services/HiveMindMovingService.cs @@ -27,6 +27,7 @@ namespace DevOpsProject.HiveMind.Logic.Services // If already moving - stop movement if (HiveInMemoryState.IsMoving) { + _logger.LogWarning("Previous movement command terminated. Previous destination: {@destination}, Current Location: {@current}, new destination: {@destination}", HiveInMemoryState.Destination, HiveInMemoryState.CurrentLocation, destination); StopMovement(); } @@ -39,8 +40,9 @@ namespace DevOpsProject.HiveMind.Logic.Services if (_movementTimer == null) { // TODO: Recalculating position each N seconds - _movementTimer = new Timer(UpdateMovement, null, TimeSpan.Zero, TimeSpan.FromSeconds(3)); - _logger.LogInformation("Movement timer started."); + int intervalFromSeconds = 3; + _movementTimer = new Timer(UpdateMovement, null, TimeSpan.Zero, TimeSpan.FromSeconds(intervalFromSeconds)); + _logger.LogInformation("Movement timer started. Destination: {@destination}, recalculation interval: {interval}", destination, intervalFromSeconds); } } } @@ -60,14 +62,13 @@ namespace DevOpsProject.HiveMind.Logic.Services if (AreLocationsEqual(currentLocation.Value, destination.Value)) { + _logger.LogInformation("Reached destination. Current location: {@currentLocation}, Destination: {@destination}", currentLocation, destination); StopMovement(); return; } Location newLocation = CalculateNextPosition(currentLocation.Value, destination.Value, 0.1f); HiveInMemoryState.CurrentLocation = newLocation; - - _logger.LogInformation($"Moved closer: {newLocation}"); } } @@ -77,7 +78,6 @@ namespace DevOpsProject.HiveMind.Logic.Services _movementTimer = null; HiveInMemoryState.IsMoving = false; HiveInMemoryState.Destination = null; - _logger.LogInformation("Movement stopped: Reached destination."); } private static bool AreLocationsEqual(Location loc1, Location loc2) diff --git a/src/CommunicationControl/DevOpsProject.HiveMind.Logic/Services/HiveMindService.cs b/src/CommunicationControl/DevOpsProject.HiveMind.Logic/Services/HiveMindService.cs index 6bf94d2..df1c01d 100644 --- a/src/CommunicationControl/DevOpsProject.HiveMind.Logic/Services/HiveMindService.cs +++ b/src/CommunicationControl/DevOpsProject.HiveMind.Logic/Services/HiveMindService.cs @@ -48,6 +48,8 @@ namespace DevOpsProject.HiveMind.Logic.Services }; var jsonContent = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json"); + _logger.LogInformation("Attempting to connect Hive. Request: {@request}, URI: {uri}", request, uriBuilder.Uri); + var retryPolicy = Policy.HandleResult(r => !r.IsSuccessStatusCode) .WaitAndRetryAsync( 10, diff --git a/src/CommunicationControl/DevOpsProject.Shared/Exceptions/HiveNotFoundException.cs b/src/CommunicationControl/DevOpsProject.Shared/Exceptions/HiveNotFoundException.cs deleted file mode 100644 index ada24fa..0000000 --- a/src/CommunicationControl/DevOpsProject.Shared/Exceptions/HiveNotFoundException.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace DevOpsProject.Shared.Exceptions -{ - public class HiveNotFoundException : Exception - { - public HiveNotFoundException() - { - } - - public HiveNotFoundException(string message) - : base(message) - { - } - - public HiveNotFoundException(string message, Exception inner) - : base(message, inner) - { - } - } -} diff --git a/src/CommunicationControl/DevOpsProject/Controllers/ClientController.cs b/src/CommunicationControl/DevOpsProject/Controllers/ClientController.cs index 0798b0d..1a4200f 100644 --- a/src/CommunicationControl/DevOpsProject/Controllers/ClientController.cs +++ b/src/CommunicationControl/DevOpsProject/Controllers/ClientController.cs @@ -32,17 +32,21 @@ namespace DevOpsProject.CommunicationControl.API.Controllers [HttpGet("hive/{hiveId}")] public async Task GetHive(string hiveId) { - var hiveModel = await _communicationControlService.GetHiveModel(hiveId); + var hiveExists = await _communicationControlService.IsHiveConnected(hiveId); + if (!hiveExists) + { + _logger.LogWarning("Failed to get Hive for HiveID: {hiveId}", hiveId); + return NotFound($"Hive with HiveID: {hiveId} is not found"); + } + var hiveModel = await _communicationControlService.GetHiveModel(hiveId); return Ok(hiveModel); } [HttpGet("hive")] public async Task GetHives() { - var hives = await _communicationControlService.GetAllHives(); - return Ok(hives); } @@ -59,6 +63,7 @@ namespace DevOpsProject.CommunicationControl.API.Controllers if (request?.Hives == null || !request.Hives.Any()) return BadRequest("No hive IDs provided."); + _logger.LogInformation("Hive moving request accepted by enpdoint. Request: {@request}", request); foreach (var id in request.Hives) { _ = Task.Run(async () => @@ -69,7 +74,7 @@ namespace DevOpsProject.CommunicationControl.API.Controllers } catch (Exception ex) { - _logger.LogError(ex, $"Failed to send control signal for HiveID: {id}"); + _logger.LogError(ex, "Failed to send control signal for HiveID: {id} \n Request: {@request}", id, request); } }); } diff --git a/src/CommunicationControl/DevOpsProject/Controllers/HiveController.cs b/src/CommunicationControl/DevOpsProject/Controllers/HiveController.cs index c346207..8c3bf9c 100644 --- a/src/CommunicationControl/DevOpsProject/Controllers/HiveController.cs +++ b/src/CommunicationControl/DevOpsProject/Controllers/HiveController.cs @@ -11,10 +11,12 @@ namespace DevOpsProject.CommunicationControl.API.Controllers public class HiveController : Controller { private readonly ICommunicationControlService _communicationControlService; + private readonly ILogger _logger; - public HiveController(ICommunicationControlService communicationControlService) + public HiveController(ICommunicationControlService communicationControlService, ILogger logger) { _communicationControlService = communicationControlService; + _logger = logger; } [HttpPost("connect")] @@ -28,6 +30,13 @@ namespace DevOpsProject.CommunicationControl.API.Controllers HiveSchema = request.HiveSchema }; + bool isConnected = await _communicationControlService.IsHiveConnected(request.HiveID); + if (isConnected) + { + _logger.LogError("Hive with HiveID: {hiveId} already connected. Request: {@request}", request.HiveID, request); + return BadRequest($"Hive with HiveID: {request.HiveID} already connected"); + } + var hiveOperationalArea = await _communicationControlService.ConnectHive(hiveModel); var connectResponse = new HiveConnectResponse { @@ -36,6 +45,7 @@ namespace DevOpsProject.CommunicationControl.API.Controllers }; return Ok(connectResponse); + } [HttpPost("telemetry")] @@ -51,13 +61,22 @@ namespace DevOpsProject.CommunicationControl.API.Controllers Timestamp = DateTime.Now }; - var telemetryUpdateTimestamp = await _communicationControlService.AddTelemetry(hiveTelemetryModel); - var telemetryResponse = new HiveTelemetryResponse + bool isHiveConnected = await _communicationControlService.IsHiveConnected(request.HiveID); + if (isHiveConnected) { - Timestamp = telemetryUpdateTimestamp - }; + var telemetryUpdateTimestamp = await _communicationControlService.AddTelemetry(hiveTelemetryModel); + var telemetryResponse = new HiveTelemetryResponse + { + Timestamp = telemetryUpdateTimestamp + }; - return Ok(telemetryResponse); + return Ok(telemetryResponse); + } + else + { + _logger.LogWarning("Failed to write telemetry. Hive with HiveID: {hiveId} is not connected. Request: {@request}", request.HiveID, request); + return NotFound($"Failed to write telemetry. Hive with HiveID: {request.HiveID} is not connected"); + } } } diff --git a/src/CommunicationControl/DevOpsProject/DI/LogicConfiguration.cs b/src/CommunicationControl/DevOpsProject/DI/LogicConfiguration.cs index e5bfa63..e55cf46 100644 --- a/src/CommunicationControl/DevOpsProject/DI/LogicConfiguration.cs +++ b/src/CommunicationControl/DevOpsProject/DI/LogicConfiguration.cs @@ -12,7 +12,5 @@ namespace DevOpsProject.CommunicationControl.API.DI return serviceCollection; } - - } }