Redis输出日志

Redis在配置文件redis.conf的logfile配置为”“时,其会将日志输出到standard output。我们查看其输出日志的代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
void serverLogRaw(int level, const char *msg) {
    const int syslogLevelMap[] = { LOG_DEBUG, LOG_INFO, LOG_NOTICE, LOG_WARNING };
    const char *c = ".-*#";
    FILE *fp;
    char buf[64];
    int rawmode = (level & LL_RAW);
    int log_to_stdout = server.logfile[0] == '\0';

    level &= 0xff; /* clear flags */
    if (level < server.verbosity) return;

    // 判断是否输出到文件还是stdout
    fp = log_to_stdout ? stdout : fopen(server.logfile,"a");
    if (!fp) return;

    if (rawmode) {
        fprintf(fp,"%s",msg);
    } else {
        int off;
        struct timeval tv;
        int role_char;
        pid_t pid = getpid();

        gettimeofday(&tv,NULL);
        struct tm tm;
        nolocks_localtime(&tm,tv.tv_sec,server.timezone,server.daylight_active);
        off = strftime(buf,sizeof(buf),"%d %b %Y %H:%M:%S.",&tm);
        snprintf(buf+off,sizeof(buf)-off,"%03d",(int)tv.tv_usec/1000);
        if (server.sentinel_mode) {
            role_char = 'X'; /* Sentinel. */
        } else if (pid != server.pid) {
            role_char = 'C'; /* RDB / AOF writing child. */
        } else {
            role_char = (server.masterhost ? 'S':'M'); /* Slave or Master. */
        }
        fprintf(fp,"%d:%c %s %c %s\n",
            (int)getpid(),role_char, buf, c[level], msg);
    }
    fflush(fp);

    if (!log_to_stdout) fclose(fp);
    if (server.syslog_enabled) syslog(syslogLevelMap[level], "%s", msg);
}

参考上述源码,自己模仿实现如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/time.h>

void ServerLog(bool should_stdout, const char *msg) {
    FILE *fp = should_stdout ? stdout : fopen("test.log", "a+");
    if (!fp) {
        fprintf(stderr, "fp == NULL\n");
        return;
    }

    char buf[64];
    int off = 0;
    pid_t pid = getpid();
    struct timeval tv;
    gettimeofday(&tv, NULL);
    time_t raw_time;
    struct tm *info;
    time(&raw_time);
    info = localtime(&raw_time);
    off = strftime(buf, sizeof(buf), "%d %b %Y %H:%M:%S.", info);
    snprintf(buf + off, sizeof(buf) - off, "%03d", (int)tv.tv_usec / 1000);
    fprintf(fp, "[%d][%s] %s\n", pid, buf, msg);
    fflush(fp);
    if (!should_stdout) {
        fclose(fp);
    }
}


int main() {
    ServerLog(true, "Output to stdout");
    ServerLog(false, "Output to file");

    return 0;
}

# 运行结果:
$ ./log
[17558][27 Feb 2020 22:05:39.318] Output to stdout
$ ./log
[17582][27 Feb 2020 22:05:40.744] Output to stdout
$ ./log
[17585][27 Feb 2020 22:05:41.426] Output to stdout
$ cat test.log
[17558][27 Feb 2020 22:05:39.319] Output to file
[17582][27 Feb 2020 22:05:40.745] Output to file
[17585][27 Feb 2020 22:05:41.427] Output to file

在后续的工作中我们也可以借这种模式,输出日志可以灵活的指定为stdout或者文件。