Логирование ошибок в файл
Этичный хакинг и тестирование на проникновение, информационная безопасность
Оглавление: Всё о логах 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
Что нужно логировать
- Начало/конец работы приложения. Нужно знать, что приложение действительно запустилось, как мы и ожидали, и завершилось так же ожидаемо.
- Вопросы безопасности. Здесь хорошо бы логировать попытки подбора пароля, логирование входа важных юзеров и т.д.
- Некоторые состояния приложения. Например, переход из одного состояния в другое в бизнес процессе.
- Некоторая информация для дебага, с соответственным уровнем логирования.
- Некоторые SQL скрипты. Есть реальные случаи, когда это нужно. Опять-таки, умелым образом регулируя уровни, можно добиться отличных результатов.
- Выполняемые нити(Thread) могут быть логированы в случаях с проверкой корректной работы.
Популярные ошибки в логировании
- Избыток логирования. Не стоит логировать каждый шаг, который чисто теоретически может быть важным. Есть правило: логи могут нагружать работоспособность не более, чем на 10%. Иначе будут проблемы с производительностью.
- Логирование всех данных в один файл. Это приведет к тому, что в определенный момент чтение/запись в него будет очень сложной, не говоря о том, что есть ограничения по размеру файлов в определенных системах.
- Использование неверных уровней логирования. У каждого уровня логирования есть четкие границы, и их стоит соблюдать. Если граница расплывчатая, можно договориться какой из уровней использовать.
Уровни логирования
- 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 уже давно обладает богатым набором функций и средств для логирования, журналирования и сбора ошибок и непредвиденных ситуаций. Кроме этого часть ошибок так и остается «за кадром», которые можно выявить и устранить уже в процессе работы, тем самым повышая стабильность сайта и избегая потери новых посетителей, которые, столкнувшись с определенными трудностями и ошибками, попросту уйдут на другой ресурс.
Обычно (утрировано и упращенно) это выглядит, например, так:
Пример «взят» не из воздуха, вот так, приблизительно, но в более сложной форме выглядит разбитие на постраничную навигацию в разделах известного новостного движка 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)
Примечание автора: правилом хорошего тона при перехвате и обработке ошибок (особенно критических, которые ведут к невозможности предоставить посетителю необходимую информацию, за которой он, собственно, и пришел к Вам на сайт) является создание для каждого вида подобных ошибок статической страницы с объяснением на человекопонятном языке без технических данных сути проблемы (также на такой странице можно оставить контакты админитрации) и перенаправление посетителя на нужную страницу в ходе возникновения ошибки.
Например, в приведенном примере с категориями можно создать страницу с подобным текстом:
Уважаемый посетитель!
Просим Вас уведомить нас о сложившийся ситуации любым удобным для Вас способом
(контактные данные)
Во первых: ваши же посетители будут четко, понятно и информативно ставить Вас в известность о произошедшей ситуации, во вторых: тем самым Вы сбережете их нервы, и даже в случае возникновения непредвиденной ситуации посетители могут продолжить изучать Ваш ресурс.
Информация к размышлению, что можно сделать лучше в этом скрипте?
Читайте также: