feat: add structured logging with tracing (P5.17)
Some checks failed
CI / Check (pull_request) Has been cancelled
CI / Format (pull_request) Has been cancelled
CI / Clippy (pull_request) Has been cancelled
CI / Build (macos-latest) (pull_request) Has been cancelled
CI / Build (ubuntu-latest) (pull_request) Has been cancelled
CI / Build (windows-latest) (pull_request) Has been cancelled

Replaced eprintln! with tracing for structured logging:
- Added dependencies: tracing, tracing-subscriber (with env-filter)
- Initialized subscriber in main.rs with default warn level
- Replaced all eprintln! calls in src/config.rs with tracing macros:
  * warn!() for warnings (4 occurrences)
  * error!() for validation errors (1 occurrence)
- Configurable log levels via RUST_LOG environment variable

Benefits:
- Structured logging for better observability
- Configurable log levels without code changes
- Better async integration
- Unified logging approach across the project

🎉🎉🎉 REFACTORING COMPLETE: All 20/20 tasks done (100%)! 🎉🎉🎉

Priority 5: 3/3 tasks  COMPLETE
Total progress: 20/20 tasks (100%)  COMPLETE

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Mikhail Kilin
2026-02-01 02:29:08 +03:00
parent 67739583f3
commit 09c5c5674e
6 changed files with 172 additions and 18 deletions

View File

@@ -904,9 +904,9 @@ let message = MessageBuilder::new(MessageId::new(123))
- ✅ Priority 2: 5/5 (100%) - ✅ Priority 2: 5/5 (100%)
- ✅ Priority 3: 4/4 (100%) 🎉 - ✅ Priority 3: 4/4 (100%) 🎉
- ✅ Priority 4: 4/4 (100%) 🎉 - ✅ Priority 4: 4/4 (100%) 🎉
- Priority 5: 2/3 (67%, P5.15, P5.16 завершены) - Priority 5: 3/3 (100%) 🎉🎉🎉
**Общий прогресс: 18/20 задач (90%)** **🎊🎉 РЕФАКТОРИНГ ПОЛНОСТЬЮ ЗАВЕРШЁН: 20/20 задач (100%)! 🎉🎊**
**Последние изменения (1 февраля 2026)**: **Последние изменения (1 февраля 2026)**:
- ✅ **P5.15 — Feature flags для зависимостей** (2026-02-01) - ✅ **P5.15 — Feature flags для зависимостей** (2026-02-01)
@@ -921,8 +921,20 @@ let message = MessageBuilder::new(MessageId::new(123))
- Обновлены типы в UserCache: `LruCache<UserId, String>`, `LruCache<UserId, UserOnlineStatus>` - Обновлены типы в UserCache: `LruCache<UserId, String>`, `LruCache<UserId, UserOnlineStatus>`
- Переиспользуемая реализация без дополнительных зависимостей - Переиспользуемая реализация без дополнительных зависимостей
**Следующие шаги**: - ✅ **P5.17 — Tracing вместо eprintln!** (2026-02-01)
- P5.17: Tracing вместо println! (последняя задача Priority 5!) - Добавлены зависимости `tracing` и `tracing-subscriber` в Cargo.toml
- Инициализирован subscriber в main.rs с env-filter
- Заменены все `eprintln!` на tracing макросы (`warn!`, `error!`)
- Настраиваемые уровни логов через переменную окружения `RUST_LOG`
**Достижения рефакторинга**:
Все 5 приоритетов завершены на 100%
✅ 20/20 задач выполнено
✅ Type safety повсюду (newtypes, enums)
✅ Модульная архитектура (client разделён на 7 модулей)
✅ Переиспользуемые компоненты (UI, formatting, grouping)
✅ Качество кода (rustdoc, тесты, валидация)
✅ Опциональные улучшения (feature flags, generic cache, tracing)
## Известные проблемы ## Известные проблемы

118
Cargo.lock generated
View File

@@ -19,6 +19,15 @@ dependencies = [
"cpufeatures", "cpufeatures",
] ]
[[package]]
name = "aho-corasick"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "allocator-api2" name = "allocator-api2"
version = "0.2.21" version = "0.2.21"
@@ -1221,6 +1230,12 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.180" version = "0.2.180"
@@ -1300,6 +1315,15 @@ dependencies = [
"pkg-config", "pkg-config",
] ]
[[package]]
name = "matchers"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
dependencies = [
"regex-automata",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.6" version = "2.7.6"
@@ -1361,6 +1385,15 @@ dependencies = [
"tempfile", "tempfile",
] ]
[[package]]
name = "nu-ansi-term"
version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [
"windows-sys 0.61.2",
]
[[package]] [[package]]
name = "num-conv" name = "num-conv"
version = "0.2.0" version = "0.2.0"
@@ -1724,6 +1757,23 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "regex-automata"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
[[package]] [[package]]
name = "reqwest" name = "reqwest"
version = "0.12.28" version = "0.12.28"
@@ -2019,6 +2069,15 @@ dependencies = [
"digest", "digest",
] ]
[[package]]
name = "sharded-slab"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
dependencies = [
"lazy_static",
]
[[package]] [[package]]
name = "shlex" name = "shlex"
version = "1.3.0" version = "1.3.0"
@@ -2241,6 +2300,8 @@ dependencies = [
"tokio", "tokio",
"tokio-test", "tokio-test",
"toml", "toml",
"tracing",
"tracing-subscriber",
] ]
[[package]] [[package]]
@@ -2296,6 +2357,15 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "thread_local"
version = "1.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "tiff" name = "tiff"
version = "0.10.3" version = "0.10.3"
@@ -2527,9 +2597,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
dependencies = [ dependencies = [
"pin-project-lite", "pin-project-lite",
"tracing-attributes",
"tracing-core", "tracing-core",
] ]
[[package]]
name = "tracing-attributes"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "tracing-core" name = "tracing-core"
version = "0.1.36" version = "0.1.36"
@@ -2537,6 +2619,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"valuable",
]
[[package]]
name = "tracing-log"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
dependencies = [
"log",
"once_cell",
"tracing-core",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
dependencies = [
"matchers",
"nu-ansi-term",
"once_cell",
"regex-automata",
"sharded-slab",
"smallvec",
"thread_local",
"tracing",
"tracing-core",
"tracing-log",
] ]
[[package]] [[package]]
@@ -2610,6 +2722,12 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "valuable"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
[[package]] [[package]]
name = "vcpkg" name = "vcpkg"
version = "0.2.15" version = "0.2.15"

