Введение: Зачем нужно логирование в TypeScript?
Логирование — это не просто запись сообщений в консоль. В современных TypeScript приложениях (серверных на Node.js, клиентских на React/Angular или full-stack проектах) логирование становится критическим инструментом для отладки, мониторинга и анализа производительности. Без качественного логирования разработчики тратят часы на воспроизведение ошибок, а DevOps-инженеры не могут быстро определить причину сбоя в production.
TypeScript, как надстройка над JavaScript, добавляет строгую типизацию, что позволяет создавать более надёжные и предсказуемые системы логирования. В этой статье мы разберём лучшие практики, которые помогут вам организовать эффективное логирование в TypeScript-проектах.
Основные принципы логирования
Уровни логирования
Правильное использование уровней логирования — основа любой системы мониторинга. В TypeScript принято использовать следующие уровни (по возрастанию важности):
debug— детальная отладочная информация (только для разработки);info— стандартные информационные сообщения (запуск сервера, запросы);warn— предупреждения (некритичные проблемы);error— ошибки, требующие внимания;fatal— критические ошибки, приводящие к остановке приложения.
Пример настройки уровней с помощью библиотеки Winston:
import winston from 'winston';
const logger = winston.createLogger({
level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
format: winston.format.json(),
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: 'error.log', level: 'error' }),
],
});
logger.info('Сервер запущен на порту 3000');
logger.warn('Память близка к лимиту');
logger.error('Ошибка подключения к БД');
Структурированные логи
Избегайте простых строковых сообщений. Используйте структурированные логи с контекстной информацией (JSON-формат). Это упрощает поиск и анализ в системах вроде ELK или Grafana.
// Плохо
logger.info(`Пользователь ${userId} выполнил действие ${action}`);
// Хорошо
logger.info('Действие пользователя', {
userId: userId,
action: action,
timestamp: new Date().toISOString(),
ip: request.ip,
});
Такой подход позволяет фильтровать логи по полям и строить графики.
Лучшие практики для TypeScript
Использование TypeScript для типизации логов
TypeScript позволяет определить интерфейсы для контекста логов, что предотвращает случайные ошибки в названиях полей:
interface LogContext {
userId: string;
action: string;
durationMs: number;
success: boolean;
}
function logUserAction(context: LogContext): void {
logger.info('User action', context);
}
// Компилятор проверит, что все поля переданы корректно
logUserAction({
userId: '123',
action: 'login',
durationMs: 150,
success: true,
});
Избегайте логирования чувствительных данных
Никогда не логируйте пароли, токены, номера кредитных карт или персональные данные (GDPR). Используйте утилиты для маскировки:
function sanitizeLogData(data: Record<string, unknown>): Record<string, unknown> {
const sensitiveFields = ['password', 'token', 'ssn'];
const sanitized = { ...data };
for (const field of sensitiveFields) {
if (sanitized[field]) {
sanitized[field] = '***';
}
}
return sanitized;
}
logger.info('User registration', sanitizeLogData(userData));
Асинхронное логирование и производительность
В высоконагруженных приложениях синхронное логирование может замедлить работу. Используйте асинхронные транспорты (например, winston поддерживает буферизацию).
import winston from 'winston';
import 'winston-daily-rotate-file';
const transport = new winston.transports.DailyRotateFile({
filename: 'app-%DATE%.log',
datePattern: 'YYYY-MM-DD',
maxSize: '20m',
maxFiles: '14d',
// Асинхронная запись
zippedArchive: true,
});
const asyncLogger = winston.createLogger({
transports: [transport],
});
Выбор библиотеки для логирования
Сравнение популярных решений
Для TypeScript-проектов на Node.js чаще всего используют:
- Winston — самый популярный, гибкий, множество транспортов (файлы, консоль, внешние сервисы).
- Pino — очень быстрый, минималистичный, отлично подходит для микросервисов.
- Bunyan — старый, но надёжный, выводит логи в JSON.
- Loglevel — лёгкая библиотека для клиентских приложений (браузер).
Пример использования Pino с TypeScript (очень высокая производительность):
import pino from 'pino';
const logger = pino({
level: process.env.LOG_LEVEL || 'info',
formatters: {
level(label) {
return { level: label };
},
},
// Для production можно отключить красивое форматирование
transport: process.env.NODE_ENV !== 'production'
? { target: 'pino-pretty' }
: undefined,
});
logger.info({ userId: 42 }, 'User logged in');
Заключение
Логирование в TypeScript — это не просто техническая необходимость, а стратегический инструмент для поддержки качества кода и быстрого реагирования на инциденты. Следуя описанным практикам, вы сможете:
- Быстро находить и исправлять ошибки;
- Собирать метрики для оптимизации производительности;
- Обеспечить безопасность данных (за счёт маскировки);
- Интегрироваться с системами мониторинга (Grafana, ELK, Datadog).
Начните с малого: выберите библиотеку (Winston или Pino), определите уровни логирования и добавьте типизацию для контекста. Постепенно вы построите систему, которая станет основой для стабильной работы вашего TypeScript-приложения.
Не забывайте регулярно пересматривать