Linux 日志输出控制

    在嵌入式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 \n");

    对于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!\n", __func__, __LINE__,log_dir);
            }
            else
            {
                printf("[%s:%d] create dir %s error!\n", __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


        上面代码可以实现不同进程调用同一套接口,根据时间和预定义的名字将日志文件打印到相应的文件中去。

 

 

你可能感兴趣的:(linux,编译调试)