muduo网络库学习之Logger类、LogStream类、LogFile类封装中的知识点
来源:互联网 发布:北京大学化学系知乎 编辑:程序博客网 时间:2024/05/29 03:16
一、Logger类、LogStream类
1、日志作用
开发过程中:
调试错误更好的理解程序
运行过程中:
诊断系统故障并处理记录系统运行状态
TRACE
指出比DEBUG粒度更细的一些信息事件(开发过程中使用)
DEBUG
指出细粒度信息事件对调试应用程序是非常有帮助的。(开发过程中使用)
INFO
表明消息在粗粒度级别上突出强调应用程序的运行过程。
WARN
系统能正常运行,但可能会出现潜在错误的情形。
ERROR
指出虽然发生错误事件,但仍然不影响系统的继续运行。
FATAL
指出每个严重的错误事件将会导致应用程序的退出。
class Logger
{
public:
enum LogLevel{
TRACE,DEBUG,INFO,WARN,ERROR,FATAL,NUM_LOG_LEVELS,
};
// compile time calculation of basename of source file
class SourceFile { };
private:
class Impl { };
class Impl { };
};
template<int SIZE>
class FixedBuffer : boost::noncopyable
class FixedBuffer : boost::noncopyable
class LogStream : boost::noncopyable
{
typedef LogStream self;
public: // 4000
};typedef detail::FixedBuffer<detail::kSmallBuffer> Buffer;
class Fmt // : boost::noncopyable
{
public:
{
public:
};template<typename T>Fmt(const char* fmt, T val){ // 按照fmt 格式将val 格式化成字符串放入buf_中length_ = snprintf(buf_, sizeof buf_, fmt, val);};
3、formatInteger() //是把数字或者指针的值当作字符串写入
C++ Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
const char digits[] = "9876543210123456789";
const char* zero = digits + 9;
const char digitsHex[] = "0123456789ABCDEF";
LogStream& LogStream::operator<<(int v)
{
formatInteger(v);
return *this;
}
template<typename T>
void LogStream::formatInteger(T v)
{ //32
if (buffer_.avail() >= kMaxNumericSize)
{
size_t len = convert(buffer_.current(), v);
buffer_.add(len);
}
}
// Efficient Integer to String Conversions, by Matthew Wilson.
template<typename T>
size_t convert(char buf[], T value)
{
T i = value;
char* p = buf;
do
{
int lsd = static_cast<int>(i % 10);
i /= 10;
*p++ = zero[lsd];
} while (i != 0);
if (value < 0)
{
*p++ = '-';
}
*p = '\0';
std::reverse(buf, p);
return p - buf;
}
LogStream& LogStream::operator<<(const void* p)
{
uintptr_t v = reinterpret_cast<uintptr_t>(p);
if (buffer_.avail() >= kMaxNumericSize)
{
char* buf = buffer_.current();
buf[0] = '0';
buf[1] = 'x';
size_t len = convertHex(buf+2, v);
buffer_.add(len+2);
}
return *this;
}
// Efficient Pointer to String Conversions
// uintptr_t on 32bit as unsigned int; on 64bit as unsigned long int
size_t convertHex(char buf[], uintptr_t value)
{
uintptr_t i = value;
char* p = buf;
do
{
int lsd = i % 16;
i /= 16;
*p++ = digitsHex[lsd];
} while (i != 0);
*p = '\0';
std::reverse(buf, p);
return p - buf;
}
4、Logger使用时序图:
#define LOG_INFO if (muduo::Logger::logLevel() <= muduo::Logger::INFO) \
muduo::Logger(__FILE__, __LINE__).stream()
muduo::Logger(__FILE__, __LINE__).stream()
LOG_INFO<<“info ...”; // 使用方式
muduo::Logger(__FILE__, __LINE__).stream()<<“info”;
muduo::Logger(__FILE__, __LINE__).stream()<<“info”;
// LogStream& stream() { return impl_.stream_; }
Logger => Impl => LogStream => operator<< FixedBuffer => g_output => g_flush
Logger => Impl => LogStream => operator<< FixedBuffer => g_output => g_flush
栈上匿名的Logger对象使用完就要析构,在~Logger()中调用 g_output,即 g_output(buf.data(), buf.length());
如果是FATAL错误,还要调用g_flush,最后abort()程序。
如果没有调用g_flush,会一直输出到缓冲区(标准输出缓冲区,文件FILE缓冲区)满才会真的输出在标准输出,或者写入到文件中去。注:可以使用setvbuf设置缓冲区的大小。
int setvbuf ( FILE * stream, char * buffer, int mode, size_t size );
默认日志信息输出到标准输出(g_output = defaultOutput、g_flush = defaultFlush),也可以输出到文件,使用SetOutput、SetFlush 设置。
测试程序:
C++ Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <muduo/base/Logging.h>
#include <errno.h>
#include <stdio.h>
using namespace muduo;
FILE *g_file;
void dummyOutput(const char *msg, int len)
{
if (g_file)
{
fwrite(msg, 1, len, g_file);
}
}
void dummyFlush()
{
fflush(g_file);
}
int main()
{
g_file = ::fopen("/tmp/muduo_log", "ae");
Logger::setOutput(dummyOutput);
Logger::setFlush(dummyFlush);
LOG_TRACE << "trace ...";
LOG_DEBUG << "debug ...";
LOG_INFO << "info ...";
LOG_WARN << "warn ...";
LOG_ERROR << "error ...";
//LOG_FATAL<<"fatal ...";
errno = 13;
LOG_SYSERR << "syserr ...";
//LOG_SYSFATAL<<"sysfatal ...";
::fclose(g_file);
return 0;
}
#include <errno.h>
#include <stdio.h>
using namespace muduo;
FILE *g_file;
void dummyOutput(const char *msg, int len)
{
if (g_file)
{
fwrite(msg, 1, len, g_file);
}
}
void dummyFlush()
{
fflush(g_file);
}
int main()
{
g_file = ::fopen("/tmp/muduo_log", "ae");
Logger::setOutput(dummyOutput);
Logger::setFlush(dummyFlush);
LOG_TRACE << "trace ...";
LOG_DEBUG << "debug ...";
LOG_INFO << "info ...";
LOG_WARN << "warn ...";
LOG_ERROR << "error ...";
//LOG_FATAL<<"fatal ...";
errno = 13;
LOG_SYSERR << "syserr ...";
//LOG_SYSFATAL<<"sysfatal ...";
::fclose(g_file);
return 0;
}
程序执行后查看写入文件的内容:
simba@ubuntu:~/Documents/build/debug/bin$ cat /tmp/muduo_log
20131102 12:33:29.812878Z 4021 TRACE main trace ... - Log_test2.cc:28
20131102 12:33:29.813108Z 4021 DEBUG main debug ... - Log_test2.cc:29
20131102 12:33:29.813112Z 4021 INFO info ... - Log_test2.cc:30
20131102 12:33:29.813114Z 4021 WARN warn ... - Log_test2.cc:31
20131102 12:33:29.813117Z 4021 ERROR error ... - Log_test2.cc:32
20131102 12:33:29.813120Z 4021 ERROR Permission denied (errno=13) syserr ... - Log_test2.cc:35
simba@ubuntu:~/Documents/build/debug/bin$
20131102 12:33:29.812878Z 4021 TRACE main trace ... - Log_test2.cc:28
20131102 12:33:29.813108Z 4021 DEBUG main debug ... - Log_test2.cc:29
20131102 12:33:29.813112Z 4021 INFO info ... - Log_test2.cc:30
20131102 12:33:29.813114Z 4021 WARN warn ... - Log_test2.cc:31
20131102 12:33:29.813117Z 4021 ERROR error ... - Log_test2.cc:32
20131102 12:33:29.813120Z 4021 ERROR Permission denied (errno=13) syserr ... - Log_test2.cc:35
simba@ubuntu:~/Documents/build/debug/bin$
5、StringPiece类
// We provide non-explicit singleton constructors so users can pass
// in a "const char*" or a "string" wherever a "StringPiece" is
// expected.
// in a "const char*" or a "string" wherever a "StringPiece" is
// expected.
只是复制字符串的指针,故不涉及具体字符串内存的拷贝,高效地传递字符串。
class StringPiece {
private:const char* ptr_;
int length_;
....
C++ Code
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
#define STRINGPIECE_BINARY_PREDICATE(cmp,auxcmp) \
bool operator cmp (const StringPiece& x) const { \
int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_); \
return ((r auxcmp 0) || ((r == 0) && (length_ cmp x.length_))); \
}
STRINGPIECE_BINARY_PREDICATE( < , < );
STRINGPIECE_BINARY_PREDICATE( <= , < );
STRINGPIECE_BINARY_PREDICATE( >= , > );
STRINGPIECE_BINARY_PREDICATE( > , > );
#undef STRINGPIECE_BINARY_PREDICATE
bool operator cmp (const StringPiece& x) const { \
int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_); \
return ((r auxcmp 0) || ((r == 0) && (length_ cmp x.length_))); \
}
STRINGPIECE_BINARY_PREDICATE( < , < );
STRINGPIECE_BINARY_PREDICATE( <= , < );
STRINGPIECE_BINARY_PREDICATE( >= , > );
STRINGPIECE_BINARY_PREDICATE( > , > );
#undef STRINGPIECE_BINARY_PREDICATE
};
void flushFunc()
{
g_logFile->flush();
int main(int argc, char *argv[])
{
char name[256];
strncpy(name, argv[0], 256);
g_logFile.reset(new muduo::LogFile(::basename(name), 200 * 1000));
muduo::Logger::setOutput(outputFunc);
muduo::Logger::setFlush(flushFunc);
muduo::string line = "1234567890 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ ";
for (int i = 0; i < 10000; ++i)
{
LOG_INFO << line << i;
usleep(1000);
}
}
执行程序后查看创建的日志文件:
二、LogFile类
日志滚动条件
文件大小(例如每写满1G换下一个文件)一个典型的日志文件名
时间(每天零点新建一个日志文件,不论前一个文件是否写满)
logfile_test.20130411-115604.popo.7743.log
// 运行程序.时间.主机名.线程名.log
class LogFile : boost::noncopyable
const string basename_; // 日志文件 basename
const size_t rollSize_; // 日志文件达到rollSize_换一个新文件
const int flushInterval_; // 日志写入文件间隔时间
time_t startOfPeriod_; // 开始记录日志时间(调整到零时时间)
time_t lastRoll_; // 上一次滚动日志文件时间
time_t lashFlush_; // 上一次日志写入文件时间
// 60*60*24
time_t start = now / kRollPerSeconds_ * kRollPerSeconds_;
表示start对齐到kR的整数倍,也就是时间调整到当天零时
// not thread safe
class LogFile::File : boost::noncopyable
class LogFile::File : boost::noncopyable
::setbuffer(fp_, buffer_, sizeof buffer_);
测试程序:
LogFile_test.cc:
C++ Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <muduo/base/LogFile.h>
#include <muduo/base/Logging.h>
boost::scoped_ptr<muduo::LogFile> g_logFile;
void outputFunc(const char *msg, int len)
{
g_logFile->append(msg, len);
#include <muduo/base/Logging.h>
boost::scoped_ptr<muduo::LogFile> g_logFile;
void outputFunc(const char *msg, int len)
{
g_logFile->append(msg, len);
// scoped_ptr<T> 重载operator->,调用LogFile::append(),
// 间接调用File::append(); 最后 ::fwrite_unlocked(fp_);
}void flushFunc()
{
g_logFile->flush();
// scoped_ptr<T> 重载operator->,调用LogFile::flush(),
//间接调用File::flush(),最后::fflush(fp_);
}int main(int argc, char *argv[])
{
char name[256];
strncpy(name, argv[0], 256);
g_logFile.reset(new muduo::LogFile(::basename(name), 200 * 1000));
muduo::Logger::setOutput(outputFunc);
muduo::Logger::setFlush(flushFunc);
muduo::string line = "1234567890 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ ";
for (int i = 0; i < 10000; ++i)
{
LOG_INFO << line << i;
// 不断地构造匿名的Logger对象,在~Logger()中调用dummyOutput,将日志信息写入文件
usleep(1000);
}
}
simba@ubuntu:~/Documents/build/debug/bin$ ls -lh *.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:37 logfile_test.20131102-123753.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:37 logfile_test.20131102-123756.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:38 logfile_test.20131102-123759.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:38 logfile_test.20131102-123802.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:38 logfile_test.20131102-123805.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:38 logfile_test.20131102-123808.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 87K Nov 2 05:38 logfile_test.20131102-123811.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:37 logfile_test.20131102-123753.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:37 logfile_test.20131102-123756.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:38 logfile_test.20131102-123759.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:38 logfile_test.20131102-123802.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:38 logfile_test.20131102-123805.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 196K Nov 2 05:38 logfile_test.20131102-123808.ubuntu.4044.log
-rw-rw-r-- 1 simba simba 87K Nov 2 05:38 logfile_test.20131102-123811.ubuntu.4044.log
因为我们设置的滚动日志文件大小为200 *1000/1024 = 196k,所以现在即使没有到另一个零时,因为文件大小已到上限,也会自动滚动文件。
参考:
muduo manual.pdf
《linux 多线程服务器编程:使用muduo c++网络库》
- muduo网络库学习之Logger类、LogStream类、LogFile类封装中的知识点
- muduo网络库学习(九)日志类Logger和LogStream,将日志信息打印到屏幕
- muduo网络库学习之MutexLock类、MutexLockGuard类、Condition类、CountDownLatch类封装中的知识点
- muduo网络库学习之BlockinngQueue<T>类、ThreadPool 类、Singleton类封装中的知识点
- muduo 6 网络库学习之BlockinngQueue<T>类、ThreadPool 类、Singleton类封装中的知识点
- muduo网络库学习之Timestamp类、AtomicIntegerT 类封装中的知识点
- muduo网络库学习之Exception类、Thread 类封装中的知识点(重点讲pthread_atfork())
- muduo 3 网络库学习之Timestamp类、AtomicIntegerT 类封装中的知识点
- muduo 5 网络库学习之MutexLock类、MutexLockGuard类、Condition类、CountDownLatch类封装中的知识点
- muduo 4 网络库学习之Exception类、Thread 类封装中的知识点(重点讲pthread_atfork())
- muduo网络库学习之ThreadLocal<T> 类、ThreadLocalSingleton<T>类封装知识点
- muduo库源码学习(base):LogStream
- muduo库的LogFile日志文件类剖析
- muduo网络库学习之muduo_http 库涉及到的类
- muduo网络库学习之muduo_inspect 库涉及到的类
- muduo网络库学习之muduo_inspect 库涉及到的类
- 【muduo网络库学习】之Acceptor类分析
- muduo网络库源码学习————日志类封装
- IIS写权限漏洞
- ios面试
- HDU4296 Buildings 贪心
- Linux 磁盘分区和文件系统
- 设计模式之装饰者模式
- muduo网络库学习之Logger类、LogStream类、LogFile类封装中的知识点
- 上层与驱动间通信
- android之在EditText、TextView中添加表情图片
- HDU4288 Coder
- iOS开发19:Storyboard的简单使用
- 3Ds MAX 光照贴图uv
- hdu 4118 Holiday's Accommodation
- 光照贴图UV Lightmapping UVs
- 0032算法笔记——【回溯法】电路板排列问题和连续邮资问题