用C++实现一个Log系统

来源:互联网 发布:iphone pro画笔软件 编辑:程序博客网 时间:2024/06/03 16:59

提要

最近在写一些C++的图形代码,在调试和测试过程中都会需要在终端打印一些信息出来。之前的做法是直接用

std::cout<<"Some Word"<<std::endl;

这样做其实非常的麻烦,每次都要打很多的字母还有特殊符号,除去我要打印的内容,还需要按下28下键盘,简直不能忍!

参考Unity里面的打log的方式

Debug.Log("Some Word");

或者Qt中的处理方式

qDebug() << "Some Word";

这两种都方便太多。

今天要实现的Log系统需要满足的特性有:

1.很方便地在终端打印各种类型数据信息;

2.可以区分Log等级;

3.打印信息的同时能够提供打印语句的文件,函数名,行号


类说明

简单地画了下UML,主要分为下面几个类


简单说一下类的作用

MessageLogContext

记录Log的上下文,也就是Log处在的文件,函数名,行号。

MessageLogger

主要的Log类,提供了上次调用的一些接口,注意一下这个宏比较有意思

qDebug MessageLogger(__FILE__, __FUNCTION__, __LINE__).debug

这样当使用

qDebug()

的时候,

宏替换就直接转换成了MessageLogger的构造函数

MessageLogger(__FILE__, __FUNCTION__, __LINE__).debug()

等于是先构造MessageLogger,然后调用这个对象的debug()方法。


Debug

具体处理Debug信息的类。

用了一个内部Stream结构体来记录Debug信息,记得在使用前要new,析构的时候delete掉。

重构了很多的<<方法,就是为了能处理多种数据类型,包括自定义的类。还可以通过模板来打印stl里面的东西。

LogToConsole是将log信息打印到终端的函数,在析构函数中会被调用。如果想要实现更加炫酷的打印log方式(各种颜色),扩展这个函数就好了。


整个Log的流程如下图


测试代码

void DebugTest(){Vector2 v = Vector2(1, 1);Vector2 v2 = Vector2(2, 1);Vector3 v3 = Vector3(0, 2, 1);Vector3 v4 = Vector3(0, 2, 1);Vector3 v5 = Vector3(23, 112, 22);Vector3 v6 = Vector3(23, 112, 22);std::vector<Vector3> vec;vec.push_back(v3);vec.push_back(v4);vec.push_back(v5);vec.push_back(v6);vec.push_back(v6);vec.push_back(v6);vec.push_back(v6);vec.push_back(v6);std::string testStr = "vector Test";qDebug() << "Hello Debug";qDebug() <<""<< v << v2<< v3;qDebug() << v3;qWarning() << vec;}

运行结果





代码清单

MessageLogContext.h
#pragma once#include <string>class MessageLogContext{public:MessageLogContext() : line(0), file(0), function(0) {}MessageLogContext(const char *fileName, const char *functionName, int lineNumber): file(fileName), function(functionName), line(lineNumber) {}int line;const char *file;const char *function;void copy(const MessageLogContext &logContext){this->file = logContext.file;this->line = logContext.line;this->function = logContext.function;}private:friend class MessageLogger;friend class Debug;};


Log.h
#pragma once#define qDebug MessageLogger(__FILE__, __FUNCTION__, __LINE__).debug#define qInfo MessageLogger(__FILE__, __FUNCTION__, __LINE__).info#define qWarning MessageLogger(__FILE__, __FUNCTION__, __LINE__).warning#define qCritical MessageLogger(__FILE__, __FUNCTION__, __LINE__).critical#define qFatal MessageLogger(__FILE__, __FUNCTION__, __LINE__).fatal#include "Debug.h"#include "MessageLogContext.h"class MessageLogger{public:MessageLogger() : context(){}MessageLogger(const char *fileName, const char *functionName, int lineNumber): context(fileName, functionName, lineNumber) {}Debug info() const;Debug warning() const;Debug critical() const;Debug debug() const;protected:private:MessageLogContext context;};




Log.cpp

#include "Log.h"Debug MessageLogger::debug() const{std::string debug = "debug";Debug dbg = Debug(&debug);MessageLogContext &ctxt = dbg.stream->context;ctxt.copy(context);dbg.stream->logType = Info;return dbg;}Debug MessageLogger::info() const{Debug dbg = Debug();MessageLogContext &ctxt = dbg.stream->context;ctxt.copy(context);dbg.stream->logType = Info;return dbg;}Debug MessageLogger::warning() const{Debug dbg = Debug();MessageLogContext &ctxt = dbg.stream->context;ctxt.copy(context);dbg.stream->logType = Warning;return dbg;}Debug MessageLogger::critical() const{Debug dbg = Debug();MessageLogContext &ctxt = dbg.stream->context;ctxt.copy(context);dbg.stream->logType = Error;return dbg;}



