логирование api что это такое

Логирование активности с использованием Web Beacon API

Beacon API — это основанный на JavaScript интерфейс для:

отправки небольшого количества данных на сервер с браузера, без ожидания ответа. В этой статье, мы рассмотрим в каких случаях будет полезен Beacon API, чем он отличается от использования XMLHTTPRequest (Ajax) для тех же целей и как его использовать.

Для чего нам очередной API?

Beacon API используется для отправки небольших по объему данных на сервер без ожидания ответа. Последняя часть утверждения является наиболее интересной. Beacon API разработан специально для того, что бы можно было отправить данные и забыть о них. Не нужно ожидать ответ, так как его и не будет.

Метафора с открытками, это такие карточки которые люди посылают/посылали друг другу. Как правило, на них писали небольшой по объему текст («Ты где? А я на море лол.», «Тут у меня шикарная погода, не то что у тебя в офисе»), кидали в почту и забывали. Никто не ожидал ответа по типу «Я уже выехал за тобой», «У меня в офисе чудесно».

Существует множество случаев, когда подход «отправил и забыл» будет уместен.

Отслеживание статистики и Аналитическая информация

Это первое, что приходит на ум. Такие большие решения как Google Analytics могут предоставлять хороший обзор на базовые вещи. Но если мы хотим, что-то более кастомизированное? Нам необходимо написать немного кода для отслеживания того, что происходит на странице (как пользователи взаимодействуют с компонентами, как далеко они скролят, какие страницы были отображены до первой продажи), затем отправить эти данные на сервер когда пользователь покидает страницу. Beacon идеально подходит для решения такой задачи, так как мы просто отправляем данные, и нам ненужен ответ от сервера.

Дебаг и Логирование

Другое применение это логирования информации из JavaScript кода. Представьте себе ситуацию когда у вас большое приложение с богатым UI/UX. Все тесты зеленые, а на проде периодически всплывает ошибка о которой вы знаете, но не можете продебажить ее из за не хватки информации. В данном случае вы можете ипользовать Beacon для диагностики.

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

Разве мы не делали этого ранее?

Я знаю о чем вы думаете. Ничто из этого не ново? Мы общаемся с севером посредством XMLHTTPRequest уже более 10 лет. Недавно мы начали использовать Fetch API, что по факту делает то же самое, просто с новым Promise интерфейсом. Так зачем нам еще один Beacon API?

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

C Beacon API не нужно дожидаться лучшего момента для CPU, сети. Просто добавить в очередь запрос с помощью beacon практически нечего не стоит.

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

Вы же понимаете насколько HTTP запросы медленные? И последнее, что вы хотите, так это впихивать HTTP запрос между переходами.

Пробуем Beacon API

Базовый пример использования очень прост:

Использование navigator.sendBeacon()

data — этот параметр может принимать несколько форматов данных, все те с которыми работает Fetch API. Это может быть Blob, BufferSource, FormData или URLSearchParams и тд.

Мне нравится использовать FormData для простых key-value данных, это не сложный и простой в использовании класс.

Поддержка браузерами

Поддержка этого API вполне себе солидная. Единственный браузер который не поддерживает, это Internet Explorer (не ожидал я такого) и Opera Mini. Но в Edge все работает. В большинстве случаев поддержка есть, но лучше на всякий случай проверить:

Пример: логируем время проведенное на странице

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

Так как нас интересует только время проведенное на странице, а не настоящее время, мы можем использовать performance.now() для получения базового timestamp при загрузке страницы:

Давайте обернем небольшой кусочек логики в удобную в использовании функцию:

Когда страница выгружается (или перед этим), наша функция logVisit() будет вызвана и если браузер поддерживает Beacon API, отправит запрос на сервер.

Пару моментов

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

Просто помните о нем.

DNT: DO NOT TRACK

В дополнение, браузеры имеют опцию которая позволяет пользователям обозначить, что они не хотят, что бы их активность отслеживалась. Do Not Track отправляет HTTP хедер, который выглядит так:

В заключение

Beacon API действительно очень удобный способ для отправки данных на сервер, особенно в контексте логирования. Поддержка браузерами на достаточно хорошем уровне и позволяет вам легко логировать любую информацию без каких либо негативных последсвий для производительности и отзывчивости вашего UI. Non-blocking природа этих запросов играет в этом очень хорошую роль, это горазно быстрей альтернатив XHR и Fetch.

Читайте также:  Что нужно спросить у гинеколога на приеме

Источник

Логирование в Java / quick start

