📄 log.c
字号:
#include <assert.h>#include <sys/types.h>#include <stdlib.h>#include <string.h>#include <stdarg.h>#include <errno.h>#include <fcntl.h>#include <sys/stat.h>#include <sys/mman.h>#include <unistd.h>#include <sys/time.h>#include <time.h>#include <stdio.h>#include <pthread.h>//#include "benchapi.h"#include "log.h"#define MAX_LOG_CNT 1000enum { false = 0, true = 1};static int has_init = 0;static int log_level;static u_int log_size;static char log_pre[32] = {0};static char log_dir[256] = {0};static struct fds_t { int seq; int opfd; u_short day;} fds_info[APP_TRACE + 1];static char* log_buffer = MAP_FAILED;static int is_need_sync = 0;pthread_mutex_t mutex;static inline void log_file_name(int lvl, int seq, char* file_name, time_t now){ struct tm tm; assert (lvl >= APP_EMERG && lvl <= APP_TRACE); localtime_r(&now, &tm); sprintf (file_name, "%s/%s%s%04d%02d%02d%03d", log_dir, log_pre, ((char*[]){ "emerg", "alert", "crit", "error", "warn", "notice", "info", "debug", "trace" })[lvl], tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, seq);}static int request_log_seq (int lvl){ char file_name[FILENAME_MAX]; int seq; time_t now = time (NULL); struct stat buf; /* * find last log and tag with seq */ for (seq = 0; seq < MAX_LOG_CNT; seq ++) { log_file_name (lvl, seq, file_name, now); if (access (file_name, F_OK)) { if (seq == 0) return 0; else break; } } if (seq == MAX_LOG_CNT) { fprintf (stderr, "too many log files\n"); return -1; } log_file_name (lvl, --seq, file_name, now); if (stat (file_name, &buf)) { fprintf (stderr, "stat %s error, %m\n", file_name); return -1; } return seq == 0 ? seq : seq - 1;}static int open_fd(int lvl, time_t now){ char file_name[FILENAME_MAX]; struct tm *tm; int val; log_file_name (lvl, fds_info[lvl].seq, file_name, now); fds_info[lvl].opfd = open (file_name, O_WRONLY|O_CREAT|O_APPEND, 0644); if (fds_info[lvl].opfd > 0) { tm = localtime (&now); fds_info[lvl].day = tm->tm_yday; val = fcntl(fds_info[lvl].opfd, F_GETFD, 0); val |= FD_CLOEXEC; fcntl(fds_info[lvl].opfd, F_SETFD, val); } return fds_info[lvl].opfd;}static int shift_fd (int lvl, time_t now){ off_t length; struct tm *tm; if (fds_info[lvl].opfd < 0 && (open_fd (lvl, now) < 0)) return -1; length = lseek (fds_info[lvl].opfd, 0, SEEK_END); tm = localtime (&now); if (length < log_size && fds_info[lvl].day == tm->tm_yday) return 0; close (fds_info[lvl].opfd); if ( fds_info[lvl].day != tm->tm_yday) fds_info[lvl].seq = 0; else fds_info[lvl].seq ++; return open_fd (lvl, now);}void boot_log (int OK, int dummy, const char* fmt, ...){#define SCREEN_COLS 80#define BOOT_OK "\e[1m\e[32m[ ok ]\e[m"#define BOOT_FAIL "\e[1m\e[31m[ failed ]\e[m" int end, i, pos; va_list ap; if (log_buffer == MAP_FAILED) { log_buffer = mmap (0, 4096, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (log_buffer == MAP_FAILED) { fprintf (stderr, "mmap log buffer failed, %m\n"); exit (-1); } } va_start(ap, fmt); end = vsprintf (log_buffer, fmt, ap); va_end (ap); pos = SCREEN_COLS - 10 - (end - dummy) % SCREEN_COLS; for (i = 0; i < pos; i++) log_buffer[end + i] = ' '; log_buffer[end + i] = '\0'; strcat (log_buffer, OK == 0 ? BOOT_OK : BOOT_FAIL); printf ("\r%s\n", log_buffer); if (OK != 0) exit (OK); }void write_log (int lvl, const char* fmt, ...){ struct tm tm; struct timezone tz; struct timeval tv; int pos, end; va_list ap; time_t now; //int i = 0; char log_buffer_local[4096] = {0}; if (!has_init) { va_start(ap, fmt); switch (lvl) { case APP_EMERG: case APP_CRIT: case APP_ALERT: case APP_ERROR: vfprintf (stderr, fmt, ap); break; default: vfprintf (stdout, fmt, ap); break; } va_end(ap); return; } if (lvl > log_level) return ; gettimeofday(&tv, &tz); now = tv.tv_sec; if (shift_fd (lvl, now) < 0) return ; localtime_r(&now, &tm);#if TEST// printf("Before write buffer=\n"); for(i = 0; i< 100; i++) {// printf("%c ",log_buffer[i]); }// printf("end\n");#endif if(true == is_need_sync) { pthread_mutex_lock(&mutex); } if (lvl == APP_INFO || lvl == APP_NOTICE || lvl == APP_WARNING) pos = sprintf (log_buffer_local, "[%02d:%02d:%02d.%06u]", tm.tm_hour, tm.tm_min, tm.tm_sec, (unsigned int)tv.tv_usec); else pos = sprintf (log_buffer_local, "[%02d:%02d:%02d.%06u][%05d]", tm.tm_hour, tm.tm_min, tm.tm_sec, (unsigned int)tv.tv_usec, getpid()); #if TEST// printf("After write buffer=\n"); for(i = 0; i< 100; i++) {// printf("%c ",log_buffer[i]); }// printf("end\n"); //usleep(10);// printf("After sleep buffer=\n"); for(i = 0; i< 100; i++) {// printf("%c ",log_buffer[i]); }// printf("end\n");#endif va_start(ap, fmt); end = vsprintf (log_buffer_local + pos, fmt, ap); va_end(ap); write (fds_info[lvl].opfd, log_buffer_local, end + pos); if(true == is_need_sync) { pthread_mutex_unlock(&mutex); }}int log_init (const char* dir, int lvl, u_int size, const char* pre_name, int need_sync){ int i, ret_code = -1; is_need_sync = need_sync; if (lvl < 0 || lvl > APP_TRACE) { fprintf (stderr, "init log error, invalid log level=%d\n", lvl); goto exit_entry; } /* * log file is no larger than 2GB */ if (size > 1<<31) { fprintf (stderr, "init log error, invalid log size=%d\n", size); goto exit_entry; } if (access (dir, W_OK)) { fprintf (stderr, "access log dir %s error, %m\n", dir); goto exit_entry; } if (log_buffer == MAP_FAILED) { log_buffer = mmap (0, 4096, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (log_buffer == MAP_FAILED) { fprintf (stderr, "mmap log buffer failed, %m\n"); goto exit_entry; } } strncpy (log_dir, dir, sizeof (log_dir) - 1); if (pre_name != NULL) strncpy (log_pre, pre_name, sizeof (log_pre) - 1); log_size = size; log_level = lvl; for (i = APP_EMERG; i <= APP_TRACE; i++) { fds_info[i].opfd = -1; fds_info[i].seq = request_log_seq (i); if (fds_info[i].seq < 0) goto exit_entry; } has_init = 1; ret_code = 0;exit_entry: BOOT_LOG (ret_code, "set log dir %s, per file size %d MB", dir, size/1024/1024);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -