Перейти к содержимому

Обзор ​

Лог — одна строка текста с уровнем и, при желании, структурированными атрибутами — данными «ключ: значение», которые иначе пришлось бы подставлять в сообщение. Логи появляются в разделе Логи проекта, с поиском по сообщению, уровню и атрибутам.

Отправлять их можно двумя способами:

  • Явно, через log.info() / warn() / error() / ... — рекомендуется: вы сами решаете, что стоит отправлять, и можете приложить атрибуты.
  • Автоматически, через ConsoleIntegration, которая пересылает каждый вызов console.log/info/warn/error/debug.

Логи — не ошибки: log.error() записывает строку уровня error, но инцидент не создаёт. Чтобы сообщить об исключении со стеком, используйте captureException() (см. Ошибки).

Отправка логов ​

У log по методу на уровень — log, debug, info, warn, error; каждый принимает сообщение и необязательный объект атрибутов (есть ещё trace и fatal — сохраняются как debug и error):

ts
import { log } from '@buglapse/node'

log.info('Server started', { port: 3000 })
log.warn('Payment retry', { orderId: 1042, attempt: 2 })
log.error('Webhook rejected', { provider: 'stripe', reason: 'bad_signature' })

Вызовы до init() встают в очередь и отправляются, когда появится клиент.

Каждый лог собирается транспортом в пачку (см. Транспорты) и получает текущие теги и контекст — глобальные и, внутри запроса или withScope(), контекст этой области (см. Теги и контекст).

Атрибуты ​

Держите сообщение постоянной строкой, а переменные части выносите в атрибуты:

ts
// Хорошо — одно сообщение, поля для поиска
log.info('Order placed', { orderId: order.id, total: order.total, currency: 'EUR' })

// Плохо — каждый вызов даёт новое сообщение, фильтровать не по чему
log.info(`Order ${order.id} placed for ${order.total} EUR`)

Каждый атрибут верхнего уровня становится фильтром поиска в панели (orderId:1042). Предпочитайте плоские объекты со строками, числами или булевыми значениями — вложенные объекты сохраняются и показываются, но фильтрами не предлагаются.

Атрибуты описывают одну строку лога; теги и контекст — всё, что поймано в их области. Атрибуты — для «что произошло в этом вызове», теги и контекст — для «кто и где».

Шаблоны через fmt ​

Когда переменные части лучше читаются внутри сообщения, пишите его с тегом fmt вместо обычного шаблонного литерала:

ts
import { fmt, log } from '@buglapse/node'

log.error(fmt`Order ${order.id} failed for ${user.email}`)

Сообщение отправляется как обычно — Order 1042 failed for ann@example.com — вместе с шаблоном и значениями в атрибутах: message.template (Order %s failed for %s) и message.parameter.0, message.parameter.1, …. Повторы одного шаблона с другими значениями сворачиваются в одну строку ×N в разделе Логи, а message.template:"Order %s failed for %s" находит их все.

Значения сохраняются как строки, числа и булевы (всё остальное — текстом), первые 20; ваш собственный атрибут с тем же ключом важнее. fmt работает и с captureMessage() — см. Ошибки.

Пересылка консоли ​

Если ваш код (или библиотека) уже логирует через console, включите ConsoleIntegration:

ts
import { init } from '@buglapse/node'
import { consoleIntegration } from '@buglapse/node/integrations'

init({
    dsn: process.env.BUGLAPSE_DSN,
    integrations: [consoleIntegration()],
})

Исходный вызов по-прежнему печатает в stdout/stderr, затем отправляется логом того же уровня. Простой объект в конце становится атрибутами; всё перед ним склеивается в сообщение:

ts
console.warn('Slow query', { table: 'orders', ms: 1840 })
// → лог warn "Slow query", атрибуты { table: "orders", ms: 1840 }

console.log('Order %s failed after %d tries', 'A-1042', 3)
// → сообщение "Order A-1042 failed after 3 tries", шаблон "Order %s failed after %s tries"

Первый аргумент в стиле printf форматируется так, как его печатает Node, и сохраняется как шаблон лога (см. Шаблоны через fmt).

Что учесть:

  • В один и тот же console пишет каждая библиотека процесса — включение может отправлять много. После включения следите за квотой логов.
  • console.error(error) превращается в сообщение {}: у Error нет перечисляемых полей для JSON.stringify. Об ошибках сообщайте через captureException().
  • Пересылаются только log, info, warn, error и debug.
  • Логгеры, которые пишут прямо в process.stdout (pino, потоковые транспорты winston), обходят console и не перехватываются — вызывайте log.*() из своего транспорта логгера.

Логи от интеграций ​

Две интеграции отправляют свои логи:

  • HttpErrorsIntegration — лог error на каждый неудачный исходящий запрос (5xx или сетевой сбой), с атрибутами method, url и status.
  • EventLoopBlockIntegration — лог warn, когда синхронная работа блокирует event loop, с атрибутом duration.

Связь логов с трейсами ​

Лог, пойманный при активном спане — где угодно внутри запроса, обработанного HttpServerIntegration, или внутри вашего asyncSpan(), — получает trace.id и span.id, и панель связывает его с этим трейсом. Лог вне спана (при запуске, в таймере верхнего уровня) с трейсом не связан.

Отбрасывание и очистка логов ​

Логи проходят через те же препроцессоры, что и остальные события, так что их можно отбросить или переписать до того, как они покинут процесс:

ts
import { addPreprocessor } from '@buglapse/node'

addPreprocessor((event) => {
    if (event.type !== 'log') return event

    if (event.payload.level === 'debug' && process.env.NODE_ENV === 'production') return null

    delete event.payload.attributes?.email

    return event
})

Фильтры и квота ​

На сервере логи проходят через Настройки → Фильтры проекта, как и все события: фильтр краулеров и выражение фильтра (например, "{{event.message}}" ~ "heartbeat"). См. Фильтрация шума.

Каждый сохранённый лог расходует месячную квоту логов организации. Когда она исчерпана, логи отклоняются до следующего месяца; на ошибки и трейсы это не влияет.

Логи в панели ​

Раздел Логи в боковом меню проекта показывает сначала новые логи, с уровнем, сообщением и временем; откройте лог, чтобы увидеть его атрибуты, теги и контекст и ссылки на пользователя и трейс. Строка поиска ищет свободный текст по сообщению и поддерживает фильтры (полный синтаксис — Поиск):

  • level: — log, debug, info, warn или error;
  • environment: — environment, переданный в init();
  • user: — определённый пользователь;
  • любой ключ атрибута, тега или контекста — orderId:1042, service:billing-api.

Например: webhook level:error environment:production.