1
2 /* $Id: zlog.c,v 1.7 2008/05/22 21:08:32 anight Exp $ */
3 /* (c) 2004-2007 Andrei Nigmatulin */
4
5 #include "fpm_config.h"
6
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <time.h>
10 #include <string.h>
11 #include <stdarg.h>
12 #include <sys/time.h>
13 #include <errno.h>
14
15 #include "php_syslog.h"
16
17 #include "zlog.h"
18 #include "fpm.h"
19 #include "zend_portability.h"
20
21 #define MAX_LINE_LENGTH 1024
22
23 static int zlog_fd = -1;
24 static int zlog_level = ZLOG_NOTICE;
25 static int launched = 0;
26 static void (*external_logger)(int, char *, size_t) = NULL;
27
28 static const char *level_names[] = {
29 [ZLOG_DEBUG] = "DEBUG",
30 [ZLOG_NOTICE] = "NOTICE",
31 [ZLOG_WARNING] = "WARNING",
32 [ZLOG_ERROR] = "ERROR",
33 [ZLOG_ALERT] = "ALERT",
34 };
35
36 #ifdef HAVE_SYSLOG_H
37 const int syslog_priorities[] = {
38 [ZLOG_DEBUG] = LOG_DEBUG,
39 [ZLOG_NOTICE] = LOG_NOTICE,
40 [ZLOG_WARNING] = LOG_WARNING,
41 [ZLOG_ERROR] = LOG_ERR,
42 [ZLOG_ALERT] = LOG_ALERT,
43 };
44 #endif
45
zlog_set_external_logger(void (* logger)(int,char *,size_t))46 void zlog_set_external_logger(void (*logger)(int, char *, size_t)) /* {{{ */
47 {
48 external_logger = logger;
49 }
50 /* }}} */
51
zlog_get_level_name(int log_level)52 const char *zlog_get_level_name(int log_level) /* {{{ */
53 {
54 if (log_level < 0) {
55 log_level = zlog_level;
56 } else if (log_level < ZLOG_DEBUG || log_level > ZLOG_ALERT) {
57 return "unknown value";
58 }
59
60 return level_names[log_level];
61 }
62 /* }}} */
63
zlog_set_launched(void)64 void zlog_set_launched(void) {
65 launched = 1;
66 }
67
zlog_print_time(struct timeval * tv,char * timebuf,size_t timebuf_len)68 size_t zlog_print_time(struct timeval *tv, char *timebuf, size_t timebuf_len) /* {{{ */
69 {
70 struct tm t;
71 size_t len;
72
73 len = strftime(timebuf, timebuf_len, "[%d-%b-%Y %H:%M:%S", localtime_r((const time_t *) &tv->tv_sec, &t));
74 if (zlog_level == ZLOG_DEBUG) {
75 len += snprintf(timebuf + len, timebuf_len - len, ".%06d", (int) tv->tv_usec);
76 }
77 len += snprintf(timebuf + len, timebuf_len - len, "] ");
78 return len;
79 }
80 /* }}} */
81
zlog_set_fd(int new_fd)82 int zlog_set_fd(int new_fd) /* {{{ */
83 {
84 int old_fd = zlog_fd;
85
86 zlog_fd = new_fd;
87 return old_fd;
88 }
89 /* }}} */
90
zlog_set_level(int new_value)91 int zlog_set_level(int new_value) /* {{{ */
92 {
93 int old_value = zlog_level;
94
95 if (new_value < ZLOG_DEBUG || new_value > ZLOG_ALERT) return old_value;
96
97 zlog_level = new_value;
98 return old_value;
99 }
100 /* }}} */
101
vzlog(const char * function,int line,int flags,const char * fmt,va_list args)102 void vzlog(const char *function, int line, int flags, const char *fmt, va_list args) /* {{{ */
103 {
104 struct timeval tv;
105 char buf[MAX_LINE_LENGTH];
106 const size_t buf_size = MAX_LINE_LENGTH;
107 size_t len = 0;
108 int truncated = 0;
109 int saved_errno;
110
111 if (external_logger) {
112 va_list ap;
113 va_copy(ap, args);
114 len = vsnprintf(buf, buf_size, fmt, ap);
115 va_end(ap);
116 if (len >= buf_size) {
117 memcpy(buf + buf_size - sizeof("..."), "...", sizeof("...") - 1);
118 len = buf_size - 1;
119 }
120 external_logger(flags & ZLOG_LEVEL_MASK, buf, len);
121 len = 0;
122 memset(buf, '\0', buf_size);
123 }
124
125 if ((flags & ZLOG_LEVEL_MASK) < zlog_level) {
126 return;
127 }
128
129 saved_errno = errno;
130 #ifdef HAVE_SYSLOG_H
131 if (zlog_fd == ZLOG_SYSLOG /* && !fpm_globals.is_child */) {
132 len = 0;
133 if (zlog_level == ZLOG_DEBUG) {
134 len += snprintf(buf, buf_size, "[%s] %s(), line %d: ", level_names[flags & ZLOG_LEVEL_MASK], function, line);
135 } else {
136 len += snprintf(buf, buf_size, "[%s] ", level_names[flags & ZLOG_LEVEL_MASK]);
137 }
138 } else
139 #endif
140 {
141 if (!fpm_globals.is_child) {
142 gettimeofday(&tv, 0);
143 len = zlog_print_time(&tv, buf, buf_size);
144 }
145 if (zlog_level == ZLOG_DEBUG) {
146 if (!fpm_globals.is_child) {
147 len += snprintf(buf + len, buf_size - len, "%s: pid %d, %s(), line %d: ", level_names[flags & ZLOG_LEVEL_MASK], getpid(), function, line);
148 } else {
149 len += snprintf(buf + len, buf_size - len, "%s: %s(), line %d: ", level_names[flags & ZLOG_LEVEL_MASK], function, line);
150 }
151 } else {
152 len += snprintf(buf + len, buf_size - len, "%s: ", level_names[flags & ZLOG_LEVEL_MASK]);
153 }
154 }
155
156 if (len > buf_size - 1) {
157 truncated = 1;
158 }
159
160 if (!truncated) {
161 len += vsnprintf(buf + len, buf_size - len, fmt, args);
162 if (len >= buf_size) {
163 truncated = 1;
164 }
165 }
166
167 if (!truncated) {
168 if (flags & ZLOG_HAVE_ERRNO) {
169 len += snprintf(buf + len, buf_size - len, ": %s (%d)", strerror(saved_errno), saved_errno);
170 if (len >= buf_size) {
171 truncated = 1;
172 }
173 }
174 }
175
176 if (truncated) {
177 memcpy(buf + buf_size - sizeof("..."), "...", sizeof("...") - 1);
178 len = buf_size - 1;
179 }
180
181 #ifdef HAVE_SYSLOG_H
182 if (zlog_fd == ZLOG_SYSLOG) {
183 buf[len] = '\0';
184 php_syslog(syslog_priorities[zlog_level], "%s", buf);
185 buf[len++] = '\n';
186 } else
187 #endif
188 {
189 buf[len++] = '\n';
190 zend_quiet_write(zlog_fd > -1 ? zlog_fd : STDERR_FILENO, buf, len);
191 }
192
193 if (zlog_fd != STDERR_FILENO && zlog_fd != -1 && !launched && (flags & ZLOG_LEVEL_MASK) >= ZLOG_NOTICE) {
194 zend_quiet_write(STDERR_FILENO, buf, len);
195 }
196 }
197 /* }}} */
198
zlog_ex(const char * function,int line,int flags,const char * fmt,...)199 void zlog_ex(const char *function, int line, int flags, const char *fmt, ...) /* {{{ */ {
200 va_list args;
201 va_start(args, fmt);
202 vzlog(function, line, flags, fmt, args);
203 va_end(args);
204 }
205 /* }}} */
206