fix: ajustes diversos
This commit is contained in:
parent
49da9f874a
commit
5ba0d62595
20
.github/workflows/deploy.yml
vendored
20
.github/workflows/deploy.yml
vendored
@ -104,7 +104,6 @@ jobs:
|
|||||||
--restart unless-stopped \
|
--restart unless-stopped \
|
||||||
-p 5000:8080 \
|
-p 5000:8080 \
|
||||||
--add-host=host.docker.internal:host-gateway \
|
--add-host=host.docker.internal:host-gateway \
|
||||||
-e Serilog__SeqUrl="http://host.docker.internal:5343" \
|
|
||||||
-e ASPNETCORE_ENVIRONMENT=Staging \
|
-e ASPNETCORE_ENVIRONMENT=Staging \
|
||||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:develop
|
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:develop
|
||||||
EOF
|
EOF
|
||||||
@ -127,7 +126,6 @@ jobs:
|
|||||||
--restart unless-stopped \
|
--restart unless-stopped \
|
||||||
-p 5000:8080 \
|
-p 5000:8080 \
|
||||||
--add-host=host.docker.internal:host-gateway \
|
--add-host=host.docker.internal:host-gateway \
|
||||||
-e Serilog__SeqUrl="http://host.docker.internal:5342" \
|
|
||||||
-e ASPNETCORE_ENVIRONMENT=Staging \
|
-e ASPNETCORE_ENVIRONMENT=Staging \
|
||||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:develop
|
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:develop
|
||||||
EOF
|
EOF
|
||||||
@ -172,14 +170,19 @@ jobs:
|
|||||||
# Puxa nova imagem
|
# Puxa nova imagem
|
||||||
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
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
|
# Executa novo container
|
||||||
docker run -d \
|
docker run -d \
|
||||||
--name qrrapido-prod \
|
--name qrrapido-prod \
|
||||||
--restart unless-stopped \
|
--restart unless-stopped \
|
||||||
-p 5001:8080 \
|
--network host \
|
||||||
-v /app/keys:/app/keys \
|
-v /app/keys:/app/keys \
|
||||||
-e ASPNETCORE_ENVIRONMENT=Production \
|
-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
|
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
||||||
|
|
||||||
# Recarrega NGINX para garantir que está apontando para o novo container
|
# Recarrega NGINX para garantir que está apontando para o novo container
|
||||||
@ -198,14 +201,19 @@ jobs:
|
|||||||
# Puxa nova imagem
|
# Puxa nova imagem
|
||||||
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
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
|
# Executa novo container
|
||||||
docker run -d \
|
docker run -d \
|
||||||
--name qrrapido-prod \
|
--name qrrapido-prod \
|
||||||
--restart unless-stopped \
|
--restart unless-stopped \
|
||||||
-p 5001:8080 \
|
--network host \
|
||||||
-v /app/keys:/app/keys \
|
-v /app/keys:/app/keys \
|
||||||
-e ASPNETCORE_ENVIRONMENT=Production \
|
-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
|
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -352,6 +352,7 @@ MigrationBackup/
|
|||||||
FodyWeavers.xsd
|
FodyWeavers.xsd
|
||||||
|
|
||||||
# Custom
|
# Custom
|
||||||
|
keys/
|
||||||
appsettings.Local.json
|
appsettings.Local.json
|
||||||
appsettings.Production.json
|
appsettings.Production.json
|
||||||
*.Development.json
|
*.Development.json
|
||||||
|
|||||||
@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace QRRapidoApp.Controllers
|
namespace QRRapidoApp.Controllers
|
||||||
{
|
{
|
||||||
@ -14,7 +15,7 @@ namespace QRRapidoApp.Controllers
|
|||||||
private readonly ILogger<HealthController> _logger;
|
private readonly ILogger<HealthController> _logger;
|
||||||
private readonly string _applicationName;
|
private readonly string _applicationName;
|
||||||
private readonly string _version;
|
private readonly string _version;
|
||||||
private static readonly DateTime _startTime = DateTime.UtcNow;
|
private static readonly DateTime _startTime = System.Diagnostics.Process.GetCurrentProcess().StartTime.ToUniversalTime();
|
||||||
|
|
||||||
public HealthController(
|
public HealthController(
|
||||||
HealthCheckService healthCheckService,
|
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
|
// For Uptime Kuma, we want to return 200 OK for healthy/degraded and 503 for unhealthy
|
||||||
var statusCode = overallStatus == "unhealthy" ? 503 : 200;
|
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
|
var response = new
|
||||||
{
|
{
|
||||||
status = overallStatus,
|
status = overallStatus,
|
||||||
application = _applicationName,
|
application = _applicationName,
|
||||||
version = _version,
|
version = _version,
|
||||||
timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"),
|
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
|
// Include critical metrics for monitoring
|
||||||
metrics = new
|
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);
|
return StatusCode(statusCode, response);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
67
Program.cs
67
Program.cs
@ -17,6 +17,7 @@ using Stripe;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
|
using Serilog.Sinks.OpenSearch;
|
||||||
using Serilog.Sinks.SystemConsole.Themes;
|
using Serilog.Sinks.SystemConsole.Themes;
|
||||||
using Microsoft.AspNetCore.Mvc.Razor;
|
using Microsoft.AspNetCore.Mvc.Razor;
|
||||||
using Microsoft.AspNetCore.HttpOverrides;
|
using Microsoft.AspNetCore.HttpOverrides;
|
||||||
@ -25,23 +26,71 @@ using Microsoft.AspNetCore.RateLimiting;
|
|||||||
using System.Threading.RateLimiting;
|
using System.Threading.RateLimiting;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
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
|
// Configure Serilog
|
||||||
Log.Logger = new LoggerConfiguration()
|
var loggerConfig = new LoggerConfiguration()
|
||||||
.ReadFrom.Configuration(builder.Configuration)
|
.ReadFrom.Configuration(builder.Configuration)
|
||||||
.Enrich.FromLogContext()
|
.Enrich.FromLogContext()
|
||||||
.Enrich.WithEnvironmentName()
|
.Enrich.WithEnvironmentName()
|
||||||
.Enrich.WithProcessId()
|
.Enrich.WithProcessId()
|
||||||
.Enrich.WithThreadId()
|
.Enrich.WithThreadId()
|
||||||
.Enrich.WithProperty("ApplicationName", builder.Configuration["ApplicationName"] ?? "QRRapido")
|
.Enrich.WithProperty("ApplicationName", builder.Configuration["ApplicationName"] ?? "QRRapido")
|
||||||
.Enrich.WithProperty("Environment", "Dev")
|
.Enrich.WithProperty("Environment", builder.Environment.EnvironmentName)
|
||||||
.WriteTo.Async(a => a.Console(
|
.WriteTo.Async(a => a.Console(
|
||||||
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}",
|
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}",
|
||||||
theme: AnsiConsoleTheme.Code))
|
theme: AnsiConsoleTheme.Code));
|
||||||
.WriteTo.Async(a => a.Seq(builder.Configuration["Serilog:SeqUrl"],
|
|
||||||
apiKey: builder.Configuration["Serilog:ApiKey"]=="" ? null : builder.Configuration["Serilog:ApiKey"]))
|
var openSearchUrl = builder.Configuration["Serilog:OpenSearchUrl"];
|
||||||
.CreateLogger();
|
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();
|
builder.Host.UseSerilog();
|
||||||
|
|
||||||
@ -89,8 +138,10 @@ builder.Services.AddMemoryCache();
|
|||||||
builder.Services.AddSingleton<IDistributedCache, MemoryDistributedCacheWrapper>();
|
builder.Services.AddSingleton<IDistributedCache, MemoryDistributedCacheWrapper>();
|
||||||
|
|
||||||
// ✅ DataProtection compartilhado via FileSystem (ADICIONAR APÓS O CACHE)
|
// ✅ DataProtection compartilhado via FileSystem (ADICIONAR APÓS O CACHE)
|
||||||
|
var keysDirectory = Path.Combine(Directory.GetCurrentDirectory(), "keys");
|
||||||
|
Directory.CreateDirectory(keysDirectory);
|
||||||
builder.Services.AddDataProtection()
|
builder.Services.AddDataProtection()
|
||||||
.PersistKeysToFileSystem(new DirectoryInfo("/app/keys"))
|
.PersistKeysToFileSystem(new DirectoryInfo(keysDirectory))
|
||||||
.SetApplicationName("QRRapido");
|
.SetApplicationName("QRRapido");
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
<PackageReference Include="Serilog.Enrichers.Thread" Version="4.0.0" />
|
<PackageReference Include="Serilog.Enrichers.Thread" Version="4.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Async" Version="2.1.0" />
|
<PackageReference Include="Serilog.Sinks.Async" Version="2.1.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.1-dev-00953" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.1-dev-00953" />
|
||||||
<PackageReference Include="Serilog.Sinks.Seq" Version="9.0.0" />
|
<PackageReference Include="Serilog.Sinks.OpenSearch" Version="1.3.0" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.6" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.6" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.4" />
|
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.4" />
|
||||||
<PackageReference Include="Stripe.net" Version="48.4.0" />
|
<PackageReference Include="Stripe.net" Version="48.4.0" />
|
||||||
|
|||||||
@ -137,22 +137,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
<div class="d-grid opacity-controlled disabled-state" id="next-button-group">
|
|
||||||
<button type="button" class="btn btn-success" id="next-btn">
|
|
||||||
<i class="fas fa-arrow-right"></i> Personalizar
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
<div class="d-grid opacity-controlled disabled-state" id="button-gerar-quick-div">
|
|
||||||
<button type="submit" class="btn btn-primary" id="generate-quick-btn">
|
|
||||||
<i class="fas fa-qrcode"></i> Gerar Rápido
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Dynamic QR Section (Premium) -->
|
<!-- Dynamic QR Section (Premium) -->
|
||||||
<div id="dynamic-qr-section" style="display: none;" class="opacity-controlled disabled-state">
|
<div id="dynamic-qr-section" style="display: none;" class="opacity-controlled disabled-state">
|
||||||
@ -520,6 +504,24 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Navigation Buttons (Global - appears for all QR types) -->
|
||||||
|
<div class="row mb-4 opacity-controlled disabled-state" id="navigation-buttons">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<div class="d-grid opacity-controlled disabled-state" id="next-button-group">
|
||||||
|
<button type="button" class="btn btn-success" id="next-btn">
|
||||||
|
<i class="fas fa-arrow-right"></i> Personalizar
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<div class="d-grid opacity-controlled disabled-state" id="button-gerar-quick-div">
|
||||||
|
<button type="submit" class="btn btn-primary" id="generate-quick-btn">
|
||||||
|
<i class="fas fa-qrcode"></i> Gerar Rápido
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Advanced customization (collapsible) -->
|
<!-- Advanced customization (collapsible) -->
|
||||||
<div class="accordion mb-3 opacity-controlled disabled-state" id="customization-accordion">
|
<div class="accordion mb-3 opacity-controlled disabled-state" id="customization-accordion">
|
||||||
<div class="accordion-item">
|
<div class="accordion-item">
|
||||||
@ -1305,6 +1307,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
new SimpleOpacityController('#qr-type', '#wifi-interface');
|
new SimpleOpacityController('#qr-type', '#wifi-interface');
|
||||||
new SimpleOpacityController('#qr-type', '#sms-interface');
|
new SimpleOpacityController('#qr-type', '#sms-interface');
|
||||||
new SimpleOpacityController('#qr-type', '#email-interface');
|
new SimpleOpacityController('#qr-type', '#email-interface');
|
||||||
|
new SimpleOpacityController('#qr-type', '#navigation-buttons');
|
||||||
new SimpleOpacityController('#qr-type', '#customization-accordion');
|
new SimpleOpacityController('#qr-type', '#customization-accordion');
|
||||||
new SimpleOpacityController('#qr-type', '#button-gerar-div');
|
new SimpleOpacityController('#qr-type', '#button-gerar-div');
|
||||||
|
|
||||||
|
|||||||
@ -59,8 +59,7 @@
|
|||||||
"ApplicationName": "QRRapido",
|
"ApplicationName": "QRRapido",
|
||||||
"Environment": "Personal",
|
"Environment": "Personal",
|
||||||
"Serilog": {
|
"Serilog": {
|
||||||
"SeqUrl": "http://172.17.0.1:5341",
|
"OpenSearchUrl": "http://localhost:9200",
|
||||||
"ApiKey": "",
|
|
||||||
"MinimumLevel": {
|
"MinimumLevel": {
|
||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
"Override": {
|
"Override": {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user