ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ. Это не исчерпывающая статья о регистрации или отслеживании.

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

Для этой задачи мы будем использовать пакеты Tracing, tracing-subscriber и tower-http.

груз.томл

[dependencies] 
axum = "0.6.1" 
tokio = { version = "1.21.2", features = ["full"] } 
tracing = "0.1.37" 
tracing-subscriber = { version = "0.3.16", features = ["env-filter"]} 
tower-http = { version = "0.3.4", features = ["trace"] }

Журналы

Вот простой пример того, как добавить ведение журнала.

main.rs

Согласно документации, когда мы используем compact(), вывод оптимизируется для коротких строк. Поля из текущего контекста диапазона добавляются к полям отформатированного события.

Если мы выполним cargo run и перейдем к locahost:3000, мы должны увидеть следующее сообщение в нашем терминале.

Теперь позвольте мне немного объяснить роль Tower-http, Tracing и Tracing-subscriber.

Отслеживание

Трассировка — это фреймворк для инструментирования программ Rust для сбора структурированной диагностической информации на основе событий.

Мы можем использовать tracing для:

  • Отправка распределенных трассировок в сборщик Open Telemetry.
  • Отлаживайте свое приложение с помощью Tokio Console.
  • Профиль, где ваше приложение проводит время.

Согласно статье Начало работы с трассировкой, крейт tracing предоставляет API, который мы будем использовать для создания трассировок. Пакет tracing-subscriber предоставляет некоторые базовые утилиты для пересылки этих трассировок внешним слушателям (например, stdout).

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

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

Башня-http

Согласно документации, tower-http — это библиотека, которая предоставляет промежуточное программное обеспечение и утилиты для HTTP, созданные поверх tower.

В документации также упоминается, что все промежуточное ПО использует крейты http и http-body в качестве абстракций HTTP. Это означает, что они совместимы с любой библиотекой или фреймворком, которые также используют эти крейты, такие как гипер, тоник и деформация.

Аксум построен с гипер, поэтому мы можем использовать tower-http.

Эта библиотека предназначена для предоставления богатого набора промежуточного программного обеспечения для решения распространенных проблем при создании HTTP-клиентов и серверов, таких как добавление высокоуровневой трассировки и ведения журнала в наши приложения. Кроме того, автоматически сжимайте или распаковывайте тела ответов и автоматически выполняйте ответы на перенаправления.

Информацию о tower-http можно найти в его документации и в этой статье.

Теперь вернемся к нашему коду.

let app = Router::new() 
         .route("/", get(hello_world)) 
         .layer( 
             TraceLayer::new_for_http() 
                  .make_span_with(trace::DefaultMakeSpan::new() 
                        .level(Level::INFO)) 
                  .on_response(trace::DefaultOnResponse::new() 
                        .level(Level::INFO)), 
);

Здесь мы создаем экземпляр маршрутизатора. И используйте метод layer, который применяет tower::Layer ко всем маршрутам в маршрутизаторе. Он используется для добавления промежуточного программного обеспечения к маршрутам.

Мы передали TraceLayer в качестве аргумента. Цитирование официальной документации:

Layer, который добавляет высокоуровневую трассировку к Service.

Служба, о которой идет речь в цитате, — это служба башни. Кроме того, мы используем new_for_http(), он создает новый TraceLayer с использованием ServerErrorsAsFailures, который поддерживает классификацию обычных HTTP-ответов на основе кода состояния, согласно документации.

Чтобы это работало, нам нужно преобразовать наш экземпляр маршрутизатора в службу башни. И мы сделали это, когда использовали into_make_service().

axum::Server::bind(&addr) 
      .serve(app.into_make_service()) 
      .await 
      .unwrap();

Теперь мы объясним, что делают make_span_with() и on_response().

В документации говорится, что on_response() настраивает действия при получении ответа. И make_span_with() настраивает, как сделать Span , в которые будет включена вся обработка запросов.

Этим функциям мы передали нужный уровень логирования. Используя метод level в обоих случаях, DefaulMakeSpan и DefaultOnResponse, мы устанавливаем уровень LEVEL::INFO. По умолчанию LEVEL::DEBUG.

Подробнее о DefaultMakeSpan и DefaultOnResponse здесь и здесь соответственно.

Симпатичный

Согласно документации, Pretty генерирует очень красивые многострочные журналы, оптимизированные для удобочитаемости человеком. Предназначен для использования в локальной разработке и отладке или для приложений командной строки, где читабельность и визуальная привлекательность являются приоритетом.

Джейсон

Чтобы добавить вывод JSON, мы должны изменить наш файл Cargo.toml и добавить функцию json в tracing_subscriber.

груз.томл

... 
tracing-subscriber = { version = "0.3.16", features = ["env-filter", "json"]} 
...

Json выводит журналы JSON с разделителями строк. Предназначен для производственного использования с системами, в которых структурированные журналы используются в виде JSON средствами анализа и просмотра.

Реестр

Цитирую документацию:

Этот модуль предоставляет тип Registry, реализацию Subscriber, которая отслеживает данные по промежутку и предоставляет их Layers. Когда Registry используется в качестве базы Subscriber стека Layer, тип layer::Context будет предоставлять методы, позволяющие Layers искать данные диапазона, хранящиеся в реестре. Хотя Registry является разумным значением по умолчанию для хранения диапазонов и событий, другие хранилища, которые сами реализуют LookupSpan и SubscriberSpanData, реализуемым данными для каждого диапазона, которые они хранят), могут использоваться в качестве замены.

Создание файлов журнала

Чтобы создать файлы журнала, мы должны добавить tracing_appender в наш файл Cargo.toml.

Груз.томл

...
tracing-appender = "0.2"

Я только что изменил этот пример из репозитория tracing.

Здесь мы создаем переменную для определения периода прокрутки и передаем ей каталог, в котором мы хотим хранить наши файлы, и имя файлов. И устанавливаем уровень логирования, в данном случае INFO.

Затем мы передаем переменную info_file в функцию with_writer().

with_writer() устанавливает MakeWriter и используется fmt::Layer или fmt::Subscriber для печати форматированных текстовых представлений событий.

Теперь, если мы установим уровень trace, вот так.

Файл будет выглядеть так.

Заключение

Tracing предлагает множество настроек. И для меня было сложной задачей найти, какие примеры будут самыми простыми для этой статьи. К счастью, у tracing_subscriber есть хорошая документация, а в репозитории есть полезные примеры. Кроме того, я просто использую info и trace в качестве уровней журнала, но они не единственные, мы можем использовать debug, warn, error, и выключить.

Было весело писать эту статью. Я сделал это, чтобы узнать больше о структуре трассировки и крейте Tower-http и о том, как они работают вместе.

Спасибо, что нашли время прочитать эту статью.

Если у вас есть какие-либо рекомендации по другим пакетам, архитектурам, как улучшить мой код, мой английский или что-то в этом роде; оставьте комментарий или свяжитесь со мной через Twitter или LinkedIn.

Исходный код находится здесь

Ссылка

Начало работы с трансом.

Разыскная документация.

Отслеживание абонентской документации.

Документация Tower-http.

Анонсирующая башня-http.

трассировочно-дополняющая документация.

пример appender-мультифайлов.

Проблема № 296: Где самый простой пример ведения журнала HTTP-запросов?

Первоначально опубликовано на https://carlosmv.hashnode.dev.