程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 用C++實現一個Log系統

用C++實現一個Log系統

編輯:關於C++

提要

最近在寫一些C++的圖形代碼,在調試和測試過程中都會需要在終端打印一些信息出來。之前的做法是直接用

 

std::cout<

 

這樣做其實非常的麻煩,每次都要打很多的字母還有特殊符號,除去我要打印的內容,還需要按下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 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 

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   
#include   
#include   
#include   
#include   
#include   
#include   
#include Math/Vector2.h  
#include Math/Vector3.h  
#include 
//#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 
	inline Debug &operator<<(const std::vector &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);
}


 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved