muduo源码分析:日志相关类(1)

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构造的时候就在构造列表中构造了ImplImpl构造的时候会格式化录入错误信息如进程号tid,时间等 到 impl的成员变量LogStream  stream_  的成员变量 buff_

buff_定义 :typedef detail::FixedBuffer Buffer ;  Buffer buff_;

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多线程服务器端编程》.陈硕






你可能感兴趣的:(muduo,c++,linux)