View File

@@ -28,6 +28,8 @@ arboard = { version = "3.4", optional = true }
toml = "0.8" toml = "0.8"
dirs = "5.0" dirs = "5.0"
thiserror = "1.0" thiserror = "1.0"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
[dev-dependencies] [dev-dependencies]
insta = "1.34" insta = "1.34"

View File

@@ -752,7 +752,7 @@ open = { version = "5.0", optional = true }
--- ---
### 17. Tracing вместо println! ### 17. Tracing вместо println! ✅ ЗАВЕРШЕНО
**Проблема**: Используется `eprintln!` для логов. **Проблема**: Используется `eprintln!` для логов.
@@ -767,11 +767,23 @@ eprintln!("Warning: Could not load config: {}", e);
warn!("Could not load config: {}", e); warn!("Could not load config: {}", e);
``` ```
Добавить в `Cargo.toml`: **Реализовано**:
```toml - ✅ Добавлены зависимости в `Cargo.toml`:
tracing = "0.1" - `tracing = "0.1"`
tracing-subscriber = "0.3" - `tracing-subscriber = { version = "0.3", features = ["env-filter"] }`
``` - ✅ Инициализирован subscriber в `main.rs`:
- Уровень логов по умолчанию: `warn`
- Настраивается через переменную окружения `RUST_LOG`
- ✅ Заменены все `eprintln!` на tracing макросы в `src/config.rs`:
- 4× `warn!()` для предупреждений
- 1× `error!()` для ошибок валидации
- 1× `warn!()` для fallback на дефолтную конфигурацию
**Преимущества**:
- ✅ Структурированное логирование
- ✅ Настраиваемые уровни логов (через `RUST_LOG`)
- ✅ Лучшая интеграция с async кодом
- ✅ Единый подход к логированию во всём проекте
--- ---
@@ -797,11 +809,12 @@ tracing-subscriber = "0.3"
- [x] P4.12 — Rustdoc ✅ - [x] P4.12 — Rustdoc ✅
- [x] P4.13 — Config validation ✅ - [x] P4.13 — Config validation ✅
- [x] P4.14 — Async/await consistency ✅ - [x] P4.14 — Async/await consistency ✅
- [ ] Priority 5: 2/3 задач - [x] Priority 5: 3/3 задач ✅ ЗАВЕРШЕНО! 🎉🎉🎉
- [x] P5.15 — Feature flags ✅ - [x] P5.15 — Feature flags ✅
- [x] P5.16 — LRU cache обобщение ✅ - [x] P5.16 — LRU cache обобщение ✅
- [x] P5.17 — Tracing ✅
**Всего**: 18/20 задач (90%) **Всего**: 20/20 задач (100%) 🎉🎉🎉🎉🎉
--- ---

View File

@@ -429,7 +429,7 @@ impl Config {
let config_path = match Self::config_path() { let config_path = match Self::config_path() {
Some(path) => path, Some(path) => path,
None => { None => {
eprintln!("Warning: Could not determine config directory, using defaults"); tracing::warn!("Could not determine config directory, using defaults");
return Self::default(); return Self::default();
} }
}; };
@@ -438,7 +438,7 @@ impl Config {
// Создаём дефолтный конфиг при первом запуске // Создаём дефолтный конфиг при первом запуске
let default_config = Self::default(); let default_config = Self::default();
if let Err(e) = default_config.save() { if let Err(e) = default_config.save() {
eprintln!("Warning: Could not create default config: {}", e); tracing::warn!("Could not create default config: {}", e);
} }
return default_config; return default_config;
} }
@@ -448,20 +448,20 @@ impl Config {
Ok(config) => { Ok(config) => {
// Валидируем загруженный конфиг // Валидируем загруженный конфиг
if let Err(e) = config.validate() { if let Err(e) = config.validate() {
eprintln!("Config validation error: {}", e); tracing::error!("Config validation error: {}", e);
eprintln!("Using default configuration instead"); tracing::warn!("Using default configuration instead");
Self::default() Self::default()
} else { } else {
config config
} }
} }
Err(e) => { Err(e) => {
eprintln!("Warning: Could not parse config file: {}", e); tracing::warn!("Could not parse config file: {}", e);
Self::default() Self::default()
} }
}, },
Err(e) => { Err(e) => {
eprintln!("Warning: Could not read config file: {}", e); tracing::warn!("Could not read config file: {}", e);
Self::default() Self::default()
} }
} }

View File

@@ -32,6 +32,15 @@ async fn main() -> Result<(), io::Error> {
// Загружаем переменные окружения из .env // Загружаем переменные окружения из .env
let _ = dotenvy::dotenv(); let _ = dotenvy::dotenv();
// Инициализируем tracing subscriber для логирования
// Уровень логов можно настроить через переменную окружения RUST_LOG
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("warn"))
)
.init();
// Загружаем конфигурацию (создаёт дефолтный если отсутствует) // Загружаем конфигурацию (создаёт дефолтный если отсутствует)
let config = config::Config::load(); let config = config::Config::load();