Сделайте мой регистратор очень эффективным для моего Java-приложения - PullRequest
0 голосов
/ 24 мая 2018

Я борюсь со следующей проблемой и прошу помощи.

В моем приложении есть модуль логгера.Это берет уровень трассировки и сообщение (в виде строки).

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

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

С помощью C / C ++ с помощью макросов было очень легко добиться:

#define LOG_IT(level, message) if(level>=App.actLevel_) LOG_MSG(message);

LOG_MSG и построение строки было выполненотолько если уровень трассировки включил это сообщение.

С Java я не вижу подобной возможности для этого.Это нужно для предотвращения: регистрация будет одной строкой (никаких копий-вставок if-else везде), а построение строк (дорогостоящая операция) будет выполняться только при необходимости.

Единственное решение, которое я знаю, это surrondкаждый логгер звонит с оператором IF.Но это именно то, чего я раньше избегал в приложении C ++, и чего я хочу избежать в своей реальной реализации Java.

Моя проблема в том, что в целевой системе доступна только Java 1.6.Поэтому поставщик не является выбором.

Что я могу сделать на Java?Как можно легко сделать этот метод C / C ++?

Ответы [ 3 ]

0 голосов
/ 24 мая 2018

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

Затем, я бы посоветовал вам взглянуть на хорошо зарекомендовавшие себя журналыAPI, такие как SLF4j.Несмотря на то, что можно создавать свои собственные, использование уже существующего API сэкономит ваше время, усилия и, прежде всего, предоставит вам больше возможностей и гибкости из коробки (т. Е. Конфигурация на основе файлов, настраиваемость (см. Mapped Diagnostic Context)).

На ваш конкретный вопрос не существует простого способа сделать то, что вы пытаетесь сделать.C / C ++ принципиально отличается от java тем, что препроцессор допускает макросы, которые вы создали выше.В действительности Java не имеет простого в использовании эквивалента, хотя есть примеры проектов, в которых используется генерация кода времени компиляции, которая, вероятно, является наиболее близким эквивалентом (например, Project Lombok, Mapstruct).

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

if ( logger.isTraceEnabled() )
{
    // Really expensive operation here
}

Или, если вы используете Java 8, стандартная библиотека журналирования требуетjava.util.function.Supplier<T> аргумент, который будет выполняться только в том случае, если текущий уровень журнала совпадает с уровнем вызываемого метода ведения журнала:

 log.fine(()-> "Value is: " + getValue());

В настоящее время для SLF4j также открыт билет для реализации этой функции здесь.

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

0 голосов
/ 25 марта 2019

Я думаю, что самая важная вещь, которую нужно здесь понять, это то, что макросовое решение C / C ++ не экономит вычислительные усилия , не создавая зарегистрированное сообщение, в случае, если уровень журнала был таким, что сообщениене быть зарегистрирован.Почему так?Просто потому, что метод макроса заставит препроцессор заменять каждое использование макроса:

LOG_IT(level, message)

с кодом:

if(level>=App.actLevel_) LOG_MSG(message);

Подставляя все, что вы передали как уровень , и все, что вы передали как сообщение вместе с макросомсам.Полученный код, который будет скомпилирован, будет точно таким же, как если бы вы скопировали и вставили макрос код в вашу программу.Единственное, в чем вам могут помочь макросы, - это избежать реального копирования и вставки, а также сделать код более читабельным и понятным.Иногда им удается это сделать, иногда они делают код более загадочным и, следовательно, его сложнее поддерживать в результате.В любом случае макросы не обеспечивают отложенного выполнения , чтобы избавить вас от фактического построения строки, как Класс Java8 Logger делает с помощью лямбда-выражений .Java откладывает выполнение тела лямбды до последнего возможного времени.Другими словами, тело лямбды выполняется после оператора if.Чтобы вернуться к своему примеру на C \ C ++, вы, как разработчик, вероятно, хотели бы, чтобы код работал независимо от уровня журнала, поэтому вам придется создать правильное строковое сообщение и передать его макросу.В противном случае на определенных уровнях журнала программа вылетит !Итак, поскольку код построения строки сообщения должен быть перед вызовом макроса, вы будете выполнять его каждый раз, независимо от уровня журнала.

Итак, чтобы сделать эквивалентный вашемукод довольно прост в Java 6!Вы просто используете встроенный класс: Logger .Этот класс поддерживает автоматическое ведение журнала уровней , поэтому вам не нужно создавать их собственную реализацию.Если вы спрашиваете, как реализовать отложенное выполнение без лямбды, я не думаю, что это возможно.

Если вы хотите сделать реальное отложенное выполнение в C \ C ++, вам придется создать код для регистрациинапример, чтобы получить указатель на функцию, возвращающую строку сообщения, вы должны заставить свой код выполнять функцию, переданную вам указателем функции в операторе if, и затем вы вызовете свой макрос, передавая не строку, а функцию, котораясоздает и возвращает строку!Я полагаю, что настоящий код C \ C ++, который делает это, выходит за рамки этого вопроса ... Ключевой концепцией здесь является то, что C \ C ++ предоставляет вам инструменты для отложенного выполнения просто потому, что они поддерживают указатели на функции.Java не поддерживает указатели функций, пока Java8 .

0 голосов
/ 24 мая 2018

В новейших библиотеках журналирования, включая java.util.logging, есть методы второй формы: Supplier<String>.

, например, log.info( ()->"Hello"); вместо log.info("Hello");.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...