В ходе моей работы в компании DataArt я, в числе прочего, занимаюсь менторской деятельностью. В частности это включает в себя проверку учебных заданий сделанных практикантами. В последнее время в заданиях наметилась тенденция «странного» использования логеров. Мы с коллегами решили включить в текст задания ссылку на статью с описанием java logging best practices, но оказалось, что такой статьи в которой бы просто и без лишних деталей на практике объяснялось бы как надо писать в лог на Java, вот так вот с ходу не находится.

Данная статья не содержит каких-то откровений, в ней не рассматриваются тонкости какого либо из многочисленных java logging frameworks. Здесь рассказываю как записать в лог так, чтобы это не вызвало удивления у Ваших коллег, основная цель написания включить ее в список обязательного чтения для практикантов. Если все еще интересно, читайте дальше

Пример №1
Хорошо
Плохо

По сути тоже самое но букв больше и читается не так легко.

Замечание между примерами
Пример №2
Хорошо
Плохо

Если логировать только ex.toString(), то потом Вы не сможете понять в какой строке изначально сработало исключение.

Пример №3

Логер надо конфигурировать. Есть конфигурация по умолчанию она выводит в консоль все сообщения с уровнем INFO и выше. Она достаточно хороша, для разработки из IDE, но для реального приложения ее обычно неплохо бы подправить.

Какие тут есть варианты

По умолчанию: Файл logging.properties для уровня INFO, вывод в консоль

#Console handler
handlers= java.util.logging.ConsoleHandler
.level=INFO

Делаем логирование более подробным выводим еще и сообщения уровня FINE

#Console handler
handlers= java.util.logging.ConsoleHandler
.level=FINE
java.util.logging.ConsoleHandler.level = FINE

Выводим лог сообщения куда-то еще

Чтобы решить эти проблемы был придуман java.util.logging.FileHandler — хэндлер который выводит лог сообщения в файл. При этом он умеет ротировать файлы, т.е. после достижения максимально допустимого размера, он дописывает в файл текщуее лог сообщение и открывает новый файл с инкрементальным префиксом. И так по кругу. Например

создаст вот такие файлы (последняя колонка — размер в байтах)

Мы указали максимальный размер 50 байтов, в реальной жизни надо скорее указывать не меньше мегабайта, например вот так (я знаю, что 1000000 это чуть меньше мегабайта, но кому охота по памяти писать 1048576, если суть дела это фактически не меняет)

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

copy & paste конфиг для реальной жизни, его вполне хватает для большинства service, console и desktop приложений.

Последняя часть магии

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

Вот так

java Djava.util.logging.config.file=logging.properties com.dataart.application.ClassName

Но к сожалению менять строку запуска не всегда можно или не всегда удобно. Второй способ тоже неплохо работает.

Что осталось за кадром

Источник

Отдельный уровень логирования для каждого запроса

Описание проблемы

Давайте разберемся, о чем идет речь. Пусть у нас есть Web-сервис. В какой-то момент он начинает сбоить на рабочих серверах, но только для некоторых запросов. Например, сбои происходят только для определенного пользователя. Или только на отдельной точке доступа… Нам необходимо найти причину. В этом случае нам на помощь приходит логирование.

Когда наше приложение работает нормально, мы хотим видеть как можно меньше записей в логе, чтобы его размер оставался маленьким. В то же время, если в приложении происходит сбой, мы хотим, чтобы в логе было достаточно записей, чтобы мы могли понять причину проблемы. Сложность здесь в том, что обычно мы устанавливаем один уровень логирования для всех логгеров в нашем приложении. Если все в порядке, мы держим этот уровень высоким (например, Warning). Если же нам нужно искать причину сбоя, мы устанавливаем его ниже (например, Debug).

Один уровень логирования на все приложение

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

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

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

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

Отдельный уровень логирования для каждого запроса

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

Итак, задача поставлена. Давайте начнем.

Реализацию свойства Logger обсудим позже. Для этого приложения я буду использовать библиотеку log4net для логирования. Данная библиотека предоставляет интересную возможность. Я говорю о наследовании уровня логирования (level inheritance). Кратко говоря, если в конфигурации этой библиотеки вы говорите, что лог с именем X должен иметь уровень логирования Info, это означает, что все логи с именами, начинающимися с X. (например, X.Y, X.Z, X.A.B) будут наследовать этот самый уровень.

Читайте также:  миньон это что такое перевод

