Логирование ошибок в файл

Обновлено: 06.07.2024

Этичный хакинг и тестирование на проникновение, информационная безопасность

Оглавление: Всё о логах Apache — от настройки до анализа

4. Криминалистические логи

5. Дополнительные настраиваемые журналы отладки. Журналы выполнения CGI скриптов

Логи ошибок Apache

Журнал ошибок обычно записывается в файл (обычно error_log в системах Unix и error.log в Windows и OS/2). В системах Unix также возможно, чтобы сервер отправлял ошибки в системный журнал или передавал их программе.

Если поместить токен %L в журнал ошибок и журнал доступа, будет создан идентификатор записи журнала, с которым вы можете сопоставить запись в журнале ошибок с записью в журнале доступа. Если загружен mod_unique_id, его уникальный идентификатор запроса также будет использоваться в качестве идентификатора записи журнала.

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

Директива ErrorLog

Описание: устанавливает место, куда сервер будет записывать ошибки.

Значение по умолчанию:

Контекст: server config, виртуальные хосты.

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

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

Дополнительные модули могут предоставлять свои собственные поставщики ErrorLog. Синтаксис похож на пример системного журнала выше.

БЕЗОПАСНОСТЬ: см. раздел «Вопросы безопасности», чтобы узнать, почему ваша безопасность может быть скомпрометирована, если каталог, в котором хранятся файлы журналов, доступен для записи кому-либо, кроме пользователя, запускающего сервер.

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

Директива ErrorLogFormat

Описание: Определение формата для записей журнала ошибок.

Контекст: server config, виртуальные хосты.

Вышеуказанное поведение можно изменить, добавив модификаторы к элементу строки формата. Модификатор — (минус) приводит к записи минуса, если соответствующий элемент не производит никакого вывода. В форматах один-раз-на-соединение/запрос также можно использовать модификатор + (плюс). Если элемент с модификатором плюс не производит никакого вывода, вся строка опускается.

Например, вот что произойдёт, если вы добавите модификаторы в токен %i, который регистрирует заголовок запроса Referer.

Некоторые элементы строки формата принимают дополнительные параметры в фигурных скобках.

Формат идентификатора журнала %L создаёт уникальный идентификатор для соединения или запроса. Это можно использовать для сопоставления того, какие строки журнала принадлежат тому же соединению или запросу, какой запрос происходит с каким соединением. Строка формата %L также доступна в mod_log_config, чтобы позволить соотносить записи журнала доступа со строками журнала ошибок. Если загружен mod_unique_id, его уникальный идентификатор будет использоваться в качестве идентификатора журнала для запросов.

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

Директива LogLevel

Описание: Контролирует вербальность ErrorLog.

Значение по умолчанию:

Контекст: server config, виртуальные хосты, директории


Рекомендуется использовать уровень как минимум crit (или более низкой значимости).

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

Также возможно изменить уровень для каждого каталога:

Директива LogLevelOverride

Описание: Переопределить вербальность ErrorLog для определённых клиентов.

Значение по умолчанию: не установлено.

Контекст: server config, виртуальные хосты.

LogLevelOverride настраивает LogLevel для запросов, поступающих с определённых клиентских IP-адресов. Это позволяет включить подробное ведение журнала только для определённых тестовых клиентов. IP-адрес проверяется в очень раннем состоянии при обработке соединения. Следовательно, LogLevelOverride позволяет изменить уровень журнала для таких вещей, как рукопожатие SSL, которые происходят до того, как будет оценена директива LogLevel в контейнере <If>.

LogLevelOverride принимает либо один IP-адрес, либо спецификацию IP-адресов CIDR/длина_подсети. Синтаксис спецификации loglevel см. в разделе Директива LogLevel.

Для запросов, соответствующих директиве LogLevelOverride, спецификации LogLevel для каждого каталога игнорируются.

Журнал событий модулей

Директива LogLevel позволяет вам указывать пороговый уровень важности попадания записи в журнал для каждого модуля. Таким образом, если вы устраняете проблему только с одним конкретным модулем, вы можете увеличить объем его информации в журнале, не получая в довесок информацию о других модулях, которые вас не интересуют. Это особенно полезно для таких модулей, как mod_proxy или mod_rewrite где вы хотите узнать подробности о том, что они пытаются сделать, и что в них происходит.

Сделайте это, указав имя модуля в вашей директиве LogLevel:

Это устанавливает для основного LogLevel значение info, но для mod_rewrite сделает значение trace5.

Это заменяет директивы ведения журналов для каждого модуля, такие как RewriteLog, которые присутствовали в более ранних версиях сервера.

Обратите внимание, что информация, которую генерируют модули, всегда попадает в лог ошибок, даже если не является по сути ошибкой! Также обратите внимание, что некоторые модули не будут показывать никакой информации, если не установить уровень трассировки в диапазоне от trace1 до trace8.

Давайте разберем реальные случаи, в которых логирование решало бы проблему. Вот пример из моей работы. Есть точки приложений, которые интегрируются с другими сервисами. Я использую логирование этих точек для “алиби”: если интеграция не сработает, будет легко разобраться, с какой стороны возникла проблема. Еще желательно логировать важную информацию, которая сохраняется в базу данных. Например создание пользователя администратора. Это как раз то, что хорошо бы логировать.

Инструменты для логирования в Java

  • log4j
  • JUL — java.util.logging
  • JCL — jakarta commons logging
  • Logback
  • SLF4J — simple logging facade for java

System.err.println

Первоначально был, разумеется, System.err.println (вывод записи в консоль). Его и сейчас используют для быстрого получения лога при дебаге. Конечно, говорить о каких-то настройках здесь не приходится, поэтому просто запомним его и пойдем дальше.

Log4j

Это уже было полноценное решение, которое создавалось из потребностей разработчиков. Получился действительно интересный инструмент, который можно использовать. В силу разных обстоятельств это решение так и не попало в JDK, чем очень расстроило все комьюнити. В log4j были возможности по конфигурации таким образом, чтобы можно было включить логирование в пакете com.example.type и выключить его в подпакете com.example.type.generic . Это позволяло быстро отсечь то, что нужно логировать, от того, что не нужно. Здесь важно отметить, что есть две версии log4j: 1.2.х и 2.х.х, которые несовместимы друг с другом. log4j добавил такое понятие как appender, то есть инструмент, с помощью которого записываются логи и layout — форматирование логов. Это позволяет записывать только то, что нужно и как нужно. Больше о appender поговорим чуть позже.

JUL — java.util.logging

Одно из ключевых преимуществ это решения — JUL включен в JDK (Java development kit). К сожалению, при его разработке за основу взяли не популярный log4j, а решение от IBM, что и повлияло на его развитие. По факту на данный момент JUL есть, но им никто не пользуется. Из “такого себе”: в JUL уровни логирования отличаются от того, что есть в Logback, Log4j, Slf4j, и это ухудшает понимание между ними. Создание логгера более менее похожее. Для этого нужно сделать импорт: Имя класса специально передается для того, чтобы знать, откуда идет логирование. Начиная с Java 8, можно передавать Supplier<String> . Это помогает считать и создавать строку только в тот момент, когда это действительно нужно, а не каждый раз, как это было до этого. Только с выходом Java 8 разработчики решили важные проблемы, после чего JUL по-настоящему стало возможно в использовании. А именно, методы с аргументом Supplier<String> msgSupplier , как показано ниже:

JCL — jakarta commons logging

Из-за того, что долгое время не было промышленного стандарта в логировании и был период, когда многие создавали свой кастомный логгер, решили выпустить JCL — общую обертку, которая использовалась бы над другими. Почему? Когда в проект добавлялись какие-то зависимости, они могли использовать логгер, отличный от логгера на проекте. Из-за этого они транзитивно добавлялись в проект, что создавало реальные проблемы при попытке все это собрать воедино. К сожалению, обертка была очень бедна на функциональность и никаких дополнений не вносила. Наверное, было бы удобно, если бы все использовали JCL для работы. Но на деле так не получалось, поэтому на данный момент применять JCL — не лучшая идея.

Logback

  • улучшена производительность;
  • добавлена нативная поддержка slf4j;
  • расширена опция фильтрации.

