npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@kiz8/logger

v0.1.0

Published

Универсальный логгер для системы управления репутацией

Downloads

7

Readme

@reputation-management/logger

Универсальный логгер для системы управления репутацией, построенный на базе Winston.

Архитектура и обзор

@reputation-management/logger представляет собой унифицированное решение для логирования в проектах системы управления репутацией. Пакет предоставляет обертку над библиотекой Winston, добавляя необходимую для проекта функциональность и интеграцию.

Основные архитектурные компоненты:

  • Ядро логгера: Основано на Winston с настраиваемыми транспортами для консоли и файлов.
  • Форматирование: Структурированные JSON-логи с метаданными и читаемое форматирование для консоли.
  • Интеграции: Готовые интеграции с Hono (HTTP), Inngest (фоновые задачи) и Vercel Fluid Functions.
  • Утилиты: Вспомогательные функции для логирования ошибок и создания дочерних логгеров.

Архитектура логгера разработана для обеспечения:

  • Гибкости: Возможность настройки под различные сценарии использования
  • Расширяемости: Простое добавление новых транспортов и форматеров
  • Консистентности: Единый формат логов во всех частях системы
  • Производительности: Оптимизированное логирование для снижения влияния на производительность

Возможности

  • Гибкая конфигурация уровней логирования
  • Логирование в консоль и файлы
  • Ротация файлов логов
  • Форматирование логов с метаданными
  • Интеграция с Hono для логирования HTTP запросов
  • Интеграция с Inngest для логирования фоновых задач
  • Интеграция с Vercel Fluid Functions
  • Создание дочерних логгеров с предустановленными метаданными

Установка

npm install @reputation-management/logger

или

yarn add @reputation-management/logger

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

Базовое использование

import { defaultLogger, LogLevel } from "@reputation-management/logger";

// Использование логгера по умолчанию
defaultLogger.info("Приложение запущено");
defaultLogger.error("Произошла ошибка", { error: "Детали ошибки" });

// Создание собственного логгера
import { createLogger } from "@reputation-management/logger";

const logger = createLogger({
  level: LogLevel.DEBUG,
  console: true,
  file: true,
  logDir: "./logs",
  defaultMeta: {
    service: "my-service",
  },
});

logger.info("Сообщение с метаданными", { userId: "123", action: "login" });

// Установка уровня логирования динамически
logger.setLevel(LogLevel.WARN); // Теперь будут логгироваться только WARN и ERROR

// Получение текущего логгера из контекста
import { getLogger } from "@reputation-management/logger";
const contextLogger = getLogger();

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

import {
  defaultLogger,
  createErrorMeta,
  formatError,
} from "@reputation-management/logger";

try {
  // Какой-то код, который может вызвать ошибку
  throw new Error("Пример ошибки");
} catch (error) {
  if (error instanceof Error) {
    // Вариант 1: Использование createErrorMeta
    defaultLogger.error("Произошла ошибка", createErrorMeta(error));

    // Вариант 2: Форматирование ошибки в строку
    defaultLogger.error(formatError(error));

    // Вариант 3: Полное логирование для критических ошибок
    defaultLogger.error("Критическая ошибка в системе", {
      ...createErrorMeta(error),
      component: "payment-service",
      operation: "processTransaction",
      transactionId: "12345",
      isRetryable: false,
    });
  }
}

// Логирование асинхронных ошибок
async function fetchData() {
  try {
    const response = await fetch("https://api.example.com/data");
    if (!response.ok) {
      throw new Error(`API error: ${response.status}`);
    }
    return await response.json();
  } catch (error) {
    defaultLogger.error(
      "Ошибка при запросе данных",
      error instanceof Error
        ? createErrorMeta(error)
        : { error: String(error) },
    );
    throw error; // Переброс ошибки для обработки выше
  }
}

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

import { defaultLogger } from "@reputation-management/logger";
import { v4 as uuidv4 } from "uuid";

