這一篇是根據
An Sample Code for Syslogd - A log pattern with categorize, level and format的變形, 主要是針對某些log屬於多重類型(type)的設計, 主要差異用了標記為紅色
brook-log.h
#ifndef _LOG_H_
#define _LOG_H_
#include <syslog.h>
#include <unistd.h>
#include <sys/syscall.h>
/*************************************************
* TYPE
*************************************************/
enum log_type {
/* 這裡我先設定有三個類別,分別為AT,CORE與DB,之後請自行新增刪減修改 */
LOG_TYPE_AT,
LOG_TYPE_CORE,
LOG_TYPE_DB,
LOG_TYPE_MAX
};
#define LOG_TYPE_BIT(t) (1 << (LOG_TYPE_##t))
/***** internal function for MACRO used *****/
void _log_type_toggle(enum log_type type);
void _log_type_clr(enum log_type type);
void _log_type_set(enum log_type type);
/***** public function to enable/disable log on certain type *****/
#define log_type_toggle(type) _log_type_toggle(LOG_TYPE_##type)
#define log_type_clr(type) _log_type_clr(LOG_TYPE_##type)
#define log_type_set(type) _log_type_set(LOG_TYPE_##type)
char *get_log_type_status(void);
/*************************************************
* Format
*************************************************/
enum log_fmt {
LOG_FMT_FUNC_AND_LINE,
LOG_FMT_TID, ///<thread ID.
LOG_FMT_LOG_TYPE,
LOG_FMT_LOG_LEVEL,
LOG_FMT_MAX,
};
/***** internal function for MACRO used *****/
void _log_fmt_toggle(enum log_fmt fmt);
void _log_fmt_set(enum log_fmt fmt);
void _log_fmt_clr(enum log_fmt fmt);
int _log_fmt_is_set(enum log_fmt fmt);
/***** public function to enable/disable certain format type *****/
#define log_fmt_toggle(fmt) _log_fmt_toggle(LOG_FMT_##fmt)
#define log_fmt_set(fmt) _log_fmt_set(LOG_FMT_##fmt)
#define log_fmt_clr(fmt) _log_fmt_clr(LOG_FMT_##fmt)
#define log_fmt_is_set(fmt) _log_fmt_is_set(LOG_FMT_##fmt)
/*************************************************
* Level
*************************************************/
/***** internal function for MACRO used *****/
int _log_type_level_is(enum log_type type, int *level);
int _log_type_level_set(enum log_type type, int level);
/***** public function to set debug level. the level is leveraged from syslog *****/
#define log_type_level_is(type, level) _log_type_level_is(LOG_TYPE_##type, level)
#define log_type_level_set(type, level) _log_type_level_set(LOG_TYPE_##type, LOG_##level)
void log_pr(int type, int level, char const *const fmt,...);
const char *log_type_str(int type);
#define _log_pr(type, level, fmt, ...) \
do { \
unsigned char func[36] = {}, tid[16] = {}, tp[16] = {}, lv[16] = {};\
if (log_fmt_is_set(FUNC_AND_LINE)) { \
snprintf(func, sizeof(func) - 1, "%s(#%d), ", __FUNCTION__, __LINE__); \
} \
\
if (log_fmt_is_set(TID)) { \
snprintf(tid, sizeof(tid) - 1, "TID:%ld, ", getpid()); \
} \
\
if (log_fmt_is_set(LOG_TYPE)) { \
snprintf(tp, sizeof(tp) - 1, "%s, ", log_type_str(type)); \
} \
if (log_fmt_is_set(LOG_LEVEL)) { \
snprintf(tp, sizeof(lv) - 1, "%s, ", #level); \
} \
log_pr(type, LOG_##level, "%s%s%s%s"fmt, func, tid, tp, lv, ##__VA_ARGS__); \
} while(0)
/***** public function *****/
/* 請呼叫下面MACRO來印log */
#define pr_emerg(type, fmt, ...) _log_pr(type, EMERG, fmt, ##__VA_ARGS__)
#define pr_alert(type, fmt, ...) _log_pr(type, ALERT, fmt, ##__VA_ARGS__)
#define pr_crit(type, fmt, ...) _log_pr(type, CRIT, fmt, ##__VA_ARGS__)
#define pr_err(type, fmt, ...) _log_pr(type, ERR, fmt, ##__VA_ARGS__)
#define pr_warn(type, fmt, ...) _log_pr(type, WARNING, fmt, ##__VA_ARGS__)
#define pr_notice(type, fmt, ...) _log_pr(type, NOTICE, fmt, ##__VA_ARGS__)
#define pr_info(type, fmt, ...) _log_pr(type, INFO, fmt, ##__VA_ARGS__)
#define pr_dbg(type, fmt, ...) _log_pr(type, DEBUG, fmt, ##__VA_ARGS__)
#endif
brook-log.c
#include <stdio.h>
#include <stdarg.h>
#include <syslog.h>
#include "brook-log.h"
#define DEFAULT_LOG_TYPE ((1 << LOG_TYPE_AT) | \
(1 << LOG_TYPE_CORE) | \
(1 << LOG_TYPE_DB))
#define DEFAULT_LOG_FMT ((1 << LOG_FMT_FUNC_AND_LINE) | \
(1 << LOG_FMT_TID) | \
(1 << LOG_FMT_LOG_TYPE))
static unsigned int _log_types = DEFAULT_LOG_TYPE;
static unsigned int _log_fmts = DEFAULT_LOG_FMT;
#define DEFAULT_LOG_OPTION (LOG_CONS | LOG_NDELAY)
#define DEFAULT_LOG_FACILITY LOG_LOCAL0
#define DEFAULT_LOG_LEVEL LOG_INFO
char const *const level_str[] = {
[LOG_EMERG] = "EMERG",
[LOG_ALERT] = "ALERT",
[LOG_CRIT] = "CRIT",
[LOG_ERR] = "ERR",
[LOG_WARNING] = "WARN",
[LOG_NOTICE] = "NOTICE",
[LOG_INFO] = "INFO",
[LOG_DEBUG] = "DEBUG",
};
char const *const level_fmt_str[] = {
[LOG_FMT_FUNC_AND_LINE] = "FUNC_AND_LINE",
[LOG_FMT_TID] = "TID",
[LOG_FMT_LOG_TYPE] = "LOG_TYPE",
};
#define AR_SZ(a) (sizeof(a)/sizeof(a[0]))
#define BIT_SET(_v, _b) \
do { \
(_v) |= (1 << (_b));\
} while(0)
#define BIT_CLR(_v, _b) \
do { \
(_v) &= ~(1 << (_b));\
} while(0)
#define BIT_TOGGLE(_v, _b) \
do { \
(_v) ^= (1 << (_b)); \
} while(0)
int _log_fmt_is_set(enum log_fmt fmt)
{
if (_log_fmts & (1 << fmt)) {
return 1;
}
return 0;
}
void _log_fmt_set(enum log_fmt fmt)
{
BIT_SET(_log_fmts, fmt);
}
void _log_fmt_clr(enum log_fmt fmt)
{
BIT_CLR(_log_fmts, fmt);
}
void _log_fmt_toggle(enum log_fmt fmt)
{
BIT_TOGGLE(_log_fmts, fmt);
}
struct log_type_str_and_level {
char const *const name;
int level;
} log_type_str_and_level[] = {
/* TYPE有增減,請更新這個ARRAY */
[LOG_TYPE_AT] = { "AT", DEFAULT_LOG_LEVEL },
[LOG_TYPE_CORE] = { "CORE", DEFAULT_LOG_LEVEL },
[LOG_TYPE_DB] = { "DB", DEFAULT_LOG_LEVEL },
[LOG_TYPE_MAX] = { "MAX", DEFAULT_LOG_LEVEL },
};
char const *log_type_str(int type)
{
int i;
char buf[64], *p;
p = buf;
memset(buf, 0, sizeof(buf));
for (i = 0; i < AR_SZ(log_type_str_and_level); i++, type >>= 1) {
if (type & 1) {
p += snprintf(p, 64 - (p - buf), "%s/", log_type_str_and_level[i].name);
}
}
return buf;
}
int _log_type_level_is(enum log_type type, int *level)
{
if (type >= 0 && type < AR_SZ(log_type_str_and_level)) {
*level = log_type_str_and_level[type].level;
return 0;
}
return -1;
}
int _log_type_level_set(enum log_type type, int level)
{
if (type >= 0 && type < AR_SZ(log_type_str_and_level) && level >= 0 && level <= LOG_DEBUG) {
log_type_str_and_level[type].level = level;
return 0;
}
return -1;
}
int log_type_is_set(enum log_type type)
{
if (_log_types & (1 << type)) {
return 1;
}
return 0;
}
void _log_type_set(enum log_type type)
{
BIT_SET(_log_types, type);
}
void _log_type_clr(enum log_type type)
{
BIT_CLR(_log_types, type);
}
void _log_type_toggle(enum log_type type)
{
BIT_TOGGLE(_log_types, type);
}
void log_pr(int type, int level, char const *const fmt,...)
{
va_list ap;
int i;
if (_log_types & type) {
for (i = 0; i < AR_SZ(log_type_str_and_level); i++) {
if (log_type_str_and_level[i].level >= level) {
va_start(ap, fmt);
vsyslog(LOG_MAKEPRI(LOG_LOCAL0, level), fmt, ap);
va_end(ap);
return;
}
}
}
}
char *get_log_type_status_str(void)
{
int i = 0, re_sz;
static char buf[1024], *p;
p = buf;
re_sz = sizeof(buf);
p += snprintf(p, re_sz, "%2s %-16s %-10s %-12s\r\n", "id", "type", "status", "level");
for (i = 0; i < AR_SZ(log_type_str_and_level); i++) {
re_sz = sizeof(buf) - (p - buf);
if (re_sz < 1) {
break;
}
p += snprintf(p, re_sz, "%2d %-16s %-10s %-12s\r\n", i, log_type_str_and_level[i].name,
log_type_is_set((enum log_type)i) ? "enabled" : "disabled",
level_str[log_type_str_and_level[i].level]);
}
return buf;
}
char *get_log_fmt_status_str(void)
{
int i = 0, re_sz;
static char buf[256], *p;
p = buf;
re_sz = sizeof(buf);
p += snprintf(p, re_sz, "%2s %-16s %-12s\r\n", "id", "fmt", "status");
for (i = 0; i < AR_SZ(level_fmt_str); i++) {
re_sz = sizeof(buf) - (p - buf);
if (re_sz < 1) {
break;
}
p += snprintf(p, re_sz, "%2d %-16s %-12s\r\n", i, level_fmt_str[i],
_log_fmt_is_set((enum log_fmt)i) ? "enabled" : "disabled");
}
return buf;
}
void init_brook_log(void)
{
openlog(NULL, DEFAULT_LOG_OPTION, DEFAULT_LOG_FACILITY);
}
void exit_brook_log(void)
{
closelog();
}
void init_brook_log() __attribute__((constructor(101)));
void exit_brook_log() __attribute__((destructor(101)));
main.c
#include <stdio.h>
#include "brook-log.h"
int main(int argc, char *argv[])
{
pr_info(LOG_TYPE_BIT(AT) | LOG_TYPE_BIT(CORE), "AT=%d", 0);
log_type_clr(AT);
pr_info(LOG_TYPE_BIT(AT) | LOG_TYPE_BIT(CORE), "AT=%d", 1);
pr_info(LOG_TYPE_BIT(AT), "AT=%d", 11);
pr_info(LOG_TYPE_BIT(CORE), "AT=%d", 12);
log_type_set(AT);
pr_info(LOG_TYPE_BIT(AT) | LOG_TYPE_BIT(CORE), "AT=%d", 2);
log_fmt_toggle(FUNC_AND_LINE);
pr_info(LOG_TYPE_BIT(AT) | LOG_TYPE_BIT(CORE), "AT=%d", 3);
log_fmt_clr(TID);
pr_info(LOG_TYPE_BIT(AT) | LOG_TYPE_BIT(CORE), "AT=%d", 4);
log_type_level_set(AT, ERR);
pr_info(LOG_TYPE_BIT(AT) | LOG_TYPE_BIT(CORE), "AT=%d", 5);
return 0;
}
結果
brook@vista:~/sample/syslog$ gcc main.c brook-log.c -o brook-log
brook@vista:~/sample/syslog$ brook-log
brook@vista:~/sample/syslog$ tail /var/log/local.log
Nov 26 09:51:26 vista brook-log: main(#6), TID:21487, AT/CORE/, AT=0
Nov 26 09:51:26 vista brook-log: main(#9), TID:21487, AT/CORE/, AT=1
Nov 26 09:51:26 vista brook-log: main(#11), TID:21487, CORE/, AT=12
Nov 26 09:51:26 vista brook-log: main(#14), TID:21487, AT/CORE/, AT=2
Nov 26 09:51:26 vista brook-log: TID:21487, AT/CORE/, AT=3
Nov 26 09:51:26 vista brook-log: AT/CORE/, AT=4
Nov 26 09:51:26 vista brook-log: AT/CORE/, AT=5