Linux 日志输出控制

2019-07-13 00:53发布

    在嵌入式Linux设备中,系统资源比较有限,在产品开发时我们会打印很多的日志信息方便工程调试和问题定位。但是在产品发布的时候,为了节省系统资源,那些调试信息或是一些不总要的信息就不需要再记入到日志当中,所以我们需要设置相应的日志等级。     Linux内核调试信息printk函数,它的输出等级在Linux内核中已经帮我们定义好。可以通过命令查看和设置系统日志等级: / # cat /proc/sys/kernel/printk 4 4 1 7 / # / # / # echo 7 4 1 7 > /proc/sys/kernel/printk / # / # / # cat /proc/sys/kernel/printk 7 4 1 7     这四个值分别表示:控制台日志级别;默认的消息日志级别;最低的控制台日志级别,默认的控制台日志级别。这四个值是在kernel的printk.c文件中被定义,数值越小,优先级越高。如果要修改默然的开机启动日志级别,可以直接修改printk.c中的定义。     对于应用层的日志输出控制,一般的应用会有自己的日志系统。如果没有日志系统,或是使用的日志系统比较混乱,也可以自己定义一套属于自己的日志系统。 #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* * Name: debug.h * Purpose: general debug system * Created By: licaibiao * Created Date: 2016.11.10 * ChangeList: */ /*must use _B_ ,have a DEBUG_ in Jason*/ #ifndef _DEBUG_B_H_ #define _DEBUG_B_H_ /* * debug control, you can switch on (delete 'x' suffix) * to enable log output and assert mechanism */ #define CONFIG_ENABLE_DEBUG /* * debug level, * if is DEBUG_LEVEL_DISABLE, no log is allowed output, * if is DEBUG_LEVEL_ERR, only ERR is allowed output, * if is DEBUG_LEVEL_INFO, ERR and INFO are allowed output, * if is DEBUG_LEVEL_DEBUG, all log are allowed output, */ enum debug_level { DEBUG_LEVEL_DISABLE = 0, DEBUG_LEVEL_ERR, DEBUG_LEVEL_INFO, DEBUG_LEVEL_DEBUG }; #ifdef CONFIG_ENABLE_DEBUG /* it can be change to others, such as file operations */ #include #define PRINT printf #define debug DEBUG_LEVEL_DISABLE #define ASSERT() do { PRINT("ASSERT: %s %s %d", __FILE__, __FUNCTION__, __LINE__); while (1); } while (0) #define ERR(...) do { if (debug >= DEBUG_LEVEL_ERR) { PRINT(__VA_ARGS__); } } while (0) #define INFO(...) do { if (debug >= DEBUG_LEVEL_INFO) { PRINT(__VA_ARGS__); } } while (0) #define DEBUG(...) do { if (debug >= DEBUG_LEVEL_DEBUG) { PRINT(__VA_ARGS__); } } while (0) #else /* CONFIG_ENABLE_DEBUG */ #define ASSERT() #define ERR(...) #define INFO(...) #define DEBUG(...) #endif /* CONFIG_ENABLE_DEBUG */ #endif /* _DEBUG_H_ */ #ifdef __cplusplus } #endif /* __cplusplus */     在应用程序中可以直接包含头文件调用接口: ERR("This is a test interface ");     对于linux应用层的日志信息,如果要将日志写入到文件中,且能够打印时间戳等信息,可以使用下面的接口: #ifndef __GPS_DEBUG_H__ #define __GPS_DEBUG_H__ #include #include #include #include #define MAX_LOGFILE_SIZE 50000 #define LOGFLAG 1 enum UserDefineLogNum { GENERAL_LOG_NUM=1, DAEMON_LOG_NUM, ROUTER_LOG_NUM, MODEM_LOG_NUM, PERIPHER_LOG_NUM, GPSSERVICE_LOG_NUM, CAPTURE_LOG_NUM, OTHER_LOG_NUM, }; #if LOGFLAG > 0 #define TRACE_TRACE_GENERAL Trace(GENERAL_LOG_NUM, __LINE__) #define TRACE_DAEMON Trace(DAEMON_LOG_NUM, __LINE__) #define TRACE_ROUTER Trace(ROUTER_LOG_NUM, __LINE__) #define TRACE_MODEM Trace(MODEM_LOG_NUM, __LINE__) #define TRACE_PERIPHER Trace(PERIPHER_LOG_NUM, __LINE__) #define TRACE_GPSSERVICE Trace(GPSSERVICE_LOG_NUM, __LINE__) #define TRACE_CAPTURE Trace(CAPTURE_LOG_NUM, __LINE__) #define TRACE_OTHER Trace(OTHER_LOG_NUM, __LINE__) #else #define TRACE printf #define TRACE_GENERAL printf #define TRACE_DAEMON printf #define TRACE_GPS printf #define TRACE_CAPTURE printf #define TRACE_PPP printf #define TRACE_COMM printf #define TRACE_UPDATE printf #endif #define SYSLOGDIR "/mnt/log/" #define SYSLOGDISK "/mnt/" #define MIX_AVAILABLE_DISK (1024+512) #define TRACE_HST (printf("%s(%d)-<%s>: ",__FILE__, __LINE__, __FUNCTION__), printf) class Trace { public: Trace(UserDefineLogNum LogNum, int nLineNo ):defineLogNum(LogNum),m_nLineNo(nLineNo) { } inline void operator()(const char *pszFmt, ...) const { va_list ptr; va_start(ptr, pszFmt); TraceV(m_nLineNo,pszFmt,ptr); va_end(ptr); } private: unsigned int availableDisk(const char * pcDir) const { if(NULL == pcDir) return -1; struct statfs diskInfo; unsigned int blocksize = 0; //每个block里包含的字节数 unsigned int availableDisk = 0; //可用空间大小 int iRet = -1; iRet = statfs(pcDir, &diskInfo); if(0 == iRet) { blocksize = diskInfo.f_bsize; availableDisk = diskInfo.f_bavail * blocksize/1024;//(K) } return availableDisk; } void TraceV(int nLine,const char *pszFmt, va_list args) const { time_t tNow; time(&tNow); struct tm *time; time=localtime(&tNow); char log_path[64] ={0}; char log_dir[64] ={0}; if(time->tm_year-100 < 16 && time->tm_year-100 > 30) { time->tm_year =116; time->tm_mon =0; } if(MIX_AVAILABLE_DISK>=availableDisk(SYSLOGDISK)) { system("rm -rf /mnt/log/*"); //统一删除不做覆盖 return; } sprintf(log_dir,"%sl-%02d%02d%02d",SYSLOGDIR,(time->tm_year-100),(1+time->tm_mon),(time->tm_mday)); if ( 0 != access(log_dir, F_OK) ) { if( mkdir(log_dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)==0 ) { printf("[%s:%d] create dir %s ok! ", __func__, __LINE__,log_dir); } else { printf("[%s:%d] create dir %s error! ", __func__, __LINE__,log_dir); perror("mkdir"); return; } } sprintf(log_path,"%s/1000000%d.log",log_dir,defineLogNum); FILE* pFile=fopen(log_path,"a+"); if (pFile==NULL) { vprintf(pszFmt,args); return; } fprintf(pFile,"%02d-%02d %02d:%02d:%02d : ",time->tm_mon+1,time->tm_mday,time->tm_hour,time->tm_min,time->tm_sec); vfprintf(pFile,pszFmt,args); fclose(pFile); return; } private: UserDefineLogNum defineLogNum; const int m_nLineNo; }; #endif         上面代码可以实现不同进程调用同一套接口,根据时间和预定义的名字将日志文件打印到相应的文件中去。