// Использование трассировки запросов
function processOrder(order, user) {
  const traceId = uuidv4();
  const logger = defaultLogger.child({
    traceId,
    userId: user.id,
    orderId: order.id,
  });

  logger.info("Начало обработки заказа");

  // Логирование каждого шага с тем же traceId
  try {
    logger.info("Проверка наличия товаров", {
      products: order.products.map((p) => p.id),
    });

    logger.info("Проверка платежной информации", {
      paymentMethod: order.paymentMethod,
    });

    logger.info("Создание заказа завершено", {
      status: "completed",
      total: order.total,
    });

    return { success: true, orderId: order.id };
  } catch (error) {
    logger.error("Ошибка при обработке заказа", createErrorMeta(error));
    return { success: false, error: error.message };
  }
}

Интеграция с Hono

import { Hono } from "hono";
import {
  defaultLogger,
  honoLoggerMiddleware,
  honoErrorLoggerMiddleware,
} from "@reputation-management/logger";

const app = new Hono();

// Базовая интеграция
// ===================

// Добавление middleware для логирования запросов
app.use("*", honoLoggerMiddleware(defaultLogger));

// Добавление middleware для логирования ошибок
app.onError(honoErrorLoggerMiddleware(defaultLogger));

// Маршруты приложения
app.get("/", (c) => c.text("Hello World"));

// Расширенная интеграция
// ======================

// Настройка middleware с дополнительными опциями
app.use(
  "*",
  honoLoggerMiddleware(defaultLogger, {
    excludePaths: ["/health", "/metrics"], // Исключить пути из логирования
    logBody: true, // Логировать тело запроса
    maskHeaders: ["authorization", "x-api-key"], // Маскировать заголовки
    getRequestId: (c) => c.req.header("x-request-id") || uuidv4(), // Функция для получения ID запроса
  }),
);

// Создание middleware для конкретной группы маршрутов
const apiRoutes = new Hono();

// Логгер с предустановленными метаданными для API
const apiLogger = defaultLogger.child({ component: "api" });

// Применение логгера только для API маршрутов
apiRoutes.use("*", honoLoggerMiddleware(apiLogger));

// Добавление API маршрутов к основному приложению
app.route("/api", apiRoutes);

// Пример обработки запроса с пользовательским логированием
app.post("/api/users", async (c) => {
  const requestLogger = apiLogger.child({
    requestId: c.get("requestId"),
    path: "/api/users",
  });

  requestLogger.info("Получен запрос на создание пользователя");

  try {
    const body = await c.req.json();
    requestLogger.debug("Тело запроса", { body });

    // Логика создания пользователя
    const user = await createUser(body);

    requestLogger.info("Пользователь успешно создан", { userId: user.id });
    return c.json({ success: true, user });
  } catch (error) {
    requestLogger.error(
      "Ошибка при создании пользователя",
      createErrorMeta(error),
    );
    return c.json({ success: false, error: error.message }, 500);
  }
});

export default app;

Интеграция с Inngest

import { Inngest } from "inngest";
import {
  defaultLogger,
  createInngestLogger,
} from "@reputation-management/logger";

// Создание клиента Inngest
const inngest = new Inngest({ name: "My App" });

// Создание функции Inngest
const myFunction = inngest.createFunction(
  { name: "My Function" },
  { event: "my/event" },
  async ({ event, step }) => {
    // Создание логгера для функции
    const logger = createInngestLogger(defaultLogger, "My Function");

    // Логирование начала выполнения
    logger.start("my/event", event.data);

    try {
      // Выполнение шага
      logger.stepStart("process-data");
      const result = await step.run("process-data", async () => {
        // Логирование внутри шага
        logger.info("Обработка данных", { data: event.data });
        return { processed: true };
      });
      logger.stepSuccess("process-data", result);

      // Дополнительные шаги с логированием
      logger.stepStart("notify-user");
      await step.run("notify-user", async () => {
        logger.info("Отправка уведомления пользователю", {
          userId: event.data.userId,
        });
        // Реализация отправки уведомления
        return { notified: true };
      });
      logger.stepSuccess("notify-user");

      // Логирование успешного завершения
      logger.success(result);
      return result;
    } catch (error) {
      // Логирование ошибки
      logger.error(error);
      throw error;
    }
  },
);