Debug.h

#pragma once#include <iostream>  #include <iomanip>  #include <fstream>  #include <string>  #include <cstdlib>  #include <stdint.h>  #include <sstream>  #include "Math/Vector2.h"  #include "Math/Vector3.h"  #include <vector>//#include "Log.h"#include "MessageLogContext.h"enum LogType{Info,Warning,Error,Default,};class Debug{public:struct Stream {Stream():ss(), space(true), context() {}Stream(std::string *s) :ss(*s), space(true), context(){}std::ostringstream ss;bool space;MessageLogContext context;LogType logType;} *stream;Debug() : stream(new Stream()) {}inline Debug(std::string *s) : stream(new Stream(s)) {}~Debug();inline Debug &operator<<(bool t) { stream->ss<<(t ? "true" : "false"); return maybeSpace(); }inline Debug &operator<<(char t) { stream->ss<< t; return maybeSpace(); }inline Debug &operator<<(signed short t) { stream->ss << t; return maybeSpace(); }inline Debug &operator<<(unsigned short t) { stream->ss << t; return maybeSpace(); }inline Debug &operator<<(std::string s) { stream->ss << s; return maybeSpace(); }inline Debug &operator<<(const char* c) { stream->ss << c; return maybeSpace(); }inline Debug &operator<<(Vector2 vec) { stream->ss << "(" << vec.x <<","<< vec.y<<")"; return maybeSpace(); }inline Debug &operator<<(Vector3 vec) { stream->ss << "(" << vec.x << "," << vec.y <<"," << vec.z << ")"; return maybeSpace(); }inline Debug &space() { stream->space = true; stream->ss << ' '; return *this; }inline Debug &nospace() { stream->space = false; return *this; }inline Debug &maybeSpace() { if (stream->space) stream->ss << ' '; return *this; }template <typename T>inline Debug &operator<<(const std::vector<T> &vec){stream->ss << '(';for (int i = 0; i < vec.size(); ++i) {stream->ss << vec.at(i);stream->ss << ", ";}stream->ss << ')';return maybeSpace();}void LogToConsole(LogType type, const MessageLogContext &context, std::string logBuffer);private:static Debug* _instance;};


Debug.cpp

#include "Debug.h"Debug::~Debug(){LogToConsole(stream->logType, stream->context, stream->ss.str());delete stream;}void Debug::LogToConsole(LogType type, const MessageLogContext &context, std::string logBuffer){std::string logString;switch (type){case Error:logString.append("Error! ");break;case Info://logString.append("");break;case Warning:logString.append("Warning! ");break;default:break;}logString.append(logBuffer);logString.append("......");logString.append(context.file);logString.append(" ");logString.append(context.function);logString.append("()");std::cout << logString <<" line: " << context.line << " "  << std::endl;//logString.append(context.line);}



参考

Qt source code

Qt Documentation http://doc.qt.io/qt-4.8/qdebug.html

http://www.cplusplus.com/

5 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 婴儿自己把眼珠子抠红了怎么办 如果美陆战队员进入台湾那怎么办? 顺产生完小孩吸不通奶怎么办 耐克空军一号白色底发黄怎么办 中行网银u盾丢了怎么办 有人用你的手机号码不停注册怎么办 获得公开你微信头像的权限是怎么办 手机能进的网站电脑进不去怎么办 苹果8p下不了微信怎么办 苹果手机版本过底不能下微信怎么办 手机打开视频跳转到qq是怎么办 淘宝店铺显示服务竟然出错了怎么办 母羊下完羊羔把羊衣吃了怎么办? 移植后56天有黑色东西怎么办 我家的金丝熊浑身都是尿怎么办 一键启动车钥匙丢了怎么办 把爷爷的遗物弄丢了怎么办 如果你娶了一个傻子你怎么办 在国外订机票手机收不到信息怎么办 网上买机票名字写错了怎么办 买机票名字错了一个字怎么办 微店没收到货却显示已收货怎么办? 手机存的照片误删了怎么办 魔兽世界把要用的装备分解了怎么办 邻居家的狗见到我就叫怎么办 我的世界玩的时间长会卡应该怎么办 网易我的世界密码账号都忘了怎么办 我的世界创建世界画面乱码了怎么办 网易我的世界云端存档不够用怎么办 玩刺激战场带耳机声音有延迟怎么办 我的世界手机版狼变色怎么办 我的世界开了光影太阳太刺眼怎么办 我的世界饥饿值掉的慢怎么办 我的世界合装备过于昂贵怎么办 我的世界故事模式屏幕是黑的怎么办 人物只剩下轮廓的图用ps怎么办 两年义务兵考军校分数不够怎么办 大学生兵考上军校后原学籍怎么办 我的世界工业附魔到精准采集怎么办 交换生在台期间遗失通行证怎么办 驾驶证上的号码是士兵证号怎么办