Added Serilog and extended logging, support for grafana loki (use Loki config key to set loki url)

This commit is contained in:
Mia Rose Winter 2024-04-09 17:11:05 +02:00
parent 61e31ec2e1
commit cdd1490801
Signed by: miawinter
GPG key ID: 4B6F6A83178F595E
8 changed files with 106 additions and 39 deletions

View file

@ -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, " +

View file

@ -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>

View file

@ -1,9 +1,2 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.EntityFrameworkCore": "Information"
}
}
}

View file

@ -1,10 +1,3 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.EntityFrameworkCore": "Warning"
}
},
"AllowedHosts": "*"
}

8
Wave/log Normal file
View 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

View file

@ -15,5 +15,6 @@
</None>
<None Include="docker-compose.yml" />
<None Include=".dockerignore" />
<None Include="provisioning\datasources\auomatic.yml" />
</ItemGroup>
</Project>

View file

@ -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:

View 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