Введение
Эффективное решение для ведения журнала является ключевым элементом успеха любого приложения. Winston – это универсальная библиотека ведения журнала и популярное решение для ведения журнала, доступное для приложений на Node.js. Среди функций Winston можно выделить поддержку нескольких вариантов хранения, уровни журналирования, запросы журнала и встроенный профилировщик.
В этом учебнике вы будете использовать Winston для ведения журнала приложения Node/Express, которое вы создадите в процессе работы. Вы также увидите, как объединить Winston с Morgan, еще одним популярным промежуточным регистратором HTTP-запросов для Node.js, чтобы объединить журналы данных HTTP-запросов с другой информацией. После завершения этого учебника на вашем сервере Ubuntu будет запущено небольшое приложение Node/Express, и Winston будет использоваться для ведения журнала ошибок и сообщений в файле и на консоли.
Предварительные требования
Для выполнения этого учебника вам понадобится:
-
Сервер Ubuntu 20.04 с пользователем sudo без прав root, который вы можете настроить, следуя начальной настройке сервера.
-
Node.js установлен с использованием официального PPA (личного архива пакетов), что объясняется в статье Как установить Node.js на Ubuntu 20.04, Опция 2.
Шаг 1 — Создание простого веб-приложения на Node/Express
Winston часто используется для регистрации событий в веб-приложениях, созданных с использованием Node.js. На этом этапе вы создадите простое веб-приложение на Node.js с использованием фреймворка Express. Вы будете использовать express-generator
, инструмент командной строки, чтобы быстро запустить веб-приложение Node/Express.
Поскольку вы установили Менеджер пакетов Node в ходе предварительных требований, вы можете использовать команду npm
для установки express-generator
:
Флаг -g
устанавливает пакет глобально, что означает, что его можно использовать как инструмент командной строки вне существующего проекта/модуля Node.
После установки express-generator
можно создать свое приложение, используя команду express
, за которой следует имя каталога, который вы хотите использовать для проекта:
В этом руководстве проект будет называться myApp
.
Примечание: Также возможно запустить инструмент express-generator
напрямую, не устанавливая его глобально как системную команду сначала. Для этого выполните эту команду:
Команда npx
– это утилита запуска команд, поставляемая с менеджером пакетов Node, которая упрощает запуск инструментов командной строки из реестра npm
.
При первом запуске он попросит вас согласиться на загрузку пакета:
Need to install the following packages:
express-generator
Ok to proceed? (y)
Ответьте y
и нажмите ENTER
. Теперь вы можете использовать npx express-generator
вместо express
.
Затем установите Nodemon, который автоматически перезагружает приложение при внесении изменений. Приложение Node.js должно быть перезапущено каждый раз, когда в исходный код вносятся изменения, чтобы эти изменения вступили в силу, поэтому Nodemon будет автоматически следить за изменениями и перезапускать приложение. Поскольку вы хотите использовать nodemon
как инструмент командной строки, установите его с флагом -g
:
Чтобы завершить настройку приложения, перейдите в каталог приложения и установите зависимости следующим образом:
По умолчанию приложения, созданные с помощью express-generator
, работают на порту 3000
, поэтому вам необходимо убедиться, что брандмауэр не блокирует этот порт.
Чтобы открыть порт 3000
, выполните следующую команду:
Теперь у вас есть все необходимое для запуска вашего веб-приложения. Для этого выполните следующую команду:
Эта команда запускает приложение на порту 3000
. Вы можете проверить его работу, перейдя в браузере по адресу http://your_server_ip:3000
. Вы должны увидеть что-то подобное:
На данном этапе вы можете открыть вторую SSH-сессию на ваш сервер для продолжения этого руководства, оставив запущенное вами веб-приложение в исходной сессии. Начиная с этого момента, первая SSH-сессия, на которой запущено приложение, будет называться Сессия A. Любые команды в Сессии A будут отображаться на темно-синем фоне, например, так:
Вы будете использовать новую SSH-сессию для выполнения команд и редактирования файлов. Эта сессия будет называться Сессия B. Любые команды в Сессии B будут отображаться на светло-голубом фоне, например, так:
За исключением случаев, когда указано иное, вы будете выполнять все оставшиеся команды в Сессии B.
На этом этапе вы создали базовое приложение. Далее вы его настроите.
Шаг 2 — Настройка переменных журналирования
Хотя стандартное приложение, созданное с помощью express-generator
, является хорошим началом, вам нужно настроить приложение так, чтобы оно вызывало правильный регистратор при необходимости.
express-generator
включает промежуточное ПО регистрации HTTP-запросов Morgan, которое вы будете использовать для регистрации данных о всех HTTP-запросах. Поскольку Morgan поддерживает потоковый вывод, он прекрасно сочетается с поддержкой потоков, встроенной в Winston, что позволяет вам объединить журналы данных HTTP-запросов с чем угодно еще, что вы выберете для регистрации с помощью Winston.
Шаблон express-generator
использует переменную logger
при ссылке на пакет morgan
. Поскольку вы будете использовать как morgan
, так и winston
, которые являются пакетами регистрации, может быть запутано называть любой из них logger
. Чтобы указать, какую переменную вы хотите использовать, вы можете изменить объявления переменных, отредактировав файл app.js
.
Чтобы открыть файл app.js
для редактирования, используйте nano
или ваш любимый текстовый редактор:
Найдите следующую строку близко к верху файла:
Измените имя переменной с logger
на morgan
:
Это обновление указывает, что объявленная переменная morgan
будет вызывать метод require()
, связанный с регистратором запросов Morgan.
Вам нужно найти, где еще в файле используется переменная logger
и изменить ее на morgan
. Вам также потребуется изменить формат журнала, используемый пакетом morgan
, на combined
, который является стандартным форматом журнала Apache и будет включать полезную информацию в журналах, такую как удаленный IP-адрес и заголовок запроса HTTP пользовательского агента.
Для этого найдите следующую строку:
Обновите ее следующим образом:
Эти изменения помогут вам понять, на какой журнальный пакет ссылается в данный момент после интеграции конфигурации Winston.
По завершении сохраните и закройте файл.
Теперь, когда ваше приложение настроено, вы можете начать работу с Winston.
Шаг 3 — Установка и настройка Winston
На этом шаге вы установите и настроите Winston. Вы также изучите доступные параметры конфигурации в составе пакета winston
и создадите регистратор для записи информации в файл и консоль.
Установите winston
с помощью следующей команды:
Полезно хранить любые файлы конфигурации поддержки или утилиты для ваших приложений в специальном каталоге. Создайте папку config
, которая будет содержать конфигурацию winston
:
Затем создайте папку, которая будет содержать ваши файлы журналов:
Наконец, установите app-root-path
:
Пакет app-root-path
полезен при указании путей в Node.js. Хотя этот пакет не имеет прямого отношения к Winston, он полезен при определении путей к файлам в Node.js. Вы будете использовать его для указания расположения файлов журналов Winston от корня проекта и для избегания некрасивого синтаксиса относительных путей.
Теперь, когда настройка обработки журналирования готова, вы можете определить свои параметры. Создайте и откройте для редактирования ~/myApp/config/winston.js
:
Файл winston.js
будет содержать вашу конфигурацию winston
.
Затем добавьте следующий код для подключения пакетов app-root-path
и winston
:
После того как эти переменные настроены, вы можете определить настройки конфигурации для ваших транспортов. Транспорты – это концепция, введенная Winston, которая относится к механизмам хранения/вывода, используемым для журналов. Winston поставляется с четырьмя встроенными основными транспортами: Консоль, Файл, HTTP и Поток.
Вы будете сосредоточены на консольном и файловом транспортах для этого урока. Консольный транспорт будет записывать информацию в консоль, а файловый транспорт будет записывать информацию в указанный файл. Каждое определение транспорта может содержать настройки конфигурации, такие как размер файла, уровни журналирования и формат журнала.
Вот краткое описание настроек, которые вы будете использовать для каждого транспорта:
уровень
: уровень сообщений для ведения журнала.имя_файла
: файл, в который будут записываться данные журнала.handleExceptions
: перехват и запись необработанных исключений.maxsize
: максимальный размер файла журнала в байтах перед созданием нового файла.maxFiles
: ограничение количества файлов, создаваемых при превышении размера файла журнала.формат
: формат вывода журнальных данных.
Уровни журналирования указывают приоритет сообщения и обозначаются целым числом. Winston использует уровни журналирования npm, которые имеют приоритет от 0 до 6 (от самого высокого до самого низкого):
- 0: ошибка
- 1: предупреждение
- 2: информация
- 3: http
- 4: подробно
- 5: отладка
- 6: глупость
При указании уровня журналирования для конкретного транспорта будут записаны все сообщения на этом уровне или выше. Например, при установке уровня информация
, будут записаны все сообщения на уровне ошибка
, предупреждение
или информация
.
Уровни журналирования указываются при вызове регистратора, что означает, что вы можете выполнить следующую команду для записи ошибки: logger.error('тестовое сообщение об ошибке')
.
Все еще в файле конфигурации добавьте следующий код для определения параметров конфигурации для транспортов файл
и консоль
в конфигурации winston
:
Затем добавьте следующий код для создания нового логгера winston
с транспортами файлов и консоли, используя свойства, определенные в переменной options
:
По умолчанию morgan
выводит только на консоль, поэтому вы определите функцию потока, которая сможет получать вывод, сгенерированный morgan
, в лог-файлы winston
. Вы будете использовать уровень info
для получения вывода обоими транспортами (файл и консоль). Добавьте следующий код в файл конфигурации:
Наконец, добавьте следующий код для экспорта логгера, чтобы его можно было использовать в других частях приложения:
Завершенный файл конфигурации winston
теперь будет выглядеть так:
Сохраните и закройте файл.
Теперь у вас настроен логгер, но ваше приложение все еще не знает о нем или как им пользоваться, поэтому вам нужно интегрировать логгер с приложением.
Шаг 4 — Интеграция Winston с приложением
Чтобы ваш логгер работал с приложением, вам нужно сделать express
осведомленным об этом. Вы видели в Шаге 2, что ваша конфигурация express
находится в app.js
, поэтому вы можете импортировать свой логгер в этот файл.
Откройте файл для редактирования:
Добавьте объявление переменной winston
возле верха файла с другими операторами require
:
Первое место, где вы используете winston
, это с morgan
. По-прежнему в app.js
найдите следующую строку:
Обновите её, чтобы добавить опцию stream
:
Здесь вы устанавливаете опцию stream
на интерфейс потока, который вы создали в рамках конфигурации winston
.
Сохраните и закройте файл.
На этом этапе вы настроили ваше приложение Express для работы с Winston. Далее вы рассмотрите данные журнала.
Шаг 5 — Доступ к данным журнала и запись пользовательских сообщений журнала
Теперь, когда приложение настроено, вы готовы увидеть некоторые данные журнала. На этом этапе вы рассмотрите записи журнала и обновите свои настройки с примером пользовательского сообщения журнала.
Если вы перезагрузите страницу в веб-браузере, вы должны увидеть что-то подобное следующему выводу в консоли сеанса SSH A:
Output[nodemon] restarting due to changes...
[nodemon] starting `node bin/www`
info: ::1 - - [25/Apr/2022:18:10:55 +0000] "GET / HTTP/1.1" 200 170 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
info: ::1 - - [25/Apr/2022:18:10:55 +0000] "GET /stylesheets/style.css HTTP/1.1" 304 - "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
Здесь две записи в журнале: первая для запроса к HTML-странице; вторая для связанного стилевого файла. Поскольку каждый транспорт настроен на обработку данных журнала уровня info
, вы также должны увидеть аналогичную информацию в файловом транспорте, расположенном в ~/myApp/logs/app.log
.
Чтобы просмотреть содержимое файла журнала, выполните следующую команду:
tail
выведет последние части файла в вашем терминале.
Вы должны увидеть что-то подобное:
{"level":"info","message":"::1 - - [25/Apr/2022:18:10:55 +0000] \"GET / HTTP/1.1\" 304 - \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36\"\n","timestamp":"2022-04-25T18:10:55.573Z"}
{"level":"info","message":"::1 - - [25/Apr/2022:18:10:55 +0000] \"GET /stylesheets/style.css HTTP/1.1\" 304 - \"http://localhost:3000/\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36\"\n","timestamp":"2022-04-25T18:10:55.588Z"}
Вывод в файл transport будет записан в виде объекта JSON, так как вы использовали winston.format.json()
в опции format
для конфигурации транспорта файла. Вы можете узнать больше о JSON в Введение в JSON.
На данный момент ваш журналировщик записывает только HTTP-запросы и связанные с ними данные. Эта информация важна для ведения журналов.
В будущем вам может понадобиться записывать пользовательские сообщения журнала, например, для записи ошибок или профилирования производительности запросов к базе данных. В качестве примера вы вызовете журналировщик из маршрута обработчика ошибок. По умолчанию пакет express-generator
уже включает обработчики ошибок 404
и 500
, поэтому вы будете работать с ними.
Откройте файл ~/myApp/app.js
:
Найдите блок кода в конце файла, который выглядит так:
Этот раздел – это окончательный маршрут обработки ошибок, который в конечном итоге отправит ответ с ошибкой обратно клиенту. Поскольку все серверные ошибки будут проходить через этот маршрут, это хорошее место для включения логгера winston
.
Поскольку вы теперь имеете дело с ошибками, вы хотите использовать уровень журнала error
. Оба транспорта настроены на регистрацию сообщений уровня error
, поэтому вы должны видеть вывод в консоли и файловых журналах.
Вы можете включить в журнал любую информацию, включая данные, такие как:
err.status
: Код статуса ошибки HTTP. Если он не указан, используйте значение по умолчанию500
.err.message
: Подробности об ошибке.req.originalUrl
: Запрошенный URL.req.path
: Часть пути в запрошенном URL.req.method
: Метод HTTP-запроса (GET, POST, PUT и т. д.).req.ip
: IP-адрес удаленного хоста.
Обновите обработчик ошибок маршрута для включения регистрации с помощью winston
:
Сохраните и закройте файл.
Для проверки этого процесса попробуйте получить доступ к несуществующей странице в вашем проекте. Запрос к несуществующей странице вызовет ошибку 404. В своем веб-браузере попробуйте загрузить следующий URL: http://ваш_ip_сервера:3000/foo
. Благодаря стартовому шаблону, созданному express-generator
, приложение настроено на обработку такой ошибки.
Ваш браузер отобразит сообщение об ошибке вот так:
Когда вы посмотрите на консоль в сеансе SSH A, там должна быть запись журнала об ошибке. Благодаря примененному форматированию colorize
, его будет легко заметить:
Output[nodemon] starting `node bin/www`
error: 404 - Not Found - /foo - GET - ::1
info: ::1 - - [25/Apr/2022:18:08:33 +0000] "GET /foo HTTP/1.1" 404 982 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
info: ::1 - - [25/Apr/2022:18:08:33 +0000] "GET /stylesheets/style.css HTTP/1.1" 304 - "http://localhost:3000/foo" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
Что касается регистратора файлов, повторное выполнение команды tail
должно показать вам новые записи журнала:
Вы увидите сообщение вроде следующего:
{"level":"error","message":"404 - Not Found - /foo - GET - ::1","timestamp":"2022-04-25T18:08:33.508Z"}
Сообщение об ошибке включает в себя все данные, которые вы явно указали winston
для регистрации в качестве части обработчика ошибок. Эта информация будет включать статус ошибки (404 – Не найдено), запрошенный URL (localhost/foo
), метод запроса (GET
), IP-адрес, сделавший запрос, и временную метку, когда запрос был сделан.
Заключение
В этом руководстве вы создали простое веб-приложение Node.js и интегрировали решение по ведению журнала Winston, которое будет эффективным инструментом для получения представления о производительности приложения.
Вы можете сделать гораздо больше для создания надежных решений по ведению журналов для ваших приложений, особенно когда ваши потребности становятся более сложными. Чтобы узнать больше о транспортах Winston, см. Документация по транспортам Winston. Чтобы создать собственные транспорты, см. Добавление собственных транспортов. Чтобы создать HTTP-конечную точку для использования с транспортом HTTP, см. winstond
. Чтобы использовать Winston в качестве инструмента профилирования, см. Профилирование.