Что такое логи в тестировании
LogRock: Тестирование через логирование
LogRock: Тестирование через логирование
Уже более 2-х лет мы работаем над своим проектом Cleverbrush. Это софт для работы с векторной графикой. Работа с графическим редактором подразумевает огромное количество вариантов использования приложения. Мы пытаемся экономить деньги и время, поэтому оптимизируем все, в том числе тестирование. Покрывать тест кейсами каждый вариант это слишком дорого и нерационально, тем более что все варианты покрыть невозможно.
В ходе разработки был создан модуль для React JS приложений — LogRock (github).
Этот модуль позволяет организовать современное логирование приложения. На основании логов мы производим тестирование. В этой статье я расскажу Вам о тонкостях использования данного модуля и как организовать тестирование через логирование.
В чем проблема?
Если сравнивать программу с живым организмом, то баг в ней — это болезнь. Причиной возникновения этой «болезни» может стать целый ряд факторов, в том числе и окружение конкретного пользователя. Это особенно актуально если мы рассматриваем веб-платформу. Иногда причинно-следственная связь очень сложная, и баг, который нашли при тестировании — результат целого ряда событий.
Как и при человеческих недугах, лучше пациента никто не объяснит свои симптомы, ни один тестировщик не сможет рассказать, что произошло, лучше чем сама программа.
Что же делать?
Для понимания что происходит нам нужен список действий, которые совершил пользователь в нашем приложении.
Для того, чтобы наша программа сама нам могла сообщить что у неё «болит», мы возьмем модуль LogRock (github) и свяжем его с ElasticSearch, LogStash и Kibana.
ElasticSearch — мощная система полнотекстового поиска. Можете посмотреть тутор по ElasticSearch здесь.
LogStash — система сбора логов из всевозможных источников, которая умеет отправлять логи в том числе и в ElasticSearch.
Kibana — веб-интерфейс к ElasticSearch с большим количеством дополнений.
Как это работает?
В случае ошибки (или просто по требованию) приложение отправляет логи на сервер где они сохраняются в файл. Logstash инкрементально сохраняет данные в ElasticSearch — в базу данных. Пользователь заходит в Kibana и видит сохраненные логи.
Так выглядит хорошо настроенная Kibana. Она отображает данные из ElasticSearch. Kibana может отображать данные в виде таблиц, графиков, карт и т. д., что очень удобно для анализа и понимания что происходит с нашим приложением.
В данной статье я НЕ буду рассматривать настройку ElasticStack!
Создание системы логирования
Для примера мы будем интегрировать систему логирования в одностраничном JS приложении, написанном на React. В действительности не важно на каком фреймворке будет написано ваше приложение. Я постараюсь описать сам подход построения лог системы.
1. Клиент
1.0 LogRock. Установка
Для установки необходимо выполнить:
1.1 LogRock. Настройка приложения
Для начала обернем наше приложение в компонент
LoggerContainer – это компонент который реагирует на ошибки вашего приложения и формирует стек.
Стек – это объект с информацией о операционной системе пользователя, браузере, какая кнопка мыши или клавиатуры была нажата и конечно же подмассив actions, где записаны все действия юзера, которые он совершил в нашей системе.
LoggerContainer имеет ряд настроек, рассмотрим часть из них
active – включает или отключает логгер
limit – задает лимит на количество сохраняемых последних действий юзером. Если юзер совершит 21 действие, то первое в данном массиве автоматически удалится. Таким образом, мы будем иметь 20 последних действий, которые предшествовали ошибке.
onError – колбек, который вызывается в момент возникновения ошибки. В него приходит объект Стека, в котором сохранена вся информация об окружении, действиях пользователя и т.д. Именно из этого колбека нам необходимо отправлять эти данные в ElasticSearch или бекенд, или сохранять в файл для дальнейшего анализа и мониторинга.
1.2 LogRock. Логирование
Для того, чтобы произвести качественное логирование действий пользователя, нам придется покрыть наш код лог-вызовами.
В комплекте модуля LogRock идет логгер, который связан с LoggerContainer
Предположим у нас есть компонент
Для того, чтобы его правильно покрыть логом, нам нужно модифицировать метод toggle
Мы добавили логгер, в котором информация разделена на 2 части. React.Toggle показывает нам, что данное действие произошло на уровне React, компонента Toggle, а далее мы имеем словесное пояснение действия и текущий state, который пришел в этот компонент. Подобное разделение на уровни не обязательно, но с таким подходом будет понятнее, где конкретно выполнился наш код.
Также мы можем использовать метод “componentDidCatch”, который введен в React 16 версии, на случай возникновения ошибки.
2. Взаимодействие с сервером
Рассмотрим следующий пример.
Допустим, у нас есть метод собирающий данные о пользователе с бекенда. Метод асинхронный, часть логики запрятана в бекенд. Как правильно покрыть логами данный код?
Во-первых, так как у нас клиентское приложение, все запросы идущие на сервер будут проходить в рамках одной сессии юзера, без перезагрузки страницы. Для того, чтобы связать действия на клиенте с действиями на сервере, мы должны создать глобальный SessionID и добавлять его в хедер к каждому запросу на сервер. На сервере же мы можем использовать любой логгер, который будет покрывать нашу логику подобно примеру с фронтенда, и в случае возникновения ошибки отправлять эти данные с прикрепленным sessionID в Elastic, в табличку Backend.
1. Генерируем SessionID на клиенте
2. Мы должны установить SessionID для всех запросов на сервер. Если мы используем библиотеки для запросов, это сделать очень просто, объявив SessionID для всех запросов.
3. В LoggerContainer есть специальное поле для SessionID
4. Сам запрос (на клиенте) будет выглядеть так:
Как это все будет работать: у нас записывается лог, перед запросом на клиенте. По нашему коду мы видим, что сейчас начнется загрузка данных с сервера. Мы прикрепили SessionID к запросу. Если у нас покрыт бекенд логами с добавлением этого SessionID и запрос завершился ошибкой, то мы можем посмотреть что случилось на бекенде.
Таким образом, мы следим за всем циклом работы нашего приложения не только на клиенте, но и на бекенде.
3. Тестировщик
Работа с тестировщиком заслуживает отдельного описания процесса.
Так как у нас стартап, формальных требований мы не имеем и иногда в работе не все логично.
Если тестировщик не понимает поведение — это случай, который как минимум нужно рассмотреть. Также, зачастую, тестировщик просто не может повторить одну ситуацию дважды. Так как шаги, приведшие к некорректному поведению, могут быть многочисленными и нетривиальными. К тому же, не все ошибки приводят к критическим последствиям, таким как Exception. Некоторые из них могут лишь менять поведение приложения, но не трактоваться системой как ошибка. Для этих целей на стейджинге можно добавить кнопку в хедере приложения для принудительной отправки логов. Тестировщик видит, что что-то работает не так, нажимает на кнопку и отправляет Стек с действиями на ElasticSearch.
Если все-таки критическая ошибка произошла, мы должны блокировать интерфейс, чтобы тестировщик не кликал дальше и не заходил в тупик.
Для этих целей, мы выводим синий экран смерти.
Мы видим вверху текст со Стеком этой критической ошибки, а внизу — действия, которые ей предшествовали. Еще мы получаем ID ошибки, тестировщику достаточно его выделить и прикрепить к тикету. В последствии эту ошибку легко можно будет найти в Kibana по этому ID.
Для этих целей в LoggerContainer есть свои свойства
bsodActive – включает/отключает BSOD (отключение BSOD применимо к продакшен коду)
bsod – это компонент. По умолчанию, он выглядит как выше приведенный скриншот.
Для вывода кнопки в UI LoggerContainer, мы можем использовать в context
4. LogRock. Взаимодействие с пользователем
Вы можете выводить логи в консоль или показывать их юзеру, для этого нужно использовать метод stdout:
stdout – это метод, который отвечает за вывод сообщений.
Для того, чтобы сообщение стало важным достаточно передать в логгер вторым параметром true. Таким образом можно вывести это сообщение для пользователя в всплывающем окне, например при неудачной загрузке данных, мы можем вывести сообщение о ошибке.
Продвинутое логирование
Если вы используете Redux, или подобные решения с одним Store, вы можете в Middleware обработки ваших Actions поставить logger, тем самым, все значимые действия будут проходить через нашу систему.
Для эффективного логирования можно оборачивать ваши данные в Proxy-объект, и ставить логгеры на всех действиях с объектом.
Для покрытия логированием сторонних методов (методов библиотек, методов Legacy кода), вы можете использовать декораторы — “@”.
Советы
Логируйте приложения в том числе и на продакшене, потому что лучше, чем реальные пользователи, узкие места никакой тестировщик не найдет.
Не забудьте указать о сборе логов в лицензионном соглашении.
НЕ логируйте пароли, банковские данные и прочую личную информацию!
Избыточность логов это тоже плохо, делайте максимально понятными подписи.
Альтернативы
В качестве альтернативных подходов я выделяю:
Что дальше
Логирование — это не только поиск ошибок, это еще и мониторинг действий пользователя, сбор данных. Логирование может быть хорошим дополнением к Google Analytics и проверкой User Experience.
Выводы
Когда вы выпускаете приложение, для него жизнь только начинается. Будьте ответственны за свое детище, получайте отзывы, следите за логами и улучшайте его. Пишите качественный софт и процветайте 🙂
Логирование как инструмент повышения стабильности веб-приложения
Авторизуйтесь
Логирование как инструмент повышения стабильности веб-приложения
техлид в Dunice
Каждый проект так или иначе имеет жизненные циклы: планирование, разработка MVP, тестирование, доработка функциональности и поддержка. Скорость роста проектов может отличаться, но при этом желание не сбавлять обороты и двигаться только вперёд у всех одинаковые. Перед нами встаёт вопрос: как при работе над крупным проектом минимизировать время на выявление, отладку и устранение ошибок и при этом не потерять в качество?
Существует много различных инструментов для повышения стабильности проекта:
В данной статье я хочу поговорить об одном из таких инструментов — логировании.
Логи — это файлы, содержащие системную информацию о работе сервера или любой другой программы, в которые вносятся определённые действия пользователя или программы.
Логи полезны для отладки различных частей приложения, а также для сбора и анализа информации о работе системы с целью выявления ошибок. Всё это необходимо для контроля работы приложения, так как даже после релиза могут встретиться ошибки, а пользователи не всегда сообщают о багах в техподдержку. Чем больше процессов у вас автоматизировано, тем быстрее будет идти разработка.
Допустим, есть клиентское приложение, балансировщик в лице Nginx, серверное приложение и база данных.
В данном примере не важны язык/фреймворк бэкенда, фронтенда или тип базы данных, а вот про веб-сервер Nginx давайте поговорим. В данный момент Nginx популярнее остальных решений для высоконагруженных сайтов. Среди известных проектов, использующих Nginx: Рамблер, Яндекс, ВКонтакте, Facebook, Netflix, Instagram, Mail.ru и многие другие. Nginx записывает логи по умолчанию, без каких-либо дополнительных настроек.
Логи доступны 2 типов:
Клиент отправляет запрос на сервер, и в данной ситуации Nginx будет записывать все входящие запросы. Если возникнут ошибки при обработке запросов, сервером будет записана ошибка.
2020/04/10 13:20:49 [error] 4891#4891: *25197 connect() failed (111: Connection refused) while connecting to upstream, client: 5.139.64.242, server: app.dunice-testing.com, request: «GET /api/v1/users/levels HTTP/2.0», upstream: «http://127.0.0.1:5000/api/v1/users/levels», host: «app.dunice-testing.com»
Всё, что мы смогли бы узнать в случае возникновения ошибки, — это лишь факт наличия таковой, не более. Это полезная информация, но мы пойдём дальше. В данной ситуации помог Nginx и его настройки по умолчанию. Но что же нужно сделать, чтобы решить проблему раз и навсегда? Необходимо настроить логирование на сервере, так как он является общей точкой для всех клиентов и имеет доступ к базе данных.
Первым делом каждый запрос должен получать свой уникальный идентификатор, что поможет отличить его от других запросов. Для этого используем UUID/v4. На случай возникновения ошибки, каждый обработчик запроса на сервере должен иметь обёртку, которая отловит эти самые ошибки. В этой ситуации может помочь конструкция try/catch, реализация которой есть в большинстве языков.
В конце каждого запроса должен сохраняться лог об успешной обработке запроса или, если произошла ошибка, сервер должен обработать её и записать следующие данные: ID запроса, все заголовки, тело запроса, параметры запроса, отметку времени и информацию об ошибке (имя, сообщение, трассировка стека).
Собранная информация даст не только понимание, где произошла ошибка, но и возможную причину её возникновения. Обычно для решения ошибки информации из лога достаточно, но в некоторых случаях может быть полезен контекст запроса. Для этого необходимо при старте запроса не только генерировать ID запроса, но и сгенерировать контекст, в который мы будем записывать всю информацию по работе сервера, начиная от результата вызова функции и заканчивая результатом запроса к базе данных. Такая реализация даст не только входные данные, но и промежуточные результаты работы сервера, что позволит понять причину появления ошибки.
При микросервисном подходе система не ограничивается одним сервером, и при запросе от клиента происходит взаимодействие нескольких серверов внутри системы. Наша реализация логирования на сервере позволит выявить дефект в работе конкретного ресурса, но не позволит понять, почему запрос вернулся с ошибкой. В данной ситуации поможет трассировка запросов.
Трассировка — процесс пошагового выполнения программы. В режиме трассировки программист видит последовательность выполнения команд и значения переменных на каждом шаге выполнения программы.
В нашем случае требуется передавать метаинформацию о запросе при взаимодействии серверов и записывать логи в единое хранилище (такими могут быть ClickHouse, Apache Cassandra или MongoDB). Такой подход позволит привязать различные контексты серверов к уникальному идентификатору запроса, а отметки времени — понять последовательность и последнюю выполненную операцию. После этого команда разработки сможет приступить к устранению.
В некоторых случаях, которые встречаются крайне редко, к ошибке приводят неочевидные факторы: компилятор, ядро операционной системы, конфигурации сервера, юзабилити, сеть. В таких случаях при возникновении ошибки потребуется дополнительно сохранять переменные окружения, слепок оперативной памяти и дамп базы. Такие случаи настолько редки, что не стоит беспочвенно акцентировать на них внимание.
С сервером разобрались, что же делать, если у нас сбои даёт клиент и запросы просто не приходят? В такой ситуации нам помогут логи на стороне клиента. Все обработчики должны отправлять информацию на сервер с пометкой, что ошибка с клиента, а также общие сведения: версия и тип браузера, тип устройства и версия операционной системы. Данная информация позволит понять, какой участок кода дал сбой и в каком окружении пользователь взаимодействовал с информацией.
Также есть возможность отправлять уведомления на почту разработчикам, если произошли ошибки, что позволит оперативно узнавать о сбоях в системе. Такие подходы активно используются в системах мониторинга и аналитики логов.
Способы, которые мы рассмотрели в статье, помогут следить за качеством продукта и минимизируют затраты на исправление недочётов в системе.
Логирование как способ отлаживать код
Почему так важно запретить самому себе отладку руками?
Когда вы отлаживаете программу, то вы, сами того не осознавая, думаете что за один отладочный сеанс исправите все проблемы, возникшие в рамках этой задачи. Но наша недальновидность не хочет верить в то, что на самом деле там не одна проблема, а несколько. И за один отладочный сеанс не получится решить все эти проблемы.
Поэтому вам надо будет несколько раз запускать этот код в отладочном режиме, проводя часы отладки над одним и тем же куском кода. И это только вы один столько времени потратили над этой частью программы. Каждый член команды, кому «посчастливится» работать с этим кодом, будет вынужден прожить ту же самую историю, которую прожили вы.
Я уже не говорю о том, что люди в командах меняются, команды меняются и так далее. Человеко-часы уходят на одно и то же. Перестаньте делать это. Я серьёзно. Возьмите ответственность за других людей на себя. Помогите им не переживать тот же самый участок вашей жизни.
Проблематика: Сложно отлаживать составной код
Возможный алгоритм решения проблемы:
Таким образом, вы избавляете других людей от отладки этого кода, т.к. если возникнет проблема, то человек посмотрит ваши логи и поймёт в чём причина. Логировать стоит только важные участки алгоритма.
Давайте посмотрим пример. Вы знаете, что по отдельности все реализации интерфейсов работают (т.к. написаны тесты, доказывающие это). Но при взаимодействии всего вместе возникает некорректное поведение. Что вам нужно? Нужно логировать ответы от «корректных» интерфейсов:
В этом примере видно, как мы трассируем отдельные части алгоритма для того, чтобы можно было зафиксировать тот или иной этап его выполнения. Посмотрев на логи, станет ясно в чём причина. В реальной жизни весь этот алгоритм стоило бы разбить на отдельные методы, но суть от этого не меняется.
Всё это в разы ускоряет написание кода. Вам не нужно бежать по циклу с F10 для того, чтобы понять на какой итерации цикла возникла проблема. Просто залогируйте состояние нужных вам объектов при определённых условиях на определённой итерации цикла.
В конечном итоге вы оставляете важные логи и удаляете побочные логи, например, где вы узнавали состояние объекта на определённой итерации цикла. Такие логи не помогут вашим коллегам, т.к. вы, скорее всего, уже поняли проблему некорректного алгоритма и исправили её. Если нет, то ведите разработку в вашей ветке до тех пор, пока не найдёте в чём причина и не исправите проблему. А вот логи, которые записывают важные результаты от выполнения других алгоритмов, понадобятся всем. Поэтому их стоит оставить.
Что если нам не нужен этот мусор? В таком случае выполняйте трассировку только в рамках отладки, а затем подчищайте за собой.
Методы тестирования через логирование
В чем суть
Если взять любое программное обеспечение и сравнить его с живым организмом, то окажется, что баг (ошибка, дефект) – это болезнь, которая поражает организм и наносит определенный вред. Проявление такой болезни может быть спровоцировано целым рядом негативных факторов, особенно если рассматривать веб-продукт в качестве старта.
Иногда причинно-следственная закономерность очень запутанная и ошибка, которую нашел тестировщик во время поиска багов – итог целого комплекса выполненных действий.Как и во время борьбы с человеческими недугами, где кроме пациента никто не сможет лучше описать текущие симптомы болезни, так и ни один QA специалист не сможет поведать, что случилось на самом деле лучше, чем непосредственно программа (утилита, веб-продукт).
Логирование как составная часть сборки ПО
Что необходимо сделать
Итак, чтобы программа могла сама сообщить нам о том, что же именно ее беспокоит, необходимо заручится поддержкой нескольких проверенных и бесплатных решений – Kibana, ElasticSearch и LogStash – которые запросто можно соединить в единый компонент.
Ключевые продукты тестирования через логирование
Как происходит работа связанных компонентов?
Допустим, у нас есть приложение, которое может сохранять логи на сервере. LogStash моментально в инкрементальной форме передает информацию на ElasticSearch, внутрь базы данных. Пользователь заходит в Kibana и видит список всех заранее сохраненных логов.
Хорошо продуманная работа утилиты Kibana позволит отображать данные в форме графиков, таблиц и интерактивных карт.
Пример №1 – тестирование через логирование на основе социальной сети
Теперь представьте, что в наших руках находится вполне сформированная социальная сеть закрытого доступа, которая была предварительно проверена на 100% работоспособность при любых обстоятельствах. Ее сущность – реальное время, она выстроена на сокетах, где очень много сторонних сервисов и информации.
За основу были взяты React+Redux. Оговоримся сразу, подход логирования никак не привязан к процессу логирования.
Попробуем провести логирование продукта, чтобы ответить на вопрос: возможно ли подобным образом сократить время на проверку ПО.
Выбираем логгер для нашего продукта. Если это часть back-end, можно воспользоваться программой Winston. Для front-end можно применить js-logger, так как его параметры поддерживают все базовые методы логирования – error, debug, log, info, warn.
Логгер обязательно должен передавать информацию в коллекцию с определенным лимитом. Если вы превысите лимит, то первый элемент будет удален. Подобная закономерность внедрена для того, чтобы не пересылать достаточно громоздкие и тяжелые данные.
Внутрь стека мы запросто можем внести метаданные: актуальный язык, определенную системой локализацию, актуальную теку, данные о браузере и системе, список последних действий и userID.
К слову, userID очень важен, ведь именно благодаря его наличию у проектной команды есть возможность понимать, у какого именно тестировщика на проекте произошла ошибка.
Для социальной сети мы применили Redux. Его функционал позволяет импортировать внутрь программного кода логгер через middleware, что существенным образом упрощает процесс сбора данных.
Наличие префикса redux позволяет понять, на каком именно слое утилиты случилась зафиксированная ошибка.
Чтобы выполнить всю работу по покрытию сервера логами можно использовать axinos. С его помощью можно вставить middleware внутрь обработки всех существующих запросов. Подкрепим наш логгер на все ошибки от сервера. Теперь каждый запрос будет обрабатываться, и если сервер не работает или не прислал что-то в ответ, мы точно об этом узнаем:
rest.interceptors.request.use(
config => config,
error => <
if (error.message) <
logger.error(error.message);
>
return Promise.reject(error);
>
);
rest.interceptors.response.use(
response => response.data,
error => <
if (error.message) <
logger.error(error.message);
>
return Promise.reject(error);
>
);
С сокетами все гораздо проще и понятнее. С помощью контракта мы решаем, что каждое сообщение будет иметь свой персонализированный статус. Если какой-то статус прибыл с ошибкой, мы его начинаем обрабатывать.
При необходимости мы можем расставлять логи внутри компонентов, в catch методах React.
Настоятельно рекомендуется ставить название компонента, чтобы во время минифицированной версии прекрасно понимать, в каком именно компоненте у нас произошла ошибка.
static displayName = ‘MyComponent’;
…
componentDidCatch(err) <
logger.error(`react.$
>
Во все сложные алгоритмы необходимо добавлять логи, покрывая при этом наиболее узкие места продукта.
После этого мы подписываемся на onerror и при возникновении ошибки посылаем в Elastic сведения со всеми данными из стека:
window.onerror = (errorMsg, url, lineNumber, lineCount, trace) => <
// create critical error
let critical = <>;
critical[CRITICAL] = serializeError(trace, lineNumber);
let criticalData = mixParams.call(this, critical, true);
this.stackCollection.add(criticalData);
// get stack data
let stackData = this.getStackData();
// send log to server
this.sendLogToServer(stackData);
>;
Это все хорошее, но не идеальное решение. Нет информации с back-end, данные представлены не в слишком развернутой форме. Но если постараться, можно сделать так, чтобы было все намного лучше!
Пример №2 – тестирование на базе готового программного продукта (CleverBush)
Представим, что у нас есть готовый продукт, который прошел все стадии разработки – от создания ПО, до разработки графики (коллажей и редакторов).
Теперь на основании возможностей первого примера мы постараемся улучшить свои умения тестировать через логирование.
Допустим, на этом проекте нет никакого Redux. Что теперь делать? Существует сразу 3 подхода, как можно организовать быстрое логирование продукта:
А если у нас традиционный стартап, то требований особых нет, и не всегда все действия выглядят логичными.
Если QA специалист не понимает суть поведения – это ошибка, с которой нужно что-то делать. К тому же, не все баги могут привести к критическому состоянию. Под эти цели на стейджинге можно создать кнопку в шапке сайта для принудительной процедуры отправки логов на сервер. QA видит, что система функционирует не так как нужно, жмет на кнопку и повторяет аналогичное действие, что и на onerror.
Специальная кнопка в шапке сайта
Но если критический баг все же состоялся, необходимо быстрее блокировать интерфейс, чтобы QA специалист не нажимал на кнопку по 10 раз, тем самым, не приводя себя в тупик.
window.onerror = (errorMsg, url, lineNumber, lineCount, trace) => <
…
// show BSOD
let bsod = BSOD(stackData);
document.body.appendChild(bsod);
…
>;
Если случилась критическая ошибка на стейджинге, можно вывести «синий экран смерти».
Сверху виден текст со стеком определенной критической ошибки, а снизу – действия, которые ей предшествовали. Так же нам приходит оригинальный ID бага. Тестировщикам просто остается выделить его и прикрепить в запрос.
Синий экран смерти
Наш продукт весьма тесно взаимодействует с back-end. В таком случае эту часть также можно покрыть логированием. Для этих целей используем Winston + record в файл посредством middleware Express. Вышеупомянутый Logstash анализирует логи из файла и отсылает их в ElasticSearch. Для того, чтобы качественно объединить логи back-end и front-end, можно генерировать ID сессии и отправлять их в название каждого сформированного запроса:
rest.defaults.headers.common.sessionId = global.__session_id__;
То есть теперь понятно, если мы создали и отправили запрос, то он в любом случае выполнится на сервере. Нам будет приходить ответ, и мы спокойно сможем продолжать работу на стороне клиента. В Kibana будет проходить фильтрация по ID запроса.
Когда отправляется стек действия на ElasticSearch, QA специалисту приходит оригинальный ID номер, который он может прикрепить к запросам.
В итоге мы имеем:
Что дает нам проверка логирования
Совет: проводите логирование продукта и на стадии выпуска, ведь только реальные пользователи, в отличие от даже самого опытного тестировщика, смогут найти узкие места функциональности вашего ПО.
Итак, логирование – это не только процедура нахождения ошибок, но и мониторинг действий клиента, сбор информации. Логирование может стать хорошим дополнением к продуктам Google Analytics и верификацией на пресловутый User Experience.