SLF4J — simple logging facade for java

Что нужно логировать

  1. Начало/конец работы приложения. Нужно знать, что приложение действительно запустилось, как мы и ожидали, и завершилось так же ожидаемо.
  2. Вопросы безопасности. Здесь хорошо бы логировать попытки подбора пароля, логирование входа важных юзеров и т.д.
  3. Некоторые состояния приложения. Например, переход из одного состояния в другое в бизнес процессе.
  4. Некоторая информация для дебага, с соответственным уровнем логирования.
  5. Некоторые SQL скрипты. Есть реальные случаи, когда это нужно. Опять-таки, умелым образом регулируя уровни, можно добиться отличных результатов.
  6. Выполняемые нити(Thread) могут быть логированы в случаях с проверкой корректной работы.

Популярные ошибки в логировании

  1. Избыток логирования. Не стоит логировать каждый шаг, который чисто теоретически может быть важным. Есть правило: логи могут нагружать работоспособность не более, чем на 10%. Иначе будут проблемы с производительностью.
  2. Логирование всех данных в один файл. Это приведет к тому, что в определенный момент чтение/запись в него будет очень сложной, не говоря о том, что есть ограничения по размеру файлов в определенных системах.
  3. Использование неверных уровней логирования. У каждого уровня логирования есть четкие границы, и их стоит соблюдать. Если граница расплывчатая, можно договориться какой из уровней использовать.

Уровни логирования

  • OFF: никакие логи не записываются, все будут проигнорированы;
  • FATAL: ошибка, после которой приложение уже не сможет работать и будет остановлено, например, JVM out of memory error;
  • ERROR: уровень ошибок, когда есть проблемы, которые нужно решить. Ошибка не останавливает работу приложения в целом. Остальные запросы могут работать корректно;
  • WARN: обозначаются логи, которые содержат предостережение. Произошло неожиданное действие, несмотря на это система устояла и выполнила запрос;
  • INFO: лог, который записывает важные действия в приложении. Это не ошибки, это не предостережение, это ожидаемые действия системы;
  • DEBUG: логи, необходимые для отладки приложения. Для уверенности в том, что система делает именно то, что от нее ожидают, или описания действия системы: “method1 начал работу”;
  • TRACE: менее приоритетные логи для отладки, с наименьшим уровнем логирования;
  • ALL: уровень, при котором будут записаны все логи из системы.

Запись и отправка логов: Appender

  • для записи в файл — решение DailyRollingFileAppender;
  • для получения данных в консоль приложения — ConsoleAppender;
  • для записи логов в базу данных — JDBCAppender;
  • для контроля передачи через TCP/IP — TelnetAppender;
  • для того, чтобы запись логов не била по быстродействию — AsyncAppender.

Узлы логирования

Написали программу с применением нейросети, но она выдает кучу ошибок? Где потом искать эти ошибки? Как структурировать полученную информацию?

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

Тогда консоль нам покажет следующее:

А в логе с файлом увидим:

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

Но Python же один из самых дружелюбных языков.) Разработчики уже подумали о нас и создали хорошую библиотеку «logging».

Для работы с ней нам необходимо импортировать библиотеку logging и указать основные параметры. Всего параметров для настройки 6.

Так же существует 5 уровней логирования информации: от DEBUG (отладка) до critical (критичные ошибки).

На этом можно закончить с теорией, и перейдем к практике.

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

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

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

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

logger.setLevel(logging.INFO) file_name = logging.FileHandler('data.log') format_log = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') file_name.setFormatter(format_log) logger.addHandler(file_name)

Вот, на этом и все) В дальнейшем мы можем использовать наш логгер простым вызовом logger.info('Division') или в случае описания ошибки logger.error(error_text). По окончанию работы скрипта данные будут сохранены в файл 'data.log'.

А теперь посмотрим, что мы получили в логе:

Использование модуля «logger» на маленьких программах, может, и не заметно, а вот на больших польза становится очевидна. Особенно, если эти логи в дальнейшем нуждаются в обработке, например, для Process Mining-а.

Вот таким простым способом мы с вами научились делать понятную и удобную запись логов в нашем скрипте!

