[Перевод] Руководство по ведению журнала Node.js

Node.js задняя часть Программа перевода самородков
[Перевод] Руководство по ведению журнала Node.js

Когда вы начинаете работать с JavaScript, первое, чему вы должны научиться, — это передаватьconsole.log()Записывать вещи в консоль. Если вы ищете, как отлаживатьJavaScript, вы найдете сотни сообщений в блогах и статей о StackOverflow, которые расскажут вам об очень «простом» использованииconsole.log()для завершения отладки. Поскольку это такая распространенная практика, мы даже начали использоватьlinterправила, такие какno-console, чтобы гарантировать, что мы не оставим непредвиденные записи в производственном коде. Но что, если мы действительно хотим записать что-то, чтобы предоставить больше информации?

В этом сообщении блога я расскажу о некоторых различных ситуациях, когда вы хотите регистрировать информацию, и о том, как это сделать в Node.js.console.logиconsole.errorи как отправить журнал в библиотеку, не затрагивая консоль пользователя.

console.log(`Let's go!`);

Сначала теория: важные детали Node.js

Хотя вы можете использовать в браузере и Node.jsconsole.logилиconsole.error, но при работе с Node.js следует помнить одну важную вещь. в названномindex.jsфайл напишите следующий код:

console.log('Hello there');
console.error('Bye bye');

а затем использовать в терминалеnode index.jsчтобы запустить его, вы увидите эти два вывода непосредственно ниже:

Screenshot of Terminal running `node index.js`

Однако, хотя они могут выглядеть одинаково, система на самом деле обрабатывает их по-разному. если ты пойдешь проверишьВ документации Node.jsconsoleчасть,ты увидишьconsole.logэто использоватьstdoutпечататьconsole.errorиспользоватьstderrпечатать.

Каждый процесс может использовать три значения по умолчанию.streamsприходить на работу. они соответственноstdin,stdoutиstderr.stdinПотоки для обработки вывода, связанного с вашим процессом. Например, нажатие кнопки или перенаправление вывода (мы сделаем это через секунду).stdoutПотоки используются для вывода вашего приложения. Наконецstderrдля сообщений об ошибках. Если вы хотите знатьstderrпочему он существует и когда его использовать,Вы можете просмотреть эту статью.

Короче говоря, это позволяет нам использовать перенаправление(>) и труба (|) для обработки ошибок и диагностической информации отдельно от фактических результатов приложения. Несмотря на то что>позволяет нам перенаправить вывод команды в файл,2>позвольте намstderrВывод перенаправляется в файл. Например, следующая команда передаст «Привет!»hello.logфайл и передать «До свидания» файлу с именемerror.logв файле.

node index.js > hello.log 2> error.log

Screenshot of terminal showing how error output is in different file

Когда вы хотите записаться?

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

В этом блоге мы пропустим первые две категории и сосредоточимся на трех последних, основанных на Node.js.

Журналы вашего серверного приложения

Есть много причин, по которым вам может понадобиться регистрация на сервере. Например, регистрируйте входящие запросы, чтобы вы могли извлечь из них информацию, например, сколько пользователей получают ошибки 404, какими могут быть эти запросы или что они используют.User-Agent. Вы также хотите знать, когда что-то пошло не так и почему.

Если вы хотите попробовать следующее в этой части статьи, сначала обязательно создайте папку. В каталоге проекта создайте файл с именемindex.jsфайл, затем используйте следующий код, чтобы инициализировать весь проект и установить егоexpress:

npm init -y
npm install express

Затем настройте сервер с промежуточным ПО, просто нужноconsole.logдля обслуживания каждого запроса. Поместите следующее вindex.jsВнутри файла:

const express = require('express');

const PORT = process.env.PORT || 3000;
const app = express();

app.use((req, res, next) => {
 console.log('%O', req);
 next();
});

app.get('/', (req, res) => {
 res.send('Hello World');
});

app.listen(PORT, () => {
 console.log('Server running on port %d', PORT);
});

мы используемconsole.log('%O', req)записать весь объект.console.logИспользование под капотомutil.format, который также поддерживает%Oи другие заполнители. ты сможешьПрочтите их в документации Node.js.

когда ты бежишьnode index.jsЗапустите сервер и перейдите кhttp://localhost:3000, вы заметите, что он выведет много информации, которая нам на самом деле не нужна.

