如何使用g3log
G3log是一款带有动态接收器的异步日志工具
示例用法
可选使用流式或类似printf的语法
LOG(INFO) << "streaming API is as easy as ABC or " << 123;
LOGF(WARNING, "Printf-style syntax is also %s", "available");
什么是g3Log
- G3log是g2log第三个版本的代理名称,它代表着g3log动态日志接收器
- G3log是一款异步、可以安全处理崩溃的日志记录器,您可以在 g2log version]阅读到更多信息
- 您可以选择使用默认的日志接收器去将所有LOG保存到文件中,或者您可以选择使用自己定制的日志接收器,或者两者都用,或着你根据你的去使用。
条件日志
int less = 1; int more = 2
LOG_IF(INFO, (less<more)) <<"If [true], then this text will be logged";
// or with printf-like syntax
LOGF_IF(INFO, (less<more), "if %d<%d then this text will be logged", less,more);
契约式设计
*CHECK(false)*会触发一个“fatal”的信息。该信息将被记录并且应用程序将退出
CHECK(less != more); // not FATAL
CHECK(less > more) << "CHECK(false) triggers a FATAL message";
详细的API文档
请查阅API.md去获取更详细的信息
您在使用g3log时获得的好处
- 易于使用,语法简洁,记录速度极快
- 所有缓慢的日志I/O磁盘访问都在后台线程中完成。这可以确保LOG调用者可以立即继续执行其他任务,而不必等待LOG调用完成
- G3log提供日志记录、契约式设计[#CHECK]以及在关闭时将日志刷新到日志文件,缓冲日志将在应用程序关闭之前写入日志接收器。
- 它的线程是安全的,因此从多个线程中使用它是完全可以的
- 它是CRASH SAFE,它会在日志记录器关闭前将已生成的日志保存到记录器中,日志记录将捕获某些致命崩溃事件 (Linux/OSX: signals, Windows: fatal OS exceptions and signals) , 所以,如果你的应用因段错误SIGSEGV二崩溃, 它将在退出之前记录并保存崩溃和所有先前缓冲的日志条目
- 它是跨平台的,由我在OSX,Windows,Ubuntu,CentOS 的客户端进行测试和使用
- G3log和G2log在全球范围内被用于商业产品和爱好项目, G2log于2011年初推出,现已退役
- 该代码是在公共领域内免费提供。这使您可以选择更改、使用和使用它来做任何事情,不附带任何条件
- g3log :是为了方便添加自定义日志接收器。 它至少在以下平台 Linux(Clang/gcc), Windows (mingw, visual studio) and OSX进行了测试,如果你有完整的C++14支持,就用g3log (C++11支持以下版本: https://github.com/KjellKod/g3log/releases/tag/1.3.1)
G3log带有接收器
Sinks是LOG调用的接收器, G3log有一个默认的接收器(与g3log使用的相同),可用于将日志保存到文件中。接收器没有限制,可以是任何类型,只要可以通过std::string或g3::LogMessageMover进行日志消息传递
std::string可以预先格式化,g3::LogMessageMover*是一个包含原始数据的封装结构,以便可以在自定义的接收器中进行处理
A sink is owned by the g3log and is added to the logger inside a std::unique_ptr
. The sink can be called though its public API through a handler which will asynchronously forward the call to the receiving sink.
创建自定义的sink十分简单,此示例展示了使用自定义日志格式(只是在默认日志格式上增加了颜色)去创建自定义sink,这个sink可以将带颜色的日志输出到前端
// in file Customsink.hpp
#pragma once
#include <string>
#include <iostream>
#include <g3log/logmessage.hpp>
struct CustomSink {
// Linux xterm color
// http://stackoverflow.com/questions/2616906/how-do-i-output-coloured-text-to-a-linux-terminal
enum FG_Color {YELLOW = 33, RED = 31, GREEN=32, WHITE = 97};
FG_Color GetColor(const LEVELS level) const {
if (level.value == WARNING.value) { return YELLOW; }
if (level.value == DEBUG.value) { return GREEN; }
if (g3::internal::wasFatal(level)) { return RED; }
return WHITE;
}
void ReceiveLogMessage(g3::LogMessageMover logEntry) {
auto level = logEntry.get()._level;
auto color = GetColor(level);
std::cout << "\033[" << color << "m"
<< logEntry.get().toString() << "\033[m" << std::endl;
}
};
// in main.cpp, main() function
auto sinkHandle = logworker->addSink(std::make_unique<CustomSink>(),
&CustomSink::ReceiveLogMessage);
添加和删除Sinks
您可以在程序运行期间安全地删除和添加接收器
牢记
- 记录器的初始化应该在启动任何其他可能调用记录器的线程之前进行
- 记录器的销毁(RAII)应该在调用记录器的其他线程关闭之后发生
添加Sinks
auto sinkHandle1 = logworker->addSink(std::make_unique<CustomSink>(),
&CustomSink::ReceiveLogMessage);
auto sinkHandle2 = logworker->addDefaultLogger(argv[0],
path_to_log_file);
logworker->removeSink(std::move(sinkHandle1)); // this will in a thread-safe manner remove the sinkHandle1
logworker->removeAllSinks(); // this will in a thread-safe manner remove any sinks.
更多的sinks你可以在这里**github.com/KjellKod/g3sinks**找到
代码示例
添加自定义接收器的示例用法,函数通过接收处理程序调用到实际的接收对象
// main.cpp
#include <g3log/g3log.hpp>
#include <g3log/logworker.hpp>
#include <memory>
#include "CustomSink.h"
int main(int argc, char**argv) {
using namespace g3;
std::unique_ptr<LogWorker> logworker{ LogWorker::createLogWorker() };
auto sinkHandle = logworker->addSink(std::make_unique<CustomSink>(),
&CustomSink::ReceiveLogMessage);
// initialize the logger before it can receive LOG calls
initializeLogging(logworker.get());
LOG(WARNING) << "This log call, may or may not happend before"
<< "the sinkHandle->call below";
// You can call in a thread safe manner public functions on your sink
// The call is asynchronously executed on your custom sink.
std::future<void> received = sinkHandle->call(&CustomSink::Foo,
param1, param2);
// If the LogWorker is initialized then at scope exit the g3::internal::shutDownLogging() will be called.
// This is important since it protects from LOG calls from static or other entities that will go out of
// scope at a later time.
//
// It can also be called manually:
g3::internal::shutDownLogging();
}
// some_file.cpp : To show how easy it is to get the logger to work
// in other parts of your software
#include <g3log/g3log.hpp>
void SomeFunction() {
...
LOG(INFO) << "Hello World";
}
使用默认文件记录器的示例用法和添加自定义接收器
// main.cpp
#include <g3log/g3log.hpp>
#include <g3log/logworker.hpp>
#include <memory>
#include "CustomSink.h"
int main(int argc, char**argv) {
using namespace g3;
auto worker = LogWorker::createLogWorker();
auto defaultHandler = worker->addDefaultLogger(argv[0],
path_to_log_file);
// logger is initialized
g3::initializeLogging(worker.get());
LOG(DEBUG) << "Make log call, then add another sink";
worker->addSink(std::make_unique<CustomSink>(),
&CustomSink::ReceiveLogMessage);
...
}