Added Serilog and extended logging, support for grafana loki (use Loki
config key to set loki url)
This commit is contained in:
parent
61e31ec2e1
commit
cdd1490801
|
@ -19,15 +19,27 @@
|
|||
using Wave.Services;
|
||||
using Wave.Utilities;
|
||||
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||
using Serilog;
|
||||
using Serilog.Events;
|
||||
using Serilog.Sinks.Grafana.Loki;
|
||||
|
||||
#region Version Information
|
||||
|
||||
string humanReadableVersion = Assembly.GetEntryAssembly()?
|
||||
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?
|
||||
.InformationalVersion.Split("+", 2)[0] ?? "unknown";
|
||||
Console.WriteLine(@"Starting Wave " + humanReadableVersion);
|
||||
|
||||
var logMessages = new List<string>();
|
||||
#endregion
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.Enrich.FromLogContext()
|
||||
.WriteTo.Console()
|
||||
.CreateBootstrapLogger();
|
||||
var logger = Log.Logger.ForContext<Program>();
|
||||
logger.Information("Starting Wave {WaveVersion}", humanReadableVersion);
|
||||
builder.Services.AddCascadingValue("Version", _ => humanReadableVersion);
|
||||
|
||||
builder.Configuration
|
||||
.AddJsonFile(Path.Combine(FileSystemService.ConfigurationDirectory, "config.json"), true, false)
|
||||
.AddYamlFile(Path.Combine(FileSystemService.ConfigurationDirectory, "config.yml"), true, false)
|
||||
|
@ -35,7 +47,28 @@
|
|||
.AddIniFile( Path.Combine(FileSystemService.ConfigurationDirectory, "config.ini"), true, false)
|
||||
.AddXmlFile( Path.Combine(FileSystemService.ConfigurationDirectory, "config.xml"), true, false)
|
||||
.AddEnvironmentVariables("WAVE_");
|
||||
builder.Services.AddCascadingValue("Version", _ => humanReadableVersion);
|
||||
|
||||
#region Logging
|
||||
|
||||
builder.Services.AddSerilog((services, configuration) => {
|
||||
configuration
|
||||
.MinimumLevel.Verbose()
|
||||
.ReadFrom.Services(services)
|
||||
.Enrich.WithProperty("Application", "Wave")
|
||||
.Enrich.WithProperty("WaveVersion", humanReadableVersion)
|
||||
.Enrich.WithProperty("AppName",
|
||||
builder.Configuration.GetSection(nameof(Customization))[nameof(Customization.AppName)])
|
||||
.Enrich.FromLogContext();
|
||||
if (builder.Configuration["loki"] is {} lokiConfiguration) {
|
||||
configuration.WriteTo.GrafanaLoki(lokiConfiguration, null, [
|
||||
"Application", "WaveVersion", "AppName", "level", "SourceContext", "RequestId", "RequestPath"
|
||||
], restrictedToMinimumLevel:LogEventLevel.Debug);
|
||||
} else {
|
||||
configuration.WriteTo.Console(restrictedToMinimumLevel:LogEventLevel.Information);
|
||||
}
|
||||
});
|
||||
|
||||
#endregion
|
||||
|
||||
builder.Services.AddRazorComponents().AddInteractiveServerComponents();
|
||||
builder.Services.AddControllers(options => {
|
||||
|
@ -63,12 +96,12 @@
|
|||
});
|
||||
} else {
|
||||
builder.Services.AddDataProtection()
|
||||
.UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration() {
|
||||
.UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration {
|
||||
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
|
||||
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
|
||||
});
|
||||
builder.Services.AddDistributedMemoryCache();
|
||||
logMessages.Add("No Redis connection string found.");
|
||||
logger.Warning("No Redis connection string found, running in-memory.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -197,7 +230,7 @@
|
|||
builder.Services.AddScoped<IEmailSender<ApplicationUser>, IdentityEmailSender>();
|
||||
} else {
|
||||
builder.Services.AddSingleton<IEmailSender<ApplicationUser>, IdentityNoOpEmailSender>();
|
||||
logMessages.Add("No 'live' email provider configured.");
|
||||
logger.Warning("No 'live' email provider configured.");
|
||||
}
|
||||
|
||||
if (emailConfig.Smtp.Keys.Any(k => k.Equals("bulk", StringComparison.CurrentCultureIgnoreCase))) {
|
||||
|
@ -211,14 +244,17 @@
|
|||
} else {
|
||||
builder.Services.AddSingleton<IEmailService, NoOpEmailService>();
|
||||
builder.Services.AddSingleton<IEmailSender<ApplicationUser>, IdentityNoOpEmailSender>();
|
||||
logMessages.Add("No email provider configured.");
|
||||
logger.Warning("No email provider configured.");
|
||||
}
|
||||
|
||||
builder.Services.AddSingleton<IMessageDisplay, MessageService>();
|
||||
builder.Services.AddSingleton<FileSystemService>();
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Localization
|
||||
|
||||
var customization = builder.Configuration.GetSection(nameof(Customization)).Get<Customization>();
|
||||
string[] cultures = ["en-US", "en-GB", "de-DE"];
|
||||
|
||||
|
@ -232,6 +268,8 @@
|
|||
.AddSupportedUICultures(cultures);
|
||||
});
|
||||
|
||||
#endregion
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
|
@ -241,6 +279,7 @@
|
|||
app.UseExceptionHandler("/Error", createScopeForErrors: true);
|
||||
}
|
||||
|
||||
app.UseSerilogRequestLogging();
|
||||
|
||||
app.UseStaticFiles(new StaticFileOptions {
|
||||
ContentTypeProvider = new FileExtensionContentTypeProvider {
|
||||
|
@ -263,10 +302,6 @@
|
|||
|
||||
app.UseRequestLocalization();
|
||||
|
||||
foreach (string message in logMessages) {
|
||||
app.Logger.LogInformation("{message}", message);
|
||||
}
|
||||
|
||||
{
|
||||
using var scope = app.Services.CreateScope();
|
||||
await using var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
|
||||
|
@ -276,13 +311,13 @@
|
|||
if (userManager.GetUsersInRoleAsync("Admin").Result.Any() is false) {
|
||||
var cache = app.Services.GetRequiredService<IDistributedCache>();
|
||||
|
||||
// Check first wheter the password exists already
|
||||
// Check first whether the password exists already
|
||||
string? admin = await cache.GetStringAsync("admin_promote_key");
|
||||
|
||||
// If it does not exist, create a new one and save it to redis
|
||||
if (string.IsNullOrWhiteSpace(admin)){
|
||||
admin = Guid.NewGuid().ToString("N")[..16];
|
||||
await cache.SetAsync("admin_promote_key", Encoding.UTF8.GetBytes(admin), new DistributedCacheEntryOptions{});
|
||||
await cache.SetAsync("admin_promote_key", Encoding.UTF8.GetBytes(admin), new DistributedCacheEntryOptions());
|
||||
}
|
||||
|
||||
app.Logger.LogWarning("There is currently no user in your installation with the admin role, " +
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
<PackageReference Include="Mjml.Net" Version="3.8.0" />
|
||||
<PackageReference Include="NetEscapades.Configuration.Yaml" Version="3.1.0" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.Grafana.Loki" Version="8.3.0" />
|
||||
<PackageReference Include="System.ServiceModel.Syndication" Version="8.0.0" />
|
||||
<PackageReference Include="Tomlyn.Extensions.Configuration" Version="1.0.5" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -1,9 +1,2 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning",
|
||||
"Microsoft.EntityFrameworkCore": "Information"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,3 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning",
|
||||
"Microsoft.EntityFrameworkCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
8
Wave/log
Normal file
8
Wave/log
Normal file
|
@ -0,0 +1,8 @@
|
|||
2024-04-09 15:23:03.138 +02:00 [INF] Starting Wave 1.0.0
|
||||
2024-04-09 15:25:01.782 +02:00 [INF] Starting Wave 1.0.0
|
||||
2024-04-09 15:30:33.291 +02:00 [INF] Starting Wave 1.0.0
|
||||
2024-04-09 15:33:55.672 +02:00 [INF] Starting Wave 1.0.0
|
||||
2024-04-09 15:40:30.616 +02:00 [INF] Starting Wave 1.0.0
|
||||
2024-04-09 15:44:58.653 +02:00 [INF] Starting Wave 1.0.0
|
||||
2024-04-09 15:52:25.338 +02:00 [INF] Starting Wave 1.0.0
|
||||
2024-04-09 15:57:09.656 +02:00 [INF] Starting Wave 1.0.0
|
|
@ -15,5 +15,6 @@
|
|||
</None>
|
||||
<None Include="docker-compose.yml" />
|
||||
<None Include=".dockerignore" />
|
||||
<None Include="provisioning\datasources\auomatic.yml" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -16,13 +16,15 @@ services:
|
|||
- "TZ=Europe/Berlin"
|
||||
- "WAVE_ConnectionStrings__DefaultConnection=Host=db; Username=wave; Password=development; Include Error Detail=true"
|
||||
- "WAVE_ConnectionStrings__Redis=redis,password=development"
|
||||
- "WAVE_Loki=http://loki:3100"
|
||||
volumes:
|
||||
- wave-files:/app/files
|
||||
- wave-config:/configuration
|
||||
networks:
|
||||
- wave
|
||||
depends_on:
|
||||
- database
|
||||
database:
|
||||
condition: service_started
|
||||
loki:
|
||||
condition: service_healthy
|
||||
database:
|
||||
image: postgres:16.1-alpine
|
||||
restart: unless-stopped
|
||||
|
@ -32,16 +34,36 @@ services:
|
|||
- "POSTGRES_PASSWORD=development"
|
||||
volumes:
|
||||
- wave-db:/var/lib/postgresql/data
|
||||
networks:
|
||||
- wave
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
restart: unless-stopped
|
||||
command: redis-server --requirepass development --save 60 1 --loglevel warning
|
||||
volumes:
|
||||
- wave-redis:/data
|
||||
networks:
|
||||
- wave
|
||||
|
||||
loki:
|
||||
image: grafana/loki:master
|
||||
ports:
|
||||
- 3100:3100
|
||||
healthcheck:
|
||||
test: wget -q --tries=1 -O- http://localhost:3100/ready
|
||||
interval: 3s
|
||||
timeout: 3s
|
||||
retries: 10
|
||||
start_period: 10s
|
||||
grafana:
|
||||
image: grafana/grafana:master
|
||||
ports:
|
||||
- 3000:3000
|
||||
volumes:
|
||||
- ./provisioning:/etc/grafana/provisioning
|
||||
environment:
|
||||
- GF_AUTH_ANONYMOUS_ENABLED=true
|
||||
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
|
||||
- GF_AUTH_DISABLE_LOGIN_FORM=true
|
||||
depends_on:
|
||||
loki:
|
||||
condition: service_healthy
|
||||
|
||||
mailhog:
|
||||
image: mailhog/mailhog:latest
|
||||
|
@ -49,13 +71,9 @@ services:
|
|||
ports:
|
||||
- 8080:8025
|
||||
profiles: ["smtp-debug"]
|
||||
networks:
|
||||
- wave
|
||||
|
||||
volumes:
|
||||
wave-files:
|
||||
wave-config:
|
||||
wave-db:
|
||||
wave-redis:
|
||||
networks:
|
||||
wave:
|
||||
wave-redis:
|
17
provisioning/datasources/auomatic.yml
Normal file
17
provisioning/datasources/auomatic.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
apiVersion: 1
|
||||
|
||||
deleteDatasources:
|
||||
- name: Wave
|
||||
orgId: 1
|
||||
|
||||
datasources:
|
||||
- name: Wave
|
||||
type: loki
|
||||
isDefault: true
|
||||
orgId: 1
|
||||
access: proxy
|
||||
url: http://loki:3100
|
||||
editable: true
|
||||
jsonData:
|
||||
timeout: 60
|
||||
maxLines: 1000
|
Loading…
Reference in a new issue