Screenshot of terminal showing too much output of request object

Если вы измените код наconsole.log('%s', req)Мы также не получим много информации без вывода всего объекта.

Screenshot of terminal printing

Мы могли бы написать собственную функцию печати, которая просто выводила бы то, что нас интересует, но давайте сделаем шаг назад и обсудим то, что нас обычно волнует. Хотя эта информация часто находится в центре нашего внимания, на самом деле нам может понадобиться другая информация. Например:

  • Временная метка - раньше знала, когда что-то произошло
  • имя компьютера/сервера - если вы используете распределенную систему
  • Идентификатор процесса - если вы используете что-то вродеpm2инструмент для запуска нескольких процессов Node.
  • message - фактическое сообщение с некоторым содержимым
  • трассировка стека - на случай, если мы зарегистрируем ошибку
  • возможно, некоторые дополнительные переменные/информация

Кроме того, поскольку мы знаем, что все идет кstdoutиstderr, то нам могут понадобиться разные уровни логов и возможность настраивать и фильтровать логи на их основе.

Мы можем получить доступ к различным разделамprocessи написать целую кучу кода JavaScript, чтобы получить это, но самое лучшее в Node.js то, что мы получаемnpmэкосистемы, и в нашем распоряжении уже есть множество библиотек. Некоторые из них:

  • pino
  • winston
  • roarr
  • bunyan(Обратите внимание, что эта библиотека не обновлялась два года)

лично мне нравитсяpinoЭта библиотека, поскольку она работает быстро и имеет лучшую экосистему, давайте посмотрим, как ее использовать.pinoПриходите помочь нам войти. Мы также можем использоватьexpress-pino-loggerpackage, чтобы помочь нам аккуратно регистрировать запросы.

Установить одновременноpinoиexpress-pino-logger:

npm install pino express-pino-logger

затем обновитеindex.jsфайл для использования регистратора и промежуточного ПО:

const express = require('express');
const pino = require('pino');
const expressPino = require('express-pino-logger');

const logger = pino({ level: process.env.LOG_LEVEL || 'info' });
const expressLogger = expressPino({ logger });

const PORT = process.env.PORT || 3000;
const app = express();

app.use(expressLogger);

app.get('/', (req, res) => {
 logger.debug('Calling res.send');
 res.send('Hello World');
});

app.listen(PORT, () => {
 logger.info('Server running on port %d', PORT);
});

В этом фрагменте кода мы передаемpinoсоздалloggerэкземпляр и передать егоexpress-pino-loggerдля создания нового промежуточного программного обеспечения и передачиapp.useназвать это. Кроме того, где мы запускаем сервер сlogger.infoзаменитьconsole.log, и добавим строку к нашему маршрутуlogger.debugдля отображения дополнительного уровня журнала.

если прошлоnode index.jsЗапустите сервер перезапуска еще раз, и вы увидите совершенно другой вывод, который печатает JSON для каждой строки. Перейдите снова кhttp://localhost:3000, вы увидите еще одну добавленную строку JSON.

Screenshot showing example pino logs from HTTP request

Если вы изучите этот JSON, вы увидите, что он содержит всю ранее упомянутую информацию, например временные метки. Вы также можете заметить нашуlogger.debugЗаявление не печатается. Это потому, что нам пришлось изменить уровень журнала по умолчанию, чтобы сделать его видимым. когда мы создаемloggerнапример, мы устанавливаем значениеprocess.env.LOG_LEVELозначает, что мы можем изменить значение через него или принять значение по умолчаниюinfo. мы можем бежатьLOG_LEVEL=debug node index.jsдля настройки уровня журнала.

Прежде чем мы это сделаем, давайте проясним тот факт, что вывод прямо сейчас не очень читаем. Это сделано намеренно.pinoСледуя философии, для повышения производительности вы должны передавать (используя|) вывод перемещает любую обработку журнала в отдельный процесс. Это включает в себя создание его для чтения или загрузку на облачный хост. мы называем это传输. Проверятьо传输документацияпонятьpinoПочему ошибка не пишетсяstderr.

мы будем использоватьpino-prettyчтобы увидеть более удобочитаемую версию журнала. Запустите в терминале:

npm install --save-dev pino-pretty
LOG_LEVEL=debug node index.js | ./node_modules/.bin/pino-pretty

