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