Лишь малая часть усилий, затраченных на продукт, является усилиями по разработке. БольшАя, если не бОльшая часть, усилий - это поддержка созданой системы. Какие средства обратной связи может дать продукт после релиза?
Самым популярным, простым и очевидным средством является ведение журнала. В журнале регистрируются все важные и потенциально важные события, происходящие в системе, аномальные ситуации и другая информация, способная помочь при последующем исследовании работы системы.
Журналирование приемлимо работает в случае одного источника событий для журналирования, однако когда источников становится несколько(например, когда у вас имеется кластер), усилия направленые, на работу с логами, возрастают многократно. Так, например, сложно анализировать логи с 4-машинного кластера. И совсем невозможно анализировать логи с системы с сотней хостов. Проблемы с обработкой логов - отчасти проблема как самой системы логирования, которая ведет лог в неудобном для выборок формате, так и инструментов для работы с логами.
Я столкнулся с проблемой логгирования и на своем проекте. У нас имеется небольшой кластер машин(в сумме - одинадцать) на которых крутятся три различных системы(11=6+3+2), написаных на Java. Две из трех систем представляют собой обычные веб-приложения, написанные на JSF. Еще одна система предназначена для выолнения Batch jobs - асинхронных задач по генерации отчетов и актуализации устаревающих данных. В качестве системы логгирования используется log4j, логи ведутся в стандартный вывод, который сохраняется в файл сервером приложений. Нагрузка на хосты кластера обеспечивается load balancer-ом используя sticky sessions(via cookies).
При возникновении проблем у пользователя, как правило у нас уже нет информации о том, на каком хосте обрабатывались его запросы(куки, обычно, к моменту инвестигейшна, уже протухают), но, обычно у нас есть промежуток времени, когда проихошла ошибка - следовательно необходимо выгружать данные со всех хостов за промежуток времени. Первая задача - собрать все логи со всех хостов за нужный день.
for i in `seq 1 6`; do scp -p app$i.project.com:/path/to/tomcat/logs/catalina.out app.catalina.out.$i ; done
Вторая задача - вырезать нужный период дат. Но для этого сначала необходимо из файла выделить отдельные записи. С этим, однако, есть проблемы.
Dec 14, 2011 12:16:39 PM org.apache.catalina.loader.WebappClassLoader loadClass INFO: Illegal access: this web application instance has been stopped already. Could not load org.richfaces.taglib.DropSupportHandler$dropListenerMapper. The eventual following stack trace is caused by an error thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access, and has no functional impact. java.lang.IllegalStateException at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1273) at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1233) at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:316) JProfiler> ERROR: could not retransform class Lorg/richfaces/taglib/DropSupportHandler$DropSupportHandlerMetaRule; (113). Dec 14, 2011 12:41:27 PM org.apache.catalina.core.StandardEngine start INFO: Starting Servlet Engine: Apache Tomcat/6.0.20
Выводимый формат плохо(очень, очень плохо) преспособлен к автоматическомсу разбору: нет соответствия между одной строкой и одной записью в логе, несяно как вычленять поля из строки, учитывая, что формат вывода(pattern layout) везде различен, присутствует мусор из-за того, что сторонние приложения пишут в стандартный вывод в обход системы логгирования. Последнее можно исправить, перенаправив лог в файл(однако теряются возможности, такие, как просмотр лога прямо в окне IDE), однако остальные пункты критичны и просто не решаются. К счастью, в log4j есть развесистая система layout, и среди всех layouts имеется XMLLayout, который генерит на каждую запись XML-фрагмент. Мы потом используем этот факт. В нашем же случае, обычно делается либо grep с подстрокой из даты, либо head|tail|awk(с условием поиска line range). Затем получившиеся фрагменты просматриваются в полу-ручном режиме используя less и //.
Это занимает дохрена времени, требует квалификации в unix shell, а главное - подвержено ошибкам из-за усталости, вызваной рутиной такой работы. Не говоря о том, что такой режим работы не позволяет мониторить логи проактивно, /on a regular basis/, так как лог представляет собой распределенную мусорку.
Логирование необходимо сделать таким, чтобы обеспечивался быстрый поиск по произвольным полям - времени, тексту сообщений и эксепшнов, классу логгера. Также необходимо учесть возможную необбходимость поиска по диагностическим контекстам(если вы не знаете, что такое NDC/MDС, я расскажу об этом позже). Система должна быть простой, не желательно выделять ей отдельные ресурсы. Также маловероятно, что для поддержки системы будет выделен отдельный человек, поэтому она должна быть robust, самоподдерживающейся, и эргономичной(слово "эргономичная" в том же контексте, что и "jvm ergonomics" - т.е. само-настраивающаяся).