From fa422ef6858a2444c72c5f35d8a70ae451a40841 Mon Sep 17 00:00:00 2001 From: Ricardo Carneiro Date: Mon, 8 Sep 2025 19:19:18 -0300 Subject: [PATCH] =?UTF-8?q?fix:=20for=C3=A7ar=20log=20no=20webhook=20e=20n?= =?UTF-8?q?o=20program.cs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BCards.Web/Program.cs | 131 +++++++++++++++----------------------- 1 file changed, 53 insertions(+), 78 deletions(-) diff --git a/src/BCards.Web/Program.cs b/src/BCards.Web/Program.cs index 9b2eac6..6f8bf67 100644 --- a/src/BCards.Web/Program.cs +++ b/src/BCards.Web/Program.cs @@ -51,80 +51,60 @@ if (isDevelopment) .MinimumLevel.Override("Microsoft.AspNetCore.Routing", LogEventLevel.Information) .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) .MinimumLevel.Override("System", LogEventLevel.Warning) + // Console sempre ativo - logs garantidos .WriteTo.Console( - restrictedToMinimumLevel: LogEventLevel.Information, - outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] [{Hostname}] {Message:lj} {Properties:j}{NewLine}{Exception}"); + restrictedToMinimumLevel: LogEventLevel.Debug, + outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}") + // Arquivo local com rotação para Docker logs não ficarem enormes + .WriteTo.File( + "./logs/bcards-dev-.log", + rollingInterval: RollingInterval.Day, + retainedFileCountLimit: 2, // Só 2 dias como você quer + restrictedToMinimumLevel: LogEventLevel.Debug, + outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}"); var openSearchUrl = builder.Configuration["Serilog:OpenSearchUrl"]; if (!string.IsNullOrEmpty(openSearchUrl)) { var indexFormat = "b-cards-dev-{0:yyyy-MM}"; - Console.WriteLine($"[DEBUG] Configurando OpenSearch HTTP (SEM AUTENTICAÇÃO):"); - Console.WriteLine($"[DEBUG] URL: {openSearchUrl}"); - Console.WriteLine($"[DEBUG] Index Format: {indexFormat}"); - Console.WriteLine($"[DEBUG] Protocol: {(openSearchUrl.StartsWith("https") ? "HTTPS" : "HTTP")}"); - try { - loggerConfig.WriteTo.OpenSearch(new OpenSearchSinkOptions(new Uri(openSearchUrl)) + // OpenSearch configurado para ser MUITO agressivo no envio + loggerConfig.WriteTo.Async(a => a.OpenSearch(new OpenSearchSinkOptions(new Uri(openSearchUrl)) { IndexFormat = indexFormat, AutoRegisterTemplate = true, - BufferBaseFilename = "./logs/buffer", - // 🔥 REMOVIDO: BasicAuthentication - SEM AUTENTICAÇÃO + BufferBaseFilename = "./logs/opensearch-buffer", // Buffer em disco ModifyConnectionSettings = conn => conn - .RequestTimeout(TimeSpan.FromSeconds(30)) - .PingTimeout(TimeSpan.FromSeconds(10)) - .ThrowExceptions(true) - .OnRequestCompleted(details => - { - if (details.Success) - { - Console.WriteLine($"[OPENSEARCH] ✅ Request OK: {details.HttpMethod} {details.Uri} - Status: {details.HttpStatusCode}"); - } - else - { - Console.WriteLine($"[OPENSEARCH] ❌ Request FAILED: {details.HttpMethod} {details.Uri}"); - Console.WriteLine($"[OPENSEARCH] Status: {details.HttpStatusCode}"); - Console.WriteLine($"[OPENSEARCH] Exception: {details.OriginalException?.Message}"); - if (details.ResponseBodyInBytes != null && details.ResponseBodyInBytes.Length > 0) - { - var responseBody = System.Text.Encoding.UTF8.GetString(details.ResponseBodyInBytes); - Console.WriteLine($"[OPENSEARCH] Response: {responseBody}"); - } - } - }), + .RequestTimeout(TimeSpan.FromSeconds(8)) + .PingTimeout(TimeSpan.FromSeconds(4)), MinimumLogEventLevel = LogEventLevel.Debug, EmitEventFailure = EmitEventFailureHandling.WriteToSelfLog, RegisterTemplateFailure = RegisterTemplateRecovery.IndexAnyway, - BatchPostingLimit = 5, // Muito pequeno para debug - Period = TimeSpan.FromSeconds(2), - // 🔥 CORRIGIDO: Dictionary + BatchPostingLimit = 10, // Lotes pequenos = envio mais frequente + Period = TimeSpan.FromSeconds(2), // Envia a cada 2 segundos + // Configurações para máxima persistência + BufferRetainedInvalidPayloadsLimitBytes = 100 * 1024 * 1024, // 100MB buffer + BufferLogShippingInterval = TimeSpan.FromSeconds(1), // Tenta reenviar rapidamente TemplateCustomSettings = new Dictionary { {"number_of_shards", "1"}, - {"number_of_replicas", "0"}, - {"index.mapping.total_fields.limit", "2000"} + {"number_of_replicas", "0"} } - }); - - Console.WriteLine($"[DEBUG] ✅ Serilog configurado para OpenSearch HTTP!"); + }), + bufferSize: 10000, // Buffer grande na memória + blockWhenFull: false); // Nunca bloquear aplicação } - catch (Exception ex) + catch (Exception) { - Console.WriteLine($"[ERROR] ❌ Falha ao configurar OpenSearch: {ex.Message}"); - Console.WriteLine($"[ERROR] Stack trace: {ex.StackTrace}"); + // Falha silenciosa - logs continuam no console e arquivo } } - else - { - Console.WriteLine("[WARNING] OpenSearchUrl não configurada!"); - } } else { - // PRODUÇÃO: Mesma lógica sem autenticação + // PRODUÇÃO permanece igual, mas também com fallback garantido loggerConfig .MinimumLevel.Information() .MinimumLevel.Override("Microsoft.AspNetCore.Hosting.Diagnostics", LogEventLevel.Warning) @@ -132,9 +112,10 @@ else .MinimumLevel.Override("Microsoft.AspNetCore.StaticFiles", LogEventLevel.Warning) .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) .MinimumLevel.Override("System", LogEventLevel.Warning) + // 🔥 GARANTIR CONSOLE EM PRODUÇÃO TAMBÉM .WriteTo.Console( restrictedToMinimumLevel: LogEventLevel.Information, - outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3}] [{Hostname}] {Message:lj}{NewLine}{Exception}") + outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}") .WriteTo.File( "/app/logs/bcards-.log", rollingInterval: RollingInterval.Day, @@ -156,44 +137,38 @@ else var indexFormat = $"b-cards-{envMapping}-{{0:yyyy-MM}}"; - loggerConfig.WriteTo.Async(a => a.OpenSearch(new OpenSearchSinkOptions(new Uri(openSearchUrl)) + try { - IndexFormat = indexFormat, - AutoRegisterTemplate = false, - BufferBaseFilename = "./logs/buffer", - // 🔥 SEM AUTENTICAÇÃO EM PRODUÇÃO TAMBÉM - ModifyConnectionSettings = conn => conn - .RequestTimeout(TimeSpan.FromSeconds(30)) - .PingTimeout(TimeSpan.FromSeconds(10)) - .ServerCertificateValidationCallback((o, certificate, chain, errors) => true), - MinimumLogEventLevel = LogEventLevel.Information, - EmitEventFailure = EmitEventFailureHandling.WriteToSelfLog, - RegisterTemplateFailure = RegisterTemplateRecovery.IndexAnyway, - BatchPostingLimit = 50, - Period = TimeSpan.FromSeconds(5), - }), bufferSize: 10000); + loggerConfig.WriteTo.Async(a => a.OpenSearch(new OpenSearchSinkOptions(new Uri(openSearchUrl)) + { + IndexFormat = indexFormat, + AutoRegisterTemplate = false, + 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) + { + // Falha silenciosa em produção - logs continuam no console/arquivo + } } } -// 🔥 LOGS DE TESTE MAIS AGRESSIVOS +// 🔥 REMOVER OS Task.Delay E Log.CloseAndFlush desnecessários var logger = loggerConfig.CreateLogger(); Log.Logger = logger; -Console.WriteLine($"[STARTUP] {DateTime.Now:HH:mm:ss} - Testando logs SEM AUTENTICAÇÃO..."); -Log.Information("=== TESTE DE LOG SEM AUTH ==="); -Log.Information("Aplicação BCards iniciando em {Environment} no host {Hostname}", +Console.WriteLine($"[STARTUP] {DateTime.Now:HH:mm:ss} - Logger configurado"); +Log.Information("=== APLICAÇÃO INICIANDO ==="); +Log.Information("BCards iniciando em {Environment} no host {Hostname}", builder.Environment.EnvironmentName, hostname); -Log.Warning("Log de WARNING - teste OpenSearch HTTP"); -Log.Error("Log de ERROR - forçando envio imediato"); -Log.Debug("Log de DEBUG - verificando conectividade"); - -// Force flush para garantir que logs sejam enviados -//Log.CloseAndFlush(); -await Task.Delay(5000); // Aguardar mais tempo - -// Recriar logger após flush -//Log.Logger = loggerConfig.CreateLogger(); -Console.WriteLine($"[STARTUP] {DateTime.Now:HH:mm:ss} - Teste de logs concluído"); // Use Serilog for the host builder.Host.UseSerilog();