muduo LogStream详解

1. 简介

LogStream用于加载任意数据到字符缓冲区。
对于任意数据,总是可以使用LogStream os;os << 数据的方式加载数据到字符缓冲区,之后缓冲区的内容可以根据需求重定向输出到不同的目标,如文件、终端、socket。

2. 类与接口

FixedBuffer为LogStream提供字符串缓冲区,成员变量:

char data_[SIZE];   // 用于缓存数据
char* cur_;         // 指向data_最后一位写入数据下一个字节的指针

在这里插入图片描述
FixedBuffer的实现为一个非类型参数的模板类,传入一个非类型参数SIZE表示缓冲区的大小。通过成员 data_首地址、cur_指针、end()完成对缓冲区的各项操作。通过append()接口把日志内容添加到缓冲区来。

LogStream
将要输出的信息加载到FixedBuffer缓冲区,等待Logger进一步处理,核心在重载<<如果我们有LogStream os,可以使用os << 数据;将任意字符类型加载到缓冲区,包括char、char[]、string、StringPiece等。

// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)

#include "LogStream.h"

#include <algorithm>
#include <limits>
#include <type_traits>
#include <assert.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>

#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif

#include <inttypes.h>

using namespace detail;

// TODO: better itoa.
#if defined(__clang__)
#pragma clang diagnostic ignored "-Wtautological-compare"
#else
#pragma GCC diagnostic ignored "-Wtype-limits"
#endif

namespace detail
{

const char digits[] = "9876543210123456789";
const char* zero = digits + 9;
static_assert(sizeof(digits) == 20, "wrong number of digits");

const char digitsHex[] = "0123456789ABCDEF";
static_assert(sizeof digitsHex == 17, "wrong number of digitsHex");

// Efficient Integer to String Conversions, by Matthew Wilson.
// 将整数value转化成字符串形式,结果保存到buf
// 返回转化后字符串的长度
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;
}

// 将value转化成16进制的字符串,结果保存到buf
// 返回转化后字符串的长度
size_t convertHex(char buf[], uintptr_t value)
{
	uintptr_t i = value;
	char* p = buf;

	do {
		int lsd = static_cast<int>(i % 16);
		i /= 16;
		*p++ = digitsHex[lsd];
	} while (i != 0);

	*p = '\0';
	std::reverse(buf, p);

	return p - buf;
}

template class FixedBuffer<kSmallBuffer>;
template class FixedBuffer<kLargeBuffer>;

}  // namespace detail

/*
 Format a number with 5 characters, including SI units.
 [0,     999]
 [1.00k, 999k]
 [1.00M, 999M]
 [1.00G, 999G]
 [1.00T, 999T]
 [1.00P, 999P]
 [1.00E, inf)
*/
std::string formatSI(int64_t s)
{
	double n = static_cast<double>(s);
	char buf[64];
	if (s < 1000)
		snprintf(buf, sizeof(buf), "%" PRId64, s);
	else if (s < 9995)
		snprintf(buf, sizeof(buf), "%.2fk", n/1e3);
	else if (s < 99950)
		snprintf(buf, sizeof(buf), "%.1fk", n/1e3);
	else if (s < 999500)
		snprintf(buf, sizeof(buf), "%.0fk", n/1e3);
	else if (s < 9995000)
		snprintf(buf, sizeof(buf), "%.2fM", n/1e6);
	else if (s < 99950000)
		snprintf(buf, sizeof(buf), "%.1fM", n/1e6);
	else if (s < 999500000)
		snprintf(buf, sizeof(buf), "%.0fM", n/1e6);
	else if (s < 9995000000)
		snprintf(buf, sizeof(buf), "%.2fG", n/1e9);
	else if (s < 99950000000)
		snprintf(buf, sizeof(buf), "%.1fG", n/1e9);
	else if (s < 999500000000)
		snprintf(buf, sizeof(buf), "%.0fG", n/1e9);
	else if (s < 9995000000000)
		snprintf(buf, sizeof(buf), "%.2fT", n/1e12);
	else if (s < 99950000000000)
		snprintf(buf, sizeof(buf), "%.1fT", n/1e12);
	else if (s < 999500000000000)
		snprintf(buf, sizeof(buf), "%.0fT", n/1e12);
	else if (s < 9995000000000000)
		snprintf(buf, sizeof(buf), "%.2fP", n/1e15);
	else if (s < 99950000000000000)
		snprintf(buf, sizeof(buf), "%.1fP", n/1e15);
	else if (s < 999500000000000000)
		snprintf(buf, sizeof(buf), "%.0fP", n/1e15);
	else
		snprintf(buf, sizeof(buf), "%.2fE", n/1e18);
	return buf;
}

