From 5ba0d62595db8470028fcd00d742e6032e0665cd Mon Sep 17 00:00:00 2001 From: Ricardo Carneiro Date: Sat, 20 Sep 2025 22:46:08 -0300 Subject: [PATCH] fix: ajustes diversos --- .github/workflows/deploy.yml | 20 +++++++--- .gitignore | 1 + Controllers/HealthController.cs | 17 ++++++++- Program.cs | 67 +++++++++++++++++++++++++++++---- QRRapidoApp.csproj | 2 +- Views/Home/Index.cshtml | 35 +++++++++-------- appsettings.json | 3 +- 7 files changed, 110 insertions(+), 35 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index b29450e..9239957 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -104,7 +104,6 @@ jobs: --restart unless-stopped \ -p 5000:8080 \ --add-host=host.docker.internal:host-gateway \ - -e Serilog__SeqUrl="http://host.docker.internal:5343" \ -e ASPNETCORE_ENVIRONMENT=Staging \ ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:develop EOF @@ -127,7 +126,6 @@ jobs: --restart unless-stopped \ -p 5000:8080 \ --add-host=host.docker.internal:host-gateway \ - -e Serilog__SeqUrl="http://host.docker.internal:5342" \ -e ASPNETCORE_ENVIRONMENT=Staging \ ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:develop EOF @@ -172,14 +170,19 @@ jobs: # Puxa nova imagem docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + # Cria o diretório de chaves no host e define as permissões corretas + sudo mkdir -p /app/keys + sudo chown -R 1000:1000 /app/keys + # Executa novo container docker run -d \ --name qrrapido-prod \ --restart unless-stopped \ - -p 5001:8080 \ + --network host \ -v /app/keys:/app/keys \ -e ASPNETCORE_ENVIRONMENT=Production \ - -e ASPNETCORE_URLS=http://+:8080 \ + -e ASPNETCORE_URLS=http://+:5001 \ + -e Serilog__OpenSearchUrl="http://localhost:9201" \ ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest # Recarrega NGINX para garantir que está apontando para o novo container @@ -198,14 +201,19 @@ jobs: # Puxa nova imagem docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + # Cria o diretório de chaves no host e define as permissões corretas + sudo mkdir -p /app/keys + sudo chown -R 1000:1000 /app/keys + # Executa novo container docker run -d \ --name qrrapido-prod \ --restart unless-stopped \ - -p 5001:8080 \ + --network host \ -v /app/keys:/app/keys \ -e ASPNETCORE_ENVIRONMENT=Production \ - -e ASPNETCORE_URLS=http://+:8080 \ + -e ASPNETCORE_URLS=http://+:5001 \ + -e Serilog__OpenSearchUrl="http://localhost:9202" \ ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest EOF diff --git a/.gitignore b/.gitignore index 9bcaa5f..1fc477e 100644 --- a/.gitignore +++ b/.gitignore @@ -352,6 +352,7 @@ MigrationBackup/ FodyWeavers.xsd # Custom +keys/ appsettings.Local.json appsettings.Production.json *.Development.json diff --git a/Controllers/HealthController.cs b/Controllers/HealthController.cs index e3f96cc..6077d5c 100644 --- a/Controllers/HealthController.cs +++ b/Controllers/HealthController.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Diagnostics.HealthChecks; using System.Diagnostics; using System.Text.Json; +using System.Threading; namespace QRRapidoApp.Controllers { @@ -14,7 +15,7 @@ namespace QRRapidoApp.Controllers private readonly ILogger _logger; private readonly string _applicationName; private readonly string _version; - private static readonly DateTime _startTime = DateTime.UtcNow; + private static readonly DateTime _startTime = System.Diagnostics.Process.GetCurrentProcess().StartTime.ToUniversalTime(); public HealthController( HealthCheckService healthCheckService, @@ -228,13 +229,17 @@ namespace QRRapidoApp.Controllers // For Uptime Kuma, we want to return 200 OK for healthy/degraded and 503 for unhealthy var statusCode = overallStatus == "unhealthy" ? 503 : 200; + var uptimeMinutes = (DateTime.UtcNow - _startTime).TotalMinutes; + var memoryBytes = GC.GetTotalMemory(false); + var memoryMB = memoryBytes / 1024.0 / 1024.0; + var response = new { status = overallStatus, application = _applicationName, version = _version, timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"), - uptime = $"{(DateTime.UtcNow - _startTime).TotalHours:F1}h", + uptime = System.FormattableString.Invariant($"{(DateTime.UtcNow - _startTime).TotalHours:F1}h"), // Include critical metrics for monitoring metrics = new { @@ -245,6 +250,14 @@ namespace QRRapidoApp.Controllers } }; + _logger.LogInformation("[HEALTH] Memory: {memoryBytes} MemoryMB: {memoryMB} ThreadPool: {threadPool} ProcessId: {processId} ActiveConnections: {activeConnections} UptimeMinutes: {uptimeMinutes}", + memoryBytes, + memoryMB, + ThreadPool.ThreadCount, + Process.GetCurrentProcess().Id, + HttpContext.Connection?.Id ?? "null", + Math.Round(uptimeMinutes, 1)); + return StatusCode(statusCode, response); } catch (Exception ex) diff --git a/Program.cs b/Program.cs index 04559ca..4a07ccf 100644 --- a/Program.cs +++ b/Program.cs @@ -17,6 +17,7 @@ using Stripe; using System.Globalization; using Serilog; using Serilog.Events; +using Serilog.Sinks.OpenSearch; using Serilog.Sinks.SystemConsole.Themes; using Microsoft.AspNetCore.Mvc.Razor; using Microsoft.AspNetCore.HttpOverrides; @@ -25,23 +26,71 @@ using Microsoft.AspNetCore.RateLimiting; using System.Threading.RateLimiting; using Microsoft.AspNetCore.Server.Kestrel.Core; -var builder = WebApplication.CreateBuilder(args); +// Fix for WSL path issues - disable StaticWebAssets completely +var options = new WebApplicationOptions +{ + Args = args, + ContentRootPath = Directory.GetCurrentDirectory(), + WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot") +}; + +// Disable StaticWebAssets for WSL compatibility +Environment.SetEnvironmentVariable("ASPNETCORE_HOSTINGSTARTUP__STATICWEBASSETS__ENABLED", "false"); + +var builder = WebApplication.CreateBuilder(options); // Configure Serilog -Log.Logger = new LoggerConfiguration() +var loggerConfig = new LoggerConfiguration() .ReadFrom.Configuration(builder.Configuration) .Enrich.FromLogContext() .Enrich.WithEnvironmentName() .Enrich.WithProcessId() .Enrich.WithThreadId() .Enrich.WithProperty("ApplicationName", builder.Configuration["ApplicationName"] ?? "QRRapido") - .Enrich.WithProperty("Environment", "Dev") + .Enrich.WithProperty("Environment", builder.Environment.EnvironmentName) .WriteTo.Async(a => a.Console( outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}", - theme: AnsiConsoleTheme.Code)) - .WriteTo.Async(a => a.Seq(builder.Configuration["Serilog:SeqUrl"], - apiKey: builder.Configuration["Serilog:ApiKey"]=="" ? null : builder.Configuration["Serilog:ApiKey"])) - .CreateLogger(); + theme: AnsiConsoleTheme.Code)); + +var openSearchUrl = builder.Configuration["Serilog:OpenSearchUrl"]; +if (!string.IsNullOrEmpty(openSearchUrl)) +{ + var environment = builder.Environment.EnvironmentName.ToLower(); + var envMapping = environment switch + { + "Production" => "prod", + "Staging" => "staging", + "Development" => "dev", + _ => environment + }; + + var indexFormat = $"qrrapido-logs-{envMapping}-{{0:yyyy-MM-dd}}"; + + try + { + loggerConfig.WriteTo.Async(a => a.OpenSearch(new OpenSearchSinkOptions(new Uri(openSearchUrl)) + { + IndexFormat = indexFormat, + AutoRegisterTemplate = true, + BufferBaseFilename = "./logs/buffer", + ModifyConnectionSettings = conn => conn + .RequestTimeout(TimeSpan.FromSeconds(30)) + .PingTimeout(TimeSpan.FromSeconds(10)), + MinimumLogEventLevel = LogEventLevel.Information, + EmitEventFailure = EmitEventFailureHandling.WriteToSelfLog, + RegisterTemplateFailure = RegisterTemplateRecovery.IndexAnyway, + BatchPostingLimit = 50, + Period = TimeSpan.FromSeconds(5), + }), bufferSize: 10000, blockWhenFull: false); + } + catch (Exception ex) + { + // Fails silently, logs will continue on console. + loggerConfig.WriteTo.Console(outputTemplate: $"Error setting up OpenSearch sink: {ex.Message}"); + } +} + +Log.Logger = loggerConfig.CreateLogger(); builder.Host.UseSerilog(); @@ -89,8 +138,10 @@ builder.Services.AddMemoryCache(); builder.Services.AddSingleton(); // ✅ DataProtection compartilhado via FileSystem (ADICIONAR APÓS O CACHE) +var keysDirectory = Path.Combine(Directory.GetCurrentDirectory(), "keys"); +Directory.CreateDirectory(keysDirectory); builder.Services.AddDataProtection() - .PersistKeysToFileSystem(new DirectoryInfo("/app/keys")) + .PersistKeysToFileSystem(new DirectoryInfo(keysDirectory)) .SetApplicationName("QRRapido"); diff --git a/QRRapidoApp.csproj b/QRRapidoApp.csproj index 2205c69..7ae28e5 100644 --- a/QRRapidoApp.csproj +++ b/QRRapidoApp.csproj @@ -20,7 +20,7 @@ - + diff --git a/Views/Home/Index.cshtml b/Views/Home/Index.cshtml index 64b491b..b34598d 100644 --- a/Views/Home/Index.cshtml +++ b/Views/Home/Index.cshtml @@ -137,22 +137,6 @@ -
-
-
- -
-
-
-
- -
-
-
+ + +
@@ -1305,6 +1307,7 @@ document.addEventListener('DOMContentLoaded', function() { new SimpleOpacityController('#qr-type', '#wifi-interface'); new SimpleOpacityController('#qr-type', '#sms-interface'); new SimpleOpacityController('#qr-type', '#email-interface'); + new SimpleOpacityController('#qr-type', '#navigation-buttons'); new SimpleOpacityController('#qr-type', '#customization-accordion'); new SimpleOpacityController('#qr-type', '#button-gerar-div'); diff --git a/appsettings.json b/appsettings.json index 0d73b69..2f9d35b 100644 --- a/appsettings.json +++ b/appsettings.json @@ -59,8 +59,7 @@ "ApplicationName": "QRRapido", "Environment": "Personal", "Serilog": { - "SeqUrl": "http://172.17.0.1:5341", - "ApiKey": "", + "OpenSearchUrl": "http://localhost:9200", "MinimumLevel": { "Default": "Information", "Override": {