← Назад к вопросам

Как искать ошибку, найденную у конкретного пользователя?

1.0 Junior🔥 111 комментариев
#Soft Skills и рабочие процессы

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как искать ошибку, найденную у конкретного пользователя

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

Этап 1: Сбор информации от пользователя

Первое, что нужно сделать — получить как можно больше информации:

// 1. Спросить пользователя о деталях
// - Браузер и версия (Chrome 125, Safari 17)
// - Операционная система (Windows 11, macOS, Linux)
// - Шаги для воспроизведения (пошагово описать действия)
// - Скриншот или видео ошибки
// - Сообщение об ошибке (если видно)
// - Время, когда произошла ошибка

// 2. Проверить версию приложения
// - console.log(document.documentElement.getAttribute('data-version'))
// - Проверить версию в localStorage или sessionStorage

// 3. Собрать системную информацию
function collectUserInfo() {
  return {
    userAgent: navigator.userAgent,
    platform: navigator.platform,
    language: navigator.language,
    onLine: navigator.onLine,
    cookiesEnabled: navigator.cookieEnabled,
    timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
    screenResolution: `${window.innerWidth}x${window.innerHeight}`,
    devicePixelRatio: window.devicePixelRatio,
    memory: navigator.deviceMemory || 'unknown',
    connection: navigator.connection?.effectiveType || 'unknown'
  };
}

console.log(collectUserInfo());

Этап 2: Включить логирование на продакшене

Настрой сбор логов для отладки:

// 1. Логирование ошибок
window.addEventListener('error', (event) => {
  const errorData = {
    message: event.message,
    filename: event.filename,
    lineno: event.lineno,
    colno: event.colno,
    timestamp: new Date().toISOString(),
    url: window.location.href,
    userAgent: navigator.userAgent
  };
  
  // Отправить на сервер
  fetch('/api/logs/errors', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(errorData)
  });
});

// 2. Логирование необработанных Promise отклонений
window.addEventListener('unhandledrejection', (event) => {
  console.error('Unhandled promise rejection:', event.reason);
  
  const errorData = {
    type: 'unhandledRejection',
    reason: String(event.reason),
    timestamp: new Date().toISOString(),
    url: window.location.href
  };
  
  fetch('/api/logs/errors', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(errorData)
  });
});

// 3. Перехват fetch ошибок
const originalFetch = window.fetch;
window.fetch = function(...args) {
  return originalFetch.apply(this, args)
    .then(response => {
      if (!response.ok) {
        console.warn(`API Error: ${response.status} ${args[0]}`);
      }
      return response;
    })
    .catch(error => {
      console.error('Fetch error:', error, 'URL:', args[0]);
      throw error;
    });
};

Этап 3: Использование DevTools и браузерных консолей

Попроси пользователя собрать информацию из браузера:

// Скрипт для экспорта логов в браузере пользователя
// Пусть пользователь вставит это в console

// Экспорт логов из localStorage
function exportLogs() {
  const logs = localStorage.getItem('app_logs') || '[]';
  const data = new Blob([logs], { type: 'application/json' });
  const url = URL.createObjectURL(data);
  
  const a = document.createElement('a');
  a.href = url;
  a.download = `logs-${Date.now()}.json`;
  a.click();
  
  URL.revokeObjectURL(url);
}

exportLogs();

// Сохранение логов консоли
const originalLog = console.log;
const logs = [];

console.log = function(...args) {
  logs.push({
    timestamp: new Date().toISOString(),
    message: args.join(' ')
  });
  originalLog.apply(console, args);
};

Этап 4: Использование сервисов логирования

Добавь интеграцию с сервисом отслеживания ошибок:

// Пример с Sentry
import * as Sentry from "@sentry/react";

Sentry.init({
  dsn: process.env.REACT_APP_SENTRY_DSN,
  environment: process.env.NODE_ENV,
  tracesSampleRate: 1.0,
  integrations: [
    new Sentry.Replay({
      maskAllText: true,
      blockAllMedia: true,
    }),
  ],
  replaysSessionSampleRate: 0.1,
  replaysOnErrorSampleRate: 1.0,
});

