Логирование процесса валидации

При построении сложных схем проверки данных в приложениях на JavaScript возникает необходимость отслеживать:

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

В библиотеке Vest отсутствует встроенная полноценная система логирования уровня enterprise, однако архитектура фреймворка позволяет организовать детальное отслеживание процесса валидации через:

  • состояние suite;
  • хуки выполнения;
  • кастомные обёртки;
  • события выполнения тестов;
  • интеграцию с внешними логгерами;
  • middleware-подход;
  • асинхронные механизмы.

Архитектура выполнения validation suite

Каждый suite в Vest представляет собой функцию, внутри которой выполняются тесты.

Базовый пример:

import { create, test, enforce } from 'vest';

const suite = create((data = {}) => {
  test('email', 'Некорректный email', () => {
    enforce(data.email).isEmail();
  });

  test('password', 'Пароль слишком короткий', () => {
    enforce(data.password).longerThanOrEquals(8);
  });
});

При запуске:

const result = suite({
  email: 'wrong',
  password: '123'
});

Vest формирует внутренний execution context, содержащий:

  • список тестов;
  • статусы;
  • ошибки;
  • pending-состояния;
  • skipped-тесты;
  • warnings;
  • execution tree.

Логирование строится вокруг этих данных.


Получение информации из result object

Объект результата — главный источник информации для логирования.

Проверка валидности

console.log(result.isValid());

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

console.log(result.hasErrors('email'));

Получение массива ошибок

console.log(result.getErrors('email'));

Полная структура ошибок

console.log(result.getErrors());

Пример результата:

{
  email: ['Некорректный email'],
  password: ['Пароль слишком короткий']
}

Базовое логирование результата

Наиболее простой подход — логирование после выполнения suite.

const result = suite(formData);

console.log('Validation result:', {
  valid: result.isValid(),
  errors: result.getErrors(),
  warnings: result.getWarnings()
});

Результат:

Validation result: {
  valid: false,
  errors: {
    email: ['Некорректный email']
  },
  warnings: {}
}

Логирование отдельных тестов

Vest позволяет организовать логирование внутри test callback.

Пример

test('email', 'Некорректный email', () => {
  console.log('[VALIDATION] Проверка email');

  enforce(data.email).isEmail();

  console.log('[VALIDATION] Email прошёл проверку');
});

Если проверка завершится исключением:

test('email', 'Некорректный email', () => {
  console.log('Start email validation');

  enforce(data.email).isEmail();

  console.log('Finish email validation');
});

Второй лог не выполнится.


Безопасное логирование через try/catch

Для отслеживания ошибок рекомендуется оборачивать проверки.

test('password', 'Пароль слишком короткий', () => {
  console.log('Password validation started');

  try {
    enforce(data.password).longerThanOrEquals(8);

    console.log('Password validation success');
  } catch (e) {
    console.error('Password validation failed', e);

    throw e;
  }
});

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

На практике логирование быстро становится дублирующимся.

Решение — выделение отдельного сервиса.

Пример logger.js

export const validationLogger = {
  info(message, meta = {}) {
    console.log('[VALIDATION]', message, meta);
  },

  error(message, meta = {}) {
    console.error('[VALIDATION ERROR]', message, meta);
  },

  warn(message, meta = {}) {
    console.warn('[VALIDATION WARNING]', message, meta);
  }
};

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

import { validationLogger } from './logger';

test('email', 'Некорректный email', () => {
  validationLogger.info('Email validation started', {
    value: data.email
  });

  enforce(data.email).isEmail();

  validationLogger.info('Email validation completed');
});

Логирование входящих данных

Часто необходимо фиксировать данные, переданные в suite.

Пример

const suite = create((data = {}) => {
  console.log('Incoming validation data:', data);

  test('email', 'Некорректный email', () => {
    enforce(data.email).isEmail();
  });
});

Маскирование чувствительных данных

Нельзя логировать:

  • пароли;
  • токены;
  • банковские карты;
  • session identifiers;
  • JWT;
  • персональные данные без необходимости.

Неправильно

console.log(data.password);

Правильно

console.log({
  ...data,
  password: '***'
});

Логирование асинхронной валидации

Vest поддерживает async validation.

Пример

test('email', 'Email уже существует', async () => {
  console.log('Checking email uniqueness');

  const exists = await api.checkEmail(data.email);

  console.log('Email check finished');

  enforce(exists).isFalsy();
});

Логирование времени выполнения

Валидация может стать узким местом производительности.

Измерение длительности

test('email', 'Некорректный email', () => {
  const start = performance.now();

  enforce(data.email).isEmail();

  const end = performance.now();

  console.log(`Validation time: ${end - start} ms`);
});

Логирование всей validation session

Полезно при отладке сложных форм.

Пример

const validateForm = data => {
  console.group('Validation session');

  console.log('Input:', data);

  const result = suite(data);

  console.log('Is valid:', result.isValid());

  console.log('Errors:', result.getErrors());

  console.groupEnd();

  return result;
};

Использование console.group

Группировка делает логи читаемыми.

console.group('Email validation');

console.log('Input:', data.email);

enforce(data.email).isEmail();

console.log('Status: success');

console.groupEnd();

Логирование skipped tests

Vest поддерживает selective validation.

Пример

import { only } from 'vest';

const result = suite(data, only('email'));

Можно логировать выполняемые поля:

console.log('Validated fields:', ['email']);

Логирование предупреждений

Vest поддерживает warnings.

Пример

import { warn } from 'vest';

test('password', 'Слабый пароль', () => {
  warn();

  enforce(data.password).matches(/[A-Z]/);
});

Логирование:

console.log(result.getWarnings());

Построение middleware для логирования

Крупные приложения используют middleware-подход.

