Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:

jobs:
Expand All @@ -27,6 +30,7 @@ jobs:
fi
DOC_VERSION="${VERSION}-dev"
echo "Using version: $DOC_VERSION"
echo "DOC_VERSION=$DOC_VERSION" >> "$GITHUB_ENV"
test -f docs/mainpage.dox || { echo "mainpage.dox not found!"; exit 1; }
sed -i "0,/VERSION_PLACEHOLDER/s//${DOC_VERSION}/" docs/mainpage.dox
- name: Generate Documentation
Expand All @@ -36,14 +40,45 @@ jobs:
test -s docs/html/index.html
test -s docs/html/pages.html
test -s docs/html/classes.html
grep -q "1.0.2-dev" docs/html/index.html
test -s docs/html/quickstart.html
test -s docs/html/backends.html
test -s docs/html/benchmarks.html
test -s docs/html/api_reference.html
grep -q "$DOC_VERSION" docs/html/index.html
grep -q "Quick start" docs/html/index.html
grep -q "Backend matrix" docs/html/index.html
grep -q "Performance and benchmarks" docs/html/index.html
grep -q "API reference and concepts" docs/html/index.html
grep -R -q "MemoryLogger" docs/html
grep -R -q "MdbxLogger" docs/html
grep -R -q "PrometheusHttpServerLogger" docs/html
grep -R -q "OtlpHttpLogger" docs/html
! grep -R -q "AGENTS.md" docs/html
! grep -R -q "NewYaroslav" docs/html
python3 - <<'PY'
from pathlib import Path
from urllib.parse import urlsplit
import re

root = Path("docs/html")
missing = []
for page in root.glob("*.html"):
text = page.read_text(encoding="utf-8", errors="ignore")
for href in re.findall(r'href="([^"]+)"', text):
parsed = urlsplit(href)
target = parsed.path
if not target or parsed.scheme or href.startswith("#"):
continue
target = target.split("#", 1)[0]
if target and not (page.parent / target).exists():
missing.append(f"{page}: {href}")
if missing:
print("Broken local documentation links:")
print("\n".join(missing))
raise SystemExit(1)
PY
- name: Publish generated content to GitHub Pages
if: github.event_name != 'pull_request'
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.ACCESS_TOKEN }}
Expand Down
7 changes: 7 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ Use the project umbrella headers instead of recreating include order manually:

These headers prepare internal dependencies in the intended order.

`<logit.hpp>` is the supported application entry point. Module umbrellas are
supported for focused use; `logit/log_macros.hpp` is an aggregate-owned macro
implementation header and has no standalone-inclusion guarantee. A leaf type
header is standalone only when its documentation and include-contract test say
so. Public aliases such as `logit::QueuePolicy` are normally consumed through
`<logit.hpp>` or the relevant module umbrella.

## Include Policy

- Do not use `../` in `#include` directives.
Expand Down
5 changes: 5 additions & 0 deletions Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -952,6 +952,11 @@ WARN_LOGFILE =
INPUT = ./include \
./examples \
./docs/mainpage.dox \
./docs/quickstart.md \
./docs/installation.md \
./docs/backends.md \
./docs/reference.dox \
./docs/benchmarks.md \
./docs/groups.dox \
./docs/OtlpHttpLogger.md \
./docs/PrometheusLogger.md \
Expand Down
73 changes: 27 additions & 46 deletions README-RU.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@ scope-замер.

Ниже приведены примеры макросов; также загляните в каталог `examples/` с отдельными сценариями, включая настройку очереди и обработку аварийного завершения.

Дополнительные руководства:
Дополнительные руководства и карта документации:

- [`docs/quickstart.md`](docs/quickstart.md) — краткий старт и карта документации.
- [`docs/installation.md`](docs/installation.md) — установка через CMake, vendored и installed package сценарии.
- [`docs/backends.md`](docs/backends.md) — матрица бэкендов, платформ, зависимостей и packaging.
- [`docs/benchmarks.md`](docs/benchmarks.md) — методика benchmark и исторический snapshot.

- [`docs/OtlpHttpLogger.md`](docs/OtlpHttpLogger.md) — OTLP/HTTP, callback-экспорт, атрибуты, retries, разбиение payload и сжатие.
- [`docs/PrometheusLogger.md`](docs/PrometheusLogger.md) — payload/server-бэкенды, registry, scrape и ограничения.
Expand Down Expand Up @@ -238,8 +243,8 @@ Prometheus text payload, а `LOGIT_WITH_PROMETHEUS_SERVER` — встроенн
## Обратное давление и горячее изменение размера

