base11. Logger日志类和Impl日志实现类

2024-03-10 21:58
文章标签 实现 日志 logger impl base11

本文主要是介绍base11. Logger日志类和Impl日志实现类,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

muduo库通过这几个宏的日志输出,既可以输出到标准输出,又可以输出到宏
__FILE__是这一行代码所在的文件名,__LINE__是这一行代码所在的行号

#define LOG_TRACE if (muduo::Logger::logLevel() <= muduo::Logger::TRACE) \//构造匿名对象,在调用完Logger.stream()之后,会自动调用析构用函数// // 匿名对象只存在于该行代码,离开这行代码后立即调用析构函数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()

Logger类图在这里插入图片描述
数据成员:

Impl impl_:一个Impl类型的impl_对象,impl_包含日志的实现以及格式化
enum LogLevel:枚举类LogLevel

typedef

typedef void (OutputFunc)(const char msg, int len)
typedef void (*FlushFunc)()

成员函数:

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():析构函数,调用impl_.finish(),是输出的最后一步
LogStream& stream():返回LogStream类型的stream_对象
static LogLevel logLevel():
static void setLogLevel(LogLevel level):设置日志等级
static void setOutput(OutputFunc):用来更改默认输出设备
static void setFlush(FlushFunc):用来更改默认输出设备的冲洗

Impl类图
Impl类包含日志的实现以及格式化
在这里插入图片描述
数据成员:

Timestamp time_:一个Timestamp类型的时间戳time_
LogStream stream_:一个类型为LogStream的stream_对象,用来输出信息到缓冲区FixedBuffer
LogLevel level_:一个LogLevel枚举类型的日志等级level_
int line_:一个line_对象
SourceFile basename_:日志文件的basename_

typedef

typedef Logger::LogLevel LogLevel

成员函数:

Impl(LogLevel level, int old_errno, const SourceFile& file, int line):构造函数
void formatTime():格式化函数
void finish():输出的最后一步

Logging.h

#ifndef MUDUO_BASE_LOGGING_H
#define MUDUO_BASE_LOGGING_H#include <muduo/base/LogStream.h>
#include <muduo/base/Timestamp.h>namespace muduo
{
//最外层日志类Logger类,负责日志的级别
class Logger
{public:enum LogLevel{TRACE,DEBUG,INFO,WARN,ERROR,FATAL,NUM_LOG_LEVELS,};// compile time calculation of basename of source fileclass SourceFile{public:template<int N>inline SourceFile(const char (&arr)[N]): data_(arr),size_(N-1){const char* slash = strrchr(data_, '/'); // builtin functionif (slash){data_ = slash + 1;size_ -= static_cast<int>(data_ - arr);}}explicit SourceFile(const char* filename): data_(filename){const char* slash = strrchr(filename, '/');if (slash){data_ = slash + 1;}size_ = static_cast<int>(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_对象LogStream& stream() { return impl_.stream_; }//static LogLevel logLevel();//设置日志等级static void setLogLevel(LogLevel level);typedef void (*OutputFunc)(const char* msg, int len);typedef void (*FlushFunc)();//setOutput()、setFlush()用来更改默认输出设备以及默认输出设备的冲洗static void setOutput(OutputFunc);static void setFlush(FlushFunc);private:
//Logger类内部包装了一个Impl类,包含日志的实现以及格式化
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_对象,用来输出信息到缓冲区FixedBufferLogStream stream_;LogLevel level_;int line_;SourceFile basename_;
};Impl impl_;};extern Logger::LogLevel g_logLevel;inline Logger::LogLevel Logger::logLevel()
{return g_logLevel;
}//muduo库通过这几个宏的日志输出,既可以输出到标准输出,又可以输出到宏
//__FILE__是这一行代码所在的文件名,__LINE__是这一行代码所在的行号
#define LOG_TRACE if (muduo::Logger::logLevel() <= muduo::Logger::TRACE) \//构造匿名对象,在调用完Logger.stream()之后,会自动调用析构用函数// // 匿名对象只存在于该行代码,离开这行代码后立即调用析构函数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);// Taken from glog/logging.h
//
// Check that the input is non NULL.  This very useful in constructor
// initializer lists.#define CHECK_NOTNULL(val) \::muduo::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val))// A small helper for CHECK_NOTNULL().
template <typename T>
T* CheckNotNull(Logger::SourceFile file, int line, const char *names, T* ptr) {if (ptr == NULL) {Logger(file, line, Logger::FATAL).stream() << names;}return ptr;
}}#endif  // MUDUO_BASE_LOGGING_H

