Блок задач

9. Паттерны проектирования

Темы
Сложность 2

Задача «Логгер (Одиночка)»

Задание

Реализовать логгер, используя паттерн одиночка.

Описание

Примерный интерфейс логгера.

class logstream {
    // реализация ...
public:
    static void set_log_file(const std::string & name);

    logstream(void);
    ~logstream(void);

    template < typename T >
    inline logstream & operator << (const T & rhs) {
        // ...
        return *this;
    }
    // ...
};
  • set_log_file – статический метод класса, позволяющий назначить файл журнала. Если в момент вызова журнал уже был открыт, то старый файл сохраняется и закрывается, отрывается новый файл, и в дальнейшем, журнал ведётся уже в него.

  • конструктор – конструируется "легковесный" объект, предоставляющий доступ к одному единственному файловому потоку, ведущему запись в журнал.

  • деструктор – "легковесный" объект уничтожается, при этом файловый поток, ведущий запись в журнал сбрасывает все буферизованные данные в файл, но сам файл не закрывает и продолжает вести запись.

  • operator << – перегруженный оператор вывода в поток. При передаче в поток манипулятора endl, происходит принудительный сброс буферизованных данных в файл журнала.

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

Пример использования

int f(int a) {
    logstream log;
    log << "f(0x" << std::hex << a << ")" << std::endl;
    int r = a * a;
    log << "f() -- return " << r << std::endl;
    return r;
}

void main(void) {
    logstream::set_log_file("test.log");
    logstream log;
    log << "main()" << std::endl;
    f(15);
    log << "main() -- return" << std::endl;
}

Дополнительно

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

В этом случае в интерфейсе logstream

logstream(const std::string & prefix = std::string());

Использование:

int f(int a) {
    logstream log("f()");
    log << " a = 0x" << std::hex << a << std::endl; // вывод "f() a = 0xf\n"
    int r = a * a;
    log << " return " << r << std::endl;            // вывод "f() return 225\n"
    return r;
}

void main(void) {
    logstream::set_log_file("test.log");
    logstream log("main()");
    f(15);
    log << " return" << std::endl;                 // вывод "main() return\n"
}