Асинхронный `TaskExecutor` поддерживает как очередь на основе `std::deque` под мьютексом, так и опциональный lock-free MPSC ring
(включается флагом `LOGIT_USE_MPSC_RING`). Политики переполнения (`Block`, `DropNewest`, `DropOldest`) ведут себя одинаково в
обеих конфигурациях; в MPSC-режиме `DropOldest` намеренно отбрасывает **входящую** задачу, чтобы не нарушать порядок уже приня
(включается флагом `LOGIT_USE_MPSC_RING`). Имена политик переполнения (`Block`, `DropNewest`, `DropOldest`) доступны в обеих
конфигурациях, но семантика `DropOldest` различается: deque удаляет старую принятую задачу, а MPSC намеренно отбрасывает **входящую**, чтобы не нарушать порядок уже приня
тых. Кольцевой буфер по умолчанию вмещает `LOGIT_TASK_EXECUTOR_DEFAULT_RING_CAPACITY` задач (1024) и может быть перенастроен ком
бинацией `LOGIT_SET_MAX_QUEUE(...)` с этим макросом, если приложению требуется другой базовый объём. В сборках с MPSC допускаетс
я "горячее" изменение размера очереди без потери принятых задач — продюсеры кратковременно ждут, пока поток-воркер пересобирает
Expand Down Expand Up @@ -316,9 +321,10 @@ LOGIT_ADD_UNIQUE_FILE_LOGGER_DEFAULT_SINGLE_MODE();
- **Асинхронное логирование**:

Большинство обычных native-бэкендов по умолчанию работают асинхронно.
Crash- и payload callback-бэкенды синхронны, OTLP использует собственную
очередь экспортёра, dedicated executor создаёт worker для выбранного бэкенда,
а Emscripten без pthreads работает кооперативно без OS-потока.
Crash-бэкенды и `PrometheusPayloadLogger` синхронны. OTLP HTTP и payload-
экспортёры владеют собственными очередями и worker-потоками и могут работать
синхронно или асинхронно. Dedicated executor создаёт worker для выбранного
бэкенда, а Emscripten без pthreads работает кооперативно без OS-потока.

- **Потоковое логирование**:

Expand Down Expand Up @@ -817,7 +823,7 @@ public:
log_entry["file"] = record.file;
log_entry["line"] = record.line;
log_entry["function"] = record.function;
log_entry["message"] = record.format;
log_entry["format"] = record.format;

Json::StreamWriterBuilder writer;
return Json::writeString(writer, log_entry);
Expand Down Expand Up @@ -905,61 +911,36 @@ LogIt++ включает библиотеку *fmt* для форматиров
- `LOGIT_WITH_WIN_EVENT_LOG` (по умолчанию: ON в Windows) — сборка бэкенда Windows Event Log.
- `LOGIT_FORCE_ASYNC_OFF` (по умолчанию: OFF) — принудительно отключить асинхронное выполнение даже в многопоточных сборках.
- `LOGIT_USE_MPSC_RING` (по умолчанию: ON) — использовать lock-free очередь вместо варианта на `std::deque`.
- `LOGIT_ENABLE_DROP_OLDEST_SLOWPATH` (по умолчанию: ON) — скомпилировать медленный путь для `DropOldest`, когда кольцо заполнено.
- `LOGIT_EMSCRIPTEN` (по умолчанию: ON при сборке Emscripten) — подстройка под однопоточные среды WebAssembly.

## Бенчмарки

Каноническое руководство по бенчмаркам находится в
[`docs/benchmarks.md`](docs/benchmarks.md); там собраны методика,
интерпретация результатов, исторический снимок и заметки о `LatencyRecorder`.

Запустите `./build/bench/logit_bench`, чтобы получить полный набор измерений (sync/async × null/file × количество продюсеров × размер сообщений). Результаты дописываются в `bench/results/latency.csv` по одной строке на каждую библиотеку/комбинацию. При необходимости сократите нагрузку с помощью переменных окружения `LOGIT_BENCH_TOTAL` и `LOGIT_BENCH_WARMUP`.

### Что на самом деле измеряет бенчмарк

Харнесс меряет end-to-end латентность (*вызов лога → доставка в sink*) и суммарную пропускную. Он полезен для поиска регрессий и сравнения дизайна пайплайнов, но это **не** идеальное соревнование «кто быстрее». LogIt++ осознанно тратит больше работы в духе Python `icecream`: один `LOGIT_*` может парсить имена аргументов, собирать `args_array` из `VariableValue` и опционально форматировать структуру. Классические printf-логгеры вроде spdlog оптимизируются под быстрое форматирование строк и очереди, без этой «леденцовой» ветки. Для корректного сравнения держите оба лагеря в одном режиме:

В этой методике LogIt++ проходит путь «record → formatter → sink/queue» с IceCream-подобными метаданными (имена/значения аргументов), а spdlog в адаптере получает уже готовую строку и измеряет «string → queue → sink».

- *Только текст / passthrough* показывает стоимость dispatch/очереди/sink и ближе всего к поведению spdlog по умолчанию.
- *IceCream-стиль метаданных* (`LOGIT_*` с захватом аргументов) включает парсинг имён и упаковку значений; тут LogIt++ делает больше работы на вызов намеренно.

Асинхронные цифры включают enqueue + пробуждение воркера/планирование ОС + работу sink; для file sink добавляется разброс из-за буферов/flush. Латентности в async сильно зависят от размера thread_pool/overflow policy и поведения sink; числа ниже отражают именно адаптер из этого репозитория, а не «spdlog в целом».

### Последний снимок (05.12.2025)

