summaryrefslogtreecommitdiff
path: root/log/log.c
blob: df73b1e9989ce8059781ed9476c3469c4cacacec (plain) (blame)
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include "log.h"


static struct {
	char *name;
	int set;
	FILE *fps[MAX_LOGFILES];
	int nfps;
	int stder;
#ifdef COLOR
	char *color;
#endif
} log_levels[LOG_LEVEL_COUNT] = {
	[LOG_DEBUG] = { 
		.name = "DEBUG", .set = 1, .fps = {0}, .nfps = 0, .stder = 1,
#ifdef COLOR
		.color = "\e[38;2;255;255;0m"
#endif
	},
	[LOG_INFO] = {
		.name = "INFO", .set = 1, .fps = {0}, .nfps = 0, .stder = 1,
#ifdef COLOR
		.color = "\e[38;2;0;224;255m"
#endif	
	},
	[LOG_WARN] = {
		.name = "WARN", .set = 1, .fps = {0}, .nfps = 0, .stder = 1,
#ifdef COLOR
		.color = "\e[38;2;255;165;0m"
#endif
	},
	[LOG_ERROR] = {
		.name = "ERROR", .set = 1, .fps = {0}, .nfps = 0, .stder = 1,
#ifdef COLOR
		.color = "\e[38;2;255;0;0m"
#endif
	}
};

static char time_format[16] = "%T";
static int nanosecond_precision = 0;


int log_set_stderr(int level, int of){
	if(level >= 0 && level < LOG_LEVEL_COUNT){
		return log_levels[level].stder = of;
	}
	return 0;
}

void log_set_level(int level, int of){
	if(level >= 0 && level < LOG_LEVEL_COUNT){
		log_levels[level].set = of;
	}
}

int log_add_fp(int level, FILE *fp){
	if(level >= 0 && level < LOG_LEVEL_COUNT && log_levels[level].nfps < MAX_LOGFILES-1){
		log_levels[level].fps[log_levels[level].nfps++] = fp;
		return 0;
	}
	return 1;
}

void log_time_format(char *tf){
	strncpy(time_format, tf, sizeof(time_format)/sizeof(time_format[0]));
}

int log_nanoseconds(int n){
	return nanosecond_precision = n%10;
}

void log_message(int level, char *file, int line, char *fmt, ...){
	struct timespec ts;
	clock_gettime(CLOCK_REALTIME, &ts);
	if(level >= 0 && level < LOG_LEVEL_COUNT && log_levels[level].set){
		struct tm *lt = localtime(&ts.tv_sec);
		char t[32] = {0};
		strftime(t, 31, time_format, lt);
		char ns[9] = {0};
		snprintf(ns, nanosecond_precision+1, "%ld", ts.tv_nsec);
		char msg[MSG_LIMIT] = {0};
		int written = snprintf(msg, MSG_LIMIT-2,
#ifdef PID
			"[%d] "
#endif
			"%s%s%s%s%s%s%s\t",
#ifdef PID
			getpid(),
#endif
			t, nanosecond_precision ? "." : "", ns,
			t[0] != '\0' ? " " : "",
#ifdef COLOR
			log_levels[level].color,
#else
			"",
#endif
			log_levels[level].name, "\e[0m"
		);
		if(level == LOG_DEBUG){
			written += snprintf(msg+written, MSG_LIMIT-2-written, "%s:%d: ",file, line);
		}
		va_list args;
		va_start(args, fmt);
		written += vsnprintf(msg+written, MSG_LIMIT-2-written, fmt, args);
		msg[written] = '\n';
		if(log_levels[level].stder) fputs(msg, stderr);
		for(int i = 0; i < log_levels[level].nfps; i++){
			if(log_levels[level].fps[i] != NULL)
				fputs(msg, log_levels[level].fps[i++]);
		}
	}
}