Отслеживание ошибок

Перехватывайте и отлаживайте JavaScript-ошибки в production с полным контекстом, стек-трейсами и записями сессий.

Обзор

StatusRadar RUM автоматически фиксирует:

  • JavaScript-ошибки: неперехваченные исключения
  • Отклонения промисов: необработанные асинхронные ошибки
  • Сетевые ошибки: неудавшиеся запросы fetch/XHR
  • Ошибки ресурсов: неудавшиеся скрипты, стили, изображения
  • Пользовательские ошибки: ошибки, специфичные для приложения

Автоматическое отслеживание ошибок

Включено по умолчанию:

const rum = new StatusRadarRUM({
  apiKey: 'your-api-key',
  appId: 'your-app-id',
  endpoint: 'https://rum.statusradar.dev/v1/ingest',

  trackErrors: true,  // Enabled by default
  captureStackTrace: true,
  captureSourceContext: true
});

Какая информация об ошибке фиксируется

1. Детали ошибки

  • Message: сообщение об ошибке
  • Type: TypeError, ReferenceError и т. д.
  • Stack trace: полный стек вызовов
  • Source: файл, строка, столбец

2. Контекст

  • Browser: user agent, версия
  • URL: страница, где произошла ошибка
  • Session: ID сессии для записи
  • User: ID пользователя (если задан)
  • Custom: любой пользовательский контекст

3. Окружение

  • Timestamp: когда произошла ошибка
  • Network: статус online/offline
  • Memory: доступный размер heap
  • Performance: состояние загрузки страницы

Типы ошибок

JavaScript-ошибки

Перехватываются автоматически:

// This error is automatically captured
function buggyFunction() {
  undefinedVariable.doSomething();  // ReferenceError
}

buggyFunction();

Зафиксированная информация:

{
  "type": "ReferenceError",
  "message": "undefinedVariable is not defined",
  "stack": "at buggyFunction (app.js:123:5)\n  at onClick (app.js:456:3)",
  "file": "app.js",
  "line": 123,
  "column": 5
}

Отклонения промисов

Необработанные асинхронные ошибки:

// Automatically captured
async function fetchData() {
  const response = await fetch('/api/data');
  if (!response.ok) {
    throw new Error('API request failed');
  }
}

fetchData();  // Unhandled rejection captured

Сетевые ошибки

Неудавшиеся HTTP-запросы:

rum.configure({
  trackNetwork: true,  // Enable network tracking
  networkErrorsOnly: false  // Track all requests or only errors
});

// Failed requests automatically tracked
fetch('/api/endpoint').catch(err => {
  // Error already captured by RUM
});

Зафиксированная информация:

{
  "type": "NetworkError",
  "url": "/api/endpoint",
  "method": "GET",
  "status": 500,
  "statusText": "Internal Server Error",
  "duration": 1234
}

Ошибки загрузки ресурсов

Неудавшиеся ресурсы:

<!-- Failed image automatically tracked -->
<img src="/missing-image.jpg" alt="Product" />

<!-- Failed script -->
<script src="/missing-script.js"></script>

Ручное отслеживание ошибок

Пользовательские ошибки

Отслеживайте ошибки, специфичные для приложения:

try {
  processPayment(order);
} catch (error) {
  rum.captureError(error, {
    context: {
      order_id: order.id,
      payment_method: order.paymentMethod,
      amount: order.total
    },
    level: 'error',  // error, warning, info
    fingerprint: ['payment', order.paymentMethod]
  });
}

Уровни ошибок

// Critical error
rum.captureError(error, { level: 'critical' });

// Warning
rum.captureError(error, { level: 'warning' });

// Info (non-error event)
rum.captureMessage('Payment processing started', {
  level: 'info',
  context: { order_id: '12345' }
});

Группировка ошибок

Группируйте похожие ошибки с помощью fingerprints:

rum.captureError(error, {
  fingerprint: ['database', 'connection', 'timeout']
});

// Errors with same fingerprint are grouped in dashboard

Контекст ошибки

Добавление пользовательского контекста

// Set global context (applied to all errors)
rum.setContext({
  environment: 'production',
  version: '1.2.3',
  build: '4567'
});

// Add tags
rum.setTags({
  server: 'us-east-1',
  deployment: 'blue'
});

// Set user context
rum.setUser({
  id: 'user-123',
  email: '[email protected]',
  subscription: 'pro'
});

Контекст для отдельной ошибки

rum.captureError(error, {
  context: {
    action: 'checkout',
    step: 'payment',
    cart_value: 249.99
  },
  tags: {
    payment_provider: 'stripe',
    currency: 'USD'
  }
});

Source Maps

Включение загрузки Source Map

Исходный код для минифицированных ошибок:

// 1. Generate source maps during build
// webpack.config.js
module.exports = {
  devtool: 'source-map',
  output: {
    sourceMapFilename: '[file].map'
  }
};

// 2. Upload source maps to StatusRadar
// Using CLI
npx @statusradar/cli upload-sourcemaps \
  --api-key YOUR_API_KEY \
  --app-id YOUR_APP_ID \
  --release 1.2.3 \
  --dir ./dist

// 3. Set release version in RUM
rum.configure({
  release: '1.2.3'  // Match uploaded source maps
});

Автоматическая загрузка (плагин Webpack)

// webpack.config.js
const StatusRadarPlugin = require('@statusradar/webpack-plugin');

