From 84a72a8557b80e657d46c335101e170ee4415e46 Mon Sep 17 00:00:00 2001 From: ThompsonNye Date: Mon, 21 Jul 2025 20:58:45 +0200 Subject: [PATCH] Add more logging and trace parameters --- src/Vegasco.Server.Api/Cars/CreateCar.cs | 32 ++++++++++++++----- src/Vegasco.Server.Api/Cars/DeleteCar.cs | 4 +++ src/Vegasco.Server.Api/Cars/GetCars.cs | 7 +++- src/Vegasco.Server.Api/Cars/UpdateCar.cs | 17 +++++++++- .../Consumptions/CreateConsumption.cs | 14 ++++++++ .../Consumptions/DeleteConsumptions.cs | 4 +++ .../Consumptions/GetConsumptions.cs | 9 ++++++ .../Consumptions/UpdateConsumption.cs | 13 ++++++++ 8 files changed, 90 insertions(+), 10 deletions(-) diff --git a/src/Vegasco.Server.Api/Cars/CreateCar.cs b/src/Vegasco.Server.Api/Cars/CreateCar.cs index aac0d7b..9766734 100644 --- a/src/Vegasco.Server.Api/Cars/CreateCar.cs +++ b/src/Vegasco.Server.Api/Cars/CreateCar.cs @@ -39,19 +39,41 @@ public static class CreateCar IEnumerable> validators, ApplicationDbContext dbContext, UserAccessor userAccessor, + ILoggerFactory loggerFactory, CancellationToken cancellationToken) { + ILogger logger = loggerFactory.CreateLogger(nameof(CreateCar)); + List failedValidations = await validators.ValidateAllAsync(request, cancellationToken: cancellationToken); if (failedValidations.Count > 0) { + logger.LogDebug( + "Validation failed for request {@Request} with errors {@Errors}", + request, + failedValidations + .Where(x => !x.IsValid) + .SelectMany(x => x.Errors) + .Select(x => x.ErrorMessage)); + return TypedResults.BadRequest(new HttpValidationProblemDetails(failedValidations.ToCombinedDictionary())); } + bool isDuplicate = await dbContext.Cars + .AnyAsync(x => x.Name.ToUpper() == request.Name.ToUpper(), cancellationToken); + + if (isDuplicate) + { + logger.LogDebug("Car with name '{CarName}' (case insensitive) already exists", request.Name); + return TypedResults.Conflict(); + } + string userId = userAccessor.GetUserId(); User? user = await dbContext.Users.FindAsync([userId], cancellationToken: cancellationToken); if (user is null) { + logger.LogDebug("User with ID '{UserId}' not found, creating new user", userId); + user = new User { Id = userId @@ -65,17 +87,11 @@ public static class CreateCar UserId = userId }; - bool isDuplicate = await dbContext.Cars - .AnyAsync(x => x.Name.ToUpper() == request.Name.ToUpper(), cancellationToken); - - if (isDuplicate) - { - return TypedResults.Conflict(); - } - await dbContext.Cars.AddAsync(car, cancellationToken); await dbContext.SaveChangesAsync(cancellationToken); + logger.LogTrace("Created new car: {@Car}", car); + Response response = new(car.Id.Value, car.Name); return TypedResults.Created($"/v1/cars/{car.Id}", response); } diff --git a/src/Vegasco.Server.Api/Cars/DeleteCar.cs b/src/Vegasco.Server.Api/Cars/DeleteCar.cs index 3dd1f26..07a6b94 100644 --- a/src/Vegasco.Server.Api/Cars/DeleteCar.cs +++ b/src/Vegasco.Server.Api/Cars/DeleteCar.cs @@ -1,4 +1,5 @@ using Microsoft.EntityFrameworkCore; +using System.Diagnostics; using Vegasco.Server.Api.Persistence; namespace Vegasco.Server.Api.Cars; @@ -21,6 +22,9 @@ public static class DeleteCar ILoggerFactory loggerFactory, CancellationToken cancellationToken) { + Activity? activity = Activity.Current; + activity?.SetTag("id", id); + int rows = await dbContext.Cars .Where(x => x.Id == new CarId(id)) .ExecuteDeleteAsync(cancellationToken); diff --git a/src/Vegasco.Server.Api/Cars/GetCars.cs b/src/Vegasco.Server.Api/Cars/GetCars.cs index 5a1ed2a..12a2977 100644 --- a/src/Vegasco.Server.Api/Cars/GetCars.cs +++ b/src/Vegasco.Server.Api/Cars/GetCars.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using System.Diagnostics; using Vegasco.Server.Api.Persistence; namespace Vegasco.Server.Api.Cars; @@ -34,11 +35,15 @@ public static class GetCars ApplicationDbContext dbContext, CancellationToken cancellationToken) { + Activity? activity = Activity.Current; + List cars = await dbContext.Cars .Select(x => new ResponseDto(x.Id.Value, x.Name)) .ToListAsync(cancellationToken); - ApiResponse response = new ApiResponse + activity?.SetTag("carCount", cars.Count); + + ApiResponse response = new() { Cars = cars }; diff --git a/src/Vegasco.Server.Api/Cars/UpdateCar.cs b/src/Vegasco.Server.Api/Cars/UpdateCar.cs index e857eb9..187b1b0 100644 --- a/src/Vegasco.Server.Api/Cars/UpdateCar.cs +++ b/src/Vegasco.Server.Api/Cars/UpdateCar.cs @@ -10,6 +10,7 @@ namespace Vegasco.Server.Api.Cars; public static class UpdateCar { public record Request(string Name); + public record Response(Guid Id, string Name); public static RouteHandlerBuilder MapEndpoint(IEndpointRouteBuilder builder) @@ -40,11 +41,22 @@ public static class UpdateCar IEnumerable> validators, ApplicationDbContext dbContext, UserAccessor userAccessor, + ILoggerFactory loggerFactory, CancellationToken cancellationToken) { + var logger = loggerFactory.CreateLogger(nameof(UpdateCar)); + List failedValidations = await validators.ValidateAllAsync(request, cancellationToken); if (failedValidations.Count > 0) { + logger.LogDebug( + "Validation failed for request {@Request} with errors {@Errors}", + request, + failedValidations + .Where(x => !x.IsValid) + .SelectMany(x => x.Errors) + .Select(x => x.ErrorMessage)); + return TypedResults.BadRequest(new HttpValidationProblemDetails(failedValidations.ToCombinedDictionary())); } @@ -60,13 +72,16 @@ public static class UpdateCar if (isDuplicate) { + logger.LogDebug("Car with name '{CarName}' (case insensitive) already exists", request.Name); return TypedResults.Conflict(); } car.Name = request.Name.Trim(); await dbContext.SaveChangesAsync(cancellationToken); + logger.LogTrace("Updated car: {@Car}", car); + Response response = new(car.Id.Value, car.Name); return TypedResults.Ok(response); } -} +} \ No newline at end of file diff --git a/src/Vegasco.Server.Api/Consumptions/CreateConsumption.cs b/src/Vegasco.Server.Api/Consumptions/CreateConsumption.cs index 9b236d3..8e1e9f7 100644 --- a/src/Vegasco.Server.Api/Consumptions/CreateConsumption.cs +++ b/src/Vegasco.Server.Api/Consumptions/CreateConsumption.cs @@ -1,5 +1,6 @@ using FluentValidation; using FluentValidation.Results; +using System.Diagnostics; using Vegasco.Server.Api.Cars; using Vegasco.Server.Api.Common; using Vegasco.Server.Api.Persistence; @@ -49,11 +50,22 @@ public static class CreateConsumption ApplicationDbContext dbContext, Request request, IEnumerable> validators, + ILoggerFactory loggerFactory, CancellationToken cancellationToken) { + ILogger logger = loggerFactory.CreateLogger(nameof(CreateConsumption)); + List failedValidations = await validators.ValidateAllAsync(request, cancellationToken); if (failedValidations.Count > 0) { + logger.LogDebug( + "Validation failed for request {@Request} with errors {@Errors}", + request, + failedValidations + .Where(x => !x.IsValid) + .SelectMany(x => x.Errors) + .Select(x => x.ErrorMessage)); + return TypedResults.BadRequest(new HttpValidationProblemDetails(failedValidations.ToCombinedDictionary())); } @@ -74,6 +86,8 @@ public static class CreateConsumption dbContext.Consumptions.Add(consumption); await dbContext.SaveChangesAsync(cancellationToken); + logger.LogTrace("Created new consumption: {@Consumption}", consumption); + return TypedResults.Created($"consumptions/{consumption.Id.Value}", new Response(consumption.Id.Value, consumption.DateTime, consumption.Distance, consumption.Amount, consumption.CarId.Value)); diff --git a/src/Vegasco.Server.Api/Consumptions/DeleteConsumptions.cs b/src/Vegasco.Server.Api/Consumptions/DeleteConsumptions.cs index 48dae75..0d0e088 100644 --- a/src/Vegasco.Server.Api/Consumptions/DeleteConsumptions.cs +++ b/src/Vegasco.Server.Api/Consumptions/DeleteConsumptions.cs @@ -1,4 +1,5 @@ using Microsoft.EntityFrameworkCore; +using System.Diagnostics; using Vegasco.Server.Api.Persistence; namespace Vegasco.Server.Api.Consumptions; @@ -21,6 +22,9 @@ public static class DeleteConsumption ILoggerFactory loggerFactory, CancellationToken cancellationToken) { + Activity? activity = Activity.Current; + activity?.SetTag("id", id); + int rows = await dbContext.Consumptions .Where(x => x.Id == new ConsumptionId(id)) .ExecuteDeleteAsync(cancellationToken); diff --git a/src/Vegasco.Server.Api/Consumptions/GetConsumptions.cs b/src/Vegasco.Server.Api/Consumptions/GetConsumptions.cs index 37b1169..4231f22 100644 --- a/src/Vegasco.Server.Api/Consumptions/GetConsumptions.cs +++ b/src/Vegasco.Server.Api/Consumptions/GetConsumptions.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using System.Diagnostics; using Vegasco.Server.Api.Cars; using Vegasco.Server.Api.Persistence; @@ -49,8 +50,14 @@ public static class GetConsumptions private static async Task> Endpoint( [AsParameters] Request request, ApplicationDbContext dbContext, + ILoggerFactory loggerFactory, CancellationToken cancellationToken) { + ILogger logger = loggerFactory.CreateLogger(nameof(GetConsumptions)); + + logger.LogTrace("Received request to get consumptions with parameters: {@Request}", request); + Activity? activity = Activity.Current; + Dictionary> consumptionsByCar = await dbContext.Consumptions .Include(x => x.Car) .GroupBy(x => x.CarId) @@ -83,6 +90,8 @@ public static class GetConsumptions literPer100Km)); } } + + activity?.SetTag("consumptionCount", responses.Count); ApiResponse apiResponse = new() { diff --git a/src/Vegasco.Server.Api/Consumptions/UpdateConsumption.cs b/src/Vegasco.Server.Api/Consumptions/UpdateConsumption.cs index 80553c2..40ab556 100644 --- a/src/Vegasco.Server.Api/Consumptions/UpdateConsumption.cs +++ b/src/Vegasco.Server.Api/Consumptions/UpdateConsumption.cs @@ -48,11 +48,22 @@ public static class UpdateConsumption Guid id, Request request, IEnumerable> validators, + ILoggerFactory loggerFactory, CancellationToken cancellationToken) { + ILogger logger = loggerFactory.CreateLogger(nameof(UpdateConsumption)); + List failedValidations = await validators.ValidateAllAsync(request, cancellationToken); if (failedValidations.Count > 0) { + logger.LogDebug( + "Validation failed for request {@Request} with errors {@Errors}", + request, + failedValidations + .Where(x => !x.IsValid) + .SelectMany(x => x.Errors) + .Select(x => x.ErrorMessage)); + return TypedResults.BadRequest(new HttpValidationProblemDetails(failedValidations.ToCombinedDictionary())); } @@ -68,6 +79,8 @@ public static class UpdateConsumption await dbContext.SaveChangesAsync(cancellationToken); + logger.LogTrace("Updated consumption: {@Consumption}", consumption); + return TypedResults.Ok(new Response(consumption.Id.Value, consumption.DateTime, consumption.Distance, consumption.Amount, consumption.CarId.Value)); } } \ No newline at end of file -- 2.49.1