Отсюда проистекает изначальная идея. Для каждого запроса я каким-то образом определю требуемый уровень логирования. Затем я создам новый именованный лог в конфигурации log4net. Этот лог будет иметь требуемый уровень логирования. После этого, все объекты логгеров, созданные в рамках текущего запроса, должны иметь имена начинающиеся с имени этого нового созданного мной лога. Единственной проблемой здесь является то, что log4net никогда не удаляет логи. Будучи однажды созданными, они существуют все время жизни приложения. По этой причине я изначально создаю по одному логу на каждый возможный уровень логирования:

Теперь у меня есть несколько логов с именами EdlinSoftware.Log.XXXX. Эти имена будут служить префиксами имен логов, используемых в запросах. Чтобы избежать коллизий между запросами, я буду хранить вычисленный префикс для данного запроса в экземпляре AsyncLocal. Значение этого объекта будет устанавливаться в новом OWIN middleware:

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

Теперь понятно, как получить экземпляр логгера в нашем контроллере:

Осталось сделать только одну вещь: как-то задать правила, по которым мы выбираем уровень логирования для каждого запроса. Это должен быть достаточно гибкий механизм. Основная идея заключается в использовании скриптинга C#. Я создам файл LogLevelRules.json, где определю набор пар “правило — уровень логирования”:

Здесь logLevel — желаемый уровень логирования, а ruleCode — код на C#, который возвращает булевское значение для заданного запроса. Приложение будет запускать коды правил один за другим. Первое правило, чей код вернет true, будет использовано для установки соответствующего уровня логирования. Если все правила вернули false, будет использован уровень по умолчанию.

Для создания делегатов из строкового представления правил, используется класс CSharpScript:

Здесь метод Compile получает список объектов, прочитанных из файла LogLevelRules.json. Он создает делегат runner для каждого правила.

Этот список делегатов может быть сохранен:

и использован в дальнейшем:

Таким образом, при запуске приложения мы читаем LogLevelRules.json, преобразуем его содержимое в список делегатов, используя класс CSharpScript, и сохраняем этот список в поле LogSupport.LogLevelSetters. Затем на каждый запрос мы выполняем делегаты из этого списка, чтобы получить уровень логирования.

Единственной вещью, которую осталось сделать, является отслеживание изменений в файле LogLevelRules.json. Если мы хотим установить уровень логирования для каких-то запросов, мы добавляем новое правило в этот файл. Чтобы заставить наше приложение применить эти изменения без перезапуска, необходимо следить за файлом:

Следует отметить, что ради краткости я опустил код потоковой синхронизации при работе с полем LogSupport.LogLevelSetters. Но на практике такая синхронизация обязательна.

Полный код приложения можно найти на GitHub.

Недостатки

Показанный выше код позволяет решить проблему задания отдельного уровня логирования для каждого запроса. Но у него есть ряд недостатков. Давайте обсудим их.

1. Этот подход меняет имена логов. Так в хранилище логов вместо «MyClassLogger» будет храниться что-то типа «Edlinsoft.Log.Debug.MyClassLogger«. С этим можно жить, но это не очень удобно. Возможно, проблему можно преодолеть, изменяя раскладку лога (log layout).

2. Теперь невозможно использовать статические экземпляры классов логгера, поскольку они должны создаваться отдельно для каждого запроса. Наиболее серьезной проблемой здесь, на мой взгляд, является то, что разработчики должны всегда об этом помнить. Кто-нибудь может случайно создать статическое поле с логгером и получить странные результаты. Преодолеть эту ситуацию можно созданием класса-обертки для логгеров вместо прямого использования классов log4net. Такая обертка может всегда создавать новые экземпляры логгеров log4net для каждой операции. В этом случае ее можно свободно использовать и в статических полях.

3. Описанный подход создает много экземпляров логгеров. На это тратится память и такты процессора как во время создания, так и во время сборки мусора. В зависимости от вашего приложения это может являться или не являться существенной проблемой.

4. Когда мы изменяем JSON-файл с правилами, код правил может содержать ошибки. Очень просто использовать блоки try-catch для того, чтобы эти ошибки не разрушили наше основное приложение. Тем не менее, мы как-то должны узнать, что что-то пошло не так. Есть два типа ошибок:

5. Код правил в JSON-файле может в принципе содержать любые инструкции. Это потенциально может вести к проблемам с безопасностью. Нужно как-то ограничивать возможности этого кода. С другой стороны, если уж злоумышленник получил возможность прямой записи в файлы вашего приложения, то проблема с безопасностью и так налицо.

Источник

Правильный подход к использованию API Вконтакте

