日志是应用的镜子,可以发现应用中的问题,重要性不言而喻。
打造一智能日志模块,让运维朝着自动化方向大步迈进。提高效率,降低成本,这也是一种创造利润的途径。
如今网络越来越方便,这个日志组件除了常规的记录日志外,可以对日志分等级显示不同的颜色,支持按日期切割,支持控制文件大小及定时清理若干天的记录文件。更重要的是,一种远程诊断的方案。公司开辟一公共外网ftp服务器,这不费不少钱吧,也放心这服务器占不满空间。现场遇到问题了,只要网络不是问题,就都不是问题,这日志组件可由运维人员去触发机器一下,或让客户手工摁一下,机器主动ftp上去一个日志文件。或者应用里增加自主触发机制,当应用执行到FATAL,严重错误不该出现的地方时,或应用异常崩溃时,主动触发上报日志文件FTP到后台服务器。后台服务器增加监视,发现是致命bug日志,主动推送邮件到开发或运维人员邮箱。开发或运维人员总是盯数据肯定不感兴趣,往往不能及时发现问题,那么这种让问题主动去找你的思路,让你主动的去关注问题,而不是等到问题暴露了才去解决。
这样运维人员还用大热天到处跑吗?还用动不动就抓包?出差?都不用的。只要网络ok,数据跑路的都能实现不用人参与。
那么一个日志模块,什么是你想要的功能?
对我而言,这几点是必须的。
1·.日志分等级记录,可控制等级。
2.不同等级日志显示不同颜色。
3.增加是否启用日志输出到文件开关,可以选择把日志保存到文件中.
4.写文件属于耗时操作,这块要考虑异步写日志,不能阻塞应用或影响应用运行时间效率。
5.按日期生成日志文件,可配置保留多少天,超过设定的天数则自动清除超过天数的日志。
6.可增加参数设定限制日志文件的大小,超过限制大小可选择是从头覆盖还是删除重记。 以下为增强功能,
7.发现应用异常时,不但主动记录日志,而且主动上报异常日志文件。可通过FTP服务自动上报日志到后台FTP服务器,
把问题的发现,变被动为主动。当应用出现不该出现的问题时,主动上报。助力自动化运维。
即只要网络是OK的,不再让用户跑路。不再被动的发现问题。让问题解决于被暴露之前,提高产品的口碑与竞争力。
8.可以由运维人员去简单的触发一下,就把终端的日志通过网络传上去,不用再去找线,不用再去找U盘,不用再去想法把日志拷贝出来再带回电脑上发给开发人员。
9.可以由后台参数控制或比如发送短信,自动控制让某一台终端上报日志。
10.支持日志压缩,压缩为zip或7z等文件,缩小体积,便于储存和通过网络传输。
日志的意义在于排查问题和运维。
若所有机器都把日志上传上去则失去了意义,且服务器也顶不住。而这种被动的触发,针对某个机器的上送是可行的且有价值的。并且还可以在应用中增加当应用出现客户没发现缺不该出现的问题时,主动触发上报异常日志。这为提高产品的稳定性,杜绝问题造成的严重性而未发现提供先机。当某天发现一机器偶然吐出一异常的bug日志时,且这日志暴露的问题若不解决将造成严重后果,而你恰好在你的邮箱里看到,这就在不知不觉中主动发现了问题。不用运维人员去找你,客户去找你,机器向你求救了。那么,救救它吧。
OK,按着这个思想,以下是一个实现,c语言的log模块:
至于FTP部分,文件压缩为zip部分,用go来写,更容易。这也就是为啥用go来开发嵌入式很合适。要是让你用c写一个ftp,你试试?
这就体现了用go开发嵌入式linux的强大之处。用go,简短的几行代码就ok了。且在终端上跑的很溜。
代码语言:javascript复制/**
日志打印示例。
使用:
mylog(DEBUG, "This is debug infon");
结果:
[2018-07-22 23:37:27:172] [DEBUG] [main.cpp:5] This is debug info
默认打印当前时间(精确到毫秒)、文件名称、行号。
*/
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <pthread.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <errno.h>
#include <dirent.h>
#include <stdlib.h>
#include "log.h"
//#ifndef LOGLEVEL
//#define LOGLEVEL DEBUG
//#endif
// 使用了GNU C扩展语法,只在gcc(C语言)生效,
// g 的c 版本编译不通过
static const char* s_loginfo[] = {
[ERROR] = "ERROR",
[WARN] = "WARN",
[INFO] = "INFO",
[DEBUG] = "DEBUG",
};
static char file_names[LOGFILE_MAXCOUNT][LOGFILE_NAMELENTH];
//记录文件名前缀(最好取自终端编号)
static char file_prifix[LOGFILE_NAMELENTH];
//linux消息队列
static int s_msg_id;
static int r_msg_id;
#define MSG_TYPE 1001
#define MAX_TEXT 1024
struct msg_st{
long int msg_type;
char text[MAX_TEXT];
};
static pthread_t tid;
//=============================================
static void get_timestamp(char *buffer)
{
time_t t;
struct tm *p;
struct timeval tv;
int len;
int millsec;
t = time(NULL);
p = localtime(&t);
gettimeofday(&tv, NULL);
millsec = (int)(tv.tv_usec / 1000);
/* 时间格式:[2011-11-15 12:47:34:888] */
len = snprintf(buffer, 32, "[d-d-d d:d:d:d] ",
p->tm_year 1900, p->tm_mon 1,
p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec, millsec);
buffer[len] = '