/*
 [0, 1023]
 [1.00Ki, 9.99Ki]
 [10.0Ki, 99.9Ki]
 [ 100Ki, 1023Ki]
 [1.00Mi, 9.99Mi]
*/
std::string formatIEC(int64_t s)
{
	double n = static_cast<double>(s);
	char buf[64];
	const double Ki = 1024.0;
	const double Mi = Ki * 1024.0;
	const double Gi = Mi * 1024.0;
	const double Ti = Gi * 1024.0;
	const double Pi = Ti * 1024.0;
	const double Ei = Pi * 1024.0;

	if (n < Ki)
		snprintf(buf, sizeof buf, "%" PRId64, s);
	else if (n < Ki*9.995)
		snprintf(buf, sizeof buf, "%.2fKi", n / Ki);
	else if (n < Ki*99.95)
		snprintf(buf, sizeof buf, "%.1fKi", n / Ki);
	else if (n < Ki*1023.5)
		snprintf(buf, sizeof buf, "%.0fKi", n / Ki);

	else if (n < Mi*9.995)
		snprintf(buf, sizeof buf, "%.2fMi", n / Mi);
	else if (n < Mi*99.95)
		snprintf(buf, sizeof buf, "%.1fMi", n / Mi);
	else if (n < Mi*1023.5)
		snprintf(buf, sizeof buf, "%.0fMi", n / Mi);

	else if (n < Gi*9.995)
		snprintf(buf, sizeof buf, "%.2fGi", n / Gi);
	else if (n < Gi*99.95)
		snprintf(buf, sizeof buf, "%.1fGi", n / Gi);
	else if (n < Gi*1023.5)
		snprintf(buf, sizeof buf, "%.0fGi", n / Gi);

	else if (n < Ti*9.995)
		snprintf(buf, sizeof buf, "%.2fTi", n / Ti);
	else if (n < Ti*99.95)
		snprintf(buf, sizeof buf, "%.1fTi", n / Ti);
	else if (n < Ti*1023.5)
		snprintf(buf, sizeof buf, "%.0fTi", n / Ti);

	else if (n < Pi*9.995)
		snprintf(buf, sizeof buf, "%.2fPi", n / Pi);
	else if (n < Pi*99.95)
		snprintf(buf, sizeof buf, "%.1fPi", n / Pi);
	else if (n < Pi*1023.5)
		snprintf(buf, sizeof buf, "%.0fPi", n / Pi);

	else if (n < Ei*9.995)
		snprintf(buf, sizeof buf, "%.2fEi", n / Ei );
	else
		snprintf(buf, sizeof buf, "%.1fEi", n / Ei );
	return buf;
}



template<int SIZE>
const char* FixedBuffer<SIZE>::debugString()
{
	*cur_ = '\0';
	return data_;
}

template<int SIZE>
void FixedBuffer<SIZE>::cookieStart()
{
}

template<int SIZE>
void FixedBuffer<SIZE>::cookieEnd()
{
}


// 静态检查,用于检查一些类型的大小
void LogStream::staticCheck()
{
	static_assert(kMaxNumericSize - 10 > std::numeric_limits<double>::digits10,
	              "kMaxNumericSize is large enough");
	static_assert(kMaxNumericSize - 10 > std::numeric_limits<long double>::digits10,
	              "kMaxNumericSize is large enough");
	static_assert(kMaxNumericSize - 10 > std::numeric_limits<long>::digits10,
	              "kMaxNumericSize is large enough");
	static_assert(kMaxNumericSize - 10 > std::numeric_limits<long long>::digits10,
	              "kMaxNumericSize is large enough");
}

// 格式化整数到缓冲区
template<typename T>
void LogStream::formatInteger(T v)
{
	if (buffer_.avail() >= kMaxNumericSize) {
		size_t len = convert(buffer_.current(), v);
		buffer_.add(len);
	}
}

// 重载<<将任意类型的数据通过运算符<<加载到缓冲区
LogStream& LogStream::operator<<(short v)
{
	*this << static_cast<int>(v);
	return *this;
}

LogStream& LogStream::operator<<(unsigned short v)
{
	*this << static_cast<unsigned int>(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<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;
}

// 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;
}

// 按照fmt格式将val 格式化成字符串放入buf_中
template<typename T>
Fmt::Fmt(const char* fmt, T val)
{
	static_assert(std::is_arithmetic<T>::value == true, "Must be arithmetic type");

	length_ = snprintf(buf_, sizeof buf_, fmt, val);
	assert(static_cast<size_t>(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);
3. 源码

Github

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值