// Теперь все ошибки автоматически отправляются на Sentry
// Ты можешь фильтровать по userId
Sentry.captureException(error, {
  contexts: {
    user: { userId: currentUser.id }
  }
});

Этап 5: Session Replay (запись сессии пользователя)

Запись действий пользователя позволяет воспроизвести проблему:

// Пример с использованием rrweb (библиотека для записи DOM)
import { record } from 'rrweb';

let events = [];

record({
  emit(event) {
    events.push(event);
    
    // Отправить на сервер если много событий
    if (events.length > 100) {
      sendEvents();
      events = [];
    }
  },
  recordCanvas: true,
  sampling: {
    mousemove: true,
    input: 'last',
    mediaInteraction: true,
  },
});

function sendEvents() {
  fetch('/api/session-replay', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      userId: getCurrentUserId(),
      events: events,
      timestamp: new Date().toISOString()
    })
  });
}

Этап 6: Добавление отслеживания API запросов

Отслеживай сетевые запросы для диагностики:

class APILogger {
  static logRequest(url, options) {
    const timestamp = new Date().toISOString();
    const log = {
      type: 'request',
      url,
      method: options?.method || 'GET',
      timestamp,
      body: options?.body?.substring(0, 200) // Первые 200 символов
    };
    
    this.save(log);
  }
  
  static logResponse(url, response) {
    const log = {
      type: 'response',
      url,
      status: response.status,
      timestamp: new Date().toISOString()
    };
    
    this.save(log);
  }
  
  static save(log) {
    const logs = JSON.parse(localStorage.getItem('api_logs') || '[]');
    logs.push(log);
    
    // Ограничиваем размер (последние 100 логов)
    if (logs.length > 100) logs.shift();
    
    localStorage.setItem('api_logs', JSON.stringify(logs));
  }
}

// Использование
const originalFetch = window.fetch;
window.fetch = function(url, options) {
  APILogger.logRequest(url, options);
  
  return originalFetch.apply(this, arguments)
    .then(response => {
      APILogger.logResponse(url, response);
      return response;
    });
};

Этап 7: Инструменты для отладки

  1. Network DevTools — проверить статусы запросов, время загрузки
  2. Application/Storage — проверить localStorage, sessionStorage, cookies
  3. Console — найти JavaScript ошибки
  4. Performance — выявить медленные операции
  5. Elements — проверить DOM и CSS

Пошаговый процесс отладки

// 1. Проверить консоль на ошибки
// F12 -> Console -> посмотреть красные ошибки

// 2. Проверить Network
// F12 -> Network -> перезагрузить страницу -> найти 404, 500 ошибки

// 3. Проверить localStorage
// F12 -> Application -> Local Storage -> посмотреть сохранённые данные

// 4. Проверить версию приложения
function getAppVersion() {
  return document.documentElement.getAttribute('data-version') || 'unknown';
}

// 5. Проверить, работает ли API
fetch('/api/health')
  .then(r => r.json())
  .then(data => console.log('API Status:', data))
  .catch(e => console.error('API Error:', e));

// 6. Проверить браузерные расширения (могут конфликтовать)
// Просить пользователя отключить расширения и перезагрузиться

Чеклист для диагностики

  • Браузер и версия ОС подтверждены
  • Ошибка воспроизводится в инкогнито режиме
  • Логи и скриншоты собраны
  • Console ошибок проверена
  • Network запросы проверены
  • localStorage/sessionStorage очищены
  • Кэш браузера очищен
  • Версия приложения актуальна
  • Браузерные расширения отключены
  • VPN/Proxy отключены

Систематический подход к отладке помогает быстро найти причину ошибки даже когда ты не можешь воспроизвести проблему на своей машине.

Как искать ошибку, найденную у конкретного пользователя? | PrepBro