glog学习(二):glog主要接口和类分析
1.glog的主要接口如下。
#define LOG(severity) COMPACT_GOOGLE_LOG_ ## severity.stream()#define SYSLOG(severity) SYSLOG_ ## severity(0).stream() // Initialize.GOOGLE_GLOG_DLL_DECL void InitGoogleLogging(const char* argv0); // ShutdownGOOGLE_GLOG_DLL_DECL void ShutdownGoogleLogging(); // 设置回调接口,如果失败调用接口.GOOGLE_GLOG_DLL_DECL void InstallFailureFunction(void (*fail_func)()); // Add or remove a LogSink as a consumer of logging data. Thread-safe. GOOGLE_GLOG_DLL_DECL void AddLogSink(LogSink *destination); GOOGLE_GLOG_DLL_DECL void RemoveLogSink(LogSink *destination);//设置日志扩展名称,thread-safe。 GOOGLE_GLOG_DLL_DECL void SetLogFilenameExtension(const char* filename_extension);// // 设置某种等级的日志标准输出,thread-safe. // GOOGLE_GLOG_DLL_DECL void SetStderrLogging(LogSeverity min_severity);// // 设置所有的日志标准输出. Thread-safe. // GOOGLE_GLOG_DLL_DECL void LogToStderr();// // Make it so that all log messages of at least a particular severity are // logged via email to a list of addresses (in addition to logging to the // usual log file(s)). The list of addresses is just a string containing // the email addresses to send to (separated by spaces, say). Thread-safe. // GOOGLE_GLOG_DLL_DECL void SetEmailLogging(LogSeverity min_severity,const char* addresses);// A simple function that sends email. dest is a commma-separated // list of addressess. Thread-safe. GOOGLE_GLOG_DLL_DECL bool SendEmail(const char *dest,const char *subject, const char *body);GOOGLE_GLOG_DLL_DECL const std::vector<std::string>& GetLoggingDirectories();// For tests only: Clear the internal [cached] list of logging directories to // force a refresh the next time GetLoggingDirectories is called. // Thread-hostile. void TestOnly_ClearLoggingDirectoriesList();// Returns a set of existing temporary directories, which will be a // subset of the directories returned by GetLogginDirectories(). // Thread-safe. GOOGLE_GLOG_DLL_DECL void GetExistingTempDirectories(std::vector<std::string>* list);// Print any fatal message again -- useful to call from signal handler // so that the last thing in the output is the fatal message. // Thread-hostile, but a race is unlikely. GOOGLE_GLOG_DLL_DECL void ReprintFatalMessage();// Truncate a log file that may be the append-only output of multiple // processes and hence can't simply be renamed/reopened (typically a // stdout/stderr). If the file "path" is > "limit" bytes, copy the // last "keep" bytes to offset 0 and truncate the rest. Since we could // be racing with other writers, this approach has the potential to // lose very small amounts of data. For security, only follow symlinks // if the path is /proc/self/fd/* GOOGLE_GLOG_DLL_DECL void TruncateLogFile(const char *path,int64 limit, int64 keep);// Truncate stdout and stderr if they are over the value specified by // --max_log_size; keep the final 1MB. This function has the same // race condition as TruncateLogFile. GOOGLE_GLOG_DLL_DECL void TruncateStdoutStderr();// Return the string representation of the provided LogSeverity level. // Thread-safe. GOOGLE_GLOG_DLL_DECL const char* GetLogSeverityName(LogSeverity severity);
使用方法如下:
(1)初始化
(2)logdestination提供文件地址,文件前缀名,输出属性的设置接口。
(3)logmessage提供日志内容的具体输出接口,封装为LOG(…)。
(4)shutdown,析构
2.直接用到的类。
从上述接口分析,我们可以得到我们直接接触到的类和文件。
2.1
LogMessage:This class more or less represents a particular log message. You create an instance of LogMessage and then stream stuff to it. When you finish streaming to it, ~LogMessage is called and the full message gets streamed to the appropriate destination.从日志中我们可以看出,日志信息的输出主要看这个类,创建LogMessage的实例,获得数据流,结束后,调用析构函数~LogMessage(),然后stream流向目的文件。
LogMessage的主要成员说明,由于一些参数太长我就省略掉了,大家可以参考具体的文档。
LogMessage |
Public: class LogStream : public std::ostream //流 LogMessage(***);//构造函数 ~LogMessage();//析构函数 void Flush(); void SendToLog(); void SendToSyslogAndLog(); static void __declspec(noreturn) Fail(); std::ostream& stream(); |
Private: void SendToSinkAndLog(); void SendToSink(); void WriteToStringAndLog(); void SaveOrSendToLog(); void Init(……); LogMessageData* allocated_; LogMessageData* data_; friend class LogDestination; LogMessage(const LogMessage&); void operator=(const LogMessage&); |
日志内容的具体输出接口为LOG(***);其实是LogMessage封装后的接口,##起到连接的作用。 LOG(INFO) << str;其实替换过去就是COMPACT_GOOGLE_LOG_INFO.stream()<<str;最终调用的还是LogMessage的构造函数。
1 #define LOG(severity) COMPACT_GOOGLE_LOG_ ## severity.stream() 2 #define SYSLOG(severity) SYSLOG_ ## severity(0).stream() 3 4 #if GOOGLE_STRIP_LOG == 0 5 #define COMPACT_GOOGLE_LOG_INFO google::LogMessage( \ 6 __FILE__, __LINE__) 7 #define LOG_TO_STRING_INFO(message) google::LogMessage( \ 8 __FILE__, __LINE__, google::GLOG_INFO, message) 9 #else 10 #define COMPACT_GOOGLE_LOG_INFO google::NullStream() 11 #define LOG_TO_STRING_INFO(message) google::NullStream() 12 #endif
下面我们看看构造函数的内容,就是初始化了一些东西,文件名称,Log等级,行号等参数。
1 LogMessage::LogMessage(const char* file, int line) 2 : allocated_(NULL) { 3 Init(file, line, GLOG_INFO, &LogMessage::SendToLog); 4 } 5 6 void LogMessage::Init(const char* file,int line,LogSeverity severity,void (LogMessage::*send_method)()) {/*do something*/ }
析构函数:
1 LogMessage::~LogMessage() { 2 Flush();//写数据 3 } 4 // Flush buffered message, called by the destructor, or any other function 5 // that needs to synchronize the log. 6 void LogMessage::Flush() {/*flush*/}
LogMessage中有一个友类,LogDestination,接下来我们看一下这个类。
2.2
LogDestination
LogDestination |
Public: friend class LogMessage; friend void ReprintFatalMessage(); friend base::Logger* base::GetLogger(LogSeverity); friend void base::SetLogger(LogSeverity, base::Logger*); static void SetLogDestination(LogSeverity severity, const char* base_filename); static void SetLogSymlink(LogSeverity severity, const char* symlink_basename); static void AddLogSink(LogSink *destination); static void RemoveLogSink(LogSink *destination); static void SetLogFilenameExtension(const char* filename_extension); static void SetStderrLogging(LogSeverity min_severity); static void SetEmailLogging(LogSeverity min_severity, const char* addresses); static void LogToStderr(); static void FlushLogFiles(int min_severity); static void FlushLogFilesUnsafe(int min_severity); static const int kNetworkBytes = 1400; static const string& hostname(); static const bool& terminal_supports_color(); static void DeleteLogDestinations(); |
Private: LogDestination(LogSeverity severity, const char* base_filename); ~LogDestination() { } static vector<LogSink*>* sinks_; static Mutex sink_mutex_; LogDestination(const LogDestination&); LogDestination& operator=(const LogDestination&); |
LogDestination主要提供了日志文件的名称设置接口和日志的书写方式。我们看个例子:
SetLogFilenameExtension:文件后缀名设置
效果如图
具体代码:
1 inline void LogDestination::SetLogFilenameExtension(const char* ext) { 2 // Prevent any subtle race conditions by wrapping a mutex lock around 3 // all this stuff. 4 MutexLock l(&log_mutex); 5 for ( int severity = 0; severity < NUM_SEVERITIES; ++severity ) { 6 log_destination(severity)->fileobject_.SetExtension(ext); 7 } 8 }
而SetExtension来自类LogFileObject,此处先不展开。我们看setExtension
1 /* 2 string filename_extension_; // option users can specify (eg to add port#) 3 */ 4 void LogFileObject::SetExtension(const char* ext) { 5 MutexLock l(&lock_); 6 if (filename_extension_ != ext) { 7 // Get rid of old log file since we are changing names 8 if (file_ != NULL) { 9 fclose(file_); 10 file_ = NULL; 11 rollover_attempt_ = kRolloverAttemptFrequency-1; 12 } 13 filename_extension_ = ext; 14 } 15 }
可以看出LogDestination其实只是一个壳,负责和LogMessage以及其他的一些类进行互动。真正实现还得看LogFileObject类。
2.3
LogFileObject
LogFileObject : public base::Logger |
LogFileObject(LogSeverity severity, const char* base_filename); virtual void Write(bool force_flush, // Should we force a flush here? // Configuration options // Normal flushing routine virtual uint32 LogSize() { void FlushUnlocked(); |
Mutex lock_; bool base_filename_selected_; string base_filename_; string symlink_basename_; string filename_extension_; // option users can specify (eg to add port#) FILE* file_; LogSeverity severity_; uint32 bytes_since_flush_; uint32 dropped_mem_length_; uint32 file_length_; unsigned int rollover_attempt_; int64 next_flush_time_; |
关于这个类,我们看一个函数:
1 void LogFileObject::Write(bool force_flush, 2 time_t timestamp, 3 const char* message, 4 int message_len) { 5 MutexLock l(&lock_); 6 7 //条件判断,不符合直接return 8 if (base_filename_selected_ && base_filename_.empty()) { 9 return; 10 } 11 12 13 if (base_filename_selected_) 14 { 15 /*如果没有创建日志文件,return*/ 16 if (!CreateLogfile(time_pid_string)) { 17 perror("Could not create log file"); 18 fprintf(stderr, "COULD NOT CREATE LOGFILE '%s'!\n", 19 time_pid_string.c_str()); 20 return; 21 } 22 } 23 else 24 { 25 ostringstream file_header_stream; 26 file_header_stream.fill('0'); 27 28 file_header_stream << "Log file created at: " 29 << 1900+tm_time.tm_year << '/' 30 << setw(2) << 1+tm_time.tm_mon << '/' 31 << setw(2) << tm_time.tm_mday 32 << ' ' 33 << setw(2) << tm_time.tm_hour << ':' 34 << setw(2) << tm_time.tm_min << ':' 35 << setw(2) << tm_time.tm_sec << '\n' 36 << "Running on machine: " 37 << LogDestination::hostname() << '\n' 38 << "Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu " 39 << "threadid file:line] msg" << '\n'; 40 const string& file_header_string = file_header_stream.str(); 41 42 const int header_len = file_header_string.size(); 43 fwrite(file_header_string.data(), 1, header_len, file_); 44 file_length_ += header_len; 45 bytes_since_flush_ += header_len; 46 } 47 /*写满了怎么办?*/ 48 // Write to LOG file 49 if ( !stop_writing ) { 50 // fwrite() doesn't return an error when the disk is full, for 51 // messages that are less than 4096 bytes. When the disk is full, 52 // it returns the message length for messages that are less than 53 // 4096 bytes. fwrite() returns 4096 for message lengths that are 54 // greater than 4096, thereby indicating an error. 55 errno = 0; 56 fwrite(message, 1, message_len, file_); 57 if ( FLAGS_stop_logging_if_full_disk && 58 errno == ENOSPC ) { // disk full, stop writing to disk 59 stop_writing = true; // until the disk is 60 return; 61 } else { 62 file_length_ += message_len; 63 bytes_since_flush_ += message_len; 64 } 65 } 66 else { 67 if ( CycleClock_Now() >= next_flush_time_ ) 68 stop_writing = false; // check to see if disk has free space. 69 return; // no need to flush 70 } 71 /*do otherthings*/ 72 }
对应的就是以下内容
Log file created at: 2019/01/28 15:27:56 Running on machine: HostName Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg I0128 15:27:56.937649 16208 glogtest.cpp:20] hello log! I0128 15:27:56.958592 16208 glogtest.cpp:21] info testhello log! W0128 15:27:56.958592 16208 glogtest.cpp:22] warning test E0128 15:27:56.958592 16208 glogtest.cpp:23] error test
我们再看一个函数:可以看出这个函数的功能就是创建文件名称。如果我们可以修改time_pid_string这个值,或者直接修改string_filename的值,就可以直接修改文件的名字,因为原始的名字真的是太长了,而且不便查找。
1 bool LogFileObject::CreateLogfile(const string& time_pid_string) { 2 string string_filename = base_filename_+filename_extension_+ 3 time_pid_string; 4 const char* filename = string_filename.c_str(); 5 int fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, FLAGS_logfile_mode); 6 if (fd == -1) return false; 7 #ifdef HAVE_FCNTL 8 // Mark the file close-on-exec. We don't really care if this fails 9 fcntl(fd, F_SETFD, FD_CLOEXEC); 10 #endif 11 12 file_ = fdopen(fd, "a"); // Make a FILE*. 13 if (file_ == NULL) { // Man, we're screwed! 14 close(fd); 15 unlink(filename); // Erase the half-baked evidence: an unusable log file 16 return false; 17 } 18 19 // We try to create a symlink called <program_name>.<severity>, 20 // which is easier to use. (Every time we create a new logfile, 21 // we destroy the old symlink and create a new one, so it always 22 // points to the latest logfile.) If it fails, we're sad but it's 23 // no error. 24 /*do something*/ 25 26 return true; // Everything worked 27 }
3.太深了……写不动了
参考网站:http://www.cnblogs.com/tianyajuanke/archive/2013/02/22/2921850.html
转载于:https://www.cnblogs.com/whutao/p/10331103.html
glog学习(二):glog主要接口和类分析相关推荐
- html与java接口,JavaWeb学习——Servlet相关的接口和类
JavaWeb学习--Servlet相关的接口和类 摘要:本文主要学习了Servlet相关的接口和类. Servlet的接口和类 三种方式 实现Servlet有三种方式: 实现javax.servle ...
- Java基础学习(二十一)之接口
1. 接口 1.1 接口概述 五孔插线面板,不同品牌都能使用,因为它们遵循同样的规范来生产的.所以说接口其实就是一种公共的规范,只要符合规范,大家都可以使用. 笔记本,USB口,鼠标,键盘,U盘 接口 ...
- libed2k源码导读:(二)Session接口以及实现分析
第二章 Session接口以及实现分析 目录 第二章 Session接口以及实现分析 2.1 获取会话状态 2.2 管理会话中所有的传输任务 2.3 管理点对点连接 2.4 管理alert 2.4.1 ...
- 从零开始学USB(二十二、USB接口HID类设备(四)_报表描述符Local类)
本地项目标签定义控件的特征. 这些项目不会转移到下一个主要项目. 如果Main项定义了多个控件,则可能会有几个类似的Local项标签. 例如,一个Input项可能有几个与之关联的Usage标签,每个控 ...
- Android消息驱动Handler类分析
Android系统中的消息驱动工作原理: 1.有一个消息队列,可以往这个消息队列中投递消息; 2.有一个消息循环,不断的从消息队列中取得消息,然后处理. 工作流程: 1.事件源将待处理的消息加入到消息 ...
- Kotlin 学习笔记(八)—— Kotlin类与对象之接口
Kotlin 学习笔记(八)-- Kotlin类与对象之接口 Kotlin学习笔记系列教程 Kotlin 学习笔记(一)-- 概述.学习曲线.开发工具.参考资料 Kotlin 学习笔记(二)-- 基础 ...
- Hibernate学习(二):heibernate核心接口
Hibernate是一种对JDBC做了轻量级封装的对象---关系映射工具,所谓轻量级封装,是指Hibernate并没有完全封装JDBC,Java应用即可以通过Hibernate API访问数据库,还可 ...
- 【Java】(二十四)File类(文件操作,文件夹操作,FileFilter接口);Properties属性集合
继续上一章,学习JavaIO框架 [Java](二十三)IO框架:流的概念与分类,字节流(对象流[序列化.反序列化]),编码方式,字符流(打印流,转换流) 上一节的学习(字节流,字符流)都是对文件内容 ...
- qml学习笔记(二):可视化元素基类Item详解(上半场anchors等等)
原博主博客地址:http://blog.csdn.net/qq21497936 本文章博客地址:http://blog.csdn.net/qq21497936/article/details/7851 ...
- List接口实现类-ArrayList、Vector、LinkedList集合深入学习以及源代码解析
学习List接口实现类 ArrayList Vector LinkedList List接口的实现类中最经常使用最重要的就是这三个:ArrayList.Vector.LinkedList. JDK ...
最新文章
- javascript 实现模拟滚动条,但不支持鼠标滚轮
- vant组件搜索并选择_Vue.js自定义弹层组件|vue仿微信/ios弹窗
- java.lang.ClassCastException: android.widget.LinearLayout$LayoutParams
- ggplot2箱式图两两比较_R绘图 第四篇:绘制箱图(ggplot2)
- linux系统如何用root用户登陆,Linux用root账号创建一个新的登录账号的方法
- springcloud gateway ribbon使用_Github点赞接近 70k 的Spring Cloud学习教程+实战项目推荐!牛批!...
- Vue中数组变动监听
- struct interface_GCTT | 接受 interface 参数,返回 struct 在 go 中意味着什么
- 为什么太重感情的人基本都是穷人?
- 线性表顺序表模板 纯本人手工创造
- 美团回应遭反垄断调查;腾讯因《地下城与勇士》被抄袭获赔3000万;iOS 14.5 正式版发布|极客头条...
- iOS开发之字典(NSDictionary)和JSON字符串(NSString)之间互转
- org.apache.hadoop.fs.ChecksumException: Checksum error
- 【前端词典】进阶必备的网络基础
- python 拆分pdf指定页_Python简单拆分PDF文件,将一个PDF文件拆分成指定份数
- 只有10分,5分,2分,1分的硬币;顾客付款x分,商品价格y分。如何找零所使用的硬币最少(递归实现)
- [转载]AlphaGo 的棋局,与人工智能有关,与人生无关
- SPSSPRO杯第十五届数学中国数学建模网络挑战赛赛题浅评
- QQ Scheme跳转接口
- 当Forms表单遇到Power BI
热门文章
- linux下dns视图配置
- 第二章 身份验证——跟我学习springmvc shiro mybatis
- java中实现多线程的两种基本方法
- linux和Dos下换行符转换
- 开源 免费 java CMS - FreeCMS1.5 标签 ajaxStore
- Eclipse 4.7(Oxygen)安装Tomcat Plugin 后没有小猫图标解决方法
- java 测试 jar_java – 从可执行jar运行spring测试
- qt socket 传递结构体 结构体中有list_GO语言入门-14、结构体
- vb导入数据到mysql_用VB程序导入与导出MySQL数据的有关问题(急)
- redis安装配置 mysql_学习环境安装 mysql 与 redis