LINUX.ORG.RU

Понимание потоков ввода-вывода в C++

 , ,


0

2

Есть такой код:

class LogStreamBase {
public:
    LogStreamBase(const ostream& os) : out(os) {}
    template<typename T>
    const LogStreamBase& operator<< (const T& var) {
        prepare();
        print_prolog();
        out << var;
        print_epilog();
    }

protected:
    virtual void print_prolog() = 0;
    virtual void print_epilog() = 0;

    const ostream& out;

};

Как работает operator <<, будучи вызванным вот так:

LogStreamDerived log;
log << "One" << "Two" << "Three";

Будут ли print_prolog и print_epilog вызваны для каждой строки, или для всей последовательности единожды?
Адекватен ли такой вариант или лучше наследовать streambuf и прикручивать его к ostream?

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

★★★★★

Последнее исправление: mersinvald (всего исправлений: 2)

Будут ли print_prolog и print_epilog вызваны для каждой строки, или для всей последовательности единожды?

для каждого вызова оператора

const LogStreamBase& operator<< (const T& var)

Адекватен ли такой вариант или лучше наследовать streambuf и прикручивать его к ostream?

лучше взять

std::stringstream
и по необходимости брать из него строку и дампить в куда нужно

shty ★★★★★
()

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

может быть лучше взять стандартный логгер, типа boost::log, spdlog или glog?

shty ★★★★★
()
Ответ на: комментарий от shty

лучше взять std::stringstream

Да, так удобнее, спасибо.

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

#define LOG(level, str, ...) log(level, __FUNCTION__ __FILE__ __LINE__ str, __VA_ARGS__)
А как тут можно провернуть подобный трюк с передачей этой информации?

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

Реагировать на перенос строки? Некрасиво и побьет форматирование комплексных сообщений, которые должны выводиться в несколько строк

Добавлять спецтип и передавать в конце? Не люблю плодить шаблоны, да и это еще более уродливо.

mersinvald ★★★★★
() автор топика
Ответ на: комментарий от shty

Для вывода форматированных сообщений в stderr/файл тащить огромную библиотеку для логгирования или еще более огромную из состава буста?

mersinvald ★★★★★
() автор топика
Ответ на: комментарий от mersinvald

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

Я вообще обычно по-рабоче-крестьянски засовываю непосредственно дамп в деструктор и когда объект разрушается он информацию сохраняет в лог (но это все чисто для дебага, для real-time мониторинга надо уже смотреть). Семантика вызова получается такая:

LogStreamDerived() << "One" << "Two" << "Three"; // вывелось в лог

или так

{
    LogStreamDerived log;
    log << "One";
    log << "Two";
    log << "Three";
} // вывелось в лог

shty ★★★★★
()
Ответ на: комментарий от mersinvald

Для вывода форматированных сообщений в stderr/файл тащить огромную библиотеку для логгирования или еще более огромную из состава буста?

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

shty ★★★★★
()
Ответ на: комментарий от shty

LogStreamDerived() << «One» << «Two» << «Three»; // вывелось в лог

Спасибо, так и сделаю

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

На скорость вообще насрать — там идет взаимодействие с REST API с частотой 5 запросов в секунду максимум, так что, если логика формирования запроса не будет работать >0.2c — уже нормально, а так запустить скорость надо еще постараться :)

mersinvald ★★★★★
() автор топика
Ответ на: комментарий от mersinvald

Что не так?
З.Ы честно с3.14зжено с stackoverflow

есть мнение, что константные объекты (std::ostream) будут сильно ругаться при попытке изменить их внутреннее состояние (записать данные в буфер)

shty ★★★★★
()
Последнее исправление: shty (всего исправлений: 1)
Ответ на: комментарий от mersinvald

В си я это делал через макрос вида

А что мешает в C++ сделать через макрос?

#include <iostream>

using std::endl;

#define LOG(level)                   \
  std::cout << "[" << level << "] "  \
            << __FUNCTION__ << ":"   \
            << __FILE__  << ":"      \
            << __LINE__ << ": "

int main() {
  LOG("debug") << "one " << "two " << "three " << endl;
  LOG("error") << 2 << "+" << 3 << "=" << 2+3 << endl;
}
theNamelessOne ★★★★★
()
Ответ на: комментарий от theNamelessOne

То, что нужна несколько большая гибкость.
Уже решил.

mersinvald ★★★★★
() автор топика
Ответ на: комментарий от mersinvald

Для вывода форматированных сообщений в stderr/файл тащить огромную библиотеку для логгирования или еще более огромную из состава буста?

Почему бы и нет? Тем более, что сначала хочется просто «вывод форматированных сообщений». Потом ротацию файлов и ещё кучу вещей. В итоге количество своих костылей оказывается размером в библиотеку.

DarkEld3r ★★★★★
()

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

Вчера попробовал spdlog — очень круто! Там одни хедеры.

BruteForce ★★★
()
Последнее исправление: BruteForce (всего исправлений: 1)
Ответ на: комментарий от DarkEld3r

Потом ротацию файлов и ещё кучу вещей

Не знаю насчет кучи, но ротация делается системными средствами.

tailgunner ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.