Logging.cc

#include <muduo/base/Logging.h>#include <muduo/base/CurrentThread.h>
#include <muduo/base/StringPiece.h>
#include <muduo/base/Timestamp.h>#include <errno.h>
#include <stdio.h>
#include <string.h>#include <sstream>namespace muduo
{/*
class LoggerImpl
{public:typedef Logger::LogLevel LogLevel;LoggerImpl(LogLevel level, int old_errno, const char* file, int line);void finish();Timestamp time_;LogStream stream_;LogLevel level_;int line_;const char* fullname_;const char* basename_;
};
*/__thread char t_errnobuf[512];
__thread char t_time[32];
__thread time_t t_lastSecond;const char* strerror_tl(int savedErrno)
{return strerror_r(savedErrno, t_errnobuf, sizeof t_errnobuf);
}Logger::LogLevel initLogLevel()
{return Logger::TRACE;/*if (::getenv("MUDUO_LOG_TRACE"))return Logger::TRACE;else if (::getenv("MUDUO_LOG_DEBUG"))return Logger::DEBUG;elsereturn Logger::INFO;*/
}Logger::LogLevel g_logLevel = initLogLevel();const char* LogLevelName[Logger::NUM_LOG_LEVELS] =
{"TRACE ","DEBUG ","INFO  ","WARN  ","ERROR ","FATAL ",
};// helper class for known string length at compile time
class T
{public:T(const char* str, unsigned len):str_(str),len_(len){assert(strlen(str) == len_);}const char* str_;const unsigned len_;
};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;
}
//默认输出函数defaultOutput()输出到标准输出stdout
void defaultOutput(const char* msg, int len)
{size_t n = fwrite(msg, 1, len, stdout);//FIXME check n(void)n;
}
//默认冲洗函数defaultFlush()冲洗stdout
void defaultFlush()
{fflush(stdout);
}
//g_output()默认调用defaultOutput()
Logger::OutputFunc g_output = defaultOutput;
//g_flush()默认调用defaultFlush()
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_ << strerror_tl(savedErrno) << " (errno=" << savedErrno << ") ";}
}void Logger::Impl::formatTime()
{int64_t microSecondsSinceEpoch = time_.microSecondsSinceEpoch();time_t seconds = static_cast<time_t>(microSecondsSinceEpoch / 1000000);int microseconds = static_cast<int>(microSecondsSinceEpoch % 1000000);if (seconds != t_lastSecond){t_lastSecond = seconds;struct tm tm_time;::gmtime_r(&seconds, &tm_time); // FIXME TimeZone::fromUtcTimeint 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_ << func << ' ';
}Logger::Logger(SourceFile file, int line, LogLevel level): impl_(level, 0, file, line)
{
}Logger::Logger(SourceFile file, int line, bool toAbort): impl_(toAbort?FATAL:ERROR, errno, file, line)
{
}//无名对象销毁时调用析构函数,把存于缓冲区(FixedBuffer类)中的数据利用g_output()输出
Logger::~Logger()
{impl_.finish();const LogStream::Buffer& buf(stream().buffer());//g_output()输出缓冲区的数据g_output(buf.data(), buf.length());//impl_.level_ == FATAL时终止程序,在终止程序之前,需要冲洗缓冲区if (impl_.level_ == FATAL){//调用g_flush()冲洗缓冲区g_flush();abort();}
}void Logger::setLogLevel(Logger::LogLevel level)
{g_logLevel = level;
}void Logger::setOutput(OutputFunc out)
{g_output = out;
}void Logger::setFlush(FlushFunc flush)
{g_flush = flush;
}

这篇关于base11. Logger日志类和Impl日志实现类的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/795653

相关文章

使用shardingsphere实现mysql数据库分片方式

《使用shardingsphere实现mysql数据库分片方式》本文介绍如何使用ShardingSphere-JDBC在SpringBoot中实现MySQL水平分库,涵盖分片策略、路由算法及零侵入配置... 目录一、ShardingSphere 简介1.1 对比1.2 核心概念1.3 Sharding-Sp

Java+AI驱动实现PDF文件数据提取与解析

《Java+AI驱动实现PDF文件数据提取与解析》本文将和大家分享一套基于AI的体检报告智能评估方案,详细介绍从PDF上传、内容提取到AI分析、数据存储的全流程自动化实现方法,感兴趣的可以了解下... 目录一、核心流程:从上传到评估的完整链路二、第一步:解析 PDF,提取体检报告内容1. 引入依赖2. 封装

Java实现复杂查询优化的7个技巧小结

《Java实现复杂查询优化的7个技巧小结》在Java项目中,复杂查询是开发者面临的“硬骨头”,本文将通过7个实战技巧,结合代码示例和性能对比,手把手教你如何让复杂查询变得优雅,大家可以根据需求进行选择... 目录一、复杂查询的痛点:为何你的代码“又臭又长”1.1冗余变量与中间状态1.2重复查询与性能陷阱1.

深度剖析SpringBoot日志性能提升的原因与解决

《深度剖析SpringBoot日志性能提升的原因与解决》日志记录本该是辅助工具,却为何成了性能瓶颈,SpringBoot如何用代码彻底破解日志导致的高延迟问题,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言第一章:日志性能陷阱的底层原理1.1 日志级别的“双刃剑”效应1.2 同步日志的“吞吐量杀手”

python 线程池顺序执行的方法实现

《python线程池顺序执行的方法实现》在Python中,线程池默认是并发执行任务的,但若需要实现任务的顺序执行,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋... 目录方案一:强制单线程(伪顺序执行)方案二:按提交顺序获取结果方案三:任务间依赖控制方案四:队列顺序消

Redis实现分布式锁全过程

《Redis实现分布式锁全过程》文章介绍Redis实现分布式锁的方法,包括使用SETNX和EXPIRE命令确保互斥性与防死锁,Redisson客户端提供的便捷接口,以及Redlock算法通过多节点共识... 目录Redis实现分布式锁1. 分布式锁的基本原理2. 使用 Redis 实现分布式锁2.1 获取锁

Linux实现查看某一端口是否开放

《Linux实现查看某一端口是否开放》文章介绍了三种检查端口6379是否开放的方法:通过lsof查看进程占用,用netstat区分TCP/UDP监听状态,以及用telnet测试远程连接可达性... 目录1、使用lsof 命令来查看端口是否开放2、使用netstat 命令来查看端口是否开放3、使用telnet

使用SpringBoot+InfluxDB实现高效数据存储与查询

《使用SpringBoot+InfluxDB实现高效数据存储与查询》InfluxDB是一个开源的时间序列数据库,特别适合处理带有时间戳的监控数据、指标数据等,下面详细介绍如何在SpringBoot项目... 目录1、项目介绍2、 InfluxDB 介绍3、Spring Boot 配置 InfluxDB4、I

基于Java和FFmpeg实现视频压缩和剪辑功能

《基于Java和FFmpeg实现视频压缩和剪辑功能》在视频处理开发中,压缩和剪辑是常见的需求,本文将介绍如何使用Java结合FFmpeg实现视频压缩和剪辑功能,同时去除数据库操作,仅专注于视频处理,需... 目录引言1. 环境准备1.1 项目依赖1.2 安装 FFmpeg2. 视频压缩功能实现2.1 主要功

使用Python实现无损放大图片功能

《使用Python实现无损放大图片功能》本文介绍了如何使用Python的Pillow库进行无损图片放大,区分了JPEG和PNG格式在放大过程中的特点,并给出了示例代码,JPEG格式可能受压缩影响,需先... 目录一、什么是无损放大?二、实现方法步骤1:读取图片步骤2:无损放大图片步骤3:保存图片三、示php