Пример обёртки

function withLogging(suite) {
  return data => {
    console.log('Validation started');

    const started = Date.now();

    const result = suite(data);

    const finished = Date.now();

    console.log('Validation completed');

    console.log('Duration:', finished - started);

    console.log('Errors:', result.getErrors());

    return result;
  };
}

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

const loggedSuite = withLogging(suite);

loggedSuite(formData);

Логирование failed fields

Иногда необходимо отдельно фиксировать только проблемные поля.

Пример

const errors = result.getErrors();

Object.entries(errors).forEach(([field, messages]) => {
  console.error('Field validation failed', {
    field,
    messages
  });
});

Логирование успешных проверок

По умолчанию Vest концентрируется на ошибках.

Для аудита иногда необходимо логировать успешные тесты.

test('username', 'Некорректный username', () => {
  enforce(data.username).longerThan(3);

  console.log('Username validation success');
});

Интеграция с внешними системами логирования

Vest легко интегрируется с:

  • Sentry
  • LogRocket
  • Datadog
  • Winston
  • Pino

Пример с Winston

import winston from 'winston';

const logger = winston.createLogger({
  transports: [
    new winston.transports.Console()
  ]
});

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

logger.info('Validation started');

const result = suite(data);

logger.info('Validation completed', {
  valid: result.isValid(),
  errors: result.getErrors()
});

Логирование в React-приложениях

В React логирование часто связывается с жизненным циклом формы.

Пример

const onSub mit = () => {
  const result = suite(formData);

  console.log('Form submit validation', {
    valid: result.isValid(),
    errors: result.getErrors()
  });

  if (result.isValid()) {
    sendForm();
  }
};

Логирование pending state

Асинхронные проверки могут находиться в состоянии ожидания.

Пример

console.log(result.isPending());

Проверка конкретного поля:

console.log(result.isPending('email'));

Трассировка порядка выполнения тестов

При сложных зависимостях важно понимать execution order.

Пример

test('email', 'Некорректный email', () => {
  console.log('1. Email validation');

  enforce(data.email).isEmail();
});

test('password', 'Некорректный пароль', () => {
  console.log('2. Password validation');

  enforce(data.password).longerThan(8);
});

Логирование conditional validation

Vest поддерживает условные проверки.

Пример

if (data.hasCompany) {
  console.log('Company validation enabled');

  test('companyName', 'Введите название компании', () => {
    enforce(data.companyName).isNotBlank();
  });
}

Логирование dynamic validation

Валидация может зависеть от runtime-состояния.

const rules = getValidationRules();

console.log('Active rules:', rules);

Логирование debounce validation

В формах с live validation важно отслеживать количество запусков.

Пример

let validationCounter = 0;

const validate = data => {
  validationCounter++;

  console.log('Validation run:', validationCounter);

  return suite(data);
};

Структурированное логирование

Строковые логи неудобны для анализа.

Лучше использовать JSON-подход.

Пример

console.log({
  type: 'validation',
  field: 'email',
  status: 'failed',
  timestamp: Date.now()
});

Формирование audit trail

Для критически важных систем ведётся журнал проверок.

Пример структуры

const auditRecord = {
  userId: user.id,
  form: 'registration',
  valid: result.isValid(),
  errors: result.getErrors(),
  createdAt: new Date().toISOString()
};

Логирование повторных запусков

Vest может переиспользовать previous state.

Пример

console.log('Validation restarted');

При оптимизации важно понимать:

  • сколько раз запускается suite;
  • какие поля триггерят повторную проверку;
  • какие тесты вызываются чаще остальных.

Создание debug mode

Практичный подход — отдельный режим диагностики.

Пример

const DEBUG_VALIDATION = true;

function debugLog(...args) {
  if (DEBUG_VALIDATION) {
    console.log(...args);
  }
}

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

debugLog('Validation started');

Отключение логов в production

Логирование может:

  • снижать производительность;
  • раскрывать внутреннюю структуру приложения;
  • утекать в browser console;
  • создавать риски безопасности.

Пример

const isProduction =
  process.env.NODE_ENV === 'production';

if (!isProduction) {
  console.log('Validation debug');
}

Логирование через Proxy

Продвинутый подход — автоматическое перехватывание вызовов.

Пример

function createLoggedEnforce(enforce) {
  return new Proxy(enforce, {
    apply(target, thisArg, args) {
      console.log('Enforce called with:', args);

      return Reflect.apply(target, thisArg, args);
    }
  });
}

Централизованный Validation Monitor

В крупных системах создаётся единый мониторинг.

Пример

class ValidationMonitor {
  constructor() {
    this.history = [];
  }

  log(entry) {
    this.history.push({
      ...entry,
      timestamp: Date.now()
    });
  }

  getHistory() {
    return this.history;
  }
}

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

const monitor = new ValidationMonitor();

monitor.log({
  field: 'email',
  status: 'failed'
});

Анализ статистики валидации

Собранные данные позволяют определить:

  • наиболее проблемные поля;
  • частые ошибки пользователей;
  • медленные проверки;
  • нестабильные async validators;
  • перегруженные формы.

Пример агрегации

const stats = {
  emailFailures: 120,
  passwordFailures: 88,
  averageValidationTime: 14
};

Типичные ошибки при логировании

Логирование конфиденциальных данных

console.log(user.password);

Избыточное количество логов

console.log('validation');
console.log('validation');
console.log('validation');

Отсутствие структуры

console.log('error');

Логирование только ошибок

Без успешных проверок сложнее анализировать execution flow.


Использование console.log в production

Для production-среды предпочтительнее:

  • централизованные logger-системы;
  • удалённый сбор telemetry;
  • structured logging;
  • log rotation;
  • severity levels;
  • correlation identifiers.