tansu

Tnsu.Monitoring (0.2.5)

Published 2026-10-30 08:35:58 +00:00 by admin

Installation

dotnet nuget add source --name tansu --username your_username --password your_token https://git.tnsu.kz/api/packages/tansu/nuget/index.json
dotnet add package --source tansu --version 0.2.5 Tnsu.Monitoring

About this package

Логирование .NET-сервисов TNSU одной строкой: builder.AddTnsuLogging(). Serilog → OTLP → Collector → VictoriaLogs, плюс консоль и файл, лог запросов и userId.

Tnsu.Monitoring

Единое логирование для .NET-сервисов TNSU: Serilog → OTLP → OpenTelemetry Collector → VictoriaLogs (monitoring.tnsu.kz). Подключается одной строкой.

Установка

Реестр организации tansu — в nuget.config рядом с решением:

<configuration>
  <packageSources>
    <add key="tansu" value="https://git.tnsu.kz/api/packages/tansu/nuget/index.json" />
  </packageSources>
</configuration>

или командой (один раз на машине):

dotnet nuget add source https://git.tnsu.kz/api/packages/tansu/nuget/index.json --name tansu

Сам пакет:

dotnet add package Tnsu.Monitoring --source tansu

Подключение

var builder = WebApplication.CreateBuilder(args);
builder.AddTnsuLogging(options => options.ServiceName = "orders");
// префикс tansu в имени не пишем — все сервисы и так наши: не tansuStroySign, а stroySign;
// имя — то же, что у фронта этого приложения (front и back различает поле log.source)

Больше ничего не нужно, в том числе в конвейере app.Use…. Так же подключается в Worker Service (Host.CreateApplicationBuilder). Без ServiceName в логах будет имя сборки.

Что включено по умолчанию

Куда VictoriaLogs (через Collector) и консоль; файл — только если включить (WriteToFile)
Уровень на сервере — Debug, локально (Development) — Information; Microsoft.* и System.* — от Warning, кроме старта приложения (Microsoft.Hosting.Lifetime: адрес, окружение, «Application started»); Hangfire — от Warning
Лог запросов каждый HTTP-запрос: метод, путь, статус, время; 2xx–4xx — Debug, 5xx и исключения — Error
Пользователь во всех записях запроса: enduser.full_name (ФИО), enduser.name (почта), enduser.id (id в Entra) и userId; при входе не через Entra — те поля, для которых нашлись claims
Сборка service.version, хэш коммита git.commit, версия пакета tnsu.monitoring.version
Файл выключен; включённый — logs/log-ГГГГММДД.txt от текущего каталога, новый файл в сутки, хранятся последние 5 дней
Консоль и файл в читаемом виде: дата, уровень, источник, сообщение
Нет связи с Collector на сервере — Error «Логи не попадают в Collector…» в консоль (и в файл, если включён; проверка раз в минуту), локально — Information

Адрес Collector зависит от площадки — см. «Куда уходят логи».

Настройки в коде

builder.AddTnsuLogging(options =>
{
    options.ServiceName = "orders-api";

    // Уровни: свой минимум и отдельные источники.
    options.MinimumLevel = LogEventLevel.Information;
    options.MinimumLevelOverrides["Microsoft.EntityFrameworkCore.Database.Command"] = LogEventLevel.Information; // SQL-запросы

    // Лог запросов: частые служебные не писать (5xx пишутся всегда) или выключить совсем.
    options.ShouldLogRequest = context => !context.Request.Path.StartsWithSegments("/health");
    // options.LogRequests = false;

    // Файл (по умолчанию выключен): включить, путь, срок хранения.
    options.WriteToFile = true;
    options.FilePath = "/var/log/orders/log-.txt";
    options.RetainedFileDays = 14;

    // Свой адрес приёма (обычно не нужен, см. «Куда уходят логи») и свои поля в каждой записи.
    // options.OtlpEndpoint = "http://localhost:4318/v1/logs";
    options.ExtraResourceAttributes["team"] = "finance";
});

Настройки без пересборки

Секция TnsuLogging в appsettings или переменные окружения (.env, docker-compose) — поверх кода.

{
  "TnsuLogging": {
    "MinimumLevel": "Information",
    "Overrides": {
      "Microsoft.EntityFrameworkCore": "Error"
    },
    "WriteToFile": true,
    "FilePath": "logs/log-.txt",
    "OtlpEndpoint": "http://localhost:4318/v1/logs"
  }
}
TnsuLogging__MinimumLevel=Information
TnsuLogging__Overrides__Microsoft.EntityFrameworkCore=Error
TnsuLogging__WriteToFile=true

Debug локально включается явно: "TnsuLogging": { "MinimumLevel": "Debug" } в appsettings.Development.json. Опечатка в уровне или в WriteToFile останавливает старт с понятной ошибкой.

Куда уходят логи

