文章目录

  • 前言
  • 一、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中是看到可以进行加解密的(后面笔者如果使用到会再次添加)。

  1. 可以正常输出Unicode字符集(中文日志)
  2. 支持加/解密
  3. 支持多线程输出日志
  4. 控制日志文件大小
  5. 日志打满后自动新建文件

|版本声明:山河君,未经博主允许,禁止转载

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++相关推荐

  1. Android 大疆无人机Mobile Sdk开发,如何输出Log日志

    职场小白迷上优美句子: <断章> -- 卞之琳 你在桥上看风景, 看风景的人在楼上看你. 明月装饰了你的窗子, 你装饰了别人的梦. 通过大疆 "桥" 连接,查看日志 精 ...

  2. bat输出log日志操作

    1.在C:/盘符下写bat文件,假设命名文件为ping.bat,代码如下:    :a    @time /t    @ping 172.0.0.1/n 100    goto a 2.cmd打开do ...

  3. 打印并输出 log/日志到文件(C++)

    #include <stdarg.h> #define MAX_LEN 1024 bool debug_mode;// 使用方法同 printf void lprintf(const ch ...

  4. php 如何输出log,php如何设置日志输出

    php设置日志输出的方法:使用php的写入文件函数,把数据写入到事先定义好的文件中,代码为[file_put_contents(file,data,mode,context)]. php设置日志输出的 ...

  5. 基于C/C++的log日志记录等级系统

    目录 log日志系统初始化 log日志输出 禁止log日志输出 log日志关闭 log日志测试 log日志系统初始化 int logger_init(int loglevel) {time_t now ...

  6. Python + logging 输出到屏幕,将log日志写入文件(亲测)

    日志 日志是跟踪软件运行时所发生的事件的一种方法.软件开发者在代码中调用日志函数,表明发生了特定的事件.事件由描述性消息描述,该描述性消息可以可选地包含可变数据(即,对于事件的每次出现都潜在地不同的数 ...

  7. log4j.properties配置与将异常输出到Log日志文件实例

    将异常输出到 log日志文件 实际项目中的使用: <dependencies><dependency><groupId>org.slf4j</groupId& ...

  8. Python3 装饰器进行log日志输出

    前言 使用Python 装饰器decorator来对函数进行日志输出_ 2021年3月 测试可用 环境 Python 3.7 代码 代码目录: logger.py -> 日志装饰器: 用来写lo ...

  9. 华为如何在开发者选项观察错误日志_爬虫scrapy框架--log日志输出配置及使用

    1.在配置文件中设置日志输出文件名和日志等级 1.为什么以日期为文件名? 因为这样可以方便开发者查看每天的日志信息,同时也可以防止单文件log日志信息堆积的越来越多,所以将当天日志信息保存到当天的日志 ...

最新文章

  1. 精选180+Python开源项目,随你选!做项目何愁没代码
  2. Java入门系列-09-循环结构
  3. ubuntu 14.04 安装 cuda 6.5
  4. 工业机器人专项检测技术——环境检测
  5. mysql经典书籍--MySQL 必知必会
  6. 苹果应用ipa图片提取
  7. SAP CRM Product category的决定逻辑
  8. linux7.0ftp,Linux(Centos7)搭建FTP服务
  9. Python学习十大良好习惯
  10. input内强制保留小数点后两位 位数不足时自动补0
  11. Java ActiveMQ 讲解(二)Spring ActiveMQ整合+注解消息监听
  12. 【MySQL】Linux下MySQL 5.5、5.6和5.7的RPM、二进制和源码安装
  13. 移动硬盘计算机无法打开硬盘,移动硬盘无法访问,详细教您移动硬盘无法访问怎么办...
  14. 编码器类型原理知识汇总(增量式/绝对式/绝对值)
  15. 错误:ssh_exchange_identification: read: connection reset by peer
  16. protocol buffer使用中的问题This is supposed to be overridden by subclasses
  17. ISO、快门、光圈、曝光
  18. html语言中kbd的含义,HTML: kbd 标签
  19. 「小白学Python」Windows安装Python
  20. 从1到n年中的闰年个数判断

热门文章

  1. 拒绝电脑捆绑,移动端照样轻松查看CAD图!
  2. 2020.9.8小米测试开发工程师笔试题复盘
  3. smic memory生成,lib转db
  4. 大陆籍核心高管层到位,SMIC能否给业界惊喜?
  5. 网上商城的制作中需要注意哪些方面的安全问题?
  6. 2010年全国金融学专业排名【zz】
  7. 申请虚拟VISA卡ONEKEY保姆级教程来了!
  8. 隔壁老王都知道的用C#+SQL Server 仓库管理系统设计和实现【建议收藏,不然看着看着就不见了】
  9. 提高数据科学效率的 8 个Python神库
  10. 一个低学历者的辛酸程序路