Console логирование

При разработке интерактивных карт на Mapbox GL JS консоль становится основным инструментом наблюдения за внутренними процессами рендеринга, загрузки данных и взаимодействия с источниками. Практически любой нестандартный сценарий — от задержек тайлов до ошибок стилей — быстрее всего диагностируется через грамотное логирование событий карты и WebGL-слоя.

Mapbox GL JS построен вокруг событийной модели. Почти всё, что происходит внутри карты, можно отследить через map.on(...). Это создаёт естественную точку интеграции с консольным выводом.

Ключевые события для наблюдения:

  • load — завершение загрузки стиля и базовой инициализации
  • render — каждый цикл перерисовки кадра
  • idle — карта завершила обработку всех запросов и рендеринг
  • data — загрузка или обновление источников данных
  • error — ошибки тайлов, стилей, шрифтов, источников

Базовая схема логирования выглядит как обёртка над событиями:

map.on('load', () => console.log('[map] load'));
map.on('idle', () => console.log('[map] idle'));
map.on('render', () => console.log('[map] render'));
map.on('data', (e) => console.log('[map] data:', e));
map.on('error', (e) => console.error('[map] error:', e.error || e));

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

Структурирование логов для сложных карт

При увеличении сложности приложения обычные console.log перестают быть информативными. В таких случаях применяются структурированные методы вывода.

Группировка событий

console.group позволяет визуально отделять блоки логов по подсистемам:

map.on('data', (e) => {
  console.group('data event');
  console.log('sourceId:', e.sourceId);
  console.log('isSourceLoaded:', e.isSourceLoaded);
  console.log('dataType:', e.dataType);
  console.groupEnd();
});

Это особенно полезно при работе с несколькими источниками (geojson, vector, raster), когда важно видеть контекст каждого события.

Табличный вывод состояний источников

При отладке слоёв и источников удобно использовать console.table:

const sources = map.getStyle().sources;

console.table(
  Object.keys(sources).map((id) => ({
    id,
    type: sources[id].type
  }))
);

Такой формат позволяет быстро оценить структуру стиля и обнаружить лишние или некорректные источники.

Логирование состояния рендеринга

Mapbox GL JS использует WebGL, и многие проблемы связаны не с данными, а с рендерингом. Для наблюдения за нагрузкой можно логировать цикл отрисовки.

let renderCount = 0;

map.on('render', () => {
  renderCount++;
  if (renderCount % 60 === 0) {
    console.log('frames rendered:', renderCount);
  }
});

Если render вызывается слишком часто без изменения данных, это может указывать на:

  • анимацию без остановки
  • бесконечные обновления источников
  • изменения стилей в цикле

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

Ошибки Mapbox часто приходят через единый канал error, но их структура различается.

map.on('error', (e) => {
  console.error('Mapbox error:', e.error);
});

Типичные категории ошибок:

  • отсутствие токена доступа
  • недоступные тайлы
  • ошибки шрифтов (glyphs)
  • некорректные GeoJSON-структуры
  • превышение лимитов WebGL

Для более детального анализа удобно разделять ошибки по типу:

map.on('error', (e) => {
  const err = e.error;

  if (err && err.status === 404) {
    console.warn('Tile not found:', err);
  } else if (err && err.message) {
    console.error('Map error message:', err.message);
  } else {
    console.error('Unknown map error:', err);
  }
});

Логирование источников данных

При работе с динамическими слоями важно отслеживать состояние источников:

map.on('sourcedata', (e) => {
  console.log('source update:', {
    sourceId: e.sourceId,
    isSourceLoaded: e.isSourceLoaded,
    dataType: e.dataType
  });
});

Особенно важно отслеживать момент, когда источник считается загруженным, поскольку многие операции (например, фильтрация слоёв) некорректны до этого состояния.

Контроль частоты обновлений

Частая проблема — избыточные обновления состояния карты. Логирование позволяет выявить такие сценарии:

let lastUpdate = performance.now();

map.on('render', () => {
  const now = performance.now();
  const delta = now - lastUpdate;

  if (delta < 16) {
    console.warn('Possible excessive render loop:', delta);
  }

  lastUpdate = now;
});

Это помогает обнаруживать ситуации, когда карта рендерится быстрее ожидаемого 60 FPS без необходимости.

Инструменты консоли для анализа производительности

Помимо стандартного логирования, используются инструменты измерения времени:

console.time('tile-load');

map.once('idle', () => {
  console.timeEnd('tile-load');
});

Также полезно измерять отдельные операции:

  • добавление слоёв
  • переключение стилей
  • обновление источников
console.time('add-layer');

map.addLayer({
  id: 'points',
  type: 'circle',
  source: 'geojson-source'
});

console.timeEnd('add-layer');

Перехват и расширение console для Mapbox

В сложных приложениях логирование часто централизуется через обёртку:

const log = {
  map: (msg, data) => console.log('[map]', msg, data),
  error: (msg, data) => console.error('[map:error]', msg, data),
  warn: (msg, data) => console.warn('[map:warn]', msg, data)
};

И использование:

map.on('load', () => log.map('loaded'));
map.on('error', (e) => log.error('error event', e));

Такой подход позволяет легко интегрировать внешние системы мониторинга без изменения логики карты.

Логирование взаимодействия пользователя

Для диагностики UI-проблем полезно отслеживать события взаимодействия:

map.on('click', (e) => {
  console.log('click:', e.lngLat, e.point);
});

map.on('move', () => {
  console.log('center:', map.getCenter());
});

Однако move и render требуют фильтрации, иначе консоль быстро перегружается. Обычно применяется троттлинг:

let lastMoveLog = 0;

map.on('move', () => {
  const now = Date.now();
  if (now - lastMoveLog > 1000) {
    console.log('center:', map.getCenter());
    lastMoveLog = now;
  }
});

Диагностика скрытых проблем через логирование

Некоторые проблемы не проявляются как ошибки, но видны через консоль:

  • постоянные data события без изменения источника
  • бесконечные render циклы
  • повторная загрузка одних и тех же тайлов
  • нестабильное состояние idle

Комбинированное логирование событий позволяет выявить такие паттерны:

map.on('data', () => console.log('data'));
map.on('render', () => console.log('render'));
map.on('idle', () => console.log('idle'));

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

Уровни детализации логов

Практика разработки карт обычно подразумевает несколько уровней логирования:

  • базовый: только error и load
  • диагностический: data, idle, render
  • расширенный: все события плюс пользовательские действия

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