Теперь все ваши сообщения журнала будут использовать|вывод оператора наpino-prettyиди в. Если вы пойдете, чтобы спросить еще разhttp://localhost:3000. Вы все еще должны видеть свойdebugИнформация.

Screenshot of pretty printed pino logs

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

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

журнал вашей библиотеки

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

Проблема в том, что ваша библиотека может захотеть вести журнал для отладки, но она не должна загромождать приложение потребителя. И наоборот, потребители должны иметь возможность включить ведение журнала, если им нужно что-то отладить. Ваша библиотека по умолчанию не должна обрабатывать это и оставить запись для вывода пользователю.

expressхороший пример. существуетexpressВ рамках фреймворка происходит многое, и при отладке вашего приложения вам может понадобиться знать, что представляет собой фреймворк. если мы запросимexpressДокументация, вы заметите, что перед командой можно поставить префиксDEBUG=express:*Такая строка кода:

DEBUG=express:* node index.js

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

Screenshot of express debug logs

Если у вас не включено ведение журнала отладки, вы не увидите никаких таких журналов. Это делается путем вызоваdebugпакет для завершения. Это позволяет нам писать сообщения в «пространствах имен», если пользователь библиотеки включает пространство имен или в егоDEBUG переменная средыподстановочные знаки, соответствующие ему в , он выведет их. использоватьdebugбиблиотека, сначала установите ее:

npm install debug

Давайте смоделируем вызов нашей библиотеки, создав новый файлrandom-id.jsДавайте попробуем и напишем в нем такой код:

const debug = require('debug');

const log = debug('mylib:randomid');

log('Library loaded');

function getRandomId() {
 log('Computing random ID');
 const outcome = Math.random()
   .toString(36)
   .substr(2);
 log('Random ID is "%s"', outcome);
 return outcome;
}

module.exports = { getRandomId };

Это создаст пространство имен сmylib:randomidизdebugЗатем регистратор зарегистрирует оба сообщения. Тогда мы в предыдущем разделеindex.jsфайл с его использованием:

const express = require('express');
const pino = require('pino');
const expressPino = require('express-pino-logger');

const randomId = require('./random-id');

const logger = pino({ level: process.env.LOG_LEVEL || 'info' });
const expressLogger = expressPino({ logger });

const PORT = process.env.PORT || 3000;
const app = express();

app.use(expressLogger);

app.get('/', (req, res) => {
 logger.debug('Calling res.send');
 const id = randomId.getRandomId();
 res.send(`Hello World [${id}]`);
});

app.listen(PORT, () => {
 logger.info('Server running on port %d', PORT);
});

Если вы используете это времяDEBUG=mylib:randomid node index.jsперезапустить сервер, и он распечатает журнал отладки нашей «библиотеки».

Screenshot of custom debug logs

Интересно, если пользователи вашей библиотеки захотят поместить эти методы отладочной информации в свои собственныеpinoжурналы, они могут использоватьpinoКоманда под названиемpino-debugбиблиотека для правильного форматирования этих журналов.

Используйте следующую команду для установки этой библиотеки:

npm install pino-debug

pino-debugЕго нужно инициализировать один раз, прежде чем мы используем его в первый раз.debug. Проще всего использовать перед запуском скриптаNode.js-rили--requireидентификатордля инициализации. Используйте следующую команду, чтобы перезапустить сервер (при условии, что вы установилиpino-colada):

DEBUG=mylib:randomid node -r pino-debug index.js | ./node_modules/.bin/pino-colada

Теперь вы можете просматривать журнал отладки библиотеки в том же формате, что и журнал приложения.

Screenshot of debug logs working with pino and pino-colada

ваш вывод CLI

Последний случай, который я рассмотрю в этом сообщении блога, — это частный случай ведения журнала для CLI, а не для библиотеки. Моя философия состоит в том, чтобы отделить логические журналы от выходных «журналов» CLI. Для любого логического журнала вы должны использовать что-то вродеdebugбиблиотека. Это позволяет вам или другим лицам повторно использовать логику, не привязываясь к конкретному варианту использования CLI.

Когда вы создаете CLI с Node.js, вы можете сделать так, чтобы все выглядело красиво, добавив цвет, счетчики или отформатировав содержимое особым визуально привлекательным способом. Однако есть несколько ситуаций, которые следует учитывать при построении CLI.

