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

Обзор ​

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

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

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

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

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

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

ts
Buglapse.log.info('User signed in')
Buglapse.log.warn('Payment retry', { orderId: 1042, attempt: 2 })
Buglapse.log.error('Checkout failed', { orderId: 1042, reason: 'card_declined' })
ts
import { log } from '@buglapse/browser'

log.debug('Cart recalculated', { items: 3, total: 59.9 })

Вызовы до init() — например, пока скрипт с CDN ещё грузится, — встают в очередь и отправляются, когда клиент готов, так что логировать рано безопасно.

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

Атрибуты ​

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

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

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

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

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

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

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

ts
import { fmt, log } from '@buglapse/browser' // или Buglapse.fmt со скриптом с CDN

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 ​

Интеграция консоли подключаемая. Со script-тегом включите Перехват консоли в Настройки → Скрипт загрузчика проекта — это вступит в силу при следующей загрузке страницы вашего сайта без изменения подключения.

С npm-пакетом добавьте интеграцию сами:

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

init({
    dsn: '{dsn}',
    integrations: [consoleIntegration()],
})

После регистрации она оборачивает console.log, console.info, console.warn, console.error и console.debug. Исходный метод выполняется первым, так что вывод в DevTools не меняется; затем вызов пересылается логом того же уровня (console.log → log, console.warn → warn, ...).

Аргументы разбираются так же, как у явного вызова Buglapse.log:

  • последний простой объект становится атрибутами лога;
  • всё перед ним склеивается через пробел в сообщение — строки как есть, остальное через JSON.stringify;
  • первый аргумент в стиле printf (%s, %d, %i, %f, %o, %O, %j) форматируется с аргументами, которые он забирает, и становится шаблоном лога, как с fmt.
ts
console.warn('Slow response', { url: '/api/cart', ms: 1840 })
// → level: warn, message: "Slow response", attributes: { url: "/api/cart", ms: 1840 }

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

console.log('items', [1, 2, 3], 42)
// → level: log, message: 'items [1,2,3] 42', без атрибутов

Что стоит помнить:

  • JSON.stringify превращает Error в {}, так что console.error(error) не несёт полезного сообщения и стека. Об исключениях сообщайте через captureException().
  • Другие методы console (table, trace, group, ...) не пересылаются.
  • Все сторонние скрипты страницы пишут в тот же console, так что перехват может прислать много шума. После включения следите за квотой логов или отбрасывайте ненужное (ниже).

Чтобы выключить во время работы, отключите интеграцию по имени:

ts
Buglapse.disable('console')

Интеграция консоли не зависит от хлебных крошек консоли: крошки записывают вызовы консоли только как контекст к последующей ошибке, а эта интеграция отправляет каждый вызов отдельным логом. См. Хлебные крошки.

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

Каждый лог получает текущий trace.id — трейс активного спана или трейс страницы, если спана нет, — и span.id, если спан активен:

ts
await Buglapse.asyncSpan('checkout', async () => {
    Buglapse.log.info('Starting checkout') // связан со спаном "checkout"
    await submitOrder()
})

В панели лог с id трейса ссылается на этот трейс. См. Связь других событий с активным спаном.

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

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

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

    if (event.payload.level === 'debug') return null

    delete event.payload.attributes?.email

    return event
})

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

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

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

Где смотреть ​

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

Строка поиска ищет свободный текст по сообщению и поддерживает фильтры (полный синтаксис — операторы вроде != и ~, кавычки — на странице Поиск):

  • level: — уровень лога: log, debug, info, warn или error;
  • environment: — environment, переданный в init(), например environment:production (см. environment и release);
  • user: — определённый пользователь (задаётся через Buglapse.setUser(), см. Пользователи);
  • browser: / os: / device: — браузер, ОС и модель устройства посетителя, например browser:Safari;
  • любой ключ атрибута, тега или контекста — например, orderId:1042, release:1.4.0.

Например: checkout level:error environment:production browser:Safari.