В своё время, бороздя просторы интернета на предмет рационального использования API Вконтакте, я не смог найти чего-то вразумительного, единственные библиотеки, которые были найдены мной были реализованы без использования каких-либо общепринятых практик и без красивого кода. Я решил исправить, сложившееся недоразумение и написал свою библиотеку для работы с API Вконтакте.
Животрепещущие подробности и подходы под хабракатом.

Так уж сложилось, что API Вк, реализован довольно хорошо, за исключением некоторых не логичных моментов, о которых я упомяну позднее. Но речь, сегодня не о качестве, а о конкретном применении.

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

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

Читайте также:  Что нужно сделать чтобы в доме появился мужчина

С момента, когда мы имеем ключ доступа, мы можем выполнять запросы к API. Общая логика запросов проста, вы передаёте специально сформированный запрос на URL API. Запрос должен содержать, название метода и аргументы.

Список методов, это одна из богатых вещей API. В нём вы можете встретить методы, которые не требуют ключ доступа для своей работы, следовательно вызывать их вы можете, не получая его.

При использовании библиотеки нам необходимо создать базовый объект, например так:

Пара примеров запросов с использованием библиотеки:

Через анонимную функцию в each, пройдёт ровно 100 объектов, содержащих данные о пользователях от 1 до 100. Заметьте, если мы уберём вызов функции, то не произойдёт никакого запроса, всё потому что вернётся объект, у которого переопределены магические методы __call и __get, что позволяет нам делать запрос, когда нам это действительно необходимо.

Одна из вещей, что открывает, нам использование генераторов — пакетное получение. То есть, мы получаем данные только тогда, когда они нам нужны. Следующий пример, позволит нам получить ВСЕ наши сообщения, запросами по 100. Будьте внимательны, метод требует от вас прав для messages, Standalone приложения, такой-же авторизации и соответственно передачи ключа доступа.

Хороший метод, который можно отыскать в API — execute. Он принимает параметр code в качестве аргумента, code — некий псевдо JavaScript, который позволяет нам выполнять наш код на стороне сервера, так-же он позволяет выполнять хранимые процедуры, которые мы можем создать при редактировании нашего приложения.

Эту вещь я не смог обойти стороной и реализовал её в библиотеке. В двух словах, она позволяет выполнить несколько запросов, как один. Смотрите следующий пример кода.

Как и обещал, одно из тех недоразумений, которое вы можете встретить в текущей версии API(5.21), метод users.get вернёт нам response, как массив, хотя в других местах, например friends.get, начиная с версии номер 5, нам возвращаются поля count и items, мне кажется это не совсем логичным, к тому же это требует лишнего кода при работе с API.

Так-же в библиотеке реализованы обработчики для некоторых операций, с вашей помощью их может стать больше.
С использованием библиотеки мы можем добиться довольно приятного и красивого кода, а это, самое важное в нашем не лёгком деле.
Вполне вероятно, что в коде остались какие-то недоразумения или баги, надеюсь на вашу внимательность и Pull Requests приветствуются.
Библиотека в большинстве своём отвечает стандарту PSR-0.

Надеюсь, мне удалось показать вам, что API Вконтакте не страшно, а даже приятно.

Благодарю за внимание!

UPDATE:
Можно установить через Composer: composer require «getjump/vk:*»

UPDATE 2:
Теперь минимальная версия 5.4, теоретически(по идее не используется большинство его функционала) может завестись и на 5.3, если не использовать короткий синтаксис для массивов.

Источник

Логирование как способ отлаживать код

Почему так важно запретить самому себе отладку руками?

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

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

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

Проблематика: Сложно отлаживать составной код

Возможный алгоритм решения проблемы:

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

Давайте посмотрим пример. Вы знаете, что по отдельности все реализации интерфейсов работают (т.к. написаны тесты, доказывающие это). Но при взаимодействии всего вместе возникает некорректное поведение. Что вам нужно? Нужно логировать ответы от «корректных» интерфейсов:

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

Всё это в разы ускоряет написание кода. Вам не нужно бежать по циклу с F10 для того, чтобы понять на какой итерации цикла возникла проблема. Просто залогируйте состояние нужных вам объектов при определённых условиях на определённой итерации цикла.

В конечном итоге вы оставляете важные логи и удаляете побочные логи, например, где вы узнавали состояние объекта на определённой итерации цикла. Такие логи не помогут вашим коллегам, т.к. вы, скорее всего, уже поняли проблему некорректного алгоритма и исправили её. Если нет, то ведите разработку в вашей ветке до тех пор, пока не найдёте в чём причина и не исправите проблему. А вот логи, которые записывают важные результаты от выполнения других алгоритмов, понадобятся всем. Поэтому их стоит оставить.

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

Источник

Строй-портал