Java — различные регистраторы, используемые с библиотеками

Моя проблема касается регистрации библиотечных классов (классов, которые используются внутри библиотек),
В настоящее время мы используем log4cxx но log4j Библиотека реализует те же понятия.

Скажем, у меня есть процесс, в котором есть несколько сущностей, A, B и C. Каждый из них использует много разных классов и функций, четко разделенных в коде.

A, B и C используют много библиотечных классов, функций, объектов, ресурсов и иногда даже глобальных переменных (устаревший код, я ничего не могу с этим поделать …) — давайте назовем их всех foo

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

  1. Мы хотим иметь возможность изменять уровень отладки только для одного из классов одновременно (или всех из них, используя root)
  2. Когда все виды foo печать в журнал, нам нужно увидеть, какой объект вызвал его, A, B или C.
  3. Как много foo мы хотим иметь возможность изменять уровень отладки отдельно для каждого foo
  4. foo следует рассматривать как общую библиотеку, она не может напрямую зависеть от A, B или C.
  5. A, B и C могут использовать один и тот же экземпляр foo (например, тот же экземпляр нашего класса обработки ресурсов используется A, B и C), в журнале мы хотели бы увидеть, какой класс используется foo,
  6. A может использовать B (или C), но нам не нужно видеть это в журнале …

Это то, что мы придумали до сих пор —

A, B и C будут иметь отдельные регистраторы. Глобальная переменная (хранящаяся в другой библиотеке со всеми нашими помощниками и оболочками) всегда будет поддерживать текущие отчеты журнала. Каждый раз, когда объект начинает обрабатывать свою логику, он устанавливает глобальную переменную в соответствующий регистратор. Когда foo хочет сообщить в журнал, он сообщает через глобальную переменную и добавив его имя (и контекст) в сообщение журнала.

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

Мы что-то здесь не так делаем?
Есть ли лучшее решение для этого?

8

Решение

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

class Logger {
public:
enum Level {
...
};
static Logger* Instance();
void Log(Level level, const char* module, const char* msg);
void AddModuleFilter(const char* context, const char* module, Level level);
void SetThreadLocalContext(const char* context);
...
};

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

// foo calls by entity A have the DEBUG log level
Logger::Instance()->AddModuleFilter("A", "foo", Logger::DEBUG);
// foo calls by entity B have the WARNING log level
Logger::Instance()->AddModuleFilter("B", "foo", Logger::WARNING);

Тогда поток вызовов будет таким:

// In entity A
Logger::Instance()->SetThreadLocalContext("A");
// Call function foo
Logger::Instance()->Log(log_level, "foo", log_msg);

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

5

Другие решения

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

Это все еще глобальная переменная внизу, но, по крайней мере, это глобальная переменная в классе (как переменная класса с именем debugLog.log где debugLog это имя класса).

1

По вопросам рекламы [email protected]