Где сервис Collector Что настроить
Linux, сервис в Docker контейнер otel-collector подключить сеть monitoring (адрес по умолчанию — http://otel-collector:4318/v1/logs)
Windows-сервер (IIS, служба) служба Windows на localhost:4318 ничего: установщик Collector прописал системную переменную OTEL_EXPORTER_OTLP_LOGS_ENDPOINT; сервис увидит её после перезапуска (iisreset, Restart-Service)
Linux, сервис прямо на хосте (systemd) контейнер otel-collector, порт на 127.0.0.1:4318 OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=http://localhost:4318/v1/logs в окружении сервиса
Локально у разработчика (Development) — ничего: логи идут прямо на https://monitoring.tnsu.kz/v1/logs

Адрес берётся из первого заданного: options.OtlpEndpoint или TnsuLogging:OtlpEndpoint → переменная OTEL_EXPORTER_OTLP_LOGS_ENDPOINT (полный адрес) или OTEL_EXPORTER_OTLP_ENDPOINT (к нему добавляется /v1/logs) → в Development https://monitoring.tnsu.kz/v1/logs → http://otel-collector:4318/v1/logs. Ошибся с адресом — на сервере в консоли будет Error «Логи не попадают в Collector…».

Сервис в Docker на Linux подключается к сети Collector'а:

services:
  orders-api:
    networks: [default, monitoring]

networks:
  monitoring:
    external: true

Collector на сервере

Collector ставится один раз на сервер, а не в каждый сервис. Есть ли он:

Сервер Проверка Если нет — инструкция
Windows Get-Service otelcol Collector на Windows-сервере — скрипт Install-Collector.ps1, он же прописывает адрес для сервисов
Linux docker ps --filter name=otel-collector Collector на Linux-сервере — docker compose up -d из collector/linux

Collector хранит очередь на диске и, если приём недоступен, доставляет логи до 4 суток спустя. Пока Collector'а нет, сервис работает как обычно, логи остаются в его консоли, а в консоль пишется Error «Логи не попадают в Collector…».

Хэш коммита и версия в логах

В каждой записи есть три поля о сборке:

Поле Откуда Что нужно сделать
tnsu.monitoring.version версия этого пакета ничего, проставляется само
git.commit хэш коммита, из которого собран сервис (10 символов, как в Gitea) передать хэш при сборке, см. ниже
service.version <Version> сервиса (из csproj или -p:Version=…) по желанию задать версию при сборке

Сборка там, где есть .git (локально, dotnet publish прямо на раннере с checkout'ом): SDK сам берёт хэш из .git, ничего делать не нужно.

Docker — .git в образ обычно не копируется, поэтому хэш передаётся аргументом сборки:

FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY . .
# Хэш коммита и версия — от пайплайна: --build-arg GIT_COMMIT=… --build-arg VERSION=…
ARG GIT_COMMIT=""
ARG VERSION="1.0.0"
RUN dotnet publish Orders.Api/Orders.Api.csproj -c Release -o /app \
    -p:SourceRevisionId=$GIT_COMMIT -p:Version=$VERSION

FROM mcr.microsoft.com/dotnet/aspnet:10.0
WORKDIR /app
COPY --from=build /app ./
ENTRYPOINT ["dotnet", "Orders.Api.dll"]

CI (Gitea Actions) — передать хэш и номер сборки:

- name: Build image
  run: |
    docker build \
      --build-arg GIT_COMMIT=$GITHUB_SHA \
      --build-arg VERSION=1.0.${{ github.run_number }} \
      -t nexus.tnsu.kz:8082/orders-api:sha-${GITHUB_SHA::8} .

Без Docker — то же параметрами dotnet publish:

dotnet publish -c Release -p:SourceRevisionId=$GITHUB_SHA -p:Version=1.0.$GITHUB_RUN_NUMBER

Если пересобрать нельзя (готовый образ), хэш можно передать переменной окружения контейнера GIT_COMMIT — пакет возьмёт её, когда в сборке хэша нет. Проверить: в интерфейсе логов service.name:=orders-api git.commit:*.

Переход со своего Serilog

Старые настройки Serilog можно удалить целиком — пакет делает то же самое сам: консоль, лог запросов, уровни. Файл выключен по умолчанию — если он нужен, WriteToFile = true (хранятся 5 дней).

  1. appsettings*.json — удалить секцию Serilog полностью (Using, MinimumLevel, WriteTo, Enrich). Свои уровни перенести в TnsuLogging:

    // было
    "Serilog": {
      "MinimumLevel": {
        "Default": "Information",
        "Override": { "Microsoft": "Warning", "Hangfire": "Warning" }
      },
      "WriteTo": [ { "Name": "Console" }, { "Name": "File", "Args": { "path": "logs/log-.txt" } } ]
    }
    
    // стало (Microsoft.*, System.* и Hangfire и так от Warning, консоль включена по умолчанию; файл — "WriteToFile": true)
    "TnsuLogging": {
      "MinimumLevel": "Information"
    }
    

    Секцию Logging (стандартную, для Microsoft.Extensions.Logging) можно оставить — пакет её не читает.

  2. Program.cs — удалить builder.Host.UseSerilog(...) / builder.Services.AddSerilog(...), Log.Logger = new LoggerConfiguration()..., ReadFrom.Configuration(...), app.UseSerilogRequestLogging() (иначе запросы запишутся дважды) и app.UseTnsuLogging() / app.UseTnsuLogUser() из версий 0.1.x. Вместо всего этого — одна строка builder.AddTnsuLogging(...).

  3. csproj — пакеты Serilog.AspNetCore, Serilog.Sinks.Console, Serilog.Sinks.File, Serilog.Settings.Configuration, Serilog.Enrichers.* больше не нужны, если сервис не использует их напрямую: нужное приходит с Tnsu.Monitoring.

  4. Код — ILogger<T> остаётся как есть. Статический Log.Information(...) из Serilog тоже работает (после builder.Build(): пакет подменяет Log.Logger своим).

Предупреждение Data Protection «No XML encryptor configured…» пакет глушит: оно приходит на каждый новый ключ и ничего не сообщает.

Стандарт полей и поиск логов — в README репозитория.

source-hash: 9f379517f26c9adf

Dependencies

ID Version Target Framework
Serilog.AspNetCore 10.0.0 net10.0
Serilog.Sinks.OpenTelemetry 4.2.0 net10.0
Details
NuGet
2026-10-30 08:35:58 +00:00
10
TNSU
22 KiB
Assets (2)
Versions (8) View all
0.2.6 2026-10-30
0.2.5 2026-10-30
0.2.4 2026-10-30
0.2.3 2026-10-30
0.2.2 2026-10-30