воскресенье, 21 декабря 2025 г.

Logs, NetCore, Chadgpt

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>

C#
Копировать код
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 и обработка исключений

C#
Копировать код
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:

JSON
Копировать код
{
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
      "Microsoft": "Information",
      "Microsoft.AspNetCore": "Warning",
      "System": "Warning",
      "TradingPlatform": "Debug",
      "BusLibrary02": "Debug"
    }
  }
}

Program.cs:

C#
Копировать код
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. Быстрый старт в коде: консоль + файл, уровни и обогащение

C#
Копировать код
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:

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:

C#
Копировать код
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. Разные минимальные уровни для ваших библиотек + отдельный файл для ошибок

C#
Копировать код
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 и читабельные значения в стандартной консоли.
var builder = WebApplication.CreateBuilder(args);
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 рабочих варианта.

  1. Сделать проект веб‑приложением (рекомендуется для минимального API)
  • csproj:
XML
Копировать код
<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:
C#
Копировать код
var builder = WebApplication.CreateBuilder(args);

    // пример регистрации логгера/сервисов
    // builder.Logging.ClearProviders();
    // builder.Logging.AddConsole();

    var app = builder.Build();

    app.MapGet("/", () => "Hello, world!");

    app.Run();
  1. Оставить консольный Sdk, но добавить ссылку на общую платформу ASP.NET Core
  • csproj:
XML
Копировать код
<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 станет доступен:
C#
Копировать код
using Microsoft.AspNetCore.Builder;

    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();
    app.MapGet("/", () => "OK");
    app.Run();
  1. Если вам не нужен веб‑хост, а лишь логирование в консольном приложении
  • Оставьте консольный Sdk и используйте встроенный хост/логирование, без WebApplication:
C#
Копировать код
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‑приложение)

XML
Копировать код
<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 — современная настройка

C#
Копировать код
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 (уровни и формат)

JSON
Копировать код
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.AspNetCore": "Warning"
    },
    "Console": {
      "FormatterName": "json",
      "FormatterOptions": {
        "IncludeScopes": true,
        "TimestampFormat": "O"
      }
    }
  },
  "OTLP": {
    "Endpoint": "http://localhost:4317"
  }
}

Высокопроизводительные события через источник сгенерированных методов

C#
Копировать код
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 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();

В этом коде нет ни одного log сообщения.
Как написать и вывести в консоль log - сообщение

У вас лог есть — он пишется в обработчике GET "/". Но он появится в консоли только когда вы вызовете этот эндпоинт (например, зайдёте в браузере или сделаете curl). Если хотите увидеть лог сразу при старте — просто залогируйте с app.Logger. И на всякий случай задайте минимальный уровень.

Быстрые варианты:

  1. Лог при старте приложения
C#
Копировать код
// перед app.Run();
app.Logger.LogInformation("Service {Name} v{Version} starting", serviceName, serviceVersion);
  1. Лог в обработчике запроса (у вас уже есть, но нужно сделать запрос)
C#
Копировать код
curl http://localhost:xxxx/

После запроса в консоли появится JSON‑лог:

C#
Копировать код
{"Timestamp":"...","Level":"Information","Category":"Demo","Message":"Hello, World!","State":{"User":"World"},"Scopes":[...]}
  1. Лог через внедрение ILogger в обработчик
C#
Копировать код
app.MapGet("/ping", (ILogger<Program> logger) =>
{
    logger.LogInformation("Ping at {Time}", DateTimeOffset.UtcNow);
    return "pong";
});
  1. На всякий случай задайте минимальный уровень логирования
C#
Копировать код
builder.Logging.SetMinimumLevel(LogLevel.Information);

или через appsettings.json:

JSON
Копировать код
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  }
}

Итоговый минимальный пример с логом на старте:

C#
Копировать код
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), стек исключения в консоль не попадет.

Что сделать, чтобы видеть исключения в консоли

  1. Логируйте исключения явно:
C#
Копировать код
try
{
    // код
}
catch (Exception ex)
{
    logger.LogError(ex, "Ошибка при выполнении операции X");
    throw; // по ситуации
}
  1. Для 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() — он логирует и показывает страницу ошибки (но это для разработки).

  1. Убедитесь, что уровни логирования не отфильтровывают нужные категории:
  • У вас уже 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"
    }
  }
}
  1. Проверьте, как именно вы логируете:
  • Важно передавать сам 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-символы и не оптимизированная сборка).

Что сделать, чтобы увидеть место ошибки:

  1. Прервать выполнение на выбросе исключения
  • Visual Studio: Debug > Windows > Exception Settings.
  • Откройте Common Language Runtime Exceptions и найдите System.ArgumentException.
  • Поставьте галочку в колонке Thrown (или просто включите Break on all exceptions).
  • Запустите под отладчиком (F5). При выбросе VS остановится, и в Call Stack будет ваша строка.
  1. Убедиться, что есть символы (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).
  1. Показ внешнего кода/полный стек
  • В окне Call Stack включите «Show External Code» (или временно снимите Tools > Options > Debugging > Enable Just My Code), чтобы увидеть кадры вне вашего проекта.
  1. Лог стека из кода (если исключение перехватывается и не останавливает отладчик)
  • Поймайте исключение и выведите его целиком — тогда в 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, или другое «мусорное» число.

Быстрая защита на месте вызова

Комментариев нет:

Отправить комментарий