1、debug_log.h头文件
/******************************************************************************
版权所有 (C), 2016-2017, 西安网络科技有限公司
******************************************************************************
文 件 名 : debug_log.h
版 本 号 : V1.0
作 者 : zhangcan
生成日期 : 2017年2月28日
功能描述 : 日志类头文件
修改历史 :
******************************************************************************/
#ifdef __cplusplus
#include <string>
#endif
#ifndef _DEBUG_LOG_H_
#define _DEBUG_LOG_H_
#ifdef __cplusplus
namespace debug_log {
class DebugLog {
public:
DebugLog() :
m_debugLevel(-1),
m_fileName("") { }
virtual ~DebugLog();
virtual void write(int level, const std::string &msg);
bool isLogFileSet();
bool isLogLevelSet();
void setDebugLogLevel(int level);
void setDebugLogFile(std::string fileName, std::string *error);
const std::string& getDebugLogFile();
int getDebugLogLevel();
private:
/* 日志级别 */
int m_debugLevel;
/* 日志文件 */
std::string m_fileName;
};
} // namespace debug_log
#endif // __cplusplus
#endif // _DEBUG_LOG_H_
/******************************************************************************
版权所有 (C), 2016-2017, 西安网络科技有限公司
******************************************************************************
文 件 名 : debug_log.cpp
版 本 号 : V1.0
作 者 : zhangcan
生成日期 : 2017年2月28日
功能描述 : 日志类接口实现
修改历史 :
******************************************************************************/
#include <stddef.h>
#include <fstream>
#include "debug_log.h"
#include "debug_log_writer.h"
namespace debug_log {
/*****************************************************************************
函 数 名 : debug_log.DebugLog.~DebugLog
功能描述 : 析构函数
输入参数 : 无
输出参数 : 无
返 回 值 : 无
作 者 : zhangcan
日 期 : 2017年2月28日
*****************************************************************************/
DebugLog::~DebugLog() {
DebugLogWriter::getInstance().close(this->m_fileName);
}
/*****************************************************************************
函 数 名 : debug_log.DebugLog.setDebugLogFile
功能描述 : 设置日志文件
输入参数 : std::string fileName
std::string *error
输出参数 : 无
返 回 值 : 无
作 者 : zhangcan
日 期 : 2017年2月28日
*****************************************************************************/
void DebugLog::setDebugLogFile(std::string fileName, std::string *error) {
if (this->isLogFileSet()) {
DebugLogWriter::getInstance().close(this->m_fileName);
}
this->m_fileName = fileName;
DebugLogWriter::getInstance().open(this->m_fileName, error);
}
/*****************************************************************************
函 数 名 : debug_log.DebugLog.setDebugLogLevel
功能描述 : 设置日志级别
输入参数 : int level
输出参数 : 无
返 回 值 : 无
作 者 : zhangcan
日 期 : 2017年2月28日
*****************************************************************************/
void DebugLog::setDebugLogLevel(int level) {
this->m_debugLevel = level;
}
/*****************************************************************************
函 数 名 : debug_log.DebugLog.isLogFileSet
功能描述 : 是否设置日志文件
输入参数 : 无
输出参数 : 无
返 回 值 : bool
作 者 : zhangcan
日 期 : 2017年2月28日
*****************************************************************************/
bool DebugLog::isLogFileSet() {
return (this->m_fileName.empty() == false);
}
/*****************************************************************************
函 数 名 : debug_log.DebugLog.isLogLevelSet
功能描述 : 是否设置日志级别
输入参数 : 无
输出参数 : 无
返 回 值 : bool
作 者 : zhangcan
日 期 : 2017年2月28日
*****************************************************************************/
bool DebugLog::isLogLevelSet() {
return (this->m_debugLevel != -1);
}
/*****************************************************************************
函 数 名 : debug_log.DebugLog.getDebugLogFile
功能描述 : 获取日志文件
输入参数 : 无
输出参数 : 无
返 回 值 : const std::string&
作 者 : zhangcan
日 期 : 2017年2月28日
*****************************************************************************/
const std::string& DebugLog::getDebugLogFile() {
return this->m_fileName;
}
/*****************************************************************************
函 数 名 : debug_log.DebugLog.getDebugLogLevel
功能描述 : 获取日志级别
输入参数 : 无
输出参数 : 无
返 回 值 : int
作 者 : zhangcan
日 期 : 2017年2月28日
*****************************************************************************/
int DebugLog::getDebugLogLevel() {
return (this->m_debugLevel < 0) ? 0 : this->m_debugLevel;
}
/*****************************************************************************
函 数 名 : debug_log.DebugLog.write
功能描述 : 写日志
输入参数 : int level
const std::string &msg
输出参数 : 无
返 回 值 : 无
作 者 : zhangcan
日 期 : 2017年2月28日
*****************************************************************************/
void DebugLog::write(int level, const std::string &msg) {
if (level <= this->m_debugLevel) {
std::string msgf = "[" + std::to_string(level) + "]" + msg;
DebugLogWriter &d = DebugLogWriter::getInstance();
d.write_log(this->m_fileName, msgf);
}
}
} // namespace debug_log
3、debug_log_writer.h头文件
/******************************************************************************
版权所有 (C), 2016-2017, 西安网络科技有限公司
******************************************************************************
文 件 名 : debug_log_writer.h
版 本 号 : V1.0
作 者 : zhangcan
生成日期 : 2017年2月28日
功能描述 : 写日志类头文件
修改历史 :
******************************************************************************/
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <map>
#include <string>
#include <cstring>
#include <iostream>
#ifndef _DEBUG_LOG_WRITER_H_
#define _DEBUG_LOG_WRITER_H_
namespace debug_log {
class DebugLogWriter {
public:
static DebugLogWriter &getInstance() {
static DebugLogWriter instance;
return instance;
}
void write_log(const std::string &fileName, const std::string &msg);
void close(const std::string &fileName);
int open(const std::string &fileName, std::string *error);
private:
DebugLogWriter() { }
~DebugLogWriter() { }
// C++ 03
// ========
// Dont forget to declare these two. You want to make sure they
// are unacceptable otherwise you may accidentally get copies of
// your singleton appearing.
DebugLogWriter(DebugLogWriter const&);
void operator=(DebugLogWriter const&);
};
} // namespace debug_log
#endif // _DEBUG_LOG_WRITER_H_
4、debug_log_writer.cpp接口实现
/******************************************************************************
版权所有 (C), 2016-2017, 西安网络科技有限公司
******************************************************************************
文 件 名 : debug_log_writer.cpp
版 本 号 : V1.0
作 者 : zhangcan
生成日期 : 2017年2月28日
功能描述 : 写日志文件类接口实现
修改历史 :
******************************************************************************/
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fstream>
#include "shared_files.h"
#include "debug_log_writer.h"
namespace debug_log {
/*****************************************************************************
函 数 名 : debug_log.DebugLogWriter.open
功能描述 : 打开文件
输入参数 : const std::string &fileName
std::string *error
输出参数 : 无
返 回 值 : int
作 者 : zhangcan
日 期 : 2017年2月28日
*****************************************************************************/
int DebugLogWriter::open(const std::string &fileName, std::string *error) {
return utils::SharedFiles::getInstance().open(fileName, error);
}
/*****************************************************************************
函 数 名 : debug_log.DebugLogWriter.close
功能描述 : 关闭文件句柄
输入参数 : const std::string &fileName
输出参数 : 无
返 回 值 : 无
作 者 : zhangcan
日 期 : 2017年2月28日
*****************************************************************************/
void DebugLogWriter::close(const std::string &fileName) {
utils::SharedFiles::getInstance().close(fileName);
}
/*****************************************************************************
函 数 名 : debug_log.DebugLogWriter.write_log
功能描述 : 写日志文件
输入参数 : const std::string &fileName
const std::string &msg
输出参数 : 无
返 回 值 : 无
作 者 : zhangcan
日 期 : 2017年2月28日
*****************************************************************************/
void DebugLogWriter::write_log(const std::string &fileName,
const std::string &msg) {
std::string err;
std::string lmsg = msg + "\n";
utils::SharedFiles::getInstance().write(fileName, lmsg, &err);
if (err.size() > 0) {
printf("[%s:%d] %s\n", __FUNCTION__, __LINE__, err.c_str());
}
}
} // namespace debug_log
5、shared_files.h头文件
/******************************************************************************
版权所有 (C), 2016-2017, 西安网络科技有限公司
******************************************************************************
文 件 名 : shared_files.h
版 本 号 : V1.0
作 者 : zhangcan
生成日期 : 2017年5月8日
功能描述 : 共享文件操作类头文件
修改历史 :
******************************************************************************/
#ifndef _UTILS_SHARED_FILES_H_
#define _UTILS_SHARED_FILES_H_
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <utility>
#include <vector>
#include <fstream>
#include <string>
namespace utils {
typedef struct file_handler {
int shm_id_structure;
pthread_mutex_t lock;
char file_name[];
} file_handler_t;
class SharedFiles {
public:
bool open(const std::string &fileName, std::string *error);
void close(const std::string &fileName);
bool write(const std::string &fileName, const std::string &msg,
std::string *error);
static SharedFiles& getInstance() {
static SharedFiles instance;
return instance;
}
protected:
std::pair<file_handler_t *, FILE *> find_handler(
const std::string &fileName);
std::pair<file_handler_t *, FILE *> add_new_handler(
const std::string &fileName, std::string *error);
private:
SharedFiles() {}
~SharedFiles() {}
// C++ 03
// ========
// Dont forget to declare these two. You want to make sure they
// are unacceptable otherwise you may accidentally get copies of
// your singleton appearing.
SharedFiles(SharedFiles const&);
void operator=(SharedFiles const&);
std::vector<std::pair<std::string,
std::pair<file_handler_t *, FILE *> > > m_handlers;
};
} // namespace utils
#endif // _UTILS_SHARED_FILES_H_
6、shared_files.cpp接口实现
/******************************************************************************
版权所有 (C), 2016-2017, 西安网络科技有限公司
******************************************************************************
文 件 名 : shared_files.cpp
版 本 号 : V1.0
作 者 : zhangcan
生成日期 : 2017年5月8日
功能描述 : 共享文件操作接口实现
修改历史 :
******************************************************************************/
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <utility>
#include <fstream>
#include <string>
#include "shared_files.h"
namespace utils {
/*****************************************************************************
函 数 名 : utils.SharedFiles.find_handler
功能描述 : 查找文件句柄
输入参数 : const std::string &fileName
输出参数 : 无
返 回 值 : std::pair<file_handler_t *, FILE *>
作 者 : zhangcan
日 期 : 2017年5月8日
*****************************************************************************/
std::pair<file_handler_t *, FILE *> SharedFiles::find_handler(
const std::string &fileName) {
for (auto i : this->m_handlers) {
if (i.first == fileName) {
return i.second;
}
}
return std::pair<file_handler_t *, FILE *>(NULL, NULL);
}
/*****************************************************************************
函 数 名 : utils.SharedFiles.add_new_handler
功能描述 : 添加文件句柄
输入参数 : const std::string &fileName
std::string *error
输出参数 : 无
返 回 值 : std::pair<file_handler_t *, FILE *>
作 者 : zhangcan
日 期 : 2017年5月8日
*****************************************************************************/
std::pair<file_handler_t *, FILE *> SharedFiles::add_new_handler(
const std::string &fileName, std::string *error) {
int ret;
FILE *fp;
int shm_id;
bool toBeCreated = true;
key_t mem_key_structure;
file_handler_t *new_debug_log;
struct shmid_ds shared_mem_info;
/* 打开文件 */
fp = fopen(fileName.c_str(), "a");
if (fp == NULL) {
error->assign("Failed to open file: " + fileName);
goto err_fh;
}
/* 创建IPC通讯ID */
mem_key_structure = ftok(fileName.c_str(), 1);
if (mem_key_structure < 0) {
error->assign("Failed to select key for the shared memory (1): ");
error->append(strerror(errno));
goto err_mem_key;
}
/* 创建共享内存对象 */
shm_id = shmget(mem_key_structure, sizeof(file_handler_t) + fileName.size() + 1, \
IPC_CREAT | IPC_EXCL | 0666);
if (shm_id < 0) {
toBeCreated = false;
shm_id = shmget(mem_key_structure, sizeof(file_handler_t) + fileName.size() + 1, \
IPC_CREAT | 0666);
if (shm_id < 0) {
error->assign("Failed to allocate shared memory (1): ");
error->append(strerror(errno));
goto err_shmget1;
}
}
/* 获得共享内存的状态 */
ret = shmctl(shm_id, IPC_STAT, &shared_mem_info);
if (ret < 0) {
error->assign("Failed to get information on shared memory (1): ");
error->append(strerror(errno));
goto err_shmctl1;
}
/* 把共享内存区对象映射到调用进程的地址空间 */
new_debug_log = reinterpret_cast<file_handler_t *>(shmat(shm_id, NULL, 0));
if ((reinterpret_cast<char *>(new_debug_log)[0]) == -1) {
error->assign("Failed to attach shared memory (1): ");
error->append(strerror(errno));
goto err_shmat1;
}
if ((toBeCreated == false) && (shared_mem_info.shm_nattch == 0)) {
toBeCreated = true;
}
if (toBeCreated == true) {
memset(new_debug_log, '\0', sizeof(file_handler_t));
pthread_mutex_init(&new_debug_log->lock, NULL);
new_debug_log->shm_id_structure = shm_id;
memcpy(new_debug_log->file_name, fileName.c_str(), fileName.size());
new_debug_log->file_name[fileName.size()] = '\0';
}
this->m_handlers.push_back(std::make_pair(fileName, std::make_pair(new_debug_log, fp)));
return std::make_pair(new_debug_log, fp);
err_shmget1:
err_shmctl1:
err_shmat1:
shmdt(new_debug_log);
err_mem_key:
fclose(fp);
err_fh:
return std::pair<file_handler_t *, FILE *>(NULL, NULL);
}
/*****************************************************************************
函 数 名 : utils.SharedFiles.open
功能描述 : 打开文件
输入参数 : const std::string &fileName
std::string *error
输出参数 : 无
返 回 值 : bool
作 者 : zhangcan
日 期 : 2017年5月8日
*****************************************************************************/
bool SharedFiles::open(const std::string &fileName, std::string *error) {
bool bRet = true;
std::pair<file_handler_t *, FILE *> a;
/* 查找文件句柄 */
a = this->find_handler(fileName);
if (a.first == NULL) {
/* 创建文件句柄 */
a = this->add_new_handler(fileName, error);
}
if ((a.first == NULL) && (error->size() == 0)) {
error->assign("Not able to open: " + fileName);
bRet = false;
}
return bRet;
}
/*****************************************************************************
函 数 名 : utils.SharedFiles.close
功能描述 : 关闭文件
输入参数 : const std::string &fileName
输出参数 : 无
返 回 值 : 无
作 者 : zhangcan
日 期 : 2017年5月8日
*****************************************************************************/
void SharedFiles::close(const std::string &fileName) {
std::pair<file_handler_t *, FILE *> a;
if (fileName.empty()) {
return;
}
a = this->find_handler(fileName);
if ((a.first == NULL) || (a.second == NULL)) {
return;
}
/* 关闭文件 */
fclose(a.second);
a.second = NULL;
/* 删除共享内存 */
shmctl(a.first->shm_id_structure, IPC_RMID, NULL);
}
/*****************************************************************************
函 数 名 : utils.SharedFiles.write
功能描述 : 写数据
输入参数 : const std::string &fileName
const std::string &msg
std::string *error
输出参数 : 无
返 回 值 : bool
作 者 : zhangcan
日 期 : 2017年5月8日
*****************************************************************************/
bool SharedFiles::write(const std::string &fileName,
const std::string &msg, std::string *error) {
bool ret = true;
size_t wrote;
std::pair<file_handler_t *, FILE *> a;
a = this->find_handler(fileName);
if (a.first == NULL) {
error->assign("file is not open: " + fileName);
return false;
}
pthread_mutex_lock(&a.first->lock);
wrote = fwrite(reinterpret_cast<const char *>(msg.c_str()), 1, msg.size(), a.second);
if (wrote < msg.size()) {
error->assign("failed to write: " + fileName);
ret = false;
}
fflush(a.second);
pthread_mutex_unlock(&a.first->lock);
return ret;
}
} // namespace utils
7、编译以上代码生成动态库
CC := g++ --std=c++11
TARGET := libDebugLog.so
INCS := ./debug_log ./utils ../include
FLAGES := $(addprefix -I, $(INCS))
SRCS := $(wildcard ./debug_log/*.cpp)
SRCS += $(wildcard ./utils/*.cpp)
$(TARGET): $(SRCS)
$(CC) -shared -fPIC $(FLAGES) -o $@ $^
@mv $(TARGET) ./libs/
.PHONY: clean
clean:
@rm -rf ./debug_log/*.o ./utils/*.o
@rm -rf ./libs/$(TARGET)
8、测试代码
/******************************************************************************
版权所有 (C), 2016-2017, 西安网络科技有限公司
******************************************************************************
文 件 名 : test_debug_log.h
版 本 号 : V1.0
作 者 : zhangcan
生成日期 : 2017年5月12日
功能描述 : 测试DebugLog类头文件
修改历史 :
******************************************************************************/
#ifdef __cplusplus
#include <stdio.h>
#include <string>
#include <sstream>
#include <fstream>
#include <iostream>
#endif
#ifndef _TEST_DEBUG_LOG_H_
#define _TEST_DEBUG_LOG_H_
#include "debug_log.h"
#ifdef __cplusplus
using debug_log::DebugLog;
class Test_1 {
public:
Test_1() :
m_debugLog(new DebugLog())
{}
~Test_1(){
if (m_debugLog != NULL) {
delete m_debugLog;
}
}
void init(int level, std::string fileName);
void debug(int level, const std::string &msg);
void test();
private:
DebugLog *m_debugLog;
};
#endif // __cplusplus
#endif // _TEST_DEBUG_LOG_H_
/******************************************************************************
版权所有 (C), 2016-2017, 西安网络科技有限公司
******************************************************************************
文 件 名 : test_debug_log.cpp
版 本 号 : V1.0
作 者 : zhangcan
生成日期 : 2017年5月11日
功能描述 : 测试DebugLog功能
修改历史 :
******************************************************************************/
#include "test_debug_log.h"
void Test_1::init(int level, std::string fileName) {
if (m_debugLog != NULL) {
std::string msg;
m_debugLog->setDebugLogLevel(level);
m_debugLog->setDebugLogFile(fileName, &msg);
if (msg.size() > 0) {
std::cout << msg << std::endl;
}
}
else {
std::cout << "new DebugLog failed!" << std::endl;
}
}
void Test_1::debug(int level, const std::string &msg) {
if (m_debugLog != NULL) {
m_debugLog->write(level, msg);
}
}
void Test_1::test() {
std::string msg;
std::stringstream head;
head << "[" << __FUNCTION__ << ":" << __LINE__ << "] ";
msg = "123456789";
msg = head.str() + msg;
debug(1, msg);
}
int main() {
Test_1 *pTest = new Test_1();
if (pTest != NULL) {
pTest->init(9, "debug.log");
}
else
{
std::cout << "new Test_1 failed!" << std::endl;
return -1;
}
pTest->test();
return 0;
}
编译代码
CC := g++ --std=c++11
INCS := ./ ../utils ../../include
LIBS := DebugLog
FLAGES := $(addprefix -I, $(INCS))
FLAGES += -L../libs/ -Wl,-rpath ../libs/ $(addprefix -l, $(LIBS))
out :
$(CC) -o test_debug_log test_debug_log.cpp $(FLAGES)
.PHONY:clean
clean:
@rm -rf test_debug_log