Одним из случаев является то, что ваш CLI может использоваться в контексте системы непрерывного наследования (CI), поэтому вы можете захотеть удалить цвета или любой причудливый декоративный вывод. Некоторые системы CI устанавливают флаг среды под названием «CI». Если вы хотите безопаснее проверить, находитесь ли вы в CI, вы можете использовать пакет, который уже поддерживает несколько систем CI, например.is-ci.

Некоторые библиотеки, такие какchalkCI был обнаружен для вас и удалены цвета для вас. Давайте посмотрим, как это выглядит.

использоватьnpm install chalkустановитьchalk, и создайтеcli.jsдокумент. Поместите в него следующее:

const chalk = require('chalk');

console.log('%s Hi there', chalk.cyan('INFO'));

Теперь, если вы используетеnode cli.jsЗапустите этот скрипт, и вы увидите соответствующий цветной вывод.

Screenshot showing colored CLI output

но ты используешьCI=true node cli.jsчтобы запустить его, вы увидите, что цвета удалены:

Screenshot showing CLI output without colors and enabled CI mode

Другой сценарий, который вы должны помнить, этоstdoutМожет работать в терминальном режиме. Означает запись содержимого в терминал. Если это так, мы можем использовать что-то вродеboxenчто-то, чтобы отобразить весь красивый вывод. В противном случае выходные данные могут быть перенаправлены в файл или переданы в другое место.

Ты можешь проверитьisTTYсоответствующие свойства потока для проверкиstdin,stdoutилиstderrНаходится в терминальном режиме. Например:process.stdout.isTTY, в этом случае используется специально для терминалов,TTYРасшифровывается как «телетайп».

В зависимости от того, как был запущен процесс Node.js, значение для каждого из трех потоков может быть разным. ты сможешьРаздел «Процесс ввода-вывода» документации Node.jsУзнайте больше об этом.

покажи намprocess.stdout.isTTYИзменение стоимости в различных ситуациях. обновить свойcli.jsфайл для проверки:

const chalk = require('chalk');

console.log(process.stdout.isTTY);
console.log('%s Hi there', chalk.cyan('INFO'));

затем используйтеnode cli.jsзапустите в своем терминале, вы увидитеtrueЗа ним последует наше красочное сообщение после печати.

Screenshot of output saying

После этого запустите то же самое, но перенаправьте вывод в файл, затем проверьте содержимое, запустив:

node cli.js > output.log
cat output.log

На этот раз вы увидите, что он напечатаетundefinedЗа ним следует простое бесцветное сообщение. так какstdoutрежим закрытого терминалаstdoutперенаправление. так какchalkиспользовалsupports-color, так что под капотом проверки наisTTY.

Screenshot saying

Однако, какchalkТакие инструменты уже обрабатывают это поведение за вас, и при разработке CLI вы всегда должны знать о ситуациях, когда ваш CLI может работать в режиме CI или вывод перенаправляется. Это также может помочь вам сделать шаг вперед в работе с CLI. Например, вы можете красиво упорядочить данные в терминале, еслиisTTYдаundefinedЕсли это так, переключитесь на более простой способ разбора.

Суммировать

Начните с JavaScript и используйтеconsole.logРегистрация вашей первой строки выполняется быстро, но вам следует больше думать о регистрации, когда вы запускаете свой код в производство. В этой статье описываются только различные доступные методы и решения для ведения журналов. Он не содержит всего, что вам нужно знать. Я предлагаю вам проверить некоторые из ваших любимых проектов с открытым исходным кодом, чтобы увидеть, как они решают проблемы ведения журналов и инструменты, которые они используют. Иди записывай все сейчас, не распечатывай свой журнал 😉

GIF of endless printing of a document

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

Если вы обнаружите ошибки в переводе или в других областях, требующих доработки, добро пожаловать наПрограмма перевода самородковВы также можете получить соответствующие бонусные баллы за доработку перевода и PR. начало статьиПостоянная ссылка на эту статьюЭто ссылка MarkDown этой статьи на GitHub.


Программа перевода самородковэто сообщество, которое переводит высококачественные технические статьи из Интернета сНаггетсДелитесь статьями на английском языке на . Охват контентаAndroid,iOS,внешний интерфейс,задняя часть,блокчейн,продукт,дизайн,искусственный интеллектЕсли вы хотите видеть более качественные переводы, пожалуйста, продолжайте обращать вниманиеПрограмма перевода самородков,официальный Вейбо,Знай колонку.