// Регистрация множества функций с одним логгером
const createUserFunction = inngest.createFunction(
  { name: "Create User" },
  { event: "user/created" },
  async ({ event, step }) => {
    const logger = createInngestLogger(defaultLogger, "Create User", {
      tenant: event.data.tenantId,
      environment: process.env.NODE_ENV,
    });

    logger.start("user/created", { userId: event.data.userId });

    // Реализация функции...

    return { success: true };
  },
);

// Мониторинг выполнения Inngest функций
function setupInngestMonitoring(inngestClient) {
  const monitoringLogger = defaultLogger.child({
    component: "inngest-monitor",
  });

  // Слушаем события выполнения функций
  inngestClient.onFunctionRun((event) => {
    monitoringLogger.info("Inngest функция запущена", {
      functionId: event.functionId,
      eventId: event.eventId,
      attemptNumber: event.attemptNumber,
    });
  });

  // Слушаем события завершения функций
  inngestClient.onFunctionComplete((event) => {
    monitoringLogger.info("Inngest функция завершена", {
      functionId: event.functionId,
      eventId: event.eventId,
      duration: event.duration,
      status: "success",
    });
  });

  // Слушаем события ошибок функций
  inngestClient.onFunctionError((event) => {
    monitoringLogger.error("Ошибка выполнения Inngest функции", {
      functionId: event.functionId,
      eventId: event.eventId,
      error: event.error,
      status: "failed",
    });
  });
}

Интеграция с Vercel Fluid Functions

import {
  defaultLogger,
  createVercelFunctionLogger,
} from "@reputation-management/logger";

export default async function handler(req, res) {
  // Создание логгера для функции
  const logger = createVercelFunctionLogger(defaultLogger, "api/example");

  // Логирование начала выполнения с расширенными метаданными
  logger.start({
    method: req.method,
    url: req.url,
    userAgent: req.headers["user-agent"],
    requestId:
      req.headers["x-request-id"] || Math.random().toString(36).substring(2),
    ip: req.headers["x-forwarded-for"] || req.connection.remoteAddress,
  });

  try {
    // Логирование информации о запросе
    logger.info("Обработка запроса", {
      query: req.query,
      headers: filterSensitiveHeaders(req.headers),
      body: req.body ? sanitizeRequestBody(req.body) : undefined,
    });

    // Измерение времени выполнения
    const startTime = Date.now();

    // Выполнение бизнес-логики
    const result = await processRequest(req);

    // Логирование времени выполнения
    const executionTime = Date.now() - startTime;
    logger.info("Запрос обработан", { executionTime });

    // Логирование успешного завершения
    logger.success({
      result: omitSensitiveData(result),
      executionTime,
    });

    return res.status(200).json(result);
  } catch (error) {
    // Расширенное логирование ошибки
    logger.error("Ошибка при обработке запроса", {
      error: error instanceof Error ? error.message : String(error),
      stack: error instanceof Error ? error.stack : undefined,
      path: req.url,
      method: req.method,
      requestId: req.headers["x-request-id"],
    });

    // Определение кода ошибки
    const statusCode = error.statusCode || 500;
    const errorMessage =
      statusCode === 500 ? "Internal Server Error" : error.message;

    // Возврат ответа с ошибкой
    return res.status(statusCode).json({
      error: errorMessage,
      requestId: req.headers["x-request-id"],
    });
  } finally {
    // Логирование завершения обработки запроса
    logger.info("Обработка запроса завершена");
  }
}

// Вспомогательные функции
function filterSensitiveHeaders(headers) {
  const filtered = { ...headers };
  const sensitiveHeaders = ["authorization", "cookie", "x-api-key"];

  for (const header of sensitiveHeaders) {
    if (filtered[header]) {
      filtered[header] = "***";
    }
  }

  return filtered;
}

