Введение: Зачем нужно логирование в TypeScript?
Логирование — это процесс записи событий, происходящих в приложении во время его работы. Для разработчика на TypeScript это не просто дополнение, а важнейший инструмент отладки, мониторинга и анализа поведения программы. Без правильно настроенного логирования вы рискуете тратить часы на поиск ошибок, которые могли бы быть обнаружены за минуты.
В этой статье мы разберем лучшие практики логирования для начинающих разработчиков на TypeScript. Вы узнаете, как выйти за рамки простого console.log, какие библиотеки использовать и как структурировать логи, чтобы они приносили реальную пользу.
1. Основы логирования: от console.log к структурированным данным
Многие новички начинают с console.log('Что-то пошло не так'). Это работает, но быстро превращается в хаос. В современной разработке на TypeScript принято использовать структурированное логирование.
Проблемы простого console.log
- Отсутствие уровней: Вы не можете отфильтровать ошибки от отладочных сообщений.
- Нет контекста: Непонятно, из какого модуля или функции пришло сообщение.
- Плохая читаемость: В production-среде логи часто парсятся машинами, а не людьми.
Первый шаг к порядку: уровни логирования
Лучшая практика — использовать стандартные уровни:
debug— для отладки во время разработки.info— для обычных событий (запрос обработан, пользователь авторизован).warn— для потенциальных проблем (нехватка памяти, устаревший API).error— для критических сбоев.
Пример простого, но уже полезного подхода:
// bad.ts
console.log('User logged in'); // ❌
// good.ts
const logger = {
info: (message: string, meta?: Record<string, unknown>) => {
console.log(JSON.stringify({ level: 'info', message, timestamp: new Date().toISOString(), ...meta }));
},
error: (message: string, error?: Error) => {
console.error(JSON.stringify({ level: 'error', message, stack: error?.stack, timestamp: new Date().toISOString() }));
}
};
logger.info('User logged in', { userId: 123 }); // ✅
Здесь мы добавляем временную метку и уровень. Это уже можно парсить. Но писать такой код вручную для каждого проекта неэффективно — используйте готовые библиотеки.
2. Выбор библиотеки для логирования в TypeScript
Для TypeScript существует несколько отличных библиотек. Рассмотрим две самые популярные: Winston и tslog. Для начинающих мы рекомендуем tslog из-за его простоты и полной поддержки TypeScript.
tslog — идеальный выбор для начинающих
Эта библиотека написана на TypeScript и предоставляет красивые, цветные логи в консоли. Она не требует сложной настройки.
// Установка: npm install tslog
import { Logger } from 'tslog';
const logger = new Logger({ name: 'MyApp' });
logger.info('Приложение запущено');
logger.warn('Память подходит к концу');
logger.error('Ошибка соединения с БД', { retryCount: 3 });
Преимущества tslog:
- Автоматическая поддержка TypeScript (типы включены).
- Красивый вывод в консоль с цветами.
- Встроенные уровни логирования.
- Минимальный порог входа.
Winston — мощный, но сложнее
Winston — это стандарт индустрии. Он позволяет отправлять логи в файлы, базы данных, Elasticsearch. Однако для простых проектов его настройка может быть избыточной.
// Установка: npm install winston
import winston from 'winston';
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.Console({ format: winston.format.simple() })
]
});
logger.info('Hello world');
Совет для начинающих: Начните с tslog. Если проект вырастет и потребует записи в файлы — мигрируйте на Winston.
3. Лучшие практики: как писать логи правильно
Даже с хорошей библиотекой можно писать бесполезные логи. Вот несколько правил, которые помогут вам.
Правило 1: Всегда добавляйте контекст
Лог "User not found" бесполезен. Какой пользователь? В каком методе? Лучше:
logger.warn(`User not found`, { userId, endpoint: '/api/users/:id' });
Правило 2: Не логируйте секреты и пароли
Никогда не пишите в логи пароли, токены или данные кредитных карт. Это угроза безопасности. Используйте фильтры или санитайзеры.
// Плохо
logger.info('Login attempt', { password: req.body.password }); // ❌
// Хорошо
logger.info('Login attempt', { username: req.body.username }); // ✅
Правило 3: Используйте единый формат
Если вы работаете в команде, договоритесь о формате. Например, JSON с полями: timestamp, level, message, service.
Правило 4: Логируйте ошибки с полным стеком
Не просто logger.error('Error'), а передавайте объект ошибки:
try {
// какой-то код
} catch (error) {
logger.error('Ошибка при обработке запроса', error instanceof Error ? error : new Error(String(error)));
}
4. Интеграция логирования в реальный проект (NestJS пример)
Рассмотрим, как внедрить логирование в популярный фреймворк NestJS (который использует TypeScript). Это отличный пример для начинающих.
Создание middleware для логирования HTTP запросов
Лучшая практика — логировать каждый входящий запрос и ответ. Это помогает отслеживать производительность и ошибки.
// logger.middleware.ts
import { Injectable, NestMiddleware, Logger } from '@nestjs/common';
import { Request