Рубрики
Без рубрики

Рекомендации по ведению журнала Java: 10+ Советов, которые Вы должны знать, чтобы получить максимальную отдачу от своих журналов

Наличие видимости в вашем Java-приложении имеет решающее значение для понимания того, как оно работает прямо сейчас, как… Помеченный java, ведение журнала, журналы.

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

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

1. Используйте стандартную библиотеку ведения журнала

Вход в Java можно выполнить несколькими различными способами. Вы можете использовать специальную библиотеку журналов, общий API или даже просто записывать журналы в файл или напрямую в специальную систему ведения журнала. Однако при выборе библиотеки ведения журнала для вашей системы подумайте заранее. Необходимо учитывать и оценивать производительность, гибкость, приложения для новых решений для централизации журналов и так далее. Если вы напрямую привязываете себя к одной структуре, переход на более новую библиотеку может занять значительное количество времени и времени. Имейте это в виду и перейдите к API, который даст вам возможность гибко менять библиотеки журналов в будущем. Точно так же, как при переключении с Log4j на Logback и на Log4j 2 , при использовании API SLF4J единственное, что вам нужно сделать, это изменить зависимость, а не код.

2. Выбирайте Своих Отправителей С Умом

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


    
        
    
    

Однако имейте в виду, что использование приложений, подобных показанному выше, делает ваш конвейер ведения журнала уязвимым для сетевых ошибок и сбоев связи. Это может привести к тому, что журналы не будут отправлены в пункт назначения, что может оказаться неприемлемым. Вы также хотите избежать ведения журнала, влияющего на вашу систему, если приложение разработано блокирующим способом. Чтобы узнать больше, ознакомьтесь с Библиотеки журналов против отправителей журналов сообщение в блоге.

3. Используйте Значимые Сообщения

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

LOGGER.warn("Communication error");

Но вы также можете создать сообщение, подобное этому:

LOGGER.warn("Error while sending documents to events Elasticsearch server, response code %d, response message %s. The message sending will be retried.", responseCode, responseMessage);

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

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

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

4. Ведение журнала Стека Java Следы

Одной из очень важных частей ведения журнала Java являются трассировки стека Java. Взгляните на следующий код:

package com.sematext.blog.logging;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.IOException;

public class Log4JExceptionNoThrowable {
    private static final Logger LOGGER = LogManager.getLogger(Log4JExceptionNoThrowable.class);

    public static void main(String[] args) {
        try {
            throw new IOException("This is an I/O error");
        } catch (IOException ioe) {
            LOGGER.error("Error while executing main thread");
        }
    }
}

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

11:42:18.952 ERROR - Error while executing main thread

Как вы можете видеть, там не так много информации. Мы знаем только, что проблема возникла, но мы не знаем, где это произошло, или в чем была проблема, и т.д. Не очень информативно.

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

package com.sematext.blog.logging;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.IOException;

public class Log4JException {
    private static final Logger LOGGER = LogManager.getLogger(Log4JException.class);

    public static void main(String[] args) {
        try {
            throw new IOException("This is an I/O error");
        } catch (IOException ioe) {
            LOGGER.error("Error while executing main thread", ioe);
        }
    }
}

Как вы можете видеть, на этот раз мы включили сам объект исключения в наше сообщение журнала:

LOGGER.error("Error while executing main thread", ioe);

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

11:30:17.527 ERROR - Error while executing main thread
java.io.IOException: This is an I/O error
    at com.sematext.blog.logging.Log4JException.main(Log4JException.java:13) [main/:?]

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

Чтобы узнать больше о том, как обрабатывать трассировки стека Java с помощью Logstash, см. Обработка многострочных трассировок стека с помощью Logstash или посмотрите Logagent , который может сделать это за вас из коробки.

5. Ведение журнала Исключений Java

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

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

try {
     throw new IOException("This is an I/O error");
} catch (IOException ioe) {
}

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

try {
    throw new IOException("This is an I/O error");
} catch (IOException ioe) {
    LOGGER.error("I/O error occurred during request processing", ioe);
    throw ioe;
}

6. Используйте Соответствующий Уровень Журнала

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

Как SLF4J фасад, так и каждая платформа ведения журнала Java, которую вы будете использовать, предоставляют методы, которые можно использовать для обеспечения надлежащего уровня журнала. Например:

LOGGER.error("I/O error occurred during request processing", ioe);

7. Войдите в JSON

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

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

LOGGER.info("This is a log message that will be logged in JSON!");

Чтобы настроить Log4J 2 для записи сообщений журнала в JSON, мы включили бы следующую конфигурацию:



    
        
            
            
        
    
    
        
            
        
    

Результат будет выглядеть следующим образом:

{"instant":{"epochSecond":1596030628,"nanoOfSecond":695758000},"thread":"main","level":"INFO","loggerName":"com.sematext.blog.logging.Log4J2JSON","message":"This is a log message that will be logged in JSON!","endOfBatch":false,"loggerFqcn":"org.apache.logging.slf4j.Log4jLogger","threadId":1,"threadPriority":5}

8. Поддерживайте согласованную структуру журнала

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

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

Один из способов сохранить общую структуру – использовать один и тот же шаблон для ваших журналов, по крайней мере для тех, которые используют одну и ту же структуру ведения журнала. Например, если ваши приложения и микросервисы используют Log4J 2 , вы можете использовать такой шаблон:


    %d %p [%t] %c{35}:%L - %m%n

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

9. Добавьте контекст в свои журналы

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

[2020-06-29 16:25:34] [ERROR ] An error occurred!

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