function sanitizeRequestBody(body) {
  if (!body) return undefined;

  const sanitized = { ...body };
  const sensitiveFields = ["password", "token", "secret", "creditCard"];

  for (const field of sensitiveFields) {
    if (sanitized[field]) {
      sanitized[field] = "***";
    }
  }

  return sanitized;
}

function omitSensitiveData(data) {
  // Реализация удаления чувствительных данных из ответа
  return data;
}

async function processRequest(req) {
  // Пример реализации бизнес-логики
  return { success: true, data: { processed: true } };
}

Мониторинг и анализ логов

import { createLogger, LogLevel } from "@reputation-management/logger";
import { format, transports } from "winston";

// Логгер с расширенными возможностями мониторинга
const monitoringLogger = createLogger({
  level: LogLevel.INFO,
  console: true,
  file: true,
  defaultMeta: {
    service: "monitoring-service",
    version: process.env.APP_VERSION || "1.0.0",
    environment: process.env.NODE_ENV || "development",
  },
});

// Добавление транспорта для отправки критических ошибок в систему оповещения
if (process.env.NODE_ENV === "production") {
  monitoringLogger.add(
    new transports.Http({
      host: "alerts.example.com",
      path: "/api/log",
      ssl: true,
      level: "error",
      format: format.json(),
      auth: {
        username: process.env.ALERT_API_USERNAME,
        password: process.env.ALERT_API_PASSWORD,
      },
    }),
  );
}

// Функция для измерения производительности операций
function measurePerformance(operationName, callback) {
  const startTime = performance.now();
  const result = callback();
  const endTime = performance.now();

  monitoringLogger.info("Метрика производительности", {
    operation: operationName,
    durationMs: endTime - startTime,
    timestamp: new Date().toISOString(),
  });

  return result;
}

// Измерение асинхронных операций
async function measureAsyncPerformance(operationName, asyncCallback) {
  const startTime = performance.now();
  try {
    const result = await asyncCallback();
    const endTime = performance.now();

    monitoringLogger.info("Метрика производительности", {
      operation: operationName,
      durationMs: endTime - startTime,
      timestamp: new Date().toISOString(),
      success: true,
    });

    return result;
  } catch (error) {
    const endTime = performance.now();

    monitoringLogger.error("Ошибка операции с метрикой", {
      operation: operationName,
      durationMs: endTime - startTime,
      timestamp: new Date().toISOString(),
      success: false,
      error: error instanceof Error ? error.message : String(error),
    });

    throw error;
  }
}

// Пример использования мониторинга
async function monitoredOperation() {
  return measureAsyncPerformance("database-query", async () => {
    // Асинхронный запрос к базе данных
    const result = await db.query("SELECT * FROM users LIMIT 100");
    return result;
  });
}

Создание дочерних логгеров

import { defaultLogger } from "@reputation-management/logger";

// Создание логгера для конкретного сервиса
const userServiceLogger = defaultLogger.child({
  service: "user-service",
  component: "auth",
});

userServiceLogger.info("Пользователь вошел в систему", { userId: "123" });

// Иерархия дочерних логгеров
const authLogger = defaultLogger.child({ component: "auth" });
const loginLogger = authLogger.child({ operation: "login" });
const registrationLogger = authLogger.child({ operation: "registration" });

// Использование дочерних логгеров
function userLogin(username, password) {
  loginLogger.info("Попытка входа в систему", { username });

  // Логика аутентификации...

  loginLogger.info("Успешный вход", { username });
}

function userRegistration(userData) {
  registrationLogger.info("Начало регистрации пользователя");

  // Логика регистрации...

  registrationLogger.info("Пользователь зарегистрирован", {
    username: userData.username,
    email: userData.email,
  });
}

// Передача логгеров между модулями
function createAuthService(options = {}) {
  const logger =
    options.logger || defaultLogger.child({ service: "auth-service" });

  return {
    login: (username, password) => {
      logger.info("Вход в систему", { username });
      // ...
    },
    logout: (userId) => {
      logger.info("Выход из системы", { userId });
      // ...
    },
    // Получение логгера для использования другими функциями
    getLogger: () => logger,
  };
}

