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