Добавил correlation id
Some checks failed
Create and publish a Docker image / Publish image (push) Failing after 1m10s

This commit is contained in:
2025-11-21 16:03:14 +03:00
parent 8ba1aea46a
commit daf3639038
5 changed files with 58 additions and 7 deletions

View File

@@ -11,7 +11,7 @@ namespace SfeduSchedule.Controllers;
[ApiController]
[Route("api/proxy")]
[EnableRateLimiting("throttle")]
public class ProxyController(ModeusService modeusService, ILogger<ScheduleController> logger) : ControllerBase
public class ProxyController(ModeusService modeusService, ILogger<ProxyController> logger) : ControllerBase
{
/// <summary>
/// Получить расписание по пользовательскому запросу.

View File

@@ -0,0 +1,34 @@
using System.Diagnostics;
namespace SfeduSchedule.Middleware;
/// <summary>
/// Middleware для добавления и обработки Correlation ID в HTTP запросах.
/// Нужно для трассировки запросов.
/// </summary>
public sealed class CorrelationIdMiddleware(RequestDelegate next, ILogger<CorrelationIdMiddleware> logger)
{
private const string HeaderName = "X-Correlation-ID";
public async Task InvokeAsync(HttpContext context)
{
// 1. Берём из заголовка, если клиент прислал
if (!context.Request.Headers.TryGetValue(HeaderName, out var correlationId) ||
string.IsNullOrWhiteSpace(correlationId))
{
// 2. Иначе используем Activity TraceId или TraceIdentifier
var activityId = Activity.Current?.TraceId.ToString();
correlationId = !string.IsNullOrEmpty(activityId)
? activityId
: context.TraceIdentifier;
}
// Положим в Items, чтобы можно было достать из сервисов
// context.Items[HeaderName] = correlationId.ToString();
// 3. Прокинем в ответ
context.Response.Headers[HeaderName] = correlationId.ToString();
await next(context);
}
}

View File

@@ -1,4 +1,5 @@
using System.Net;
using System.Diagnostics;
using System.Reflection;
using System.Threading.RateLimiting;
using Microsoft.AspNetCore.Authentication;
@@ -15,10 +16,13 @@ using SfeduSchedule.Auth;
using SfeduSchedule.Jobs;
using SfeduSchedule.Middleware;
using SfeduSchedule.Services;
using SfeduSchedule.Logging;
using X.Extensions.Logging.Telegram.Extensions;
using Microsoft.Extensions.Logging.Console;
using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;
var builder = WebApplication.CreateBuilder(args);
#region Работа с конфигурацией
var configuration = builder.Configuration;
var preinstalledJwtToken = configuration["TOKEN"];
@@ -36,15 +40,25 @@ if (string.IsNullOrEmpty(configuration["MODEUS_URL"]))
var permitLimit = int.TryParse(configuration["PERMIT_LIMIT"], out var parsedPermitLimit) ? parsedPermitLimit : 40;
var timeLimit = int.TryParse(configuration["TIME_LIMIT"], out var parsedTimeLimit) ? parsedTimeLimit : 10;
#endregion
#region Работа с папкой данных
// создать папку data если не существует
var dataDirectory = Path.Combine(AppContext.BaseDirectory, "data");
if (!Directory.Exists(dataDirectory)) Directory.CreateDirectory(dataDirectory);
GlobalConsts.JwtFilePath = Path.Combine(dataDirectory, "jwt.txt");
var pluginsPath = Path.Combine(dataDirectory, "Plugins");
#endregion
#region Работа с логированием
builder.Logging.ClearProviders();
builder.Logging.AddConsole();
// Configure the console logger to include logging scopes so TraceId from the CorrelationIdMiddleware is visible
builder.Logging.AddSimpleConsole(options =>
{
options.SingleLine = true;
options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff ";
});
builder.Logging.AddFilter("Quartz", LogLevel.Warning);
if (!string.IsNullOrEmpty(tgChatId) && !string.IsNullOrEmpty(tgToken))
builder.Logging.AddTelegram(options =>
@@ -61,6 +75,7 @@ if (!string.IsNullOrEmpty(tgChatId) && !string.IsNullOrEmpty(tgToken))
{ "Quartz", LogLevel.Warning }
};
});
#endregion
// Включаем MVC контроллеры
var mvcBuilder = builder.Services.AddControllers();
@@ -70,7 +85,7 @@ builder.Services.AddHttpClient("modeus", client =>
});
builder.Services.AddSingleton<ModeusHttpClient>();
builder.Services.AddScoped<ModeusService>();
builder.Services.AddHttpClient<ModeusHttpClient>("authClient");
builder.Services.AddHttpClient("authClient");
builder.Services.AddAuthentication()
.AddScheme<AuthenticationSchemeOptions, ApiKeyAuthenticationHandler>(
@@ -226,6 +241,9 @@ var logger = app.Services.GetRequiredService<ILogger<Program>>();
// Используем настройки из DI (Configure<ForwardedHeadersOptions>)
app.UseForwardedHeaders();
// Корреляция логов по запросам
app.UseMiddleware<CorrelationIdMiddleware>();
if (string.IsNullOrEmpty(preinstalledJwtToken))
{
var schedulerFactory = app.Services.GetRequiredService<ISchedulerFactory>();

View File

@@ -121,8 +121,7 @@ public class ModeusHttpClient
catch
{
_logger.LogWarning(
"GetGuidAsync: Не удалось получить идентификатор пользователя, {FullName}, json: {Json}", fullName,
json);
"GetGuidAsync: не удалось получить идентификатор пользователя. FullName={FullName}", fullName);
return null;
}

View File

@@ -30,7 +30,7 @@ public class ModeusService
var schedule = await GetScheduleAsync(msr);
if (schedule == null)
{
_logger.LogError("GetScheduleJsonAsync: Schedule is null. Request: {@msr}", msr);
_logger.LogError("GetScheduleJsonAsync: schedule is null. {@Request}", msr);
throw new Exception("Schedule is null");
}
@@ -189,7 +189,7 @@ public class ModeusService
var serializer = new CalendarSerializer();
var serializedCalendar = serializer.SerializeToString(calendar);
_logger.LogInformation("GetIcsAsync: Serialized calendar created. Length: {Length}",
_logger.LogInformation("GetIcsAsync: serialized calendar created. Length: {Length}",
serializedCalendar?.Length ?? 0);
return serializedCalendar;
}