// Использование
const authService = createAuthService({
  logger: defaultLogger.child({
    service: "custom-auth-service",
    tenant: "tenant-123",
  }),
});

// Получение логгера из сервиса для дальнейшего использования
const serviceLogger = authService.getLogger();
serviceLogger.debug("Отладочная информация из сервиса аутентификации");

Конфигурация

Логгер поддерживает следующие параметры конфигурации:

| Параметр | Тип | По умолчанию | Описание | | ----------- | -------- | ------------------------------------ | --------------------------------------------- | | level | LogLevel | LogLevel.INFO | Уровень логирования | | logDir | string | './logs' | Директория для хранения логов | | maxSize | string | '20m' | Максимальный размер файла лога перед ротацией | | maxDays | number | 14 | Максимальное количество дней хранения логов | | console | boolean | true | Включить логирование в консоль | | file | boolean | true | Включить логирование в файл | | datePattern | string | 'YYYY-MM-DD' | Формат даты для имени файла | | filePrefix | string | 'app' | Префикс для имени файла | | defaultMeta | object | { service: 'reputation-management' } | Дополнительные метаданные для каждого лога | | colorize | boolean | true | Включить цветное форматирование в консоли |

Уровни логирования

Логгер поддерживает следующие уровни логирования (в порядке убывания важности):

  1. ERROR - Ошибки, требующие внимания
  2. WARN - Предупреждения, которые не являются ошибками
  3. INFO - Информационные сообщения
  4. HTTP - HTTP запросы
  5. VERBOSE - Подробная информация
  6. DEBUG - Отладочная информация
  7. SILLY - Детальная отладочная информация

API документация

Основные компоненты

Logger

Класс Logger предоставляет основные методы для логирования:

| Метод | Описание | | ------------------------- | ----------------------------------------------------------- | | error(message, meta?) | Логирование ошибок | | warn(message, meta?) | Логирование предупреждений | | info(message, meta?) | Логирование информационных сообщений | | http(message, meta?) | Логирование HTTP запросов | | verbose(message, meta?) | Логирование подробной информации | | debug(message, meta?) | Логирование отладочной информации | | silly(message, meta?) | Логирование детальной отладочной информации | | child(meta) | Создание дочернего логгера с предустановленными метаданными |

Экспортируемые функции

| Функция | Описание | | -------------------------------------------------- | --------------------------------------------------------------- | | createLogger(options) | Создает новый экземпляр логгера с указанными опциями | | defaultLogger | Предустановленный экземпляр логгера с настройками по умолчанию | | createErrorMeta(error) | Создает метаданные для логирования ошибок, включая стек вызовов | | formatError(error) | Форматирует ошибку в строку для логирования | | honoLoggerMiddleware(logger) | Создает middleware для логирования HTTP запросов в Hono | | honoErrorLoggerMiddleware(logger) | Создает middleware для логирования ошибок в Hono | | createInngestLogger(logger, functionName) | Создает логгер для функций Inngest | | createVercelFunctionLogger(logger, functionPath) | Создает логгер для Vercel Fluid Functions |

Типы

| Тип | Описание | | --------------- | ----------------------------------------------------------------------------------------------- | | LogLevel | Перечисление уровней логирования (ERROR, WARN, INFO, HTTP, VERBOSE, DEBUG, SILLY) | | LoggerOptions | Интерфейс опций для создания логгера | | LogMeta | Тип для метаданных логирования (расширяет Record<string, any>) |

Параметры конфигурации (LoggerOptions)

| Параметр | Тип | По умолчанию | Описание | | ------------- | -------- | ------------------------------------ | --------------------------------------------- | | level | LogLevel | LogLevel.INFO | Минимальный уровень логирования | | logDir | string | './logs' | Директория для хранения файлов логов | | maxSize | string | '20m' | Максимальный размер файла лога перед ротацией | | maxDays | number | 14 | Максимальное количество дней хранения логов | | console | boolean | true | Включить логирование в консоль | | file | boolean | true | Включить логирование в файл | | datePattern | string | 'YYYY-MM-DD' | Формат даты для имени файла | | filePrefix | string | 'app' | Префикс для имени файла | | defaultMeta | object | { service: 'reputation-management' } | Дополнительные метаданные для каждого лога | | colorize | boolean | true | Включить цветное форматирование в консоли |

