Структурированное логирование является одним из ключевых аспектов построения масштабируемых и поддерживаемых приложений во Fresh. В отличие от обычного текстового логирования, структурированные логи представляют собой объекты с заранее определённой схемой, что упрощает последующую фильтрацию, агрегацию и анализ данных.
Формат логов Логи должны иметь единый формат, чаще всего JSON, где каждая запись содержит обязательные поля:
timestamp — отметка времени события в ISO 8601
формате.level — уровень логирования (debug,
info, warn, error).message — описание события.context — объект с дополнительными данными,
относящимися к событию (например, идентификатор запроса, имя
пользователя, состояние приложения).Контекстность Логи должны передавать контекст выполнения. В Fresh это часто реализуется через middleware или глобальные объекты состояния, которые добавляют к каждой записи уникальные идентификаторы запросов и метаданные.
Предсказуемость структуры Все записи должны следовать единой схеме. Это позволяет использовать лог-агрегаторы (например, Loki, Elasticsearch, Grafana) для построения аналитики без дополнительных преобразований.
Fresh не имеет встроенной сложной системы логирования, поэтому чаще
всего используется комбинация стандартного console с
обёртками для структурирования. Простейший пример:
function log(level, message, context = {}) {
const logEntry = {
timestamp: new Date().toISOString(),
level,
message,
context,
};
console.log(JSON.stringify(logEntry));
}
// Использование
log("info", "Запрос обработан успешно", { userId: 42, path: "/api/data" });
Такой подход позволяет сразу отправлять логи в систему сбора без дополнительного парсинга.
Fresh активно использует маршрутизацию через routes. Для
логирования каждого запроса удобно использовать middleware:
import { HandlerContext } from "$fresh/server.ts";
export async function handler(req: Request, ctx: HandlerContext) {
const requestId = crypto.randomUUID();
const startTime = Date.now();
try {
const resp = await ctx.next(); // передача запроса дальше
const duration = Date.now() - startTime;
log("info", "Запрос обработан", {
requestId,
path: new URL(req.url).pathname,
method: req.method,
status: resp.status,
durationMs: duration
});
return resp;
} catch (err) {
log("error", "Ошибка при обработке запроса", {
requestId,
path: new URL(req.url).pathname,
method: req.method,
error: err.message,
});
throw err;
}
}
Особое внимание уделяется requestId — уникальному
идентификатору запроса. Он позволяет связывать все логи, относящиеся к
одной операции, даже если обработка включает асинхронные вызовы или
внутренние сервисы.
Использование уровней логирования упрощает фильтрацию информации:
debug — подробная отладочная информация, которая нужна
только разработчику.info — ключевые события работы приложения.warn — предупреждения, которые не мешают выполнению, но
требуют внимания.error — ошибки, приводящие к сбоям или некорректной
работе.В Fresh можно реализовать условную фильтрацию, чтобы, например, в
production выводить только info, warn и
error, а в development — все уровни:
const LOG_LEVELS = { debug: 0, info: 1, warn: 2, error: 3 };
const CURRENT_LEVEL = "info";
function log(level, message, context = {}) {
if (LOG_LEVELS[level] >= LOG_LEVELS[CURRENT_LEVEL]) {
console.log(JSON.stringify({ timestamp: new Date().toISOString(), level, message, context }));
}
}
Структурированные логи легко интегрировать с внешними платформами мониторинга и алертинга:
Для интеграции достаточно направлять сериализованные JSON-записи через HTTP или писать их в файл, который считывается агентом логирования.
requestId,
userId, sessionId), чтобы связывать
события.context для всех
логов.Структурированное логирование во Fresh превращает обычные сообщения об ошибках в мощный инструмент анализа и мониторинга, позволяя быстро выявлять проблемы и улучшать качество приложения.