Предприятие «Яндекса», «Ланита», ВТБ и Gigabyte выпустило первые 200 серверов в России Статьи редакции

В 2022 году СП планирует открыть собственный завод под Рязанью и продавать серверы госкомпаниям и ведомствам, которые должны перейти на «железо» российской сборки.

Продавец ООО "Радуга" и маркетплейс Ozon отменяют невыгодные заказы. Наверное именно так делают "детство более ярким"

3 и 4 декабря поговорим о трендах в индустрии, технологиях и научном мире.

McDonald’s в России запустила подписку на кофе и другие горячие напитки Статьи редакции

Абонемент на две недели обойдётся в 369 рублей — по нему можно ежедневно получать маленький американо или капучино.

Исков о клевете больше, чем у крупного новостного издания: какую ответственность несёт за контент Netflix Статьи редакции

На видеосервис подают в суд за произведения, которые он только распространяет — пока закон на его стороне, пишет The Hollywood Reporter.

Поездка началась: как сервис по заказу такси DiDi вышел на рынки Мексики, Чили и Новой Зеландии

И почему этот опыт помог ему закрепиться в России.

Стив Возняк рассказал о главных технологических вызовах ближайшего десятилетия

Сооснователь Apple Computer Inc. Стив Возняк (Steve Wozniak) выступил на Демо-дне акселерационных программ по развитию предпринимательских талантов для школьников — SberZ — и студентов, аспирантов и научных сотрудников — SberStudent. Зрители присылали свои вопросы в ходе трансляции, на самые интересные из них Стив ответил в прямом эфире.

Стив Возняк стал специальным гостем Демо-дня молодёжных акселераторов Сбера

Как мы улучшили общение с пользователями и оптимизировали внутренние процессы работы службы поддержки

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

Представьте себе, что вы — заказчик разработки новой функциональности в программе. Это решение очень нужно вашему бизнесу, по всем расчётам оно поможет существенно увеличить вашу прибыль и, возможно, опередить конкурентов. Вы долго уточняли и согласовывали техническое задание, и вам не терпится увидеть готовое решение в действии. Как его…

Изучаем PHP. Выявление и логирование ошибок: стабильность и безопасность сайта изображение поста

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

Это при том, что PHP уже давно обладает богатым набором функций и средств для логирования, журналирования и сбора ошибок и непредвиденных ситуаций. Кроме этого часть ошибок так и остается «за кадром», которые можно выявить и устранить уже в процессе работы, тем самым повышая стабильность сайта и избегая потери новых посетителей, которые, столкнувшись с определенными трудностями и ошибками, попросту уйдут на другой ресурс.

Обычно (утрировано и упращенно) это выглядит, например, так:

Пример «взят» не из воздуха, вот так, приблизительно, но в более сложной форме выглядит разбитие на постраничную навигацию в разделах известного новостного движка DLE. А также вот так (echo mysql_error(); die()) выводится, зачастую, в браузер посетителя возникновение mysql ошибки в Joomla 1.5 и более новых версий (чуть сложнее, но смысл остается тот же).

Здесь была осознанно допущена одна оплошность. Дело в том, что данный вариант будет работать отлично! И в повседневной работе программист не увидит выполнение echo mysql_error().

Но почему не следует выводить в браузер отладочную информацию и ошибки исполнения PHP?

Итак, первое, из за того, что мы обходимся без проверки, что же приходит со стороны клиента, например, отрицательные значения $id и $limit, которые допускаются для типа данных integer, или несуществующие значения приведут к выводу отладочной информации mysql_error(). Итак, ясным по белому, мы дадим информацию злоумышленнику о существующих таблицах и пищу для размышления, как же проще осуществить mysql injection в другом месте, где используются эти же таблицы при составлении запросов. Или же в некоторых случаях покажем посетителям техническую информацию, которую видеть они не должны. С одной стороны здесь нам помогут более строгие проверки входных данных. Перепишем этот пример с использованием выше сказанного:

Мы предотвратили, как минимум, возникновение нескольких исключительных ситуаций. Мы знаем, что нам нужны только лишь целые положительные значения $id,$limit – поэтому используем явное приведени типов для этих переменных, оператор приведения к целому (int) и функцию получения целого числа abs(). Также мы знаем, что количество выбранных новостей не должно быть равно нулю, поэтому определяем минимальный «порог» в 10 новостей $limit = $limit ? $limit : 10;, формируя запрос, мы проверяем данные, и если они есть и отличны от 0, то добавляем их в mysql запрос по частям.

Все бы хорошо, но и здесь могут быть подводные камни. И все равно существует некоторая вероятность того, что при манипуляции с входными данными злоумышленник увидит вывод той самой информации echo mysql_error();. Зачастую это может получиться даже чисто случайно.

Другой распространенный пример. Многие программисты добавляют вывод технической информации еще на этапе подключения к базе данных. Что, в случае отсутствия соединения с базой данных (сверх нагрузки/временной недоступности сервера баз данных) также выводит отладочную информацию посетителям. При этом там, зачастую, могут в простом тексте встречаться даже логин/название базы/хост подключения к базе данных. А сам программист может никогда и не увидеть подобной информации, и даже не узнать о временном полягании проекта (например из за превышения числа подсоединений к базе данных в случае с увеличением аудитории, как итог: при частом повторении проблемы потеря новых посетителей, раскрытие важных технических данных).

А ведь сбор такой информации бывает полезным для профилирования приложения и дальнейшего его усовершенствования (обеспечения стабильности работы). Для выявления «подводных» камней в стабильной работе сайта.

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

Какие функции и данные для логирования в PHP могут быть полезны?

    – для генерации исключения. , error_reporting – для подавления вывода ошибок – для установки собственной функции «перехвата» ошибок – для отлова критических ошибок (которая работает, как нужно, начиная с php 5.2) – функция получения последней ошибки, произошедшей в скрипте, очень полезна в случае прерывания скрипта из за возникновения критической ошибки – суперглобальный массив – источник информации – где и когда и какая ошибка произошла – функция для получения значения переменных среды окружения сервера, в том случае, если какие-то данные в суперглобальном массиве $_SERVER отсутствуют

Примечание автора: желательно подключить подобный код как можно раньше, еще на этапе инициализации созданного php приложения:

Зачастую, подобной информации хватит с головой и для логирования и исправления ошибок, которые были не замечены на этапе разработки, так и для отлова злоумышленников. Но есть один тип ошибок, который не будет перехвачен. Это критические ошибки PHP E_ERROR, которые приводят к прерыванию php скрипта . Начиная с версии PHP 5.2 для перехвата критических ошибок можно определить собственную функцию при мопощи register_shutdown_function. Мы создаем собственную функцию для этих целей critical_error, в которой при помощи функции error_get_last получаем информацию о текущей ошибке. Так как данная функция будет всегда выполняться после завершения php скрипта, мы логируем информацию только об ошибках с типом E_ERROR.

Можно было бы использовать функцию error_log с указанием пути к источнику логирования, но было отдано предпочтение простым файловым функциям, при помощи которых можно установить функцией flockприоритетное эксклюзивное запирание во избежание попыток одновременной записи в логфайл несколькими скриптами (и возникновения «битых» файлов).

Давайте на примере все того же скрипта с mysql рассмотрим принцип логирования mysql ошибок (впрочем, по такому же принципу можно построить логирование любых внештатных ситуаций):

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

Примечание автора: также для генерации и перехвата ошибок Вы можете использовать конструкции try<>catch(Exeption $e)

Примечание автора: правилом хорошего тона при перехвате и обработке ошибок (особенно критических, которые ведут к невозможности предоставить посетителю необходимую информацию, за которой он, собственно, и пришел к Вам на сайт) является создание для каждого вида подобных ошибок статической страницы с объяснением на человекопонятном языке без технических данных сути проблемы (также на такой странице можно оставить контакты админитрации) и перенаправление посетителя на нужную страницу в ходе возникновения ошибки.

Например, в приведенном примере с категориями можно создать страницу с подобным текстом:

Уважаемый посетитель!

Просим Вас уведомить нас о сложившийся ситуации любым удобным для Вас способом

(контактные данные)

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

Информация к размышлению, что можно сделать лучше в этом скрипте?

Читайте также: