https://ask.chadgpt.ru/share/0bede210-185a-472a-bd1b-014f239967a9
Logs, NetCore, Chadgpt
Ниже — несколько разных, компактных примеров. Сначала со стандартной консолью (Microsoft.Extensions.Logging), потом — с Serilog. Все примеры совместимы с минимальным хостом .NET 6+.
Стандартная консоль (Microsoft.Extensions.Logging)
Пример 1. Базовая настройка + использование ILogger<t>
var builder = WebApplication.CreateBuilder(args);
// Консоль + Debug, временные метки и Scopes
builder.Logging.ClearProviders();
builder.Logging.AddConsole(o =>
{
o.IncludeScopes = true;
o.TimestampFormat = "[HH:mm:ss] ";
});
builder.Logging.AddDebug();
// Общий минимум
builder.Logging.SetMinimumLevel(LogLevel.Debug);
// Фильтры фреймворка
builder.Logging.AddFilter("Microsoft", LogLevel.Information);
builder.Logging.AddFilter("Microsoft.AspNetCore", LogLevel.Warning);
builder.Logging.AddFilter("System", LogLevel.Warning);
// Ваши пространства
builder.Logging.AddFilter("TradingPlatform", LogLevel.Debug);
builder.Logging.AddFilter("BusLibrary02", LogLevel.Debug);
builder.Services.AddSingleton<PriceService>();
var app = builder.Build();
app.MapGet("/price", (PriceService svc, ILogger<Program> log) =>
{
using (log.BeginScope(new Dictionary<string, object> { ["RequestId"] = Guid.NewGuid() }))
{
log.LogInformation("Запрос цены");
var price = svc.GetPrice("BTCUSDT");
log.LogDebug("Цена получена: {Price}", price);
return Results.Ok(price);
}
});
app.Run();
public class PriceService
{
private readonly ILogger<PriceService> _log;
public PriceService(ILogger<PriceService> log) => _log = log;
public decimal GetPrice(string symbol)
{
_log.LogTrace("Начинаю вычисление цены для {Symbol}", symbol);
return 42123.45m;
}
}Пример 2. Категория-строкой, EventId и обработка исключений
var builder = WebApplication.CreateBuilder(args);
builder.Logging.ClearProviders();
builder.Logging.AddConsole();
var app = builder.Build();
var calcLogger = app.Services.GetRequiredService<ILoggerFactory>()
.CreateLogger("TradingPlatform.Calculations");
app.MapGet("/calc", () =>
{
var eventId = new EventId(1001, "CalcStarted");
calcLogger.LogInformation(eventId, "Старт вычисления");
try
{
throw new InvalidOperationException("Демо-ошибка");
}
catch (Exception ex)
{
calcLogger.LogError(ex, "Ошибка при вычислении");
}
return Results.Ok();
});
app.Run();Пример 3. Конфигурация логирования через appsettings.json
appsettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"Microsoft": "Information",
"Microsoft.AspNetCore": "Warning",
"System": "Warning",
"TradingPlatform": "Debug",
"BusLibrary02": "Debug"
}
}
}Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Logging.ClearProviders();
builder.Logging.AddConsole(o => { o.IncludeScopes = true; o.TimestampFormat = "[HH:mm:ss] "; });
builder.Logging.AddDebug();
// Минимумы и фильтры подтянутся из appsettings.json
var app = builder.Build();
app.Run();Serilog
Пример 1. Быстрый старт в коде: консоль + файл, уровни и обогащение
using Serilog;
using Serilog.Events;
var builder = WebApplication.CreateBuilder(args);
// Настройка Serilog программно
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
.Enrich.FromLogContext()
.Enrich.WithProperty("App", "TradingPlatform")
.WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] ({SourceContext}) {Message:lj}{NewLine}{Exception}")
.WriteTo.File("logs/app-.log", rollingInterval: RollingInterval.Day,
retainedFileCountLimit: 7,
restrictedToMinimumLevel: LogEventLevel.Debug)
.CreateLogger();
builder.Host.UseSerilog();
builder.Services.AddSingleton<Worker>();
var app = builder.Build();
app.MapGet("/", (Worker w, ILogger<Program> log) =>
{
using (Serilog.Context.LogContext.PushProperty("RequestId", Guid.NewGuid()))
{
log.LogInformation("Hello from {Component}", nameof(Program));
w.Do();
return Results.Ok();
}
});
app.Run();
public class Worker
{
private readonly ILogger<Worker> _log;
public Worker(ILogger<Worker> log) => _log = log;
public void Do()
{
_log.LogDebug("Работа началась");
_log.LogInformation("Структурное значение: {@Obj}", new { A = 1, B = "x" });
}
}Пример 2. Конфигурация Serilog через appsettings.json
appsettings.json:
{
"Serilog": {
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Information",
"Microsoft.AspNetCore": "Warning",
"System": "Warning",
"TradingPlatform": "Debug",
"BusLibrary02": "Debug"
}
},
"Enrich": [ "FromLogContext", "WithThreadId" ],
"WriteTo": [
{
"Name": "Console",
"Args": {
"outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] ({SourceContext}) {Message:lj} {Properties:j}{NewLine}{Exception}"
}
},
{
"Name": "File",
"Args": {
"path": "logs/app-.log",
"rollingInterval": "Day",
"retainedFileCountLimit": 10,
"shared": true
}
}
]
}
}Program.cs:
using Serilog;
var builder = WebApplication.CreateBuilder(args);
// Читает Serilog из конфигурации (appsettings.json, переменные окружения и т.д.)
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(builder.Configuration)
.CreateLogger();
builder.Host.UseSerilog();
var app = builder.Build();
// Красивое логирование запросов
app.UseSerilogRequestLogging(options =>
{
options.MessageTemplate = "HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms";
});
app.MapGet("/", (ILogger<Program> log) =>
{
log.LogInformation("Старт обработчика");
return "OK";
});
app.Run();Пример 3. Разные минимальные уровни для ваших библиотек + отдельный файл для ошибок
using Serilog;
using Serilog.Events;
var builder = WebApplication.CreateBuilder(args);
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.MinimumLevel.Override("TradingPlatform", LogEventLevel.Debug)
.MinimumLevel.Override("BusLibrary02", LogEventLevel.Debug)
.Enrich.FromLogContext()
.WriteTo.Console()
.WriteTo.File("logs/errors-.log", rollingInterval: RollingInterval.Day,
restrictedToMinimumLevel: LogEventLevel.Error)
.CreateLogger();
builder.Host.UseSerilog();
var app = builder.Build();
app.MapGet("/demo", (ILogger<Program> log) =>
{
log.LogDebug("Детальный лог только для ваших неймспейсов");
try
{
throw new Exception("Что-то пошло не так");
}
catch (Exception ex)
{
log.LogError(ex, "Ошибка в обработчике");
}
return Results.Ok();
});
app.Run();Подсказки
- Категория логгера — это имя типа T в ILogger<t> или строка в CreateLogger("Category"). Убедитесь, что фильтры настроены под ваши категории.
- Для структурированного логирования всегда используйте шаблоны с именованными свойствами: {Property}, {@Object} для разворота объектов. Это даст полноценные поля в Serilog и читабельные значения в стандартной консоли.
Severity Code Description Project File Line Suppression State Details
Error (active) CS0103 The name 'WebApplication' does not exist in the current context Log01 F:\Projects\VS\GS.Log\Log01\Program.cs 5
У меня
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.1" />
</ItemGroup>
</Project>
Ошибка из‑за того, что тип WebApplication находится в ASP.NET Core (общая среда Microsoft.AspNetCore.App), а ваш проект — консольный (Microsoft.NET.Sdk) и не ссылается на ASP.NET Core.
У вас есть 3 рабочих варианта.
- Сделать проект веб‑приложением (рекомендуется для минимального API)
- csproj:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>Примечания:
- Уберите пакет Microsoft.Extensions.Logging — он уже входит в Microsoft.AspNetCore.App (через Web SDK).
- Program.cs:
var builder = WebApplication.CreateBuilder(args);
// пример регистрации логгера/сервисов
// builder.Logging.ClearProviders();
// builder.Logging.AddConsole();
var app = builder.Build();
app.MapGet("/", () => "Hello, world!");
app.Run();- Оставить консольный Sdk, но добавить ссылку на общую платформу ASP.NET Core
- csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
</Project>Примечания:
- Пакет Microsoft.Extensions.Logging можно удалить (он уже в Microsoft.AspNetCore.App).
- После этого WebApplication станет доступен:
using Microsoft.AspNetCore.Builder;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "OK");
app.Run();- Если вам не нужен веб‑хост, а лишь логирование в консольном приложении
- Оставьте консольный Sdk и используйте встроенный хост/логирование, без WebApplication:
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
var builder = Host.CreateApplicationBuilder(args);
builder.Logging.ClearProviders();
builder.Logging.AddConsole();
using var host = builder.Build();
var logger = host.Services.GetRequiredService<ILoggerFactory>()
.CreateLogger("App");
logger.LogInformation("Hello from console with logging!");
await host.RunAsync(); // или host.StartAsync(); ... await host.StopAsync();В этом случае пакет Microsoft.Extensions.Logging в csproj можно оставить; он нужен.
Итого: для WebApplication выберите вариант 1 или 2; для чистого консольного логирования — вариант 3.
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.8" />
</ItemGroup>
</Project>
Потому что там желтые треугольники на Microsoft.AspNetCore.App стоят.
-----
Выбери из вариантов логированния самый наиболее современный.
Asp.NetCore 8 - 10
Коротко: самый современный стек логирования для ASP.NET Core 8–10 — встроенный Microsoft.Extensions.Logging + OpenTelemetry (структурные логи, JSON-консоль, экспорт по OTLP). Не ссылайтесь на пакет Microsoft.AspNetCore.App — он входит во фреймворк и руками не добавляется.
Почему «желтые треугольники»:
- <packagereference include="Microsoft.AspNetCore.App" version="2.2.8"> устаревший мета‑пакет. В ASP.NET Core 8–10 он не нужен и конфликтует. Удалите его.
Правильный csproj (Web‑приложение)
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<!-- Пакеты для OpenTelemetry (опционально, если нужен экспорт/инструментация) -->
<ItemGroup>
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Exporter.Otlp" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.9.0" />
</ItemGroup>
</Project>Program.cs — современная настройка
using System.Diagnostics;
using Microsoft.Extensions.Logging.Console;
using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
var builder = WebApplication.CreateBuilder(args);
// 1) Структурные логи в JSON + минимальный шум
builder.Logging.ClearProviders();
builder.Logging.AddConsole(options =>
{
options.FormatterName = ConsoleFormatterNames.Json;
});
builder.Logging.AddOpenTelemetry(otlp =>
{
otlp.IncludeFormattedMessage = true;
otlp.IncludeScopes = true;
otlp.ParseStateValues = true;
// Экспорт логов в OTLP (вместе с трассами/метриками ниже)
});
// 2) Единый ресурс для логов/трасс/метрик
var serviceName = "MyService";
var serviceVersion = "1.0.0";
var resourceBuilder = ResourceBuilder.CreateDefault()
.AddService(serviceName: serviceName, serviceVersion: serviceVersion);
// 3) Трейсинг + метрики (по желанию, чтобы всё шло в одну телеметрию)
builder.Services.AddOpenTelemetry()
.ConfigureResource(rb => rb.AddService(serviceName, serviceVersion))
.WithTracing(t => t
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddSource(serviceName) // если используете ActivitySource
.AddOtlpExporter()) // экспорт трасс в OTLP
.WithMetrics(m => m
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddRuntimeInstrumentation()
.AddProcessInstrumentation()
.AddOtlpExporter()); // экспорт метрик в OTLP
// 4) Конфигурирование уровней через appsettings.json тоже работает (см. ниже)
var app = builder.Build();
app.MapGet("/", (ILoggerFactory lf) =>
{
var logger = lf.CreateLogger("Demo");
logger.LogInformation("Hello, {User}!", "World");
return "OK";
});
app.Run();Пример appsettings.json (уровни и формат)
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.AspNetCore": "Warning"
},
"Console": {
"FormatterName": "json",
"FormatterOptions": {
"IncludeScopes": true,
"TimestampFormat": "O"
}
}
},
"OTLP": {
"Endpoint": "http://localhost:4317"
}
}Высокопроизводительные события через источник сгенерированных методов
using Microsoft.Extensions.Logging;
static partial class Log // можно в отдельный файл
{
[LoggerMessage(EventId = 1, Level = LogLevel.Information, Message = "User {UserId} signed in")]
public static partial void UserSignedIn(this ILogger logger, string userId);
[LoggerMessage(EventId = 2, Level = LogLevel.Error, Message = "Failed to process order {OrderId}")]
public static partial void OrderFailed(this ILogger logger, string orderId, Exception ex);
}
// Использование:
// logger.UserSignedIn(userId);
// logger.OrderFailed(orderId, ex);Куда отправлять:
- Только локально: оставьте AddConsole(JSON). OpenTelemetry-пакеты можно не ставить.
- В систему наблюдаемости: добавьте OTLP (в Jaeger, Grafana Loki/Grafana Tempo/OTel Collector, New Relic, Datadog и т. п.) — через AddOpenTelemetry и AddOtlpExporter.
Итого:
- Уберите PackageReference на Microsoft.AspNetCore.App — он лишний и устаревший.
- Используйте встроенный Microsoft.Extensions.Logging с JSON‑консолью, структурными полями и source‑generator LoggerMessage.
- Для единой телеметрии добавьте OpenTelemetry (логи, трейсы, метрики) и экспорт по OTLP. Это — актуальный и рекомендуемый подход для ASP.NET Core 8–10.
using Microsoft.Extensions.Logging.Console;
using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
var builder = WebApplication.CreateBuilder(args);
// 1) Структурные логи в JSON + минимальный шум
builder.Logging.ClearProviders();
builder.Logging.AddConsole(options =>
{
options.FormatterName = ConsoleFormatterNames.Json;
});
builder.Logging.AddOpenTelemetry(otlp =>
{
otlp.IncludeFormattedMessage = true;
otlp.IncludeScopes = true;
otlp.ParseStateValues = true;
// Экспорт логов в OTLP (вместе с трассами/метриками ниже)
});
// 2) Единый ресурс для логов/трасс/метрик
var serviceName = "MyService";
var serviceVersion = "1.0.0";
var resourceBuilder = ResourceBuilder.CreateDefault()
.AddService(serviceName: serviceName, serviceVersion: serviceVersion);
// 3) Трейсинг + метрики (по желанию, чтобы всё шло в одну телеметрию)
builder.Services.AddOpenTelemetry()
.ConfigureResource(rb => rb.AddService(serviceName, serviceVersion))
.WithTracing(t => t
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddSource(serviceName) // если используете ActivitySource
.AddOtlpExporter()) // экспорт трасс в OTLP
.WithMetrics(m => m
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddRuntimeInstrumentation()
.AddProcessInstrumentation()
.AddOtlpExporter()); // экспорт метрик в OTLP
// 4) Конфигурирование уровней через appsettings.json тоже работает (см. ниже)
var app = builder.Build();
app.MapGet("/", (ILoggerFactory lf) =>
{
var logger = lf.CreateLogger("Demo");
logger.LogInformation("Hello, {User}!", "World");
return "OK";
});
app.Run();
В этом коде нет ни одного log сообщения.
Как написать и вывести в консоль log - сообщение
У вас лог есть — он пишется в обработчике GET "/". Но он появится в консоли только когда вы вызовете этот эндпоинт (например, зайдёте в браузере или сделаете curl). Если хотите увидеть лог сразу при старте — просто залогируйте с app.Logger. И на всякий случай задайте минимальный уровень.
Быстрые варианты:
- Лог при старте приложения
// перед app.Run();
app.Logger.LogInformation("Service {Name} v{Version} starting", serviceName, serviceVersion);- Лог в обработчике запроса (у вас уже есть, но нужно сделать запрос)
- Запустите приложение
- Откройте http://localhost:xxxx/ в браузере или:
curl http://localhost:xxxx/После запроса в консоли появится JSON‑лог:
{"Timestamp":"...","Level":"Information","Category":"Demo","Message":"Hello, World!","State":{"User":"World"},"Scopes":[...]}- Лог через внедрение ILogger в обработчик
app.MapGet("/ping", (ILogger<Program> logger) =>
{
logger.LogInformation("Ping at {Time}", DateTimeOffset.UtcNow);
return "pong";
});- На всякий случай задайте минимальный уровень логирования
builder.Logging.SetMinimumLevel(LogLevel.Information);или через appsettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}Итоговый минимальный пример с логом на старте:
var builder = WebApplication.CreateBuilder(args);
builder.Logging.ClearProviders();
builder.Logging.AddConsole(o => o.FormatterName = ConsoleFormatterNames.Json);
builder.Logging.SetMinimumLevel(LogLevel.Information);
var app = builder.Build();
app.Logger.LogInformation("Service {Name} v{Version} starting", "MyService", "1.0.0");
app.MapGet("/", (ILogger<Program> logger) =>
{
logger.LogInformation("Hello, {User}!", "World");
return "OK";
});
app.Run();----------------------------------------------------------------------------------// Настройка логгера для вывода в консоль
builder.Logging.ClearProviders();
builder.Logging.AddConsole();
builder.Logging.AddDebug();
builder.Logging.SetMinimumLevel(LogLevel.Information);
Что делает эта настройка в проекте RAzorPage ?та конфигурация настраивает систему логирования в ASP.NET Core (в т.ч. в Razor Pages) так:
builder.Logging.ClearProviders();
Убирает все провайдеры логов, которые добавляются по умолчанию (Console, EventSource, EventLog на Windows и т.д.). Начинаете «с нуля».builder.Logging.AddConsole();
Включает вывод логов в консоль (видно в терминале/консоли при запуске приложения, Docker‑логе и т.п.).builder.Logging.AddDebug();
Включает вывод в Debug-поток (видно в окне Output → Debug в Visual Studio/VS Code с отладкой).builder.Logging.SetMinimumLevel(LogLevel.Information);
Устанавливает глобальный минимальный уровень логирования на Information. В логи попадут сообщения уровней Information, Warning, Error, Critical; Trace и Debug — отфильтруются.
Что это означает для Razor Pages на практике:
- Вы будете видеть в консоли и в окне Output стандартные логи пайплайна ASP.NET Core (запросы, обработка, ошибки), ваших страниц/обработчиков, middleware, а также библиотек (например, EF Core), но только начиная с уровня Information.
- Системные провайдеры, которые вы удалили
ClearProviders(), работать не будут (например, EventLog на Windows), если вы их не добавите явно. - Если у вас есть настройки логирования в appsettings.json, этот код их переопределяет в части провайдеров и глобального минимального уровня. Тонкую фильтрацию по категориям можно добавить дополнительно, например:
C#Копировать кодbuilder.Logging.AddFilter("Microsoft.AspNetCore", LogLevel.Warning);
builder.Logging.AddFilter("MyApp.Pages", LogLevel.Debug);
Итог: логи идут только в консоль и Debug-вывод, и только от уровня Information и выше.
Как сделать чтобы все Логи высвечивались
Как будет выглядеть эти настройкиЕсли нужно видеть вообще все логи (включая Trace/Debug) в консоли и в Output (Debug), установите минимальный уровень Trace и не ставьте ограничивающих фильтров.
Вариант 1. Program.cs (минимальный хостинг .NET 6/7/8)
C#Копировать кодvar builder = WebApplication.CreateBuilder(args);
// Очищаем провайдеры и включаем нужные
builder.Logging.ClearProviders();
builder.Logging.AddConsole();
builder.Logging.AddDebug();
// Показывать абсолютно всё
builder.Logging.SetMinimumLevel(LogLevel.Trace);
// (не добавляйте AddFilter, если хотите видеть всё без исключений)
// Если нужно — можно явно поставить Trace для системных категорий:
// builder.Logging.AddFilter("", LogLevel.Trace);
// builder.Logging.AddFilter("Microsoft", LogLevel.Trace);
// builder.Logging.AddFilter("System", LogLevel.Trace);
// (необязательно) настроить формат консоли
builder.Logging.AddSimpleConsole(options =>
{
options.SingleLine = false;
options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff ";
options.IncludeScopes = true;
});
var app = builder.Build();
// ...
app.Run();
Вариант 2. Через appsettings.json
JSONКопировать код{
"Logging": {
"LogLevel": {
"Default": "Trace",
"Microsoft": "Trace",
"System": "Trace",
"Microsoft.Hosting.Lifetime": "Trace"
}
}
}
Если используете appsettings.Development.json, продублируйте там те же уровни, чтобы в Dev всё точно было на Trace.
Проверка:
- Убедитесь, что нигде в коде/конфиге нет
AddFilter с уровнем выше Trace. - Если используете сторонний логгер (например, Serilog), минимальный уровень тоже должен быть
Verbose/Trace, а sink-и (Console, Debug) — подключены.
Какой вид примут log-сообщения в случае этой настройки
builder.Logging.AddSimpleConsole(options =>
{
options.SingleLine = false;
options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff ";
options.IncludeScopes = true;
});
--
?При такой настройке SimpleConsole вывод будет многострочным, с вашим форматом времени в начале, коротким именем уровня, категорией и EventId на первой строке. Затем — отдельные строки с скоупами (если есть), потом сам текст сообщения и, при наличии, исключение со стеком.
Пример (IncludeScopes = true, есть два скоупа, есть исключение):
2025-12-21 14:37:12.345 info: MyApp.Services.UserService[42]
=> userId=123 => op=Create
Пользователь создан
System.InvalidOperationException: Что-то пошло не так
at MyApp.Services.UserService.Create(...) in C:\src\UserService.cs:line 57
...
Без скоупов и без исключения:
2025-12-21 14:37:12.345 dbug: MyApp.Controllers.HomeController[0]
Обрабатываем запрос
Структура строк:
- Префикс: "<timestamp> <level>: <category>[<eventid>]"
- Timestamp — ваш формат: "yyyy-MM-dd HH:mm:ss.fff "
- level — краткое имя уровня: trce/dbug/info/warn/fail/crit
- Category — имя логгера (обычно полное имя типа)
- EventId — числовой идентификатор события
- Далее (при IncludeScopes = true): строка со скоупами вида "=> scope1 => scope2"
- Далее: строка(и) с текстом сообщения
- Если было исключение: его сообщение и стек на следующих строках
Цвета для уровней (если включена цветная консоль) применяются к первой строке, но в тексте выше они не отображены.
Я что-то не увидел выведенные логи.
Выведи логи которые будут иметь при такой конфигурацииНиже — пример того, как будут выглядеть строки в консольном логере при включённом IncludeScopes = true, с цветовой разметкой (цвета тут не отображены), с сообщениями и с исключением. Формат: первая строка — «уровень: Категория[EventId]», затем (из‑за IncludeScopes) строка со скоупами, далее текст сообщения, затем (если есть) исключение и стек.
PlaintextКопировать кодinfo: MyApp.Services.OrderService[101]
=> CorrelationId: 7f2a9c8e9c2b4e2a8b1d => User: alice
Заказ 123 создан успешно
debug: MyApp.Data.InventoryRepository[42]
=> CorrelationId: 7f2a9c8e9c2b4e2a8b1d => User: alice
Запрос остатков: SKU=ABC-001, склад=msk-main
warn: MyApp.Services.InventoryService[0]
=> CorrelationId: 7f2a9c8e9c2b4e2a8b1d => User: alice
Низкий остаток товара SKU=ABC-001: 2 шт
error: MyApp.Controllers.OrdersController[500]
=> CorrelationId: 7f2a9c8e9c2b4e2a8b1d => User: alice
Ошибка при подтверждении заказа 123
System.InvalidOperationException: Невозможно подтвердить заказ в статусе Draft
at MyApp.Domain.Order.Confirm() in /src/MyApp/Domain/Order.cs:line 87
at MyApp.Services.OrderService.ConfirmAsync(Int32 orderId) in /src/MyApp/Services/OrderService.cs:line 152
at MyApp.Controllers.OrdersController.Confirm(Int32 id) in /src/MyApp/Controllers/OrdersController.cs:line 74
trace: MyApp.Infrastructure.Http.HttpClientHandler[200]
=> CorrelationId: 7f2a9c8e9c2b4e2a8b1d => User: alice
HTTP GET https://api.example.com/products/ABC-001 -> 200 OK (142 ms)
Если в конфигурации отключить IncludeScopes, в этих записях пропадёт строка со скоупами (та, что начинается с "=> ..."). Если включён Timestamp (UseUtcTimestamp или включён форматтер с временем), перед уровнем появится метка времени, например:
PlaintextКопировать код2025-12-21 12:34:56.789 +03:00 info: MyApp.Services.OrderService[101]
=> CorrelationId: 7f2a9c8e9c2b4e2a8b1d => User: alice
Заказ 123 создан успешно
Нужен пример под вашу точную категорию/форматтер (Simple/Json/Systemd) и уровни? Напишите, что именно включено, и я сгенерирую точный вывод.
Почему в такой конфигурации логов я Вижу еxception в Панели Output Debug в Visual Studio,
а в Консоли я не вижу этих exception ?
Повторю установки
// Настройка логгера для вывода в консоль
builder.Logging.ClearProviders();
builder.Logging.AddConsole();
builder.Logging.AddDebug();
//builder.Logging.SetMinimumLevel(LogLevel.Information);
builder.Logging.SetMinimumLevel(LogLevel.Trace);
----Короткий ответ: в окне Output (Debug) вы видите «first‑chance» исключения от отладчика Visual Studio, а в консоли — только то, что вы сами залогировали через ILogger. Если исключение где‑то перехватывается и не логируется, консоль его не покажет.
Почему так происходит
- Output (Debug) в VS показывает уведомления от отладчика о каждом брошенном исключении (first‑chance), даже если оно было поймано и обработано. Это не лог приложения.
- Консольный провайдер ILogger выводит только ваши лог‑сообщения. Если вы не вызываете logger.LogError(ex, "...") (или другой уровень с параметром exception), стек исключения в консоль не попадет.
Что сделать, чтобы видеть исключения в консоли
- Логируйте исключения явно:
C#Копировать кодtry
{
// код
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка при выполнении операции X");
throw; // по ситуации
}
- Для ASP.NET Core — подключите middleware, который логирует необработанные исключения:
C#Копировать кодapp.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is Exception ex)
{
var logger = context.RequestServices.GetRequiredService<ILoggerFactory>()
.CreateLogger("GlobalException");
logger.LogError(ex, "Unhandled exception");
}
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
});
});
В Dev-режиме можно также добавить app.UseDeveloperExceptionPage() — он логирует и показывает страницу ошибки (но это для разработки).
- Убедитесь, что уровни логирования не отфильтровывают нужные категории:
- У вас уже
SetMinimumLevel(LogLevel.Trace), это ок. - Если хотите точнее:
C#Копировать кодbuilder.Logging.AddFilter("Microsoft", LogLevel.Information);
builder.Logging.AddFilter("System", LogLevel.Information);
Или задайте через appsettings.json:
JSONКопировать код{
"Logging": {
"LogLevel": {
"Default": "Trace",
"Microsoft": "Information",
"System": "Information"
}
}
}
- Проверьте, как именно вы логируете:
- Важно передавать сам
Exception отдельным параметром: logger.LogError(ex, "msg"). Если вы делаете logger.LogError($"Ошибка: {ex}"), стек не будет форматирован как исключение, а выведется просто строка. - Для событий платформы (например,
System.Net.Http) включите соответствующие уровни категорий, иначе детали могут не попадать в лог.
Итог
- Видите в Output, но не в консоли — это нормально: Output показывает first‑chance отладчика, а консоль — только то, что вы залогировали.
- Решение: логировать исключения через ILogger с параметром
Exception, и при необходимости настроить фильтры категорий/уровней.
Вот мой код
---
public class Program
{
public static void Main(string[] args)
{
Console.OutputEncoding = System.Text.Encoding.UTF8;
var builder = WebApplication.CreateBuilder(args);
// Настройка логгера для вывода в консоль
builder.Logging.ClearProviders();
builder.Logging.AddConsole();
builder.Logging.AddDebug();
//builder.Logging.SetMinimumLevel(LogLevel.Information);
builder.Logging.SetMinimumLevel(LogLevel.Trace);
// ========== КОНФИГУРАЦИЯ СЕРВИСОВ ==========
ConfigureServices(builder.Services);
var app = builder.Build();
// ========== КОНФИГУРАЦИЯ ПРИЛОЖЕНИЯ ==========
ConfigureApp(app);
app.Run();
}
private static void ConfigureServices(IServiceCollection services)
{
Console.WriteLine("📦 Настройка сервисов...");
// Основные компоненты
services.AddSingleton<TickerManager>();
services.AddSingleton<QuoteSyncService>();
// Фабрика для ChartContainer (зависит от TickerManager)
services.AddSingleton<ChartContainer>(sp =>
{
var tickerManager = sp.GetRequiredService<TickerManager>();
var container = new ChartContainer(tickerManager);
Console.WriteLine($"📊 ChartContainer создан с {container.Count} графиками");
return container;
});
// Фоновые сервисы
services.AddHostedService<QuotesGeneratorService>(sp =>
{
var loggerFactory = sp.GetRequiredService<ILoggerFactory>();
var tickerManager = sp.GetRequiredService<TickerManager>();
var quoteSyncService = sp.GetRequiredService<QuoteSyncService>();
return new QuotesGeneratorService(
loggerFactory.CreateLogger<QuotesGeneratorService>(),
tickerManager,
quoteSyncService
);
});
services.AddHostedService<TradingStrategyService>(sp =>
{
var loggerFactory = sp.GetRequiredService<ILoggerFactory>();
var tickerManager = sp.GetRequiredService<TickerManager>();
var quoteSyncService = sp.GetRequiredService<QuoteSyncService>();
return new TradingStrategyService(
loggerFactory.CreateLogger<TradingStrategyService>(),
tickerManager
, quoteSyncService
);
});
// Web компоненты
services.AddRazorPages();
services.AddControllers();
// Health checks (опционально)
services.AddHealthChecks();
Console.WriteLine("✅ Сервисы настроены");
}
private static void ConfigureApp(WebApplication app)
{
Console.WriteLine("🔧 Настройка приложения...");
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
Console.WriteLine("🔍 Режим разработки включен");
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
Console.WriteLine("🔒 Режим продакшн включен");
}
// Middleware pipeline
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
// Endpoints
app.MapRazorPages();
app.MapControllers();
app.MapHealthChecks("/health");
// Стартовые сообщения
app.Lifetime.ApplicationStarted.Register(() =>
{
Console.WriteLine("\n" + new string('=', 50));
Console.WriteLine("🚀 ТОРГОВАЯ ПЛАТФОРМА ЗАПУЩЕНА");
Console.WriteLine(new string('=', 50));
Console.WriteLine("📊 Тикеров: 24 (AAA-XXX)");
Console.WriteLine("📈 Графиков: 24 (по одному на тикер)");
Console.WriteLine("🤖 Стратегий: 72 (3 стратегии на каждый тикер)");
Console.WriteLine("⏱️ Генерация котировок: каждую секунду");
Console.WriteLine("🌐 Графики доступны по адресу: https://localhost:{порт}/Finance");
Console.WriteLine(new string('=', 50) + "\n");
});
app.Lifetime.ApplicationStopping.Register(() =>
{
Console.WriteLine("\n" + new string('=', 50));
Console.WriteLine("🛑 ОСТАНОВКА ПЛАТФОРМЫ");
Console.WriteLine(new string('=', 50));
});
Console.WriteLine("✅ Приложение настроено");
app.Lifetime.ApplicationStarted.Register(() =>
{
Console.WriteLine("\n" + new string('=', 50));
Console.WriteLine("🚀 ТОРГОВАЯ ПЛАТФОРМА ЗАПУЩЕНА");
Console.WriteLine(new string('=', 50));
// Получаем TickerManager и выводим статистику
var tickerManager = app.Services.GetRequiredService<TickerManager>();
tickerManager.PrintTickerStats();
Console.WriteLine("📈 Графиков: 24 (по одному на тикер)");
Console.WriteLine("🤖 Стратегий: 72 (3 стратегии на каждый тикер)");
Console.WriteLine("⏱️ Генерация котировок: каждую секунду");
Console.WriteLine("🌐 Графики доступны по адресу: https://localhost:{порт}/Finance");
Console.WriteLine(new string('=', 50) + "\n");
});
}
}
---
Добавь в мой код и выложи полный код вот с этими включениями:
Для ASP.NET Core — подключите middleware, который логирует необработанные исключения:
app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is Exception ex)
{
var logger = context.RequestServices.GetRequiredService<ILoggerFactory>()
.CreateLogger("GlobalException");
logger.LogError(ex, "Unhandled exception");
}
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
});
});
-----
В Dev-режиме можно также добавить app.UseDeveloperExceptionPage() — он логирует и показывает страницу ошибки (но это для разработки).
----C#Копировать кодusing System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
public class Program
{
public static void Main(string[] args)
{
Console.OutputEncoding = System.Text.Encoding.UTF8;
var builder = WebApplication.CreateBuilder(args);
// Настройка логгера для вывода в консоль
builder.Logging.ClearProviders();
builder.Logging.AddConsole();
builder.Logging.AddDebug();
//builder.Logging.SetMinimumLevel(LogLevel.Information);
builder.Logging.SetMinimumLevel(LogLevel.Trace);
// ========== КОНФИГУРАЦИЯ СЕРВИСОВ ==========
ConfigureServices(builder.Services);
var app = builder.Build();
// ========== КОНФИГУРАЦИЯ ПРИЛОЖЕНИЯ ==========
ConfigureApp(app);
app.Run();
}
private static void ConfigureServices(IServiceCollection services)
{
Console.WriteLine("📦 Настройка сервисов...");
// Основные компоненты
services.AddSingleton<TickerManager>();
services.AddSingleton<QuoteSyncService>();
// Фабрика для ChartContainer (зависит от TickerManager)
services.AddSingleton<ChartContainer>(sp =>
{
var tickerManager = sp.GetRequiredService<TickerManager>();
var container = new ChartContainer(tickerManager);
Console.WriteLine($"📊 ChartContainer создан с {container.Count} графиками");
return container;
});
// Фоновые сервисы
services.AddHostedService<QuotesGeneratorService>(sp =>
{
var loggerFactory = sp.GetRequiredService<ILoggerFactory>();
var tickerManager = sp.GetRequiredService<TickerManager>();
var quoteSyncService = sp.GetRequiredService<QuoteSyncService>();
return new QuotesGeneratorService(
loggerFactory.CreateLogger<QuotesGeneratorService>(),
tickerManager,
quoteSyncService
);
});
services.AddHostedService<TradingStrategyService>(sp =>
{
var loggerFactory = sp.GetRequiredService<ILoggerFactory>();
var tickerManager = sp.GetRequiredService<TickerManager>();
var quoteSyncService = sp.GetRequiredService<QuoteSyncService>();
return new TradingStrategyService(
loggerFactory.CreateLogger<TradingStrategyService>(),
tickerManager
, quoteSyncService
);
});
// Web компоненты
services.AddRazorPages();
services.AddControllers();
// Health checks (опционально)
services.AddHealthChecks();
Console.WriteLine("✅ Сервисы настроены");
}
private static void ConfigureApp(WebApplication app)
{
Console.WriteLine("🔧 Настройка приложения...");
if (app.Environment.IsDevelopment())
{
// В Dev-режиме — страница разработчика с логированием ошибок
app.UseDeveloperExceptionPage();
Console.WriteLine("🔍 Режим разработки включен");
}
else
{
// Глобальный обработчик необработанных исключений с логированием
app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is Exception ex)
{
var logger = context.RequestServices.GetRequiredService<ILoggerFactory>()
.CreateLogger("GlobalException");
logger.LogError(ex, "Unhandled exception");
}
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
});
});
app.UseHsts();
Console.WriteLine("🔒 Режим продакшн включен");
}
// Middleware pipeline
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
// Endpoints
app.MapRazorPages();
app.MapControllers();
app.MapHealthChecks("/health");
// Стартовые сообщения
app.Lifetime.ApplicationStarted.Register(() =>
{
Console.WriteLine("\n" + new string('=', 50));
Console.WriteLine("🚀 ТОРГОВАЯ ПЛАТФОРМА ЗАПУЩЕНА");
Console.WriteLine(new string('=', 50));
Console.WriteLine("📊 Тикеров: 24 (AAA-XXX)");
Console.WriteLine("📈 Графиков: 24 (по одному на тикер)");
Console.WriteLine("🤖 Стратегий: 72 (3 стратегии на каждый тикер)");
Console.WriteLine("⏱️ Генерация котировок: каждую секунду");
Console.WriteLine("🌐 Графики доступны по адресу: https://localhost:{порт}/Finance");
Console.WriteLine(new string('=', 50) + "\n");
});
app.Lifetime.ApplicationStopping.Register(() =>
{
Console.WriteLine("\n" + new string('=', 50));
Console.WriteLine("🛑 ОСТАНОВКА ПЛАТФОРМЫ");
Console.WriteLine(new string('=', 50));
});
Console.WriteLine("✅ Приложение настроено");
app.Lifetime.ApplicationStarted.Register(() =>
{
Console.WriteLine("\n" + new string('=', 50));
Console.WriteLine("🚀 ТОРГОВАЯ ПЛАТФОРМА ЗАПУЩЕНА");
Console.WriteLine(new string('=', 50));
// Получаем TickerManager и выводим статистику
var tickerManager = app.Services.GetRequiredService<TickerManager>();
tickerManager.PrintTickerStats();
Console.WriteLine("📈 Графиков: 24 (по одному на тикер)");
Console.WriteLine("🤖 Стратегий: 72 (3 стратегии на каждый тикер)");
Console.WriteLine("⏱️ Генерация котировок: каждую секунду");
Console.WriteLine("🌐 Графики доступны по адресу: https://localhost:{порт}/Finance");
Console.WriteLine(new string('=', 50) + "\n");
});
}
}
1. По сравнению с моим кодом вывод в консоль не изменился.
Output Debug
Exception thrown: 'System.ArgumentException' in System.Private.CoreLib.dll
Exception thrown: 'System.ArgumentException' in System.Private.CoreLib.dll
Exception thrown: 'System.ArgumentException' in System.Private.CoreLib.dll
Почему не выводится местонахождение в коде - номер строки и модуль ?
Если нет возможности обнаружить место ошибки, то такая информация бесполезна.Коротко: сообщения «Exception thrown: 'System.ArgumentException' in System.Private.CoreLib.dll» в окне Output — это лишь уведомления о first‑chance исключениях. Они не содержат номер строки по дизайну. Чтобы увидеть строку/модуль, нужно либо остановиться на месте выброса, либо иметь полноценный стек в сообщении исключения (а для этого нужны PDB-символы и не оптимизированная сборка).
Что сделать, чтобы увидеть место ошибки:
- Прервать выполнение на выбросе исключения
- Visual Studio: Debug > Windows > Exception Settings.
- Откройте Common Language Runtime Exceptions и найдите System.ArgumentException.
- Поставьте галочку в колонке Thrown (или просто включите Break on all exceptions).
- Запустите под отладчиком (F5). При выбросе VS остановится, и в Call Stack будет ваша строка.
- Убедиться, что есть символы (PDB) и не оптимизированная сборка
- Конфигурация Debug.
- В свойствах проекта: Build → Optimize code = выключено.
- Build → Advanced → Debugging information = full/portable.
- Запустите под F5, не из «опубликованной»/single-file сборки.
- В окне Debug > Windows > Modules проверьте, что для вашего модуля «Symbols loaded = Yes». Если нет — укажите путь к .pdb (Tools > Options > Debugging > Symbols).
- Показ внешнего кода/полный стек
- В окне Call Stack включите «Show External Code» (или временно снимите Tools > Options > Debugging > Enable Just My Code), чтобы увидеть кадры вне вашего проекта.
- Лог стека из кода (если исключение перехватывается и не останавливает отладчик)
- Поймайте исключение и выведите его целиком — тогда в Console пойдут строки и номера (при наличии PDB):
try
{
// ...
}
catch (ArgumentException ex)
{
Console.WriteLine(ex); // содержит сообщение, тип и стек с номерами строк
throw; // опционально, чтобы не скрыть проблему
} - Альтернатива: подписаться на AppDomain.CurrentDomain.FirstChanceException и логировать ex.ToString().
Почему сейчас вы видите только «System.Private.CoreLib.dll» и без строк:
- Это first‑chance уведомление в Output, оно не содержит стека/строк.
- Отладчик не останавливается на исключении (нет Break on throw).
- Символы не загружены или сборка оптимизирована/Release — номера строк теряются.
- Исключение может выбрасываться и перехватываться внутри фреймворка; без остановки вы увидите только сообщение.
Итог: включите Break on throw для ArgumentException, убедитесь в PDB и Debug-сборке, и посмотрите Call Stack — там будет модуль и точная строка. Если нужно, дам точные шаги для вашей IDE/версии .NET (VS, VS Code, Rider).
Что сделать, чтобы увидеть место ошибки:
Прервать выполнение на выбросе исключения
Visual Studio: Debug > Windows > Exception Settings.
Откройте Common Language Runtime Exceptions и найдите System.ArgumentException.
Поставьте галочку в колонке Thrown (или просто включите Break on all exceptions).
Запустите под отладчиком (F5). При выбросе VS остановится, и в Call Stack будет ваша строка.
----
Вот сейчас все полезно.
Нашел ошибочную строку.
System.ArgumentException
HResult=0x80070057
Message=Not a legal OleAut date.
Source=System.Private.CoreLib
StackTrace:
at System.DateTime.DoubleDateToTicks(Double value)
at System.DateTime.FromOADate(Double d)
at QuoteEngine.GetCurrentQuote() in F:\Projects\VS\GS.TradeContext\RazorChartDirFin02253\Core\QuoteEngine.cs:line 119Отлично, вы нашли место. Ошибка “Not a legal OleAut date” означает, что в DateTime.FromOADate передано значение, которое нельзя преобразовать в OLE Automation date.
Что проверить сразу
- Логируйте само значение d, которое попадает в FromOADate.
- Частые причины:
- d = NaN или Infinity.
- d вне диапазона OLE Automation: от -657435.0 до примерно 2958465.9999999 (т.е. от 1899-12-30 до 9999-12-31).
- Перепутали формат времени: передали Unix timestamp (секунды/миллисекунды с 1970-01-01) вместо OADate.
- Ошибки парсинга числа (локаль: запятая/точка).
- Пустые/NULL значения, которые по пути превращаются в 1E+308, -1, или другое «мусорное» число.
Быстрая защита на месте вызова
Комментариев нет:
Отправить комментарий