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

Node.js

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

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

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

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

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

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

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

Однако, несмотря на то, что они выглядят одинаково, система обрабатывает их по-разному. ПроверитьДокументация Node.js о представлении консоли,Мы видим, что,console.logвывод кstdout,console.errorвывод вstderr.

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

Короче говоря, мы можем использовать перенаправление (>) и трубы (|) оператор разделяет ошибки приложения и результаты диагностической информации.>оператор позволяет намstdoutперенаправить вывод в файл, а2>позвольте намstderrВывод перенаправляется в файл. Например, эта команда импортирует "Hello there" в файл с именемHello.logфайл и импортировать "Bye Bye" в файл с именемerror.logдокумент.

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

Когда нам нужен лог?

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

  • Быстрая отладка исключений во время разработки
  • Ведение журнала в браузере для анализа или диагностики
  • Журналы приложений службы регистрации для записи входящих запросов и любых сбоев, которые могли произойти.
  • Дополнительные журналы отладки для библиотеки, чтобы помочь пользователям в устранении неполадок
  • Печать хода выполнения, подтверждающих сообщений или ошибок через интерфейс командной строки

Ниже мы пропустим первые два сценария и сосредоточимся на последних трех сценариях, связанных с 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('$0',req)Используется для записи всего объекта.console.logнижнее использованиеutil.formatПоддержка метода%OЗаполнитель. Подробности можно найти наОфициальная документация Node.jsпонять в.

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

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

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

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

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

Мы могли бы сделать все это, обратившись к частям процесса и написав кучу 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экземпляр регистратора и передать егоexpress-pino-loggerсоздать новое промежуточное программное обеспечение регистратора, чтобыapp.useпередача. Кроме того, при запуске службы мы используемlogger.infoзаменятьconsole.log, и добавил в маршрут дополнительнуюlogger.debug, чтобы отобразить различные уровни журналов.

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

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

Перед этим давайте обсудим тот факт, что теперь вывод на самом деле очень читабелен. Однако это намеренно. Пино следует принципу более высокой производительности. Мы также можем передать (используя|) вынести логи всех процессов в отдельный процесс для улучшения его читабельности или выгрузки данных на облачный сервер. Этот процесс называетсяtransports. ПроверитьДокументация по транспорту, а также понять, почему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сообщения уровня.

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

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

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

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

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

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

DEBUG=express:* node index.js

Запустите команду с существующим приложением, и вы увидите много дополнительных выходных данных, которые помогут вам отладить проблему.

Если ведение журнала отладки не включено, вы их не увидите. Это делается через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Новый экземпляр журнала отладки, который печатает два сообщения. Переходим к предыдущей главе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, который распечатает журнал отладки для нашей «библиотеки».

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

Установите библиотеку, используя:

npm install pino-debug

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

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

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

Вывод CLI (интерфейс командной строки)

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

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

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

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

Установите мел с помощью npm и создайте файл с именемclip .jsдокумент. Вставьте следующий код:

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

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

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

Другой сценарий, который вы должны иметь в виду, — это если ваш стандартный вывод работает в режиме терминала, то есть содержимое записывается на терминал. Если это так, мы можем использоватьboxenЧто-то вроде этого, чтобы отобразить весь красивый вывод. Если нет, скорее всего, вывод куда-то перенаправляется в файл или канал.

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

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

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

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

Теперь запустите в своем терминалеnode clip.js, вы увидите true, за которым следует наше цветное сообщение.

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

node clip .js > output.log
cat output.log

Вы увидите, что на этот раз он печатает undefined, за которым следует сообщение сплошного цвета, потому что перенаправление stdout отключает режим терминала stdout.chalkиспользовалsupport-colorПроверьте, поддерживается ли TTY в соответствующем потоке.

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

Суммировать

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

оригинал:A Guide to Node.js Logging