1 /* (c) 2004-2007 Andrei Nigmatulin */
2
3 #include "fpm_config.h"
4
5 #include <stdio.h>
6 #include <unistd.h>
7 #include <time.h>
8 #include <string.h>
9 #include <stdarg.h>
10 #include <sys/time.h>
11 #include <errno.h>
12
13 #include "php_syslog.h"
14
15 #include "zlog.h"
16 #include "fpm.h"
17 #include "zend_portability.h"
18
19 /* buffer is used for fmt result and it should never be over 2048 */
20 #define MAX_BUF_LENGTH 2048
21
22 /* maximal length for wrapping prefix */
23 #define MAX_WRAPPING_PREFIX_LENGTH 512
24
25 #define EXTRA_SPACE_FOR_PREFIX 128
26
27 static int zlog_fd = -1;
28 static int zlog_level = ZLOG_NOTICE;
29 static int zlog_limit = ZLOG_DEFAULT_LIMIT;
30 static zlog_bool zlog_buffering = ZLOG_DEFAULT_BUFFERING;
31 static int launched = 0;
32 static void (*external_logger)(int, char *, size_t) = NULL;
33
34 static const char *level_names[] = {
35 [ZLOG_DEBUG] = "DEBUG",
36 [ZLOG_NOTICE] = "NOTICE",
37 [ZLOG_WARNING] = "WARNING",
38 [ZLOG_ERROR] = "ERROR",
39 [ZLOG_ALERT] = "ALERT",
40 };
41
42 #ifdef HAVE_SYSLOG_H
43 const int syslog_priorities[] = {
44 [ZLOG_DEBUG] = LOG_DEBUG,
45 [ZLOG_NOTICE] = LOG_NOTICE,
46 [ZLOG_WARNING] = LOG_WARNING,
47 [ZLOG_ERROR] = LOG_ERR,
48 [ZLOG_ALERT] = LOG_ALERT,
49 };
50 #endif
51
zlog_set_external_logger(void (* logger)(int,char *,size_t))52 void zlog_set_external_logger(void (*logger)(int, char *, size_t)) /* {{{ */
53 {
54 external_logger = logger;
55 }
56 /* }}} */
57
zlog_get_level_name(int log_level)58 const char *zlog_get_level_name(int log_level) /* {{{ */
59 {
60 if (log_level < 0) {
61 log_level = zlog_level;
62 } else if (log_level < ZLOG_DEBUG || log_level > ZLOG_ALERT) {
63 return "unknown value";
64 }
65
66 return level_names[log_level];
67 }
68 /* }}} */
69
zlog_set_launched(void)70 void zlog_set_launched(void) /* {{{ */
71 {
72 launched = 1;
73 }
74 /* }}} */
75
zlog_print_time(struct timeval * tv,char * timebuf,size_t timebuf_len)76 size_t zlog_print_time(struct timeval *tv, char *timebuf, size_t timebuf_len) /* {{{ */
77 {
78 struct tm t;
79 size_t len;
80
81 len = strftime(timebuf, timebuf_len, "[%d-%b-%Y %H:%M:%S",
82 localtime_r((const time_t *) &tv->tv_sec, &t));
83 if (zlog_level == ZLOG_DEBUG) {
84 len += snprintf(timebuf + len, timebuf_len - len, ".%06d", (int) tv->tv_usec);
85 }
86 len += snprintf(timebuf + len, timebuf_len - len, "] ");
87 return len;
88 }
89 /* }}} */
90
zlog_set_fd(int new_fd)91 int zlog_set_fd(int new_fd) /* {{{ */
92 {
93 int old_fd = zlog_fd;
94
95 zlog_fd = new_fd;
96 return old_fd;
97 }
98 /* }}} */
99
zlog_set_level(int new_value)100 int zlog_set_level(int new_value) /* {{{ */
101 {
102 int old_value = zlog_level;
103
104 if (new_value < ZLOG_DEBUG || new_value > ZLOG_ALERT) return old_value;
105
106 zlog_level = new_value;
107 return old_value;
108 }
109 /* }}} */
110
zlog_set_limit(int new_value)111 int zlog_set_limit(int new_value) /* {{{ */
112 {
113 int old_value = zlog_limit;
114
115 zlog_limit = new_value;
116 return old_value;
117 }
118 /* }}} */
119
zlog_set_buffering(zlog_bool buffering)120 int zlog_set_buffering(zlog_bool buffering) /* {{{ */
121 {
122 int old_value = zlog_buffering;
123
124 zlog_buffering = buffering;
125 return old_value;
126 }
127 /* }}} */
128
zlog_truncate_buf(char * buf,size_t buf_size,size_t space_left)129 static inline size_t zlog_truncate_buf(char *buf, size_t buf_size, size_t space_left) /* {{{ */
130 {
131 memcpy(buf + buf_size - sizeof("...") + 1 - space_left, "...", sizeof("...") - 1);
132 return buf_size - space_left;
133 }
134 /* }}} */
135
zlog_external(int flags,char * buf,size_t buf_size,const char * fmt,va_list args)136 static inline void zlog_external(
137 int flags, char *buf, size_t buf_size, const char *fmt, va_list args) /* {{{ */
138 {
139 va_list ap;
140 size_t len;
141
142 va_copy(ap, args);
143 len = vsnprintf(buf, buf_size, fmt, ap);
144 va_end(ap);
145
146 if (len >= buf_size) {
147 len = zlog_truncate_buf(buf, buf_size, 0);
148 }
149 external_logger(flags & ZLOG_LEVEL_MASK, buf, len);
150 }
151 /* }}} */
152
zlog_buf_prefix(const char * function,int line,int flags,char * buf,size_t buf_size,int use_syslog)153 static size_t zlog_buf_prefix(
154 const char *function, int line, int flags,
155 char *buf, size_t buf_size, int use_syslog) /* {{{ */
156 {
157 struct timeval tv;
158 size_t len = 0;
159
160 #ifdef HAVE_SYSLOG_H
161 if (use_syslog /* && !fpm_globals.is_child */) {
162 if (zlog_level == ZLOG_DEBUG) {
163 len += snprintf(buf, buf_size, "[%s] %s(), line %d: ",
164 level_names[flags & ZLOG_LEVEL_MASK], function, line);
165 } else {
166 len += snprintf(buf, buf_size, "[%s] ", level_names[flags & ZLOG_LEVEL_MASK]);
167 }
168 } else
169 #endif
170 {
171 if (!fpm_globals.is_child) {
172 gettimeofday(&tv, 0);
173 len = zlog_print_time(&tv, buf, buf_size);
174 }
175 if (zlog_level == ZLOG_DEBUG) {
176 if (!fpm_globals.is_child) {
177 len += snprintf(buf + len, buf_size - len, "%s: pid %d, %s(), line %d: ",
178 level_names[flags & ZLOG_LEVEL_MASK], getpid(), function, line);
179 } else {
180 len += snprintf(buf + len, buf_size - len, "%s: %s(), line %d: ",
181 level_names[flags & ZLOG_LEVEL_MASK], function, line);
182 }
183 } else {
184 len += snprintf(buf + len, buf_size - len, "%s: ",
185 level_names[flags & ZLOG_LEVEL_MASK]);
186 }
187 }
188
189 return len;
190 }
191 /* }}} */
192
vzlog(const char * function,int line,int flags,const char * fmt,va_list args)193 void vzlog(const char *function, int line, int flags, const char *fmt, va_list args) /* {{{ */
194 {
195 char buf[MAX_BUF_LENGTH];
196 size_t buf_size = MAX_BUF_LENGTH;
197 size_t len = 0;
198 int truncated = 0;
199 int saved_errno;
200
201 if (external_logger) {
202 zlog_external(flags, buf, buf_size, fmt, args);
203 }
204
205 if ((flags & ZLOG_LEVEL_MASK) < zlog_level) {
206 return;
207 }
208
209 saved_errno = errno;
210 len = zlog_buf_prefix(function, line, flags, buf, buf_size, zlog_fd == ZLOG_SYSLOG);
211
212 if (len > buf_size - 1) {
213 truncated = 1;
214 } else {
215 len += vsnprintf(buf + len, buf_size - len, fmt, args);
216 if (len >= buf_size) {
217 truncated = 1;
218 }
219 }
220
221 if (!truncated) {
222 if (flags & ZLOG_HAVE_ERRNO) {
223 len += snprintf(buf + len, buf_size - len,
224 ": %s (%d)", strerror(saved_errno), saved_errno);
225 if (len >= zlog_limit) {
226 truncated = 1;
227 }
228 }
229 }
230
231 if (truncated) {
232 len = zlog_truncate_buf(buf, zlog_limit < buf_size ? zlog_limit : buf_size, 1);
233 }
234
235 #ifdef HAVE_SYSLOG_H
236 if (zlog_fd == ZLOG_SYSLOG) {
237 buf[len] = '\0';
238 php_syslog(syslog_priorities[zlog_level], "%s", buf);
239 buf[len++] = '\n';
240 } else
241 #endif
242 {
243 buf[len++] = '\n';
244 zend_quiet_write(zlog_fd > -1 ? zlog_fd : STDERR_FILENO, buf, len);
245 }
246
247 if (zlog_fd != STDERR_FILENO && zlog_fd != -1 &&
248 !launched && (flags & ZLOG_LEVEL_MASK) >= ZLOG_NOTICE) {
249 zend_quiet_write(STDERR_FILENO, buf, len);
250 }
251 }
252 /* }}} */
253
zlog_ex(const char * function,int line,int flags,const char * fmt,...)254 void zlog_ex(const char *function, int line, int flags, const char *fmt, ...) /* {{{ */
255 {
256 va_list args;
257 va_start(args, fmt);
258 vzlog(function, line, flags, fmt, args);
259 va_end(args);
260 }
261 /* }}} */
262
263 /* predefine stream init that is used by zlog_msg_ex */
264 static inline void zlog_stream_init_internal(
265 struct zlog_stream *stream, int flags, size_t capacity, int fd);
266
zlog_msg_ex(const char * function,int line,int flags,const char * prefix,const char * msg)267 void zlog_msg_ex(const char *function, int line, int flags,
268 const char *prefix, const char *msg) /* {{{ */
269 {
270 struct zlog_stream stream;
271 size_t prefix_len = strlen(prefix);
272 size_t msg_len = strlen(msg);
273
274 zlog_stream_init_internal(&stream, flags, msg_len + prefix_len, 0);
275 zlog_stream_prefix_ex(&stream, function, line);
276 zlog_stream_str(&stream, prefix, prefix_len);
277 zlog_stream_str(&stream, msg, msg_len);
278 zlog_stream_finish(&stream);
279 zlog_stream_destroy(&stream);
280 }
281 /* }}} */
282
283 /* STREAM OPS */
284
zlog_stream_buf_alloc_ex(struct zlog_stream * stream,size_t needed)285 static zlog_bool zlog_stream_buf_alloc_ex(struct zlog_stream *stream, size_t needed) /* {{{ */
286 {
287 char *buf;
288 size_t size = stream->buf.size ?: stream->buf_init_size;
289
290 if (stream->buf.data) {
291 size = MIN(zlog_limit, MAX(size * 2, needed));
292 buf = realloc(stream->buf.data, size);
293 } else {
294 size = MIN(zlog_limit, MAX(size, needed));
295 buf = malloc(size);
296 }
297
298 if (buf == NULL) {
299 return 0;
300 }
301
302 stream->buf.data = buf;
303 stream->buf.size = size;
304
305 return 1;
306 }
307 /* }}} */
308
zlog_stream_buf_alloc(struct zlog_stream * stream)309 inline static zlog_bool zlog_stream_buf_alloc(struct zlog_stream *stream) /* {{{ */
310 {
311 /* if there is enough space in the buffer, we do not need to reallocate */
312 if (stream->buf.data && stream->buf.size >= MIN(zlog_limit, stream->buf_init_size)) {
313 return 1;
314 }
315 return zlog_stream_buf_alloc_ex(stream, 0);
316 }
317 /* }}} */
318
zlog_stream_direct_write_ex(struct zlog_stream * stream,const char * buf,size_t len,const char * append,size_t append_len)319 static inline ssize_t zlog_stream_direct_write_ex(
320 struct zlog_stream *stream, const char *buf, size_t len,
321 const char *append, size_t append_len) /* {{{ */
322 {
323 if (stream->use_fd) {
324 zend_quiet_write(stream->fd, buf, len);
325 if (append_len > 0) {
326 zend_quiet_write(stream->fd, append, append_len);
327 }
328 }
329
330 if (stream->use_stderr) {
331 zend_quiet_write(STDERR_FILENO, buf, len);
332 if (append_len > 0) {
333 zend_quiet_write(STDERR_FILENO, append, append_len);
334 }
335 }
336
337 return len;
338 }
339 /* }}} */
340
zlog_stream_direct_write(struct zlog_stream * stream,const char * buf,size_t len)341 static ssize_t zlog_stream_direct_write(
342 struct zlog_stream *stream, const char *buf, size_t len) /* {{{ */
343 {
344 return zlog_stream_direct_write_ex(stream, buf, len, NULL, 0);
345 }
346 /* }}} */
347
zlog_stream_unbuffered_write(struct zlog_stream * stream,const char * buf,size_t len)348 static inline ssize_t zlog_stream_unbuffered_write(
349 struct zlog_stream *stream, const char *buf, size_t len) /* {{{ */
350 {
351 const char *append;
352 size_t append_len = 0, required_len, reserved_len;
353 ssize_t written;
354
355 if (stream->len == 0) {
356 stream->len = zlog_stream_prefix_ex(stream, stream->function, stream->line);
357 }
358
359 /* msg_suffix_len and msg_quote are used only for wrapping */
360 reserved_len = stream->len + stream->msg_suffix_len + stream->msg_quote;
361 required_len = reserved_len + len;
362 if (required_len >= zlog_limit) {
363 if (stream->wrap) {
364 size_t available_len;
365 if (required_len == zlog_limit) {
366 append = NULL;
367 append_len = 0;
368 } else {
369 append = "\n";
370 append_len = 1;
371 }
372 available_len = zlog_limit - reserved_len - 1;
373 zlog_stream_direct_write(stream, buf, available_len);
374 if (append != NULL) {
375 if (stream->msg_quote) {
376 zlog_stream_direct_write(stream, "\"", 1);
377 }
378 if (stream->msg_suffix) {
379 zlog_stream_direct_write(stream, stream->msg_suffix, stream->msg_suffix_len);
380 }
381 zlog_stream_direct_write(stream, append, append_len);
382 }
383 stream->len = 0;
384 written = zlog_stream_unbuffered_write(
385 stream, buf + available_len, len - available_len);
386 if (written > 0) {
387 return available_len + written;
388 }
389
390 return written;
391 }
392 /* this would be used in case of an option for disabling wrapping in direct write */
393 stream->full = 1;
394 if (required_len == zlog_limit) {
395 append = NULL;
396 } else {
397 append = "...";
398 append_len = sizeof("...") - 1;
399 len = zlog_limit - stream->len - append_len;
400 }
401 }
402
403 written = zlog_stream_direct_write_ex(stream, buf, len, append, append_len);
404 if (written > 0) {
405 /* currently written will be always len as the write is blocking
406 * - this should be address if we change to non-blocking write */
407 stream->len += written;
408 }
409
410 return written;
411 }
412 /* }}} */
413
zlog_stream_buf_copy_cstr(struct zlog_stream * stream,const char * str,size_t str_len)414 static inline ssize_t zlog_stream_buf_copy_cstr(
415 struct zlog_stream *stream, const char *str, size_t str_len) /* {{{ */
416 {
417 if (stream->buf.size - stream->len <= str_len && !zlog_stream_buf_alloc_ex(stream, str_len)) {
418 return -1;
419 }
420
421 memcpy(stream->buf.data + stream->len, str, str_len);
422 stream->len += str_len;
423
424 return str_len;
425 }
426 /* }}} */
427
zlog_stream_buf_copy_char(struct zlog_stream * stream,char c)428 static inline ssize_t zlog_stream_buf_copy_char(struct zlog_stream *stream, char c) /* {{{ */
429 {
430 if (stream->buf.size - stream->len < 1 && !zlog_stream_buf_alloc_ex(stream, 1)) {
431 return -1;
432 }
433
434 stream->buf.data[stream->len++] = c;
435
436 return 1;
437 }
438 /* }}} */
439
zlog_stream_buf_flush(struct zlog_stream * stream)440 static ssize_t zlog_stream_buf_flush(struct zlog_stream *stream) /* {{{ */
441 {
442 ssize_t written;
443
444 #ifdef HAVE_SYSLOG_H
445 if (stream->use_syslog) {
446 zlog_stream_buf_copy_char(stream, '\0');
447 php_syslog(syslog_priorities[zlog_level], "%s", stream->buf.data);
448 --stream->len;
449 }
450 #endif
451
452 if (external_logger != NULL) {
453 external_logger(stream->flags & ZLOG_LEVEL_MASK,
454 stream->buf.data + stream->prefix_len, stream->len - stream->prefix_len);
455 }
456 zlog_stream_buf_copy_char(stream, '\n');
457 written = zlog_stream_direct_write(stream, stream->buf.data, stream->len);
458 stream->len = 0;
459
460 return written;
461 }
462 /* }}} */
463
zlog_stream_buf_append(struct zlog_stream * stream,const char * str,size_t str_len)464 static ssize_t zlog_stream_buf_append(
465 struct zlog_stream *stream, const char *str, size_t str_len) /* {{{ */
466 {
467 int over_limit = 0;
468 size_t available_len, required_len, reserved_len;
469
470 if (stream->len == 0) {
471 stream->len = zlog_stream_prefix_ex(stream, stream->function, stream->line);
472 }
473
474 /* msg_suffix_len and msg_quote are used only for wrapping */
475 reserved_len = stream->len + stream->msg_suffix_len + stream->msg_quote;
476 required_len = reserved_len + str_len;
477 if (required_len >= zlog_limit) {
478 over_limit = 1;
479 available_len = zlog_limit - reserved_len - 1;
480 } else {
481 available_len = str_len;
482 }
483
484 if (zlog_stream_buf_copy_cstr(stream, str, available_len) < 0) {
485 return -1;
486 }
487
488 if (!over_limit) {
489 return available_len;
490 }
491
492 if (stream->wrap) {
493 if (stream->msg_quote) {
494 zlog_stream_buf_copy_char(stream, '"');
495 }
496 if (stream->msg_suffix != NULL) {
497 zlog_stream_buf_copy_cstr(stream, stream->msg_suffix, stream->msg_suffix_len);
498 }
499 zlog_stream_buf_flush(stream);
500 zlog_stream_prefix_ex(stream, stream->function, stream->line);
501 return available_len + zlog_stream_buf_append(
502 stream, str + available_len, str_len - available_len);
503 }
504
505 stream->len = zlog_truncate_buf(stream->buf.data, stream->len, 0);
506 stream->full = 1;
507 return available_len;
508 }
509 /* }}} */
510
zlog_stream_init_internal(struct zlog_stream * stream,int flags,size_t capacity,int fd)511 static inline void zlog_stream_init_internal(
512 struct zlog_stream *stream, int flags, size_t capacity, int fd) /* {{{ */
513 {
514 if (fd == 0) {
515 fd = zlog_fd;
516 }
517
518 memset(stream, 0, sizeof(struct zlog_stream));
519 stream->flags = flags;
520 stream->use_syslog = fd == ZLOG_SYSLOG;
521 stream->use_fd = fd > 0;
522 stream->use_buffer = zlog_buffering || external_logger != NULL || stream->use_syslog;
523 stream->buf_init_size = capacity;
524 stream->use_stderr = fd < 0 ||
525 (
526 fd != STDERR_FILENO && fd != STDOUT_FILENO && !launched &&
527 (flags & ZLOG_LEVEL_MASK) >= ZLOG_NOTICE
528 );
529 stream->prefix_buffer = (flags & ZLOG_LEVEL_MASK) >= zlog_level &&
530 (stream->use_fd || stream->use_stderr || stream->use_syslog);
531 stream->fd = fd > -1 ? fd : STDERR_FILENO;
532 }
533 /* }}} */
534
zlog_stream_init(struct zlog_stream * stream,int flags)535 void zlog_stream_init(struct zlog_stream *stream, int flags) /* {{{ */
536 {
537 zlog_stream_init_internal(stream, flags, 1024, 0);
538 }
539 /* }}} */
540
zlog_stream_init_ex(struct zlog_stream * stream,int flags,int fd)541 void zlog_stream_init_ex(struct zlog_stream *stream, int flags, int fd) /* {{{ */
542 {
543 zlog_stream_init_internal(stream, flags, 1024, fd);
544 stream->wrap = 1;
545 }
546 /* }}} */
547
zlog_stream_set_decorating(struct zlog_stream * stream,zlog_bool decorate)548 void zlog_stream_set_decorating(struct zlog_stream *stream, zlog_bool decorate) /* {{{ */
549 {
550 if (decorate) {
551 stream->decorate = 1;
552 } else {
553 stream->decorate = 0;
554 stream->msg_quote = 0;
555 stream->prefix_buffer = 0;
556 }
557 }
558 /* }}} */
559
zlog_stream_set_wrapping(struct zlog_stream * stream,zlog_bool wrap)560 void zlog_stream_set_wrapping(struct zlog_stream *stream, zlog_bool wrap) /* {{{ */
561 {
562 stream->wrap = wrap ? 1 : 0;
563 }
564 /* }}} */
565
zlog_stream_set_is_stdout(struct zlog_stream * stream,zlog_bool is_stdout)566 void zlog_stream_set_is_stdout(struct zlog_stream *stream, zlog_bool is_stdout) /* {{{ */
567 {
568 stream->is_stdout = is_stdout ? 1 : 0;
569 }
570 /* }}} */
571
zlog_stream_set_child_pid(struct zlog_stream * stream,int child_pid)572 void zlog_stream_set_child_pid(struct zlog_stream *stream, int child_pid) /* {{{ */
573 {
574 stream->child_pid = child_pid;
575 }
576 /* }}} */
577
zlog_stream_set_msg_quoting(struct zlog_stream * stream,zlog_bool quote)578 void zlog_stream_set_msg_quoting(struct zlog_stream *stream, zlog_bool quote) /* {{{ */
579 {
580 stream->msg_quote = quote && stream->decorate ? 1 : 0;
581 }
582 /* }}} */
583
zlog_stream_set_msg_prefix(struct zlog_stream * stream,const char * fmt,...)584 zlog_bool zlog_stream_set_msg_prefix(struct zlog_stream *stream, const char *fmt, ...) /* {{{ */
585 {
586 char buf[MAX_WRAPPING_PREFIX_LENGTH];
587 size_t len;
588 va_list args;
589
590 if (!stream->decorate) {
591 return ZLOG_TRUE;
592 }
593
594 va_start(args, fmt);
595 len = vsnprintf(buf, MAX_WRAPPING_PREFIX_LENGTH - 1, fmt, args);
596 va_end(args);
597
598 if (stream->msg_prefix_len < len) {
599 stream->msg_prefix = stream->msg_prefix_len ? realloc(stream->msg_prefix, len + 1) : malloc(len + 1);
600 if (stream->msg_prefix == NULL) {
601 return ZLOG_FALSE;
602 }
603 }
604 memcpy(stream->msg_prefix, buf, len);
605 stream->msg_prefix[len] = 0;
606 stream->msg_prefix_len = len;
607
608 return len;
609 }
610 /* }}} */
611
zlog_stream_set_msg_suffix(struct zlog_stream * stream,const char * suffix,const char * final_suffix)612 zlog_bool zlog_stream_set_msg_suffix(
613 struct zlog_stream *stream, const char *suffix, const char *final_suffix) /* {{{ */
614 {
615 size_t len;
616 if (!stream->wrap || !stream->decorate) {
617 return ZLOG_TRUE;
618 }
619
620 if (suffix != NULL && final_suffix != NULL) {
621 stream->msg_suffix_len = strlen(suffix);
622 stream->msg_final_suffix_len = strlen(final_suffix);
623 len = stream->msg_suffix_len + stream->msg_final_suffix_len + 2;
624 if (stream->msg_suffix != NULL) {
625 free(stream->msg_suffix);
626 }
627 stream->msg_suffix = malloc(len);
628 if (stream->msg_suffix == NULL) {
629 return ZLOG_FALSE;
630 }
631 stream->msg_final_suffix = stream->msg_suffix + stream->msg_suffix_len + 1;
632 memcpy(stream->msg_suffix, suffix, stream->msg_suffix_len + 1);
633 memcpy(stream->msg_final_suffix, final_suffix, stream->msg_final_suffix_len + 1);
634 return ZLOG_TRUE;
635 }
636 if (suffix != NULL) {
637 stream->msg_suffix_len = strlen(suffix);
638 len = stream->msg_suffix_len + 1;
639 stream->msg_suffix = malloc(len);
640 if (stream->msg_suffix != NULL) {
641 free(stream->msg_suffix);
642 }
643 if (stream->msg_suffix == NULL) {
644 return ZLOG_FALSE;
645 }
646 memcpy(stream->msg_suffix, suffix, len);
647 return ZLOG_TRUE;
648 }
649 if (final_suffix != NULL) {
650 stream->msg_final_suffix_len = strlen(final_suffix);
651 len = stream->msg_final_suffix_len + 1;
652 stream->msg_final_suffix = malloc(len);
653 if (stream->msg_final_suffix != NULL) {
654 free(stream->msg_suffix);
655 }
656 if (stream->msg_final_suffix == NULL) {
657 return ZLOG_FALSE;
658 }
659 memcpy(stream->msg_final_suffix, final_suffix, len);
660 return ZLOG_TRUE;
661 }
662
663 return ZLOG_TRUE;
664 }
665 /* }}} */
666
zlog_stream_prefix_ex(struct zlog_stream * stream,const char * function,int line)667 ssize_t zlog_stream_prefix_ex(struct zlog_stream *stream, const char *function, int line) /* {{{ */
668 {
669 size_t len;
670
671 if (!stream->prefix_buffer) {
672 return 0;
673 }
674 if (stream->wrap && stream->function == NULL) {
675 stream->function = function;
676 stream->line = line;
677 }
678
679 if (stream->use_buffer) {
680 if (!zlog_stream_buf_alloc(stream)) {
681 return -1;
682 }
683 len = zlog_buf_prefix(
684 function, line, stream->flags,
685 stream->buf.data, stream->buf.size, stream->use_syslog);
686 stream->len = stream->prefix_len = len;
687 if (stream->msg_prefix != NULL) {
688 zlog_stream_buf_copy_cstr(stream, stream->msg_prefix, stream->msg_prefix_len);
689 }
690 if (stream->msg_quote) {
691 zlog_stream_buf_copy_char(stream, '"');
692 }
693 return stream->len;
694 } else {
695 char sbuf[1024];
696 ssize_t written;
697 len = zlog_buf_prefix(function, line, stream->flags, sbuf, 1024, stream->use_syslog);
698 written = zlog_stream_direct_write(stream, sbuf, len);
699 if (stream->msg_prefix != NULL) {
700 written += zlog_stream_direct_write(
701 stream, stream->msg_prefix, stream->msg_prefix_len);
702 }
703 if (stream->msg_quote) {
704 written += zlog_stream_direct_write(stream, "\"", 1);
705 }
706 return written;
707 }
708 }
709 /* }}} */
710
zlog_stream_vformat(struct zlog_stream * stream,const char * fmt,va_list args)711 ssize_t zlog_stream_vformat(struct zlog_stream *stream, const char *fmt, va_list args) /* {{{ */
712 {
713 char sbuf[1024];
714 size_t len;
715
716 len = vsnprintf(sbuf, 1024, fmt, args);
717
718 return zlog_stream_str(stream, sbuf, len);
719 }
720 /* }}} */
721
zlog_stream_format(struct zlog_stream * stream,const char * fmt,...)722 ssize_t zlog_stream_format(struct zlog_stream *stream, const char *fmt, ...) /* {{{ */
723 {
724 ssize_t len;
725
726 va_list args;
727 va_start(args, fmt);
728 len = zlog_stream_vformat(stream, fmt, args);
729 va_end(args);
730
731 return len;
732 }
733 /* }}} */
734
zlog_stream_str(struct zlog_stream * stream,const char * str,size_t str_len)735 ssize_t zlog_stream_str(struct zlog_stream *stream, const char *str, size_t str_len) /* {{{ */
736 {
737 /* reset stream if it is finished */
738 if (stream->finished) {
739 stream->finished = 0;
740 stream->len = 0;
741 stream->full = 0;
742 } else if (stream->full) {
743 /* do not write anything if the stream is full */
744 return 0;
745 }
746
747 if (stream->use_buffer) {
748 return zlog_stream_buf_append(stream, str, str_len);
749 }
750
751 return zlog_stream_unbuffered_write(stream, str, str_len);
752 }
753 /* }}} */
754
zlog_stream_finish_buffer_suffix(struct zlog_stream * stream)755 static inline void zlog_stream_finish_buffer_suffix(struct zlog_stream *stream) /* {{{ */
756 {
757 if (stream->msg_quote) {
758 zlog_stream_buf_copy_char(stream, '"');
759 }
760 if (stream->msg_suffix != NULL) {
761 zlog_stream_buf_copy_cstr(stream, stream->msg_suffix, stream->msg_suffix_len);
762 }
763 if (stream->msg_final_suffix != NULL) {
764 if (stream->len + stream->msg_final_suffix_len >= zlog_limit) {
765 zlog_bool quoting = stream->msg_quote;
766 size_t final_suffix_wrap = stream->len + stream->msg_final_suffix_len + 1 - zlog_limit;
767 zlog_stream_buf_copy_cstr(
768 stream, stream->msg_final_suffix,
769 stream->msg_final_suffix_len - final_suffix_wrap);
770 zlog_stream_buf_copy_char(stream, '\n');
771 zlog_stream_buf_flush(stream);
772 stream->msg_quote = 0;
773 zlog_stream_prefix_ex(stream, stream->function, stream->line);
774 stream->msg_quote = quoting;
775 zlog_stream_buf_copy_cstr(
776 stream,
777 stream->msg_final_suffix + (stream->msg_final_suffix_len - final_suffix_wrap),
778 final_suffix_wrap);
779 zlog_stream_buf_copy_char(stream, '\n');
780 } else {
781 zlog_stream_buf_copy_cstr(
782 stream, stream->msg_final_suffix, stream->msg_final_suffix_len);
783 }
784 }
785 }
786 /* }}} */
787
zlog_stream_finish_direct_suffix(struct zlog_stream * stream)788 static inline void zlog_stream_finish_direct_suffix(struct zlog_stream *stream) /* {{{ */
789 {
790 if (stream->msg_quote) {
791 zlog_stream_direct_write(stream, "\"", 1);
792 ++stream->len;
793 }
794 if (stream->msg_suffix != NULL) {
795 /* we should always have space for wrap suffix so we don't have to check it */
796 zlog_stream_direct_write(stream, stream->msg_suffix, stream->msg_suffix_len);
797 stream->len += stream->msg_suffix_len;
798 }
799 if (stream->msg_final_suffix != NULL) {
800 if (stream->len + stream->msg_final_suffix_len >= zlog_limit) {
801 zlog_bool quoting = stream->msg_quote;
802 size_t final_suffix_wrap = stream->len + stream->msg_final_suffix_len + 1 - zlog_limit;
803 zlog_stream_direct_write_ex(
804 stream, stream->msg_final_suffix,
805 stream->msg_final_suffix_len - final_suffix_wrap, "\n", 1);
806 stream->msg_quote = 0;
807 zlog_stream_prefix_ex(stream, stream->function, stream->line);
808 stream->msg_quote = quoting;
809 zlog_stream_direct_write_ex(
810 stream,
811 stream->msg_final_suffix + (stream->msg_final_suffix_len - final_suffix_wrap),
812 final_suffix_wrap, "\n", 1);
813 } else {
814 zlog_stream_direct_write_ex(
815 stream, stream->msg_final_suffix, stream->msg_final_suffix_len, "\n", 1);
816 }
817 } else {
818 zlog_stream_direct_write(stream, "\n", 1);
819 }
820 }
821 /* }}} */
822
zlog_stream_finish(struct zlog_stream * stream)823 zlog_bool zlog_stream_finish(struct zlog_stream *stream) /* {{{ */
824 {
825 if (stream->finished || stream->len == 0) {
826 return ZLOG_TRUE;
827 }
828
829 if (stream->use_buffer) {
830 if (stream->decorate) {
831 zlog_stream_finish_buffer_suffix(stream);
832 }
833 zlog_stream_buf_flush(stream);
834 } else {
835 if (stream->decorate) {
836 zlog_stream_finish_direct_suffix(stream);
837 } else {
838 zlog_stream_direct_write(stream, "\n", 1);
839 }
840 }
841 stream->finished = 1;
842
843 return ZLOG_TRUE;
844 }
845 /* }}} */
846
zlog_stream_destroy(struct zlog_stream * stream)847 void zlog_stream_destroy(struct zlog_stream *stream) /* {{{ */
848 {
849 if (stream->buf.data != NULL) {
850 free(stream->buf.data);
851 }
852 if (stream->msg_prefix != NULL) {
853 free(stream->msg_prefix);
854 }
855 if (stream->msg_suffix != NULL) {
856 free(stream->msg_suffix);
857 } else if (stream->msg_final_suffix != NULL) {
858 free(stream->msg_final_suffix);
859 }
860 }
861 /* }}} */
862
zlog_stream_close(struct zlog_stream * stream)863 zlog_bool zlog_stream_close(struct zlog_stream *stream) /* {{{ */
864 {
865 zlog_bool finished = zlog_stream_finish(stream);
866 zlog_stream_destroy(stream);
867
868 return finished;
869 }
870 /* }}} */
871