C + + дизайн оболочки журнала - PullRequest
5 голосов
/ 25 октября 2011

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

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

Есть предложения по дизайну такой оболочки?

РЕДАКТИРОВАТЬ: одна функция, которую я должен иметь в этой оболочке, - это маркировка компонентов.Я хочу, чтобы в моем классе алгоритма появилось «X:» перед строками журнала, а в классе моего менеджера - «Y:».Как распространить эти теги на нижележащий журнал и как создать механизм именования тегов компонентов, является одним из основных вопросов проектирования.

Ответы [ 3 ]

2 голосов
/ 25 октября 2011

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

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

Некоторые библиотекитолько хочет что-то простое, как это:

void logDebug(const std::string &msg);
void logWarning(const std::string &msg);
void logError(const std::string &msg);

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

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

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

ОБНОВЛЕНИЕ:

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

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

Я не знаю, как вы указываете X или Y в своем примере.Как вы это делаете, не очень понятно из приведенного нами описания.Я собираюсь просто использовать строку для демонстрации, но вы должны заменить ее на что-то безопасное, если это возможно.

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

void setLoggingContext("X:");

Если это меняется на разных уровнях абстракции, я бы рассмотрел реализацию RAII на основе стека.

LoggingTag tag("X:");

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

void foo() {
  LoggingTag tag("X:");
  logWarning("foo");
  bar();
  baz();
}

void bar() {
  LoggingTag tag("Y:");
  logWarning("bar");
  baz();
}

void baz() {
  logWarning("baz");
}

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

Если вы хотите использовать теги на основе какого-либо типа, вы можете сделать что-то простое, как это.

struct LoggingTag {
  LoggingTag(const std::string &tag_) : tag(tag_) {}
  template<typename T>
    static LoggingTag ByType() {
      return LoggingTag(typeid(T).name());
    }
  std::string tag;
};

void foo() {
  LoggingTag tag = LogginTag::ByType<int>();
}

Это не заставит кого-либо использовать typeid(T).name(), если он не захочет, но даст вам удобство.

1 голос
/ 25 октября 2011

Мне нравится такой подход:

class Log {
public:
    virtual logString(const std::string&)=0;
};

template <typename T>
Log& operator<<(Log& logger, const T& object) {
        std::stringstream converter;
        converter << object;
        logger.logString(converter.str());
        return logger;
}

Просто и быстро!Все, что вам нужно сделать, это переопределить метод logString ...

0 голосов
/ 01 февраля 2016

Взгляните на библиотеку zf_log .Он очень маленький (~ 2000k строк, ~ 10KB при компиляции) и быстрый (см. Таблицу сравнения в README.md ).Это очень близко к тому, что вы описываете как обертка.Он предоставляет вам абстрактный API, который вы можете использовать в своем проекте, и позволяет указать, какую фактическую реализацию ведения журнала использовать.См. custom_output.c пример, где syslog используется как средство вывода.Его также можно использовать в закрытых библиотеках, не рискуя вступить в конфликт с другим кодом, который может использовать эту библиотеку (см. ZF_LOG_LIBRARY_PREFIX определение для получения дополнительной информации).Даже если это не совсем то, что вы ищете, я думаю, это может послужить хорошим примером для вашей обертки.

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