如何优雅的跨平台输出log日志 C++
文章目录
- 前言
- 一、glog
- 1.基本满足的功能
- 2.进阶的功能
- 2.glog源码编译
- 二、使用
- 1.初步使用
- 2.跨线程使用
- 3.测试疯狂打中文日志日志
- 总结
前言
作为一名合格的程序员,进行调试,找bug的时候不可能单单只靠断点或者进行printf输出,这种方式不仅不够准确与及时,比如解决一些不能够必现的问题,而且如果产品到了用户发生了问题,没有日志就很有可能遗漏了当时的场景。
所以我们就需要一种可以记录程序运行状态的日志,这里采用的是goole推出的glog,是一种跨windows、mac、ios、android、linux的强大开源工具。笔者为了方便书写代码,添加了部分宏定义。
本文只在windows下进行示范,其他平台基本一致。
一、glog
1.基本满足的功能
一个合格的日志在笔者看来最少要拥有日志类型、日期、时间、文件名、行号、线程号、日志内容才能够准确的帮助定位到一些问题的所在,也就是这样的格式:
IWEF | mmdd | hh:mm:ss.uuuuuu | threadid | file:line] | msg |
---|
其中类型含义:
I | W | E | F |
---|---|---|---|
INFO | WARNNING | ERROR | FATAL |
最终输出的日志看起来像是这样的
Log file created at: 2022/04/06 17:37:49
Running on machine: A120282
Running duration (h:mm:ss): 0:00:00
Log line format: [IWEF]yyyymmdd hh:mm:ss.uuuuuu threadid file:line] msg
I20220406 17:37:49.679339 20356 main.cpp:21] hello world
2.进阶的功能
在实际使用过程中,除了上面基本的功能,其实有的时候会遇到以下的问题:例如格式化输出日志,日志打满,如何多线程使用,更有的希望在用户那边使用的时候进行加密处理。笔者会接下来做一些测试证明以下glog都是支持的,除了加解密笔者自己没有进行尝试过,但是从glog的API中是看到可以进行加解密的(后面笔者如果使用到会再次添加)。
- 可以正常输出Unicode字符集(中文日志)
- 支持加/解密
- 支持多线程输出日志
- 控制日志文件大小
- 日志打满后自动新建文件
|版本声明:山河君,未经博主允许,禁止转载
2.glog源码编译
直接从github上下载,使用CMake编译就好了,如果想省事,可以直接下载别人编好的
github:https://github.com/google/glog
笔者这边编译的是动态库,注意有些头文件需要稍微移动一下,总体使用的头文件和编译成功的库如下:
二、使用
这边就直接省略工程创建和基本的配置拉…
1.初步使用
这里值得注意的是一些flag的配置,使用的拼接的语法,感兴趣的小伙伴可以自行跟踪代码进去查看。google的注释写的真的是没话说。
同时,如果采用不同的连接方式(静态/动态) 宏定义(如动态库为:GLOG_NO_ABBREVIATED_SEVERITIES)是不同的,不过在编译的时候有错误输出,可以很直观的看到,就不过多介绍了。
要注意宏定义要加载glog/logging.h 头文件之前
#define GLOG_NO_ABBREVIATED_SEVERITIES#include "glog/logging.h"
#include <string>
#include <iostream>int main()
{std::string strLogName = "test";std::string strLogPath = "E:/log/";std::string strDestination = strLogPath + strLogName;google::InitGoogleLogging(strLogName.c_str());google::SetStderrLogging(google::GLOG_FATAL);google::SetLogDestination(google::GLOG_INFO, strDestination.c_str());FLAGS_colorlogtostderr = true; //如果输出到终端是否需要颜色标记FLAGS_logbufsecs = 0; //设置日志输出等待时间FLAGS_max_log_size = 50; //设置输出日志文件大小FLAGS_stop_logging_if_full_disk = true; //磁盘满时是否停止LOG(INFO) << "hello " << "world";google::ShutdownGoogleLogging();return 0;
}
直接进行运行,可以看到磁盘E:/log/
下有对应的文件生成
且文件内容为
Log file created at: 2022/04/06 17:37:49
Running on machine: A120282
Running duration (h:mm:ss): 0:00:00
Log line format: [IWEF]yyyymmdd hh:mm:ss.uuuuuu threadid file:line] msg
I20220406 17:37:49.679339 20356 main.cpp:21] hello world
2.跨线程使用
跨线程使用核心其实就是全局使用,跟踪glog源码,我们可以很清楚的看到再每次输入日志,并刷新到log文件中,其实都会进行加锁,所以使用时不必担心跨线程使用时造成资源竞态。
glog源码节选:
inline void LogDestination::FlushLogFiles(int min_severity) {// Prevent any subtle race conditions by wrapping a mutex lock around// all this stuff.MutexLock l(&log_mutex);for (int i = min_severity; i < NUM_SEVERITIES; i++) {LogDestination* log = log_destination(i);if (log != NULL) {log->logger_->Flush();}}
}
所以我们只要在真正使用之前进行创建就可以了。
这里为了方便,新建一个Logger类
头文件:
#pragma once
#define GLOG_NO_ABBREVIATED_SEVERITIES#include "glog/logging.h"
#include <string>
#include <iostream>//方便输出采用宏定义方式#define LOG_DEBUG DLOG(INFO)
#define LOG_INFO LOG(INFO)
#define LOG_WARNING LOG(WARNING)
#define LOG_ERROR LOG(ERROR)
#define LOG_FATAL LOG(FATAL)class Logger
{public:static Logger* GetInstance(const std::string &strLogPath, const std::string &strLogName);~Logger();private:Logger(const std::string &strLogPath, const std::string &strLogName);static Logger* m_pInstance;
};
源文件:
#include "Logger.h"
Logger* Logger::m_pInstance = nullptr;Logger* Logger::GetInstance(const std::string &strLogPath, const std::string &strLogName)
{if (m_pInstance == nullptr){m_pInstance = new Logger(strLogPath, strLogName);LOG_INFO << "The Logger is new init";}else{LOG_INFO << "The logger has init";}return m_pInstance;
}Logger::Logger(const std::string &strLogPath, const std::string &strLogName)
{std::string strDestiona = strLogPath + strLogName + "_";google::InitGoogleLogging(strLogName.c_str());google::SetStderrLogging(google::GLOG_FATAL);google::SetLogDestination(google::GLOG_INFO, strDestiona.c_str());FLAGS_colorlogtostderr = true;FLAGS_logbufsecs = 0;FLAGS_max_log_size = 50;FLAGS_stop_logging_if_full_disk = true;
}Logger::~Logger()
{LOG_INFO << "The logger is over";google::ShutdownGoogleLogging();
}
main函数(测试):
#include "Logger.h"
#include <string>
#include <iostream>
#include <thread>void Thread1()
{int i = 100;while (i--){LOG_INFO << "this is thread one";}
}void Thread2()
{int i = 100;while (i--){LOG_INFO << "this is thread two";}
}int main()
{Logger* pLogger = Logger::GetInstance("E:/Log/", "LogTest");std::thread thread1(Thread1);std::thread thread2(Thread2);thread1.join();thread2.join();delete pLogger;return 0;
}
我们可以看到,多线程输出并没有杂乱的现象
Log file created at: 2022/04/06 18:25:39
Running on machine: A120282
Running duration (h:mm:ss): 0:00:00
Log line format: [IWEF]yyyymmdd hh:mm:ss.uuuuuu threadid file:line] msg
I20220406 18:25:39.786847 6324 logger.cpp:9] The Logger is new init
I20220406 18:25:39.790838 23468 main.cpp:11] this is thread one
I20220406 18:25:39.790838 23468 main.cpp:11] this is thread one
I20220406 18:25:39.790838 23468 main.cpp:11] this is thread one
I20220406 18:25:39.790838 23468 main.cpp:11] this is thread one
I20220406 18:25:39.790838 23468 main.cpp:11] this is thread one
I20220406 18:25:39.790838 23468 main.cpp:11] this is thread one
I20220406 18:25:39.790838 23468 main.cpp:11] this is thread one
I20220406 18:25:39.790838 16488 main.cpp:20] this is thread two
I20220406 18:25:39.790838 23468 main.cpp:11] this is thread one
I20220406 18:25:39.790838 16488 main.cpp:20] this is thread two
I20220406 18:25:39.790838 23468 main.cpp:11] this is thread one
I20220406 18:25:39.790838 16488 main.cpp:20] this is thread two
3.测试疯狂打中文日志日志
测试main.cpp
#include "Logger.h"
#include <string>
#include <iostream>
#include <thread>void Thread1()
{int i = 100;while (true){LOG_INFO << "你好";}
}int main()
{Logger* pLogger = Logger::GetInstance("E:/Log/", "LogTest");std::thread thread1(Thread1);thread1.join();delete pLogger;return 0;
}
由输出日志看,每到50M之后,会新建一个日志,同时中文也没有乱码
Log file created at: 2022/04/06 18:34:25
Running on machine: A120282
Running duration (h:mm:ss): 0:00:00
Log line format: [IWEF]yyyymmdd hh:mm:ss.uuuuuu threadid file:line] msg
I20220406 18:34:25.704986 11584 logger.cpp:9] The Logger is new init
I20220406 18:34:25.708976 19268 main.cpp:11] 你好
I20220406 18:34:25.708976 19268 main.cpp:11] 你好
I20220406 18:34:25.708976 19268 main.cpp:11] 你好
I20220406 18:34:25.708976 19268 main.cpp:11] 你好
I20220406 18:34:25.708976 19268 main.cpp:11] 你好
总结
如果想在工程任意地方使用,只要包含Logger.h
头文件即可。
如果感觉对您有点用,请点个赞吧
如何优雅的跨平台输出log日志 C++相关推荐
- Android 大疆无人机Mobile Sdk开发,如何输出Log日志
职场小白迷上优美句子: <断章> -- 卞之琳 你在桥上看风景, 看风景的人在楼上看你. 明月装饰了你的窗子, 你装饰了别人的梦. 通过大疆 "桥" 连接,查看日志 精 ...
- bat输出log日志操作
1.在C:/盘符下写bat文件,假设命名文件为ping.bat,代码如下: :a @time /t @ping 172.0.0.1/n 100 goto a 2.cmd打开do ...
- 打印并输出 log/日志到文件(C++)
#include <stdarg.h> #define MAX_LEN 1024 bool debug_mode;// 使用方法同 printf void lprintf(const ch ...
- php 如何输出log,php如何设置日志输出
php设置日志输出的方法:使用php的写入文件函数,把数据写入到事先定义好的文件中,代码为[file_put_contents(file,data,mode,context)]. php设置日志输出的 ...
- 基于C/C++的log日志记录等级系统
目录 log日志系统初始化 log日志输出 禁止log日志输出 log日志关闭 log日志测试 log日志系统初始化 int logger_init(int loglevel) {time_t now ...
- Python + logging 输出到屏幕,将log日志写入文件(亲测)
日志 日志是跟踪软件运行时所发生的事件的一种方法.软件开发者在代码中调用日志函数,表明发生了特定的事件.事件由描述性消息描述,该描述性消息可以可选地包含可变数据(即,对于事件的每次出现都潜在地不同的数 ...
- log4j.properties配置与将异常输出到Log日志文件实例
将异常输出到 log日志文件 实际项目中的使用: <dependencies><dependency><groupId>org.slf4j</groupId& ...
- Python3 装饰器进行log日志输出
前言 使用Python 装饰器decorator来对函数进行日志输出_ 2021年3月 测试可用 环境 Python 3.7 代码 代码目录: logger.py -> 日志装饰器: 用来写lo ...
- 华为如何在开发者选项观察错误日志_爬虫scrapy框架--log日志输出配置及使用
1.在配置文件中设置日志输出文件名和日志等级 1.为什么以日期为文件名? 因为这样可以方便开发者查看每天的日志信息,同时也可以防止单文件log日志信息堆积的越来越多,所以将当天日志信息保存到当天的日志 ...
最新文章
- 精选180+Python开源项目,随你选!做项目何愁没代码
- Java入门系列-09-循环结构
- ubuntu 14.04 安装 cuda 6.5
- 工业机器人专项检测技术——环境检测
- mysql经典书籍--MySQL 必知必会
- 苹果应用ipa图片提取
- SAP CRM Product category的决定逻辑
- linux7.0ftp,Linux(Centos7)搭建FTP服务
- Python学习十大良好习惯
- input内强制保留小数点后两位 位数不足时自动补0
- Java ActiveMQ 讲解(二)Spring ActiveMQ整合+注解消息监听
- 【MySQL】Linux下MySQL 5.5、5.6和5.7的RPM、二进制和源码安装
- 移动硬盘计算机无法打开硬盘,移动硬盘无法访问,详细教您移动硬盘无法访问怎么办...
- 编码器类型原理知识汇总(增量式/绝对式/绝对值)
- 错误:ssh_exchange_identification: read: connection reset by peer
- protocol buffer使用中的问题This is supposed to be overridden by subclasses
- ISO、快门、光圈、曝光
- html语言中kbd的含义,HTML: kbd 标签
- 「小白学Python」Windows安装Python
- 从1到n年中的闰年个数判断