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


Если у вас возникла проблема, методов поиска причины в современной разработке существует несколько. Один из них древнее журналистики и проституции: «отладка printf’ом», им ещё Керниган в 1970-х занимался и в книге рекомендовал. Суть в том, что вы обкладываете код выводом нужного на консоль (в лог, в stdout, на светодиод, etc), дальше медитируете на результат.

В разных языках выглядит разно, но суть одна: printf (C), print (Python), System.out.println (Java), console.log (JavaScript).


Почему это до сих пор широко используется?

Во-первых, иногда у вас нет возможности подлезть к софту отладчиком. Скажем, запускается на удалённом закрытом сервере, от которого вам раз в сутки дают логи на анализ. Или скрипт на стороне клиента [не] работает, вы ему только и говорите, что «ребутнись и скажи, что в лог наплевалось».

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

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

В-чётвёртых, иногда вам нужно не просто значение переменной в логе видеть, но красиво читать красивое «Количество яблоков и грушов в ящике равно 146% от запланированного Василием Петровичем».

В-пятых, да просто многие привыкли так. Отсыпал ведро принтэфов, сидишь, портянку из Матрицы на экране наблюдаешь, чай пьёшь с плюшкой московской, ГОСТ 24557-89.


Как правильно «обкладывать логами» (что в быту нередко синоним обсуждаемого, так и говорят, мол, «да нафиг ты гадаешь, обложи логами, сразу увидишь»)? Зависит от того, что вы делаете (сбор значений за промежуток [в поисках деградации чего-то в какой-то момент], локализация проблемной строчки кода), конечно, но общие правила таковы…

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

Во-вторых, иногда не нужно городить свой забор логов, достаточно включить уровни DEBUG или TRACE используемого вами софта (сервера, фреймворка, библиотеки). Умолчательно вменяемые разработчики их выключают, а если вы ленивы как бревно, можете и не знать, что там на каждый чих в лог отсыпать могут. Изучите матчасть.

В-третьих, следите за тем, чтобы в логируемом не было side effects. Один из лучших способов выстрелить себе в ухо – ляпнуть в коде что-то типа printf(i++), после чего бегать по опенспейсу с воплями «почему оно пропускает элемент массива?! почемууууу?!?!?!».

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

В-пятых, следите за тем, чтобы не схлопотать ваш вариант null pointer exception. Получить его можно вот так: System.out.println(c.m()), где с внезапно однажды окажется null или undefined.

В-шестых, помните, что логировать вы можете не только переменные, но и выражения. Совет кажется тривиальным, но видел это забывших. Упрощённо выглядит так: printf(x == y).

Наиболее частые в моей практике места для printf:

  • начало функции / метода – посмотреть, что пришло на вход;
  • перед возвратом из функции / метода – посмотреть, что отдаётся;
  • внутри циклов вывод того, что там за элементы по факту получаются;
  • до и после строчки под подозрением;
  • межстрочные – перед каждой строчкой кода ставится printf("WTF 1") (понятно, потом printf("WTF 2") и т.д.), так будете ловить строчку, на которой что-то молча падает.

Обобщающее правило звучит так: вставляйте лог там, где меняется что-то вам нужное. Иными словами, не надо всякий раз выводить в лог константу (вы и так знаете её значение), не надо выводить в лог что-то на всякий случай (почти всегда это бесполезно).

Также следует помнить, что вы удалите эти printf. Не надо час думать о том, куда же влепить эту отладку в код. Первым делом влепите ВЕЗДЕ, начните с коврового логометания. Ну вот щедро фигак по площадям и пусть будет. Запустили софт, посмотрели на происходящее, удалили почти всё, что влепили, отсыпали уже более точечно. Запустили. Снова удалили, досыпали в пару-тройку обнаруженных мест. Запустили. Снова удалили. Оставили только нужное, добавив одну-две строчки. Запустили. Проблемная строчка найдена. Удаляете вообще всё лишнее, исправляете ошибку, запускаете, убеждаетесь в исправлении, удаляете и остальное.


Завершу терминологией. Если очень хочется блеснуть, такую отладку ещё называют tracing. И лучше говорить именно «трейсинг» (ну, как сможете), а не родную «трассировку», которая вот ни фига не про трейсинг, но про debug с протыкиванием бряков.