Tnsu.Monitoring (0.2.1)
Installation
dotnet nuget add source --name tansu --username your_username --password your_token https://git.tnsu.kz/api/packages/tansu/nuget/index.jsondotnet add package --source tansu --version 0.2.1 Tnsu.MonitoringAbout 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-api");
Больше ничего не нужно, в том числе в конвейере app.Use…. Так же подключается в Worker Service
(Host.CreateApplicationBuilder). Без ServiceName в логах будет имя сборки.
Что включено по умолчанию
| Куда | VictoriaLogs (через Collector), консоль и файл |
| Уровень | на сервере — Debug, локально (Development) — Information; Microsoft.* и System.* — от 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["Hangfire"] = LogEventLevel.Warning;
// Лог запросов: частые служебные не писать (5xx пишутся всегда) или выключить совсем.
options.ShouldLogRequest = context => !context.Request.Path.StartsWithSegments("/health");
// options.LogRequests = false;
// Файл: путь, срок хранения или выключить.
options.FilePath = "/var/log/orders/log-.txt";
options.RetainedFileDays = 14;
// options.WriteToFile = false;
// Свой адрес приёма (обычно не нужен, см. «Куда уходят логи») и свои поля в каждой записи.
// options.OtlpEndpoint = "http://localhost:4318/v1/logs";
options.ExtraResourceAttributes["team"] = "finance";
});
Настройки без пересборки
Секция TnsuLogging в appsettings или переменные окружения (.env, docker-compose) — поверх кода.
{
"TnsuLogging": {
"MinimumLevel": "Information",
"Overrides": {
"Hangfire": "Warning",
"Microsoft.EntityFrameworkCore": "Error"
},
"WriteToFile": true,
"FilePath": "logs/log-.txt",
"OtlpEndpoint": "http://localhost:4318/v1/logs"
}
}
TnsuLogging__MinimumLevel=Information
TnsuLogging__Overrides__Hangfire=Warning
TnsuLogging__WriteToFile=false
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'а; файл в контейнере обычно не нужен — логи и так
в docker logs:
services:
orders-api:
environment:
TnsuLogging__WriteToFile: "false"
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 можно удалить целиком — пакет делает то же самое сам: консоль, файл на 5 дней, лог запросов, уровни.
-
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.* и так от Warning, консоль и файл включены по умолчанию) "TnsuLogging": { "MinimumLevel": "Information", "Overrides": { "Hangfire": "Warning" } }Секцию
Logging(стандартную, дляMicrosoft.Extensions.Logging) можно оставить — пакет её не читает. -
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(...). -
csproj — пакеты
Serilog.AspNetCore,Serilog.Sinks.Console,Serilog.Sinks.File,Serilog.Settings.Configuration,Serilog.Enrichers.*больше не нужны, если сервис не использует их напрямую: нужное приходит сTnsu.Monitoring. -
Код —
ILogger<T>остаётся как есть. СтатическийLog.Information(...)из Serilog тоже работает (послеbuilder.Build(): пакет подменяетLog.Loggerсвоим).
Предупреждение Data Protection «No XML encryptor configured…» пакет глушит: оно приходит на каждый новый ключ и ничего не сообщает.
Стандарт полей и поиск логов — в README репозитория.
source-hash: 1ea69b5ee73bc4cc