1.stringPiece 类:当字符串来用
统一 char * 字符串 和 std::string 。通过char *字符串 或者 string作参数 传递 字符串 ,形参为stringPiece类型,就不会有内存拷贝
stringPiece 只有两个变量
const char* ptr_; //字符串首地址
int length_; //字符串长度
其实 形参 为 const char * 也可以做到不拷贝内存,只是sting类型的实参传递时,要用stirng::c_str( ) 来传递
FixedBuffer类:缓冲区,非类型模板
主要就是两个成员变量
char data_[SIZE]; //日志数据实际存储位置
char* cur_; //data_下次可写入的位置
LogStream:包含一个FixedBuffer类型的成员变量buff_
logtream就是负责将数值类型,字符串格式化写入FixedBuffer类型的成员buff_中
Fmt 类:一个格式化工具类,构造函数就两个参数,一个是格式化样式,一个是要被格式化的对象-数值类型
LogStream类型可以直接通过<<操作将Fmt 写入缓冲区buff_ : ./LogStream.h:inline LogStream& operator<<(LogStream& s, const Fmt& fmt)
使用方法:
muduo::LogStream os;
os << muduo::Fmt("%4.2f", 1.2);
2.日志写入流程
#define LOG_INFO if (muduo::Logger::logLevel() <= muduo::Logger::INFO) \
muduo::Logger(__FILE__, __LINE__).stream()
写日志的方法:
LOG_INFO<<“测试日志写入 ...”;// 使用方式
LOG_INFO宏展开的实际代码:muduo::Logger(__FILE__, __LINE__).stream() << “ 测试日志写入……”;
调用过程
Logger => Impl => LogStream => operator<< FixedBuffer => g_output => g_flush
logger实例析构时调用 g_output => g_flush
muduo::Logger(__FILE__, __LINE__) : Logger构造的时候就在构造列表中构造了Impl,Impl构造的时候会格式化录入错误信息如进程号tid,时间等 到 impl的成员变量LogStream stream_ 的成员变量 buff_中
buff_定义 :typedef detail::FixedBuffer
stream() << “ 测试日志写入……” :stream() 返回的就是 impl的成员变量 LogStream stream_. 操作"<<" 实现将字符串录入stream_的成员变量buff_
3.枚举对应字符串例表提示:NUM_LOG_LEVELS为枚举的最后一个,使用默认从0开始
38 const char* LogLevelName[Logger::NUM_LOG_LEVELS] =
39 {
40 "TRACE ",
41 "DEBUG ",
42 "INFO ",
43 "WARN ",
44 "ERROR ",
45 "FATAL ",
46 };
base/Logging.h
#ifndef MUDUO_BASE_LOGGING_H
#define MUDUO_BASE_LOGGING_H
#include
#include
namespace muduo
{
class Logger
{
public:
enum LogLevel
{
TRACE,
DEBUG,
INFO,
WARN,
ERROR,
FATAL,
NUM_LOG_LEVELS,
};
//__FILE__ 日志记录的信息原文
class SourceFile
{
public:
template
//这来两个构造函数编译器能区分? __FILE__ 调用哪一个??
// muduo::Logger(__FILE__, __LINE__).stream() 调用第二个构造函数char *的
inline SourceFile(const char (&arr)[N])
: data_(arr),
size_(N-1)
{
const char* slash = strrchr(data_, '/');//返回最后一个 '/'
//截取的文件名
if(slash)
{
data_ = slash + 1;
size_ = static_cast(data_ - arr );//这里好像不对,应该是 N-1 - (slash-arr)
}
}
explicit SourceFile(const char* filename)
: data_(filename)
{
const char* slash = strrchr(filename, '/');
if(slash)
data_ = slash + 1;
size_ = static_cast(strlen(data_));
}
const char* data_;
int size_;
};
Logger(SourceFile file, int line);
Logger(SourceFile file, int line, LogLevel level);
Logger(SourceFile file, int line, LogLevel level, const char* func);
Logger(SourceFile file, int line, bool toAbort);
~Logger();
LogStream& stream(){ return impl_.stream_;}
static LogLevel logLevel();
static void setLogLevel(LogLevel level);
typedef void (*OutputFunc)(const char* msg, int len);
typedef void (*FlushFunc)();
static void setOutput(OutputFunc);
static void setFlush(FlushFunc);
private:
class Impl
{
public:
typedef Logger::LogLevel LogLevel;
Impl(LogLevel level, int old_errno, const SourceFile& file, int line);
void formatTime();
void finish();
Timestamp time_;
LogStream stream_;
LogLevel level_;
int line_;
SourceFile basename_;
};
Impl impl_;
};
extern Logger::LogLevel g_logLevel;
inline Logger::LogLevel Logger::logLevel()
{
return g_logLevel;
}
#define LOG_TRACE if (muduo::Logger::logLevel() <= muduo:: Logger::TRACE) \
muduo::Logger(__FILE__, __LINE__, muduo::Logger::TRACE, __func__).stream()
#define LOG_DEBUG if (muduo::Logger::logLevel() <= muduo:: Logger::DEBUG) \
muduo::Logger(__FILE__, __LINE__, muduo::Logger::DEBUG, __func__).stream()
#define LOG_INFO if (muduo::Logger::logLevel() <= muduo:: Logger::INFO) \
muduo::Logger(__FILE__, __LINE__).stream()
#define LOG_WARN muduo::Logger(__FILE__, __LINE__, muduo:: Logger::WARN).stream()
#define LOG_ERROR muduo::Logger(__FILE__, __LINE__, muduo:: Logger::ERROR).stream()
#define LOG_FATAL muduo::Logger(__FILE__, __LINE__, muduo:: Logger::FATAL).stream()
#define LOG_SYSERR muduo::Logger(__FILE__, __LINE__, false). stream()
#define LOG_SYSFATAL muduo::Logger(__FILE__, __LINE__, true). stream()
const char* strerror_tl(int savedErrno);//通过saveErrno 获取错误提示信息
//检查val是否是NULL,#val 会替换 val 变量名的字符
//连续的字符串会自动拼接"'val变量名' Must be …… "
#define CHECK_NOTNULL(val) \
::muduo::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val))
template
T* CheckNotNull(Logger::SourceFile file, int line, const char* names, T* ptr)
{
//val
if(ptr == NULL)
Logger(file, line, Logger::FATAL).stream() << names;
return ptr;
}
}
#endif
base/Logging.cc
#include
#include
#include
#include
#include
#include
#include
#include
namespace muduo
{
__thread char t_errnobuf[512];
__thread char t_time[32];
__thread time_t t_lastSecond;
//将错误提示存在t_errnobuf 中
const char* strerror_tl(int savedErrno)
{
return strerror_r(savedErrno, t_errnobuf, sizeof t_errnobuf);
}
Logger::LogLevel initLogLevel()
{
if(::getenv("MUDUO_LOG_TRACE"))
return Logger::TRACE;
else if(::getenv("MUDUO_LOG_DEBUG"))
return Logger::DEBUG;
else
return Logger::INFO;
}
Logger::LogLevel g_logLevel = initLogLevel();
const char* LogLevelName[Logger::NUM_LOG_LEVELS] =
{
"TRACE ",
"DEBUG ",
"INFO ",
"WARN ",
"ERROR ",
"FATAL ",
};
//存储字符串指针和长度。//在编译期就可以获取string 的长度??
class T
{
public:
T(const char* str, unsigned len)
: str_(str),
len_(len)
{
assert( strlen(str) == len_);
}
const char* str_;
const unsigned len_;
};
//在muduo命名空间内 声明并定义
inline LogStream& operator<<(LogStream& s, T v)
{
s.append(v.str_, v.len_);
return s;
}
inline LogStream& operator<<(LogStream& s, const Logger::SourceFile& v)
{
s.append(v.data_, v.size_);
return s;
}
void defaultOutput(const char* msg, int len)
{
// 这里如果n < len ,没有输出完全,但是没作处理
size_t n = fwrite(msg, 1, len, stdout);
(void) n;
}
void defaultFlush()
{
fflush(stdout);
}
Logger::OutputFunc g_output = defaultOutput;
Logger::FlushFunc g_flush = defaultFlush;
}
using namespace muduo;
Logger::Impl::Impl(LogLevel level, int savedErrno, const SourceFile& file, int line)
:time_(Timestamp::now()),
stream_(),
level_(level),
line_(line),
basename_(file)
{
formatTime();
CurrentThread::tid();
stream_ << T(CurrentThread::tidString(), 6);
stream_ << T(LogLevelName[level], 6);
if(savedErrno !=0 )
stream_<(microSecondsSinceEpoch / 1000000);
int microseconds = static_cast(microSecondsSinceEpoch % 1000000);
if(seconds != t_lastSecond)
{
t_lastSecond = seconds;
struct tm tm_time;
::gmtime_r(&seconds, &tm_time);//FIXME TimeZone::fromUtcTime
int len = snprintf(t_time, sizeof(t_time), "%4d%02d%02d%02d:%02d:%02d", tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday,tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec);
assert(len == 17);
(void) len;
}
Fmt us(".%06dZ ", microseconds);
assert(us.length() == 9);
stream_ << T(t_time, 17) << T(us.data(), 9);
}
void Logger::Impl::finish()
{
stream_<<" - " << basename_ << ':' << line_ << '\n';
}
Logger::Logger(SourceFile file, int line)
: impl_(INFO, 0, file, line)
{}
Logger::Logger(SourceFile file, int line, LogLevel level, const char* func)
: impl_(level, 0, file, line)
{
impl_.stream_<
base/LogStream.h
#ifndef MUDUO_BASE_lOGSTREAM_H
#define MUDUO_BASE_lOGSTREAM_H
#include
#include
#include
#include //memcpy
#ifndef MUDUO_STD_STRING
#include
#endif
#include
namespace muduo
{
namespace detail
{
const int kSmallBuffer = 4000;
const int kLargeBuffer = 4000*1000;
template
class FixedBuffer : boost::noncopyable
{
public:
FixedBuffer()
: cur_(data_)
{
setCookie(cookieStart);
}
~FixedBuffer()
{
setCookie(cookieEnd);
}
void append(const char* /*restrict*/ buf, size_t len)
{
//FIXME: append partially
// 当可用空间大于 len 才添加到末尾
if(implicit_cast(avail()) > len)
{
memcpy(cur_, buf, len);
cur_ += len;
}
}
const char* data() const { return data_;}
int length() const {return static_cast(cur_-data_);}
char* current(){return cur_;}
int avail() const {return static_cast(end() - cur_);}
void add(size_t len) {cur_ += len; }
void reset() { cur_ = data_;}
void bzero() {::bzero(data_, sizeof data_);}
const char* debugString();
void setCookie(void (*cookie)() ) { cookie_ = cookie; }
//for used by unit test
string asString() const { return string(data_,length()); }
private:
const char* end() const { return data_ + sizeof data_; }
//Must be outline function for cookies
//??
static void cookieStart();
static void cookieEnd();
void (*cookie_)();
char data_[SIZE];
char* cur_;
};
}
class LogStream : boost::noncopyable
{
typedef LogStream self;
public:
typedef detail::FixedBuffer Buffer;
self& operator<<(bool v)
{
buffer_.append(v ? "1" : "0", 1 );
return *this;
}
self& operator<<(short);
self& operator<<(unsigned short);
self& operator<<(int);
self& operator<<(unsigned int);
self& operator<<(long);
self& operator<<(unsigned long);
self& operator<<(long long);
self& operator<<(unsigned long long);
self& operator<<(const void*);
self& operator<<(float v)
{
*this << static_cast(v);
return *this;
}
self& operator<<(double);
// self& operator<<(long double);
self& operator<<(char v)
{
buffer_.append(&v, 1);
return *this;
}
// self& operator<<(signed char);
// self& operator<<(unsigned char);
self& operator<<(const char* v)
{
buffer_.append(v, strlen(v));
return *this;
}
self& operator<<(const string& v)
{
buffer_.append(v.c_str(), v.size());
return *this;
}
#ifndef MUDUO_STD_STRING
self& operator<<(const std::string& v)
{
buffer_.append(v.c_str(), v.size());
return *this;
}
#endif
self& operator<<(const StringPiece& v)
{
buffer_.append(v.data(), v.size());
return *this;
}
void append(const char* data, int len){ buffer_.append(data, len); }
const Buffer& buffer() const { return buffer_ ; }
void resetBuffer() {buffer_.reset(); }
private:
void staticCheck();
template
void formatInteger(T);
Buffer buffer_;
//数字格式化时的最大字节数
static const int kMaxNumericSize = 32;
};
class Fmt //: boost::noncopyable
{
public:
template
Fmt(const char* fmt, T val);
const char* data() const { return buf_; }
int length() const { return length_; }
private:
char buf_[32];
int length_;
};
inline LogStream& operator<<(LogStream& s, const Fmt& fmt)
{
s.append(fmt.data(), fmt.length());
return s;
}
}
#endif
base/LogStream.cc
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace muduo;
using namespace muduo::detail;
#pragma GCC diagnostic ignored "-Wtype-limits"
namespace muduo
{
namespace detail
{
const char digits[] = "9876543210123456789";
const char* zero = digits + 9;
BOOST_STATIC_ASSERT( sizeof(digits) == 20 );
const char digitsHex[] = "0123456789ABCDEF";
BOOST_STATIC_ASSERT(sizeof(digitsHex) == 17 );
template
size_t convert(char buf[], T value)
{
T i = value;
char* p = buf;
do
{
int lsd = static_cast(i % 10);
i /= 10;
*p++ =zero[lsd];
}while(i !=0 );
if(value < 0 )
{
*p++ = '-';
}
*p = '\0';
std::reverse(buf, p);
return p-buf;
}
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;
}
}
}
template
const char* FixedBuffer::debugString()
{
*cur_ = '\0';
return data_;
}
template
void FixedBuffer::cookieEnd()
{}
template
void FixedBuffer::cookieStart()
{}
template class FixedBuffer;
template class FixedBuffer;
void LogStream::staticCheck()
{
BOOST_STATIC_ASSERT(kMaxNumericSize-10 > std::numeric_limits::digits10);
BOOST_STATIC_ASSERT(kMaxNumericSize - 10 > std::numeric_limits::digits10);
BOOST_STATIC_ASSERT(kMaxNumericSize - 10 > std::numeric_limits::digits10);
BOOST_STATIC_ASSERT(kMaxNumericSize - 10 > std::numeric_limits::digits10);
}
template
void LogStream::formatInteger(T v)
{
if(buffer_.avail() >= kMaxNumericSize)
{
size_t len = convert(buffer_.current(), v);//追加到curr_后面
buffer_.add(len);
}
}
LogStream& LogStream::operator<<(short v)
{
*this<(v);
return *this;
}
LogStream& LogStream::operator<<(unsigned short v)
{
*this << static_cast(v);
return *this;
}
LogStream& LogStream::operator<<(int v)
{
formatInteger(v);
return *this;
}
LogStream& LogStream::operator<<(unsigned int v)
{
formatInteger(v);
return *this;
}
LogStream& LogStream::operator<<(long v)
{
formatInteger(v);
return *this;
}
LogStream& LogStream::operator<<(unsigned long v)
{
formatInteger(v);
return *this;
}
LogStream& LogStream::operator<<(long long v)
{
formatInteger(v);
return *this;
}
LogStream& LogStream::operator<<(unsigned long long v)
{
formatInteger(v);
return *this;
}
LogStream& LogStream::operator<<(const void* p)
{
uintptr_t v = reinterpret_cast(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;
}
// FIXME: replace this with Grisu3 by Florian Loitsch.
LogStream& LogStream::operator<<(double v)
{
if (buffer_.avail() >= kMaxNumericSize)
{
int len = snprintf(buffer_.current(), kMaxNumericSize, "%.12g", v);
buffer_.add(len);
}
return *this;
}
template
Fmt::Fmt(const char* fmt, T val)
{
BOOST_STATIC_ASSERT(boost::is_arithmetic::value == true);
length_ = snprintf(buf_, sizeof buf_, fmt, val);
assert(static_cast(length_) < sizeof buf_);
}
// Explicit instantiations
template Fmt::Fmt(const char* fmt, char);
template Fmt::Fmt(const char* fmt, short);
template Fmt::Fmt(const char* fmt, unsigned short);
template Fmt::Fmt(const char* fmt, int);
template Fmt::Fmt(const char* fmt, unsigned int);
template Fmt::Fmt(const char* fmt, long);
template Fmt::Fmt(const char* fmt, unsigned long);
template Fmt::Fmt(const char* fmt, long long);
template Fmt::Fmt(const char* fmt, unsigned long long);
template Fmt::Fmt(const char* fmt, float);
template Fmt::Fmt(const char* fmt, double);
参考:c++教程网
muduo网络库
linux多线程服务器端编程》.陈硕