Я ищу небольшую легкую систему ведения журнала в С++. Я нашел некоторые существующие рамки, но мне не нужны все их функции на данный момент. В первую очередь я ищу небольшую систему, которая может, например, настроить выходной файл журнала. Я ищу существующее решение, поскольку я не хочу изобретать велосипед.
Класс малого регистратора
Ответ 1
Я настоятельно рекомендую эту простую систему регистрации: http://www.drdobbs.com/cpp/201804215. Он состоит из одного файла заголовка. Я успешно использовал его в Linux, Windows и Mac OS X.
Вы записываете в журнал следующим образом:
FILE_LOG(logWARNING) << "Ops, variable x should be " << expectedX << "; is " << realX;
Мне очень нравится синтаксис потока. Это ненавязчивый, типичный и выразительный. Структура ведения журнала автоматически добавляет \n
в конце строки, а также дату, время и отступ.
Настройка журналов довольно проста:
FILELog::ReportingLevel() = logDEBUG3;
FILE* log_fd = fopen( "mylogfile.txt", "w" );
Output2FILE::Stream() = log_fd;
Эта структура также легко расширяется. На работе мы недавно внесли некоторые изменения в него, чтобы теперь он использовал std::ofstream
вместо FILE*
. В результате мы теперь можем добавлять приятные функции, такие как шифрование журналов, путем объединения потоков.
Ответ 2
Для тех, кто хочет простое решение, я рекомендую: easylogging++
Только один заголовок только для библиотеки протоколов С++. Это очень легкий вес, надежный, быстродействующий, поточный и безопасный тип и состоит из многих встроенные функции. Это позволяет записывать журналы самостоятельно настраиваемый формат. Он также обеспечивает поддержку для регистрации ваших классов, сторонних библиотек, STL и сторонних контейнеров и т.д.
В этой библиотеке есть все, что необходимо для предотвращения использования внешних библиотеки.
Простой пример: (более сложные примеры доступны по ссылке выше).
#include "easylogging++.h"
INITIALIZE_EASYLOGGINGPP
int main(int argv, char* argc[]) {
LOG(INFO) << "My first info log using default logger";
return 0;
}
Пример вывода внутри класса:
2015-08-28 10: 38: 45,900 DEBUG [по умолчанию] [пользователь @localhost] [Config:: Config (const string)] [src/Config.cpp: 7] Чтение файла конфигурации: 'Config.json'
Я попробовал log4cpp и boost:: log, но они не так просты, как этот.
ДОПОЛНИТЕЛЬНОЕ СОДЕРЖАНИЕ: Минимальная версия - заголовок журнала
Я создал небольшой код для еще более простых приложений на основе easylogging, но не требует инициализации (помните, что он, вероятно, не является потокобезопасным). Вот код:
/*
* File: Log.h
* Author: Alberto Lepe <[email protected]>
*
* Created on December 1, 2015, 6:00 PM
*/
#ifndef LOG_H
#define LOG_H
#include <iostream>
using namespace std;
enum typelog {
DEBUG,
INFO,
WARN,
ERROR
};
struct structlog {
bool headers = false;
typelog level = WARN;
};
extern structlog LOGCFG;
class LOG {
public:
LOG() {}
LOG(typelog type) {
msglevel = type;
if(LOGCFG.headers) {
operator << ("["+getLabel(type)+"]");
}
}
~LOG() {
if(opened) {
cout << endl;
}
opened = false;
}
template<class T>
LOG &operator<<(const T &msg) {
if(msglevel >= LOGCFG.level) {
cout << msg;
opened = true;
}
return *this;
}
private:
bool opened = false;
typelog msglevel = DEBUG;
inline string getLabel(typelog type) {
string label;
switch(type) {
case DEBUG: label = "DEBUG"; break;
case INFO: label = "INFO "; break;
case WARN: label = "WARN "; break;
case ERROR: label = "ERROR"; break;
}
return label;
}
};
#endif /* LOG_H */
Использование:
#include "Log.h"
int main(int argc, char** argv) {
//Config: -----(optional)----
structlog LOGCFG = {};
LOGCFG.headers = false;
LOGCFG.level = DEBUG;
//---------------------------
LOG(INFO) << "Main executed with " << (argc - 1) << " arguments";
}
Этот код напечатает сообщение с помощью "cout", но вы можете изменить его, чтобы использовать "cerr" или добавить файл и т.д. Я надеюсь, что это полезно кому-то. (Примечание: я не специалист по С++, так что этот код может взорваться в крайних случаях).
Ответ 3
Я рекомендую попробовать plog библиотека (я автор). Это около 1000 строк кода, только заголовка и прост в использовании:
#include <plog/Log.h>
int main()
{
plog::init(plog::debug, "Sample.log");
LOGD << "Hello log!";
LOGD_IF(true) << "conditional logging";
return 0;
}
Ответ 4
все упомянутые регистраторы до сих пор используют макросы для протоколирования вызовов. Для меня это так уродливо, меня не волнует, что повышает производительность, я не буду приближаться к нему.
https://github.com/gabime/spdlog - это то, что мне нравится. Чистый синтаксис, обрабатывает все типичные обычаи. Быстро и мало. например для регистратора файлов это:
auto my_logger = spd::basic_logger_mt("basic_logger", "logs/basic.txt");
my_logger->info("Some log message");
Ответ 5
Если у вас нет ограничений по размеру для проекта, и вы ожидаете, что он будет жить долгое время, я бы предложил посмотреть Apache Log4cxx, Это не небольшая библиотека, но она поддерживает практически все, что вы когда-либо хотели (в том числе некоторые вещи, которые вы даже не знали, что вы хотели) при регистрации и переносимость.
В любом крупном проекте рано или поздно вы захотите, чтобы ваше решение для ведения журналов делало больше, чем "небольшой класс журнала", поэтому действительно зачем изобретать колесо.
Ответ 6
Этот вопрос имеет мою попытку с некоторой причудливостью. Он полностью Standard С++ и не делает никаких предположений платформы. Он в основном состоит из временного объекта, используемого следующим образом:
Debug(5) << "This is level 5 debug info.\n";
Я уверен, что вы можете выяснить, как указать разные файлы и другие материалы, когда у вас есть основной макет. Я попытался сохранить класс структурирован таким образом, чтобы в сборке выпуска каждая форма вывода Debug удалялась как можно лучше.
Имейте в виду: если вы укажете имя файла каждый раз, когда вы его создадите, и откройте файл и закройте его снова, производительность будет страдать. В случае с несколькими выходными файлами было бы лучше иметь несколько статических членов данных, которые открывают разные файлы при запуске программы или если они будут открываться в первый раз.