module.exports = {
  plugins: [
    new StatusRadarPlugin({
      apiKey: process.env.STATUSRADAR_API_KEY,
      appId: process.env.STATUSRADAR_APP_ID,
      release: process.env.GIT_SHA,
      uploadSourceMaps: true,
      deleteAfterUpload: true  // Remove maps from build
    })
  ]
};

Фильтрация ошибок

Фильтрация на стороне клиента

Игнорируйте известные ошибки:

rum.configure({
  ignoreErrors: [
    // Ignore by message
    'ResizeObserver loop limit exceeded',
    'Non-Error promise rejection captured',

    // Ignore by regex
    /^Script error\.?$/,
    /chrome-extension:\/\//,

    // Ignore by custom function
    (error) => {
      return error.message.includes('AdBlock');
    }
  ]
});

Паттерны игнорирования

rum.configure({
  // Ignore errors from specific files
  denyUrls: [
    /extensions\//i,
    /^chrome:\/\//i,
    /^moz-extension:\/\//i
  ],

  // Only capture errors from your domain
  allowUrls: [
    /https?:\/\/((www|app)\.)?yoursite\.com/
  ]
});

Фильтрация на стороне сервера

Настройте в Dashboard:

  1. Dashboard → Observability → Apps → Settings
  2. Раздел Error Filters
  3. Добавьте правила для отбрасывания ошибок по шаблону

Оповещения об ошибках

Настройка оповещений

  1. Dashboard → Alerts → Create Alert
  2. Выберите триггер «Error Rate»
  3. Настройте порог:
    • Ошибок в минуту > 10
    • Рост частоты ошибок > 50%
    • Обнаружен новый тип ошибки
  4. Выберите канал уведомлений (Email, Slack и т. д.)

Каналы оповещений

  • Email
  • Slack
  • Telegram
  • Discord
  • Webhooks
  • SMS (Twilio)
  • Голосовые звонки

См.: Каналы оповещений

Dashboard ошибок

Просмотр ошибок

Dashboard → Observability → Apps → [Your App] → Errors

Отображает:

  • Таймлайн частоты ошибок: ошибки во времени
  • Top errors: самые частые ошибки
  • New errors: недавно появившиеся ошибки
  • Распределение ошибок: по браузеру, ОС, странице

Детали ошибки

Нажмите на любую ошибку, чтобы посмотреть:

  • Полный стек-трейс
  • Session replay (если включено)
  • Контекст пользователя
  • Информацию об устройстве/браузере
  • Похожие ошибки

Поиск и фильтрация

Фильтруйте ошибки по:

  • Типу ошибки
  • Шаблону URL
  • Пользователю
  • Браузеру
  • Диапазону дат
  • Пользовательским тегам

Интеграция с Session Replay

Ошибки автоматически связываются с session replay:

  1. Откройте ошибку в dashboard
  2. Нажмите «View Session»
  3. Посмотрите запись, предшествующую ошибке
  4. Увидьте точные действия пользователя, вызвавшие ошибку

Паттерны отладки

Выявление паттернов ошибок

Группируйте похожие ошибки:

// 1. Add error fingerprint
rum.captureError(error, {
  fingerprint: [error.name, error.code]
});

// 2. Dashboard shows grouped errors
// 3. Click group to see all instances

Ошибки, о которых сообщили пользователи

Собирайте обратную связь пользователей вместе с ошибками:

window.addEventListener('error', (event) => {
  const feedback = prompt('An error occurred. Can you describe what happened?');

  rum.captureError(event.error, {
    context: {
      user_feedback: feedback,
      user_action: 'reported_error'
    }
  });
});

Отслеживание восстановления после ошибок

Отслеживайте, как пользователи восстанавливаются после ошибок:

try {
  submitForm();
} catch (error) {
  rum.captureError(error);
  showErrorMessage();

  // Track recovery attempt
  retryButton.onclick = () => {
    rum.trackEvent('error_recovery_attempted', {
      error_type: error.name
    });
    submitForm();
  };
}

Соображения о производительности

Выборка

Применяйте выборку к ошибкам, чтобы уменьшить объём:

rum.configure({
  errorSampleRate: 0.1  // Capture 10% of errors
});

// Or sample by error type
rum.configure({
  beforeSend: (event) => {
    if (event.type === 'error') {
      // Sample low-priority errors
      if (event.level === 'warning' && Math.random() > 0.1) {
        return null;  // Drop 90% of warnings
      }
    }
    return event;
  }
});

Пакетная отправка ошибок

Ошибки отправляются пакетами вместе с другими событиями:

rum.configure({
  batchSize: 50,
  batchInterval: 10000  // Send every 10 seconds
});

Лучшие практики

СТОИТ ✅

  • Задавать контекст пользователя для более удобной отладки
  • Использовать fingerprints ошибок для группировки
  • Загружать source maps для production
  • Добавлять пользовательский контекст к ошибкам
  • Настраивать оповещения о критических ошибках
  • Включать session replay для визуального контекста

НЕ СТОИТ ❌

  • Фиксировать каждое предупреждение (используйте выборку)
  • Включать чувствительные данные в контекст ошибки
  • Игнорировать CORS-ошибки от расширений
  • Отслеживать ошибки из среды разработки
  • Логировать пароли/токены в сообщениях об ошибках

Справочник по API

// Capture error
rum.captureError(error: Error, options?: object)

// Capture message
rum.captureMessage(message: string, options?: object)

// Set context
rum.setContext(context: object)

// Set tags
rum.setTags(tags: object)

// Set user
rum.setUser(user: object)

// Ignore errors
rum.configure({
  ignoreErrors: string[] | RegExp[] | Function[]
})

Дальнейшие шаги

On this page