在看開源項目的twemproxy時,發現它的日誌系統寫的很小巧,稍微改改就可以變成自己的日誌系統,可以添加一個log.ini文件來配置日誌級別等等。
具體測試代碼如下:
#include <stdio.h>
#include <stdarg.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
struct logger {
char *name;
int level;
int fd;
int nerror;
};
#define LOG_EMERG 0 /* system in unusable */
#define LOG_ALERT 1 /* action must be taken immediately */
#define LOG_CRIT 2 /* critical conditions */
#define LOG_ERR 3 /* error conditions */
#define LOG_WARN 4 /* warning conditions */
#define LOG_NOTICE 3 /* normal but significant condition (default) */
#define LOG_INFO 6 /* informational */
#define LOG_DEBUG 7 /* debug messages */
#define LOG_VERB 8 /* verbose messages */
#define LOG_VVERB 9 /* verbose messages on crack */
#define LOG_VVVERB 10 /* verbose messages on ganga */
#define LOG_PVERB 11 /* periodic verbose messages on crack */
#define LOG_MAX_LEN 256 /* max length of log message */
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define nc_scnprintf(_s, _n, ...) \
_scnprintf((char *)(_s), (size_t)(_n), __VA_ARGS__)
#define nc_vscnprintf(_s, _n, _f, _a) \
_vscnprintf((char *)(_s), (size_t)(_n), _f, _a)
#define nc_strftime(_s, _n, fmt, tm) \
(int)strftime((char *)(_s), (size_t)(_n), fmt, tm)
#define nc_write(_d, _b, _n) \
write(_d, _b, (size_t)(_n))
#define loga(...) do { \
_log(__FILE__, __LINE__, 0, __VA_ARGS__); \
} while (0)
#define log_stderr(...) do { \
_log_stderr(__VA_ARGS__); \
} while (0)
static struct logger logger;
int
log_init(int level, char *name)
{
struct logger *l = &logger;
l->level = MAX(LOG_EMERG, MIN(level, LOG_PVERB));
l->name = name;
if (name == NULL || !strlen(name)) {
l->fd = STDERR_FILENO;
} else {
l->fd = open(name, O_WRONLY | O_APPEND | O_CREAT, 0644);
if (l->fd < 0) {
log_stderr("opening log file '%s' failed: %s", name,
strerror(errno));
return -1;
}
}
return 0;
}
int
_scnprintf(char *buf, size_t size, const char *fmt, ...)
{
va_list args;
int n;
va_start(args, fmt);
n = _vscnprintf(buf, size, fmt, args);
va_end(args);
return n;
}
int
_vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
{
int n;
n = vsnprintf(buf, size, fmt, args);
/*
* The return value is the number of characters which would be written
* into buf not including the trailing '\0'. If size is == 0 the
* function returns 0.
*
* On error, the function also returns 0. This is to allow idiom such
* as len += _vscnprintf(...)
*
* See: http://lwn.net/Articles/69419/
*/
if (n <= 0) {
return 0;
}
if (n < (int) size) {
return n;
}
return (int)(size - 1);
}
void
_log(const char *file, int line, int panic, const char *fmt, ...)
{
struct logger *l = &logger;
int len, size, errno_save;
char buf[LOG_MAX_LEN];
va_list args;
ssize_t n;
struct timeval tv;
if (l->fd < 0) {
return;
}
errno_save = errno;
len = 0; /* length of output buffer */
size = LOG_MAX_LEN; /* size of output buffer */
gettimeofday(&tv, NULL);
buf[len++] = '[';
len += nc_strftime(buf + len, size - len, "%Y-%m-%d %H:%M:%S.", localtime(&tv.tv_sec));
len += nc_scnprintf(buf + len, size - len, "%03ld", tv.tv_usec/1000);
len += nc_scnprintf(buf + len, size - len, "] [pid:%d", getpid());
len += nc_scnprintf(buf + len, size - len, "] %s:%d ", file, line);
va_start(args, fmt);
len += nc_vscnprintf(buf + len, size - len, fmt, args);
va_end(args);
buf[len++] = '\n';
n = nc_write(l->fd, buf, len);
if (n < 0) {
l->nerror++;
}
errno = errno_save;
if (panic) {
abort();
}
}
void
_log_stderr(const char *fmt, ...)
{
struct logger *l = &logger;
int len, size, errno_save;
char buf[4 * LOG_MAX_LEN];
va_list args;
ssize_t n;
errno_save = errno;
len = 0; /* length of output buffer */
size = 4 * LOG_MAX_LEN; /* size of output buffer */
va_start(args, fmt);
len += nc_vscnprintf(buf, size, fmt, args);
va_end(args);
buf[len++] = '\n';
n = nc_write(STDERR_FILENO, buf, len);
if (n < 0) {
l->nerror++;
}
errno = errno_save;
}
void
log_deinit(void)
{
struct logger *l = &logger;
if (l->fd < 0 || l->fd == STDERR_FILENO) {
return;
}
close(l->fd);
}
int main(int argc, char *argv[])
{
log_init(LOG_INFO, "a.log");
loga("hello");
loga("nihao");
log_deinit();
return 0;
}
運行後生成a.log文件,文件內容如下,具體輸出什麼格式的日誌可以自己定製:
[2019-08-06 01:12:04.984] [pid:38316] log.c:209 hello
[2019-08-06 01:12:04.985] [pid:38316] log.c:210 nihao