feat(api): integrate Serilog bootstrap and in-app log viewer
This commit is contained in:
@@ -2,65 +2,145 @@ using DigitalData.TaskFlow.Application;
|
||||
using DigitalData.TaskFlow.API.Middleware;
|
||||
using DigitalData.TaskFlow.API.Options;
|
||||
using DigitalData.TaskFlow.Infrastructure;
|
||||
using Microsoft.OpenApi;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Scalar.AspNetCore;
|
||||
using Serilog;
|
||||
using Serilog.Events;
|
||||
using Serilog.Ui.Core.Extensions;
|
||||
using Serilog.Ui.SqliteDataProvider.Extensions;
|
||||
using Serilog.Ui.Web.Extensions;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
var config = builder.Configuration;
|
||||
var tempConfig = new ConfigurationBuilder()
|
||||
.SetBasePath(Directory.GetCurrentDirectory())
|
||||
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: false)
|
||||
.Build();
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddApplicationServices(config);
|
||||
builder.Services.AddInfrastructureServices(config);
|
||||
var logDirectoryRaw = tempConfig.GetValue<string>("Application:LogDirectory") ?? "logs";
|
||||
var logDirectory = Path.IsPathRooted(logDirectoryRaw)
|
||||
? logDirectoryRaw
|
||||
: Path.Combine(AppContext.BaseDirectory, logDirectoryRaw);
|
||||
Directory.CreateDirectory(logDirectory);
|
||||
var sqliteDbPath = Path.Combine(logDirectory, "logs.db");
|
||||
|
||||
builder.Services.AddControllers();
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen(options =>
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.MinimumLevel.Information()
|
||||
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
|
||||
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
|
||||
.MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning)
|
||||
.MinimumLevel.Override("System", LogEventLevel.Warning)
|
||||
.Enrich.FromLogContext()
|
||||
.WriteTo.File(
|
||||
path: Path.Combine(logDirectory, "taskflow-.log"),
|
||||
rollingInterval: RollingInterval.Day,
|
||||
retainedFileCountLimit: 30,
|
||||
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
|
||||
.WriteTo.SQLite(sqliteDbPath, storeTimestampInUtc: true)
|
||||
.CreateBootstrapLogger();
|
||||
|
||||
try
|
||||
{
|
||||
options.SwaggerDoc("v1", new OpenApiInfo
|
||||
Log.Information("Starting TaskFlow API");
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
var config = builder.Configuration;
|
||||
|
||||
builder.Host.UseSerilog((context, services, loggerConfiguration) =>
|
||||
{
|
||||
Title = "DigitalData TaskFlow API",
|
||||
Version = "v1",
|
||||
Description = "Integration API for taskFLOW workflow and document operations.",
|
||||
Contact = new OpenApiContact
|
||||
loggerConfiguration
|
||||
.ReadFrom.Configuration(context.Configuration)
|
||||
.ReadFrom.Services(services)
|
||||
.Enrich.FromLogContext()
|
||||
.WriteTo.File(
|
||||
path: Path.Combine(logDirectory, "taskflow-.log"),
|
||||
rollingInterval: RollingInterval.Day,
|
||||
retainedFileCountLimit: 30,
|
||||
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
|
||||
.WriteTo.SQLite(sqliteDbPath, storeTimestampInUtc: true);
|
||||
|
||||
if (context.HostingEnvironment.IsDevelopment())
|
||||
{
|
||||
Name = "Digital Data GmbH",
|
||||
Url = new Uri("https://digitaldata.works/"),
|
||||
Email = "info-flow@digitaldata.works"
|
||||
loggerConfiguration.WriteTo.Console(
|
||||
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
builder.Services
|
||||
.AddOptions<SwaggerOptions>()
|
||||
.Bind(config.GetSection(SwaggerOptions.SectionName));
|
||||
// Add services to the container.
|
||||
builder.Services.AddApplicationServices(config);
|
||||
builder.Services.AddInfrastructureServices(config);
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
var swaggerOptions = app.Services
|
||||
.GetRequiredService<Microsoft.Extensions.Options.IOptions<SwaggerOptions>>()
|
||||
.Value;
|
||||
|
||||
var enableSwagger = app.Environment.IsDevelopment() || swaggerOptions.EnabledInProduction;
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
app.UseMiddleware<ExceptionHandlingMiddleware>();
|
||||
|
||||
if (enableSwagger)
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
app.MapScalarApiReference(options =>
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen(options =>
|
||||
{
|
||||
options.Title = "DigitalData TaskFlow API";
|
||||
options.Theme = ScalarTheme.BluePlanet;
|
||||
options.SwaggerDoc("v1", new OpenApiInfo
|
||||
{
|
||||
Title = "DigitalData TaskFlow API",
|
||||
Version = "v1",
|
||||
Description = """
|
||||
Integration API for taskFLOW workflow and document operations.
|
||||
|
||||
---
|
||||
|
||||
- [Serilog Log Viewer](/serilog-ui)
|
||||
""",
|
||||
Contact = new OpenApiContact
|
||||
{
|
||||
Name = "Digital Data GmbH",
|
||||
Url = new Uri("https://digitaldata.works/"),
|
||||
Email = "info-flow@digitaldata.works"
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
builder.Services
|
||||
.AddOptions<SwaggerOptions>()
|
||||
.Bind(config.GetSection(SwaggerOptions.SectionName));
|
||||
|
||||
builder.Services.AddSerilogUi(options =>
|
||||
{
|
||||
options.UseSqliteServer(databaseOptions =>
|
||||
{
|
||||
databaseOptions.WithConnectionString($"Data Source={sqliteDbPath}");
|
||||
databaseOptions.WithTable("Logs");
|
||||
});
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
var swaggerOptions = app.Services
|
||||
.GetRequiredService<Microsoft.Extensions.Options.IOptions<SwaggerOptions>>()
|
||||
.Value;
|
||||
|
||||
var enableSwagger = app.Environment.IsDevelopment() || swaggerOptions.EnabledInProduction;
|
||||
|
||||
app.UseMiddleware<ExceptionHandlingMiddleware>();
|
||||
app.UseSerilogRequestLogging();
|
||||
|
||||
if (enableSwagger)
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
app.MapScalarApiReference(options =>
|
||||
{
|
||||
options.Title = "DigitalData TaskFlow API";
|
||||
options.Theme = ScalarTheme.BluePlanet;
|
||||
});
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
app.UseSerilogUi();
|
||||
app.UseAuthorization();
|
||||
app.MapControllers();
|
||||
|
||||
Log.Information("TaskFlow API started successfully");
|
||||
app.Run();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.Fatal(exception, "TaskFlow API failed to start");
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Log.CloseAndFlush();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
|
||||
Reference in New Issue
Block a user