Расширенное использование

Настройка форматирования логов

import { createLogger, LogLevel, format } from "@reputation-management/logger";
import { format as winstonFormat } from "winston";

// Создание логгера с пользовательским форматированием
const logger = createLogger({
  level: LogLevel.INFO,
  console: true,
  file: true,
  // Добавление пользовательского форматера
  format: winstonFormat.combine(
    winstonFormat.timestamp(),
    winstonFormat.json(),
    winstonFormat((info) => {
      info.custom_field = "custom_value";
      return info;
    })(),
  ),
});

Расширение логгера дополнительными транспортами

import { createLogger, LogLevel } from "@reputation-management/logger";
import { transports } from "winston";

// Создание логгера с дополнительным транспортом
const logger = createLogger({
  level: LogLevel.INFO,
  console: true,
  file: true,
});

// Добавление транспорта Syslog
logger.add(
  new transports.Syslog({
    host: "logs.papertrailapp.com",
    port: 12345,
    protocol: "tls4",
    localhost: "my-app",
    eol: "\n",
  }),
);

Создание иерархии логгеров для разных компонентов

import { defaultLogger } from "@reputation-management/logger";

// Логгер для API-слоя
const apiLogger = defaultLogger.child({ component: "api" });

// Логгеры для разных контроллеров
const userController = apiLogger.child({ controller: "user" });
const orderController = apiLogger.child({ controller: "order" });

// Использование
userController.info("Получение профиля пользователя", { userId: "123" });
orderController.info("Создание заказа", { orderId: "456", userId: "123" });

Лучшие практики логирования в продакшене

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

    logger.info("Пользователь авторизован", {
      userId: user.id,
      role: user.role,
      requestId: context.requestId,
    });
  2. Централизованное управление уровнями логирования:

    // config.ts
    export const LOG_LEVEL = process.env.LOG_LEVEL || "info";
    
    // logger.ts
    import { LOG_LEVEL } from "./config";
    import { createLogger, LogLevel } from "@reputation-management/logger";
    
    export const logger = createLogger({
      level: LOG_LEVEL as LogLevel,
      // другие настройки
    });
  3. Трассировка запросов через метаданные:

    // middleware.ts
    import { v4 as uuidv4 } from "uuid";
    
    app.use("*", (c, next) => {
      c.set("requestId", uuidv4());
      return next();
    });
    
    // route-handler.ts
    app.get("/api/users", (c) => {
      const requestId = c.get("requestId");
      logger.info("Запрос списка пользователей", { requestId });
      // ...
    });

Руководство для разработчиков

Установка и настройка

# Клонирование репозитория
git clone [URL-репозитория]
cd packages/logger

# Установка зависимостей
pnpm install

# Сборка пакета
pnpm run build

# Запуск тестов
pnpm run test

# Проверка линтером
pnpm run lint

Добавление новых интеграций

Для добавления интеграции с новой платформой:

  1. Создайте новый файл в директории src/integrations/
  2. Реализуйте фабричную функцию для создания специализированного логгера
  3. Добавьте экспорт в src/index.ts
  4. Обновите документацию и добавьте примеры использования

Структура проекта

packages/logger/
src/
  ├── constants.ts    # Константы и настройки по умолчанию
  ├── format.ts       # Форматирование логов
  ├── index.ts        # Основной экспорт
  ├── integrations/   # Интеграции с другими платформами
  ├── logger.ts       # Основная реализация логгера
  ├── types.ts        # Типы и интерфейсы
  └── utils.ts        # Вспомогательные функции

Вклад в развитие проекта

Мы приветствуем вклад сообщества! Подробнее о процессе разработки и правилах можно узнать в CONTRIBUTING.md.

Лицензия

MIT