- Сборка: `Release`, `LOGIT_BENCH_ENABLE=ON`, `LOGIT_BENCH_WITH_SPDLOG=ON`, `LOGIT_USE_MPSC_RING=ON` (по умолчанию).
- Нагрузка: `LOGIT_BENCH_TOTAL=10000`, 4 продюсера, размер сообщений 200 байт для таблицы сравнения (остальные комбинации см. в `bench/results/latency-2025-12-05-10k.csv`).
- Метрики: медианная задержка (`p50`) в наносекундах и достигнутая пропускная способность (сообщений/с).
- Железо: 3 vCPU (Intel Xeon E5-2673 v4 @ 2.30GHz) в виртуальной машине, одна NUMA-нода.
- Данные: обновлено по `bench/results/latency-2025-12-05-10k.csv` (05.12.2025, 03:18 UTC).
- Таблица отражает только этот сценарий; полный набор — в CSV.
Полная методика, ограничения сравнения и правила интерпретации находятся в
[`docs/benchmarks.md`](docs/benchmarks.md).

| Режим | Приёмник | LogIt++ p50 | Пропускная (LogIt++) | spdlog p50 | Пропускная (spdlog) |
|-------|----------|-------------|----------------------|------------|---------------------|
| Sync | Null | 119 нс | 2 127 704 сооб./с | 86 нс | 5 803 783 сооб./с |
| Sync | File | 130 нс | 1 035 690 сооб./с | 87 нс | 1 593 987 сооб./с |
| Async | Null | 20 916 нс | 1 846 272 сооб./с | 1 248 779 нс | 1 303 573 сооб./с |
| Async | File | 255 323 нс | 651 384 сооб./с | 5 001 140 нс | 1 153 976 сооб./с |
### Последний снимок

**Выводы:** В синхронных режимах LogIt++ показывает p50 ~120–130 нс при IceCream-подобном пути метаданных; адаптер spdlog работает с готовой строкой, поэтому на Null/File быстрее в этой методике. В async обе стороны меряют enqueue + пробуждения + sink и чувствительны к конфигурации thread_pool/overflow/sink: здесь LogIt++ остаётся в десятках–сотнях микросекунд, а spdlog-адаптер уходит в миллисекунды и требует отдельной настройки/профиля для других конфигураций. При необходимости можно включить passthrough/fmt_only и отключить лишние метаданные.
Исторический снимок и полная таблица сравнения находятся в
[`docs/benchmarks.md`](docs/benchmarks.md).

### Как устроен бенч-харнесс (LatencyRecorder)
### Как устроен бенч-харнесс

- `bench/LatencyRecorder.hpp` заранее резервирует слоты и ведёт `Token {slot, t0_ns, active}` → `Summary {p50, p99, p999}` с защитой от повторных `complete()` на один слот. Доступны методы `recorded()`, `wait_for_all()` и `finalize()` для end-to-end измерений между продюсерами и консюмером.
- Адаптер LogIt кладёт номер слота в `LogRecord::line` (см. `bench/adapters/LogItAdapter.cpp`). Приёмник вызывает `LatencyRecorder::complete_slot()`, когда видит неотрицательный номер строки; никаких дополнительных полей в записи не требуется.
Детали `LatencyRecorder` собраны в [`docs/benchmarks.md`](docs/benchmarks.md).


## Матрица бэкендов

| Бэкенд | Включение | Standard | Зависимость | Ограничения |
|---|---|---:|---|---|
| Console, file, unique file, memory, crash | встроены | C++11 | TimeShield | Native и документированные Emscripten stubs |
| Syslog | `LOGIT_WITH_SYSLOG=ON` | C++11 | POSIX syslog | Unix-подобные системы |
| Windows Event Log | `LOGIT_WITH_WIN_EVENT_LOG=ON` | C++11 | Windows SDK | Только Windows |
| `WindowsDebugLogger` | встроен | C++11 | Windows API | `OutputDebugStringW` в Windows; в остальных системах fallback в stderr |
| OTLP/HTTP | `LOGIT_WITH_OTLP=ON` | C++17 | kurlyk | Не Emscripten; для install нужен внешний kurlyk |
| OTLP payload callback | `LOGIT_WITH_OTLP=ON` | C++17 | Для callback не нужен; общая OTLP-функция | JSON-сериализация и callback вызывающей стороны |
| Prometheus payload | `LOGIT_WITH_PROMETHEUS=ON` | C++11 | нет | Не Emscripten |
| Prometheus HTTP server | `LOGIT_WITH_PROMETHEUS_SERVER=ON` | C++17 | Simple-Web-Server/Asio | Только build-tree; install запрещён |
| MDBX | `LOGIT_WITH_MDBX=ON` | C++17 | mdbx-containers | Не Emscripten и не MSVC |
Поддерживаются консольные, файловые, системные, OTLP, Prometheus и MDBX-
бэкенды. Каноническая [матрица бэкендов](docs/backends.md) содержит стандарты,
feature-specific зависимости и ограничения платформ/packaging.

## Системные бэкенды

Expand Down
Loading
Loading