[2020-06-29 16:25:34] [main] [ERROR ] com.sematext.blog.logging.ParsingErrorExample - A parsing error occurred for user with id 1234!

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

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


Это приведет к появлению сообщения журнала, аналогичного следующему:

17:13:08.059 INFO - This is the first INFO level log message!

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


Это приведет к появлению такого сообщения в журнале:

17:24:01.710 com.sematext.blog.logging.Log4j2 com.sematext.blog.logging.Log4j2.main(Log4j2.java:12) INFO - This is the first INFO level log message!

10. Ведение журнала Java в контейнерах

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

Чтобы настроить ведение журнала в контейнерной среде вам нужно выбрать подход, который вы хотите использовать. Вы можете использовать один из предоставленных драйверы для ведения журнала – как journald , logagent , системный журнал или файл JSON. Для этого помните, что ваше приложение должно записывать файл журнала не в временное хранилище контейнера, а в стандартный вывод. Это можно легко сделать, настроив структуру ведения журнала для записи журнала в консоль. Например, с Log4J 2 вы бы просто использовали следующую конфигурацию приложения:


    
        
    

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


    
        
    
    

11. Не регистрируйте слишком много или слишком Маленький

Как разработчики, мы склонны думать, что все может быть важным – мы склонны отмечать каждый шаг нашего алгоритма или бизнес-кода как важный. С другой стороны, мы иногда поступаем наоборот – мы не добавляем ведение журнала там, где должны, или регистрируем только уровни журнала ФАТАЛЬНЫХ ОШИБОК и ОШИБОК. Оба подхода не очень хорошо подойдут. При написании кода и добавлении ведения журнала подумайте о том, что будет важно, чтобы увидеть, правильно ли работает приложение, и что будет важно, чтобы иметь возможность диагностировать неправильное состояние приложения и исправить его. Используйте это как свой путеводный свет, чтобы решить, что и где регистрировать. Имейте в виду, что добавление слишком большого количества журналов приведет к информационной усталости, а недостаток информации приведет к невозможности устранения неполадок.

12. Имейте в виду аудиторию

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

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

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

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

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

13. Избегайте Регистрации Конфиденциальной Информации

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

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

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

Наконец, маскировка конфиденциальной информации может быть выполнена в самой структуре ведения журнала. Давайте посмотрим, как это можно сделать, расширив Log4j 2 . Наш код, который создает события журнала, выглядит следующим образом (полный пример можно найти на Sematext Github ):

public class Log4J2Masking {
    private static Logger LOGGER = LoggerFactory.getLogger(Log4J2Masking.class);
    private static final Marker SENSITIVE_DATA_MARKER = MarkerFactory.getMarker("SENSITIVE_DATA_MARKER");

    public static void main(String[] args) {
        LOGGER.info("This is a log message without sensitive data");
        LOGGER.info(SENSITIVE_DATA_MARKER, "This is a a log message with credit card number 1234-4444-3333-1111 in it");
    }
}

Если бы вы запустили весь пример с Github, результат был бы следующим:

21:20:42.099 - This is a log message without sensitive data
21:20:42.101 - This is a a log message with credit card number ****-****-****-**** in it

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

@Plugin(name = "sample_logging_mask", category = "Converter")
@ConverterKeys("sc")
public class LoggingConverter extends LogEventPatternConverter {
    private static Pattern PATTERN = Pattern.compile("\\b([0-9]{4})-([0-9]{4})-([0-9]{4})-([0-9]{4})\\b");

    public LoggingConverter(String[] options) {
        super("sc", "sc");
    }

    public static LoggingConverter newInstance(final String[] options) {
        return new LoggingConverter(options);
    }

    @Override
    public void format(LogEvent event, StringBuilder toAppendTo) {
        String message = event.getMessage().getFormattedMessage();
        String maskedMessage = message;

        if (event.getMarker() != null && "SENSITIVE_DATA_MARKER".compareToIgnoreCase(event.getMarker().getName()) == 0) {
            Matcher matcher = PATTERN.matcher(message);
            if (matcher.find()) {
                maskedMessage = matcher.replaceAll("****-****-****-****");
            }
        }

        toAppendTo.append(maskedMessage);
    }
}

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

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



    
        
            
        
    
    
        
            
        
    

Как вы можете видеть, мы добавили атрибут packages в нашу конфигурацию, чтобы указать платформе, где искать наш конвертер. Затем мы использовали % sc шаблон для предоставления сообщения журнала. Мы делаем это, потому что не можем перезаписать значение по умолчанию %m шаблон. Как только Log4j2 найдет наш %sc шаблон он будет использовать наш конвертер, который принимает форматированное сообщение о событии журнала, использует простое регулярное выражение и заменяет данные, если они были найдены. Вот так просто.

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

14. Используйте решение для управления журналами для централизации и мониторинга журналов Java

С усложнением приложений объем ваших журналов также будет расти. Вам может сойти с рук ведение журнала в файл и использование журналов только при необходимости устранения неполадок, но когда объем данных растет, быстро становится сложно и медленно устранять неполадки таким образом, когда это произойдет, рассмотрите возможность использования решения для управления журналами для централизации и мониторинга ваших журналов. Вы можете либо выбрать собственное решение на основе программного обеспечения с открытым исходным кодом, например Elastic Stack , либо использовать один из инструментов управления журналами , доступных на рынке, таких как Sematext Cloud или Sematext Enterprise .

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

Вывод

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

Оригинал: “https://dev.to/sematext/java-logging-best-practices-10-tips-you-should-know-to-get-the-most-out-of-your-logs-593c”