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.Middleware;
|
||||||
using DigitalData.TaskFlow.API.Options;
|
using DigitalData.TaskFlow.API.Options;
|
||||||
using DigitalData.TaskFlow.Infrastructure;
|
using DigitalData.TaskFlow.Infrastructure;
|
||||||
using Microsoft.OpenApi;
|
using Microsoft.OpenApi.Models;
|
||||||
using Scalar.AspNetCore;
|
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 tempConfig = new ConfigurationBuilder()
|
||||||
var config = builder.Configuration;
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: false)
|
||||||
|
.Build();
|
||||||
|
|
||||||
// Add services to the container.
|
var logDirectoryRaw = tempConfig.GetValue<string>("Application:LogDirectory") ?? "logs";
|
||||||
builder.Services.AddApplicationServices(config);
|
var logDirectory = Path.IsPathRooted(logDirectoryRaw)
|
||||||
builder.Services.AddInfrastructureServices(config);
|
? logDirectoryRaw
|
||||||
|
: Path.Combine(AppContext.BaseDirectory, logDirectoryRaw);
|
||||||
|
Directory.CreateDirectory(logDirectory);
|
||||||
|
var sqliteDbPath = Path.Combine(logDirectory, "logs.db");
|
||||||
|
|
||||||
builder.Services.AddControllers();
|
Log.Logger = new LoggerConfiguration()
|
||||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
.MinimumLevel.Information()
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
|
||||||
builder.Services.AddSwaggerGen(options =>
|
.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",
|
loggerConfiguration
|
||||||
Version = "v1",
|
.ReadFrom.Configuration(context.Configuration)
|
||||||
Description = "Integration API for taskFLOW workflow and document operations.",
|
.ReadFrom.Services(services)
|
||||||
Contact = new OpenApiContact
|
.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",
|
loggerConfiguration.WriteTo.Console(
|
||||||
Url = new Uri("https://digitaldata.works/"),
|
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}");
|
||||||
Email = "info-flow@digitaldata.works"
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
builder.Services
|
// Add services to the container.
|
||||||
.AddOptions<SwaggerOptions>()
|
builder.Services.AddApplicationServices(config);
|
||||||
.Bind(config.GetSection(SwaggerOptions.SectionName));
|
builder.Services.AddInfrastructureServices(config);
|
||||||
|
|
||||||
var app = builder.Build();
|
builder.Services.AddControllers();
|
||||||
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
var swaggerOptions = app.Services
|
builder.Services.AddSwaggerGen(options =>
|
||||||
.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 =>
|
|
||||||
{
|
{
|
||||||
options.Title = "DigitalData TaskFlow API";
|
options.SwaggerDoc("v1", new OpenApiInfo
|
||||||
options.Theme = ScalarTheme.BluePlanet;
|
{
|
||||||
|
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