[core] mv log_error_{open,cycle.close} to server.c
[lighttpd.git] / src / log.c
blob9624de08032777e3cb4ec887180f0f1ac423b85e
1 #include "first.h"
3 #include "base.h"
4 #include "log.h"
6 #include <sys/types.h>
7 #include <errno.h>
8 #include <time.h>
9 #include <string.h>
10 #include <stdarg.h>
12 #ifdef HAVE_SYSLOG_H
13 # include <syslog.h>
14 #endif
16 #ifndef HAVE_CLOCK_GETTIME
17 #ifdef HAVE_SYS_TIME_H
18 # include <sys/time.h> /* gettimeofday() */
19 #endif
20 #endif
22 int log_clock_gettime_realtime (struct timespec *ts) {
23 #ifdef HAVE_CLOCK_GETTIME
24 return clock_gettime(CLOCK_REALTIME, ts);
25 #else
26 /* Mac OSX does not provide clock_gettime()
27 * e.g. defined(__APPLE__) && defined(__MACH__) */
28 struct timeval tv;
29 gettimeofday(&tv, NULL);
30 ts->tv_sec = tv.tv_sec;
31 ts->tv_nsec = tv.tv_usec * 1000;
32 return 0;
33 #endif
36 /* retry write on EINTR or when not all data was written */
37 ssize_t write_all(int fd, const void* buf, size_t count) {
38 ssize_t written = 0;
40 while (count > 0) {
41 ssize_t r = write(fd, buf, count);
42 if (r < 0) {
43 switch (errno) {
44 case EINTR:
45 /* try again */
46 break;
47 default:
48 /* fail - repeating probably won't help */
49 return -1;
51 } else if (0 == r) {
52 /* really shouldn't happen... */
53 errno = EIO;
54 return -1;
55 } else {
56 force_assert(r <= (ssize_t) count);
57 written += r;
58 buf = r + (char const*) buf;
59 count -= r;
63 return written;
66 /* lowercase: append space, uppercase: don't */
67 static void log_buffer_append_printf(buffer *out, const char *fmt, va_list ap) {
68 for(; *fmt; fmt++) {
69 int d;
70 char *s;
71 buffer *b;
72 off_t o;
74 switch(*fmt) {
75 case 's': /* string */
76 s = va_arg(ap, char *);
77 buffer_append_string_c_escaped(out, s, (NULL != s) ? strlen(s) : 0);
78 buffer_append_string_len(out, CONST_STR_LEN(" "));
79 break;
80 case 'b': /* buffer */
81 b = va_arg(ap, buffer *);
82 buffer_append_string_c_escaped(out, CONST_BUF_LEN(b));
83 buffer_append_string_len(out, CONST_STR_LEN(" "));
84 break;
85 case 'd': /* int */
86 d = va_arg(ap, int);
87 buffer_append_int(out, d);
88 buffer_append_string_len(out, CONST_STR_LEN(" "));
89 break;
90 case 'o': /* off_t */
91 o = va_arg(ap, off_t);
92 buffer_append_int(out, o);
93 buffer_append_string_len(out, CONST_STR_LEN(" "));
94 break;
95 case 'x': /* int (hex) */
96 d = va_arg(ap, int);
97 buffer_append_string_len(out, CONST_STR_LEN("0x"));
98 buffer_append_uint_hex(out, d);
99 buffer_append_string_len(out, CONST_STR_LEN(" "));
100 break;
101 case 'S': /* string */
102 s = va_arg(ap, char *);
103 buffer_append_string_c_escaped(out, s, (NULL != s) ? strlen(s) : 0);
104 break;
105 case 'B': /* buffer */
106 b = va_arg(ap, buffer *);
107 buffer_append_string_c_escaped(out, CONST_BUF_LEN(b));
108 break;
109 case 'D': /* int */
110 d = va_arg(ap, int);
111 buffer_append_int(out, d);
112 break;
113 case 'O': /* off_t */
114 o = va_arg(ap, off_t);
115 buffer_append_int(out, o);
116 break;
117 case 'X': /* int (hex) */
118 d = va_arg(ap, int);
119 buffer_append_string_len(out, CONST_STR_LEN("0x"));
120 buffer_append_uint_hex(out, d);
121 break;
122 case '(':
123 case ')':
124 case '<':
125 case '>':
126 case ',':
127 case ' ':
128 buffer_append_string_len(out, fmt, 1);
129 break;
134 static int log_buffer_prepare(buffer *b, server *srv, const char *filename, unsigned int line) {
135 switch(srv->errorlog_mode) {
136 case ERRORLOG_PIPE:
137 case ERRORLOG_FILE:
138 case ERRORLOG_FD:
139 if (-1 == srv->errorlog_fd) return -1;
140 /* cache the generated timestamp */
141 if (srv->cur_ts != srv->last_generated_debug_ts) {
142 buffer_string_prepare_copy(srv->ts_debug_str, 255);
143 buffer_append_strftime(srv->ts_debug_str, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
145 srv->last_generated_debug_ts = srv->cur_ts;
148 buffer_copy_buffer(b, srv->ts_debug_str);
149 buffer_append_string_len(b, CONST_STR_LEN(": ("));
150 break;
151 case ERRORLOG_SYSLOG:
152 /* syslog is generating its own timestamps */
153 buffer_copy_string_len(b, CONST_STR_LEN("("));
154 break;
157 buffer_append_string(b, filename);
158 buffer_append_string_len(b, CONST_STR_LEN("."));
159 buffer_append_int(b, line);
160 buffer_append_string_len(b, CONST_STR_LEN(") "));
162 return 0;
165 static void log_write(server *srv, buffer *b) {
166 switch(srv->errorlog_mode) {
167 case ERRORLOG_PIPE:
168 case ERRORLOG_FILE:
169 case ERRORLOG_FD:
170 buffer_append_string_len(b, CONST_STR_LEN("\n"));
171 write_all(srv->errorlog_fd, CONST_BUF_LEN(b));
172 break;
173 case ERRORLOG_SYSLOG:
174 syslog(LOG_ERR, "%s", b->ptr);
175 break;
179 int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) {
180 va_list ap;
182 if (-1 == log_buffer_prepare(srv->errorlog_buf, srv, filename, line)) return 0;
184 va_start(ap, fmt);
185 log_buffer_append_printf(srv->errorlog_buf, fmt, ap);
186 va_end(ap);
188 log_write(srv, srv->errorlog_buf);
190 return 0;
193 int log_error_write_multiline_buffer(server *srv, const char *filename, unsigned int line, buffer *multiline, const char *fmt, ...) {
194 va_list ap;
195 size_t prefix_len;
196 buffer *b = srv->errorlog_buf;
197 char *pos, *end, *current_line;
199 if (buffer_string_is_empty(multiline)) return 0;
201 if (-1 == log_buffer_prepare(b, srv, filename, line)) return 0;
203 va_start(ap, fmt);
204 log_buffer_append_printf(b, fmt, ap);
205 va_end(ap);
207 prefix_len = buffer_string_length(b);
209 current_line = pos = multiline->ptr;
210 end = multiline->ptr + buffer_string_length(multiline);
212 for ( ; pos <= end ; ++pos) {
213 switch (*pos) {
214 case '\n':
215 case '\r':
216 case '\0': /* handles end of string */
217 if (current_line < pos) {
218 /* truncate to prefix */
219 buffer_string_set_length(b, prefix_len);
221 buffer_append_string_len(b, current_line, pos - current_line);
222 log_write(srv, b);
224 current_line = pos + 1;
225 break;
226 default:
227 break;
231 return 0;