Coverage Report

Created: 2023-11-19 07:29

/src/tarantool/src/lib/core/say.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2010-2016, Tarantool AUTHORS, please see AUTHORS file.
3
 *
4
 * Redistribution and use in source and binary forms, with or
5
 * without modification, are permitted provided that the following
6
 * conditions are met:
7
 *
8
 * 1. Redistributions of source code must retain the above
9
 *    copyright notice, this list of conditions and the
10
 *    following disclaimer.
11
 *
12
 * 2. Redistributions in binary form must reproduce the above
13
 *    copyright notice, this list of conditions and the following
14
 *    disclaimer in the documentation and/or other materials
15
 *    provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
 * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
 * SUCH DAMAGE.
30
 */
31
#include "say.h"
32
#include "fiber.h"
33
#include "errinj.h"
34
#include "tt_static.h"
35
#include "tt_strerror.h"
36
37
#include <errno.h>
38
#include <stdarg.h>
39
#include <stdio.h>
40
#include <string.h>
41
#include <netdb.h>
42
#include <netinet/in.h>
43
#include <sys/types.h>
44
#include <unistd.h>
45
#include <fcntl.h>
46
#include <syslog.h>
47
#include <sys/socket.h>
48
#include <sys/un.h>
49
#include <arpa/inet.h>
50
#include <coio_task.h>
51
52
pid_t log_pid = 0;
53
/**
54
 * The global log level. Used as an optimization by the say() macro to
55
 * avoid unnecessary calls to say_default().
56
 * Calculated as MAX(log_default->level, log_level_flightrec).
57
 */
58
int log_level = S_INFO;
59
/**
60
 * Log level of flight recorder. Log is passed to flight recorder only if
61
 * it's log level not less that this. -1 is used if we should not pass logs
62
 * to flight recorder (it is currently disabled). Used in Lua via FFI.
63
 */
64
int log_level_flightrec = -1;
65
/**
66
 * This function is called for every log which log level is not less than
67
 * log_level_flightrec.
68
 */
69
void
70
(*log_write_flightrec)(int level, const char *filename, int line,
71
           const char *error, const char *format, va_list ap);
72
73
enum say_format log_format = SF_PLAIN;
74
enum { SAY_SYSLOG_DEFAULT_PORT = 512 };
75
76
/** List of logs to rotate */
77
static RLIST_HEAD(log_rotate_list);
78
79
static const char logger_syntax_reminder[] =
80
  "expecting a file name or a prefix, such as '|', 'pipe:', 'syslog:'";
81
/**
82
 * True if Tarantool process runs in background mode, i.e. has no
83
 * controlling terminal.
84
 */
85
static bool log_background;
86
87
static void
88
say_default(int level, const char *filename, int line, const char *error,
89
      const char *format, ...);
90
91
static int
92
say_format_boot(struct log *log, char *buf, int len, int level,
93
    const char *module, const char *filename, int line,
94
    const char *error, const char *format, va_list ap);
95
96
/*
97
 * Callbacks called before/after writing to stderr.
98
 */
99
static say_stderr_callback_t before_stderr_callback;
100
static say_stderr_callback_t after_stderr_callback;
101
102
/** Default logger used before logging subsystem is initialized. */
103
static struct log log_boot = {
104
  .fd = STDERR_FILENO,
105
  .level = S_INFO,
106
  .type = SAY_LOGGER_BOOT,
107
  .path = NULL, /* iff type == SAY_LOGGER_FILE */
108
  .nonblock = false,
109
  .format_func = say_format_boot,
110
  .pid = 0,
111
  .syslog_ident = NULL,
112
};
113
114
/** Default logger used after bootstrap. */
115
static struct log log_std;
116
117
static struct log *log_default = &log_boot;
118
119
sayfunc_t _say = say_default;
120
121
const char *
122
_say_strerror(int errnum)
123
0
{
124
0
  return tt_strerror(errnum);
125
0
}
126
127
static const char level_chars[] = {
128
  [S_FATAL] = 'F',
129
  [S_SYSERROR] = '!',
130
  [S_ERROR] = 'E',
131
  [S_CRIT] = 'C',
132
  [S_WARN] = 'W',
133
  [S_INFO] = 'I',
134
  [S_VERBOSE] = 'V',
135
  [S_DEBUG] = 'D',
136
};
137
138
static_assert(lengthof(level_chars) == say_level_MAX,
139
        "level_chars is not defined for one of log levels");
140
141
static const char *level_strs[] = {
142
  [S_FATAL] = "FATAL",
143
  [S_SYSERROR] = "SYSERROR",
144
  [S_ERROR] = "ERROR",
145
  [S_CRIT] = "CRIT",
146
  [S_WARN] = "WARN",
147
  [S_INFO] = "INFO",
148
  [S_VERBOSE] = "VERBOSE",
149
  [S_DEBUG] = "DEBUG",
150
};
151
152
static_assert(lengthof(level_strs) == say_level_MAX,
153
        "level_strs is not defined for one of log levels");
154
155
const char*
156
say_log_level_str(int level)
157
0
{
158
0
  if (level < 0 || level >= (int)lengthof(level_strs))
159
0
    return NULL;
160
0
  return level_strs[level];
161
0
}
162
163
static int
164
level_to_syslog_priority(int level)
165
0
{
166
0
  switch (level) {
167
0
  case S_FATAL:
168
0
    return LOG_ERR;
169
0
  case S_SYSERROR:
170
0
    return LOG_ERR;
171
0
  case S_ERROR:
172
0
    return LOG_ERR;
173
0
  case S_CRIT:
174
0
    return LOG_ERR;
175
0
  case S_WARN:
176
0
    return LOG_WARNING;
177
0
  case S_INFO:
178
0
    return LOG_INFO;
179
0
  case S_VERBOSE:
180
0
    return LOG_INFO;
181
0
  case S_DEBUG:
182
0
    return LOG_DEBUG;
183
0
  default:
184
0
    return LOG_ERR;
185
0
  }
186
0
}
187
188
/**
189
 * Helper function that fills the given tm struct with the current local time.
190
 * tm_sec is set to the number of seconds that passed since the last minute
191
 * (0-60). Note, in contrast to tm.tm_sec, it has a fractional part.
192
 */
193
static void
194
get_current_time(struct tm *tm, double *tm_sec)
195
0
{
196
  /* Don't use ev_now() since it requires a working event loop. */
197
0
  ev_tstamp now = ev_time();
198
0
  time_t now_seconds = (time_t)now;
199
0
  localtime_r(&now_seconds, tm);
200
0
  *tm_sec = now - now_seconds + tm->tm_sec;
201
0
}
202
203
enum say_logger_type
204
log_type(void)
205
0
{
206
0
  return log_default->type;
207
0
}
208
209
int
210
log_get_fd(void)
211
0
{
212
0
  return log_default->fd;
213
0
}
214
215
void
216
log_set_fd(int new_fd)
217
0
{
218
0
  log_default->fd = new_fd;
219
0
}
220
221
void
222
log_set_level(struct log *log, enum say_level level)
223
0
{
224
0
  log->level = level;
225
0
}
226
227
void
228
log_set_format(struct log *log, log_format_func_t format_func)
229
0
{
230
0
  log->format_func = format_func;
231
0
}
232
233
void
234
say_set_log_level(int new_level)
235
0
{
236
0
  log_level = MAX(new_level, log_level_flightrec);
237
0
  log_set_level(log_default, (enum say_level) new_level);
238
0
}
239
240
int
241
say_get_log_level(void)
242
0
{
243
0
  return log_default->level;
244
0
}
245
246
void
247
say_set_log_format(enum say_format format)
248
0
{
249
0
  log_format_func_t format_func;
250
251
0
  switch (format) {
252
0
  case SF_JSON:
253
0
    format_func = say_format_json;
254
0
    break;
255
0
  case SF_PLAIN:
256
0
    format_func = say_format_plain;
257
0
    break;
258
0
  default:
259
0
    unreachable();
260
0
  }
261
262
0
  log_set_format(log_default, format_func);
263
0
  log_format = format;
264
0
}
265
266
void
267
say_set_flightrec_log_level(int new_level)
268
0
{
269
0
  log_level = MAX(new_level, log_default->level);
270
0
  log_level_flightrec = new_level;
271
0
}
272
273
static const char *say_format_strs[] = {
274
  [SF_PLAIN] = "plain",
275
  [SF_JSON] = "json",
276
  [say_format_MAX] = "unknown"
277
};
278
279
enum say_format
280
say_format_by_name(const char *format)
281
0
{
282
0
  return STR2ENUM(say_format, format);
283
0
}
284
285
/**
286
 * Sets O_NONBLOCK flag in case if lognonblock is set.
287
 */
288
static void
289
log_set_nonblock(struct log *log)
290
0
{
291
0
  if (!log->nonblock)
292
0
    return;
293
0
  int flags;
294
0
  if ((flags = fcntl(log->fd, F_GETFL, 0)) < 0 ||
295
0
      fcntl(log->fd, F_SETFL, flags | O_NONBLOCK) < 0) {
296
0
    say_syserror("fcntl, fd=%i", log->fd);
297
0
  }
298
0
}
299
300
/**
301
 * Rotate logs on SIGHUP
302
 */
303
static int
304
log_rotate(struct log *log)
305
0
{
306
0
  if (pm_atomic_load(&log->type) != SAY_LOGGER_FILE)
307
0
    return 0;
308
309
0
  ERROR_INJECT(ERRINJ_LOG_ROTATE, { usleep(10); });
310
311
0
  int fd = open(log->path, O_WRONLY | O_APPEND | O_CREAT,
312
0
          S_IRUSR | S_IWUSR | S_IRGRP);
313
0
  if (fd < 0) {
314
0
    diag_set(SystemError, "logrotate can't open %s", log->path);
315
0
    return -1;
316
0
  }
317
  /*
318
   * The whole charade's purpose is to avoid log->fd changing.
319
   * Remember, we are a signal handler.
320
   */
321
0
  dup2(fd, log->fd);
322
0
  close(fd);
323
324
0
  log_set_nonblock(log);
325
326
  /* We are in ev signal handler
327
   * so we don't have to be worry about async signal safety
328
   */
329
0
  log_say(log, S_INFO, __FILE__, __LINE__, NULL,
330
0
    "log file has been reopened");
331
  /*
332
   * log_background applies only to log_default logger
333
   */
334
0
  if (log == log_default && log_background &&
335
0
    log->type == SAY_LOGGER_FILE) {
336
0
    dup2(log_default->fd, STDOUT_FILENO);
337
0
    dup2(log_default->fd, STDERR_FILENO);
338
0
  }
339
340
0
  return 0;
341
0
}
342
343
struct rotate_task {
344
  struct coio_task base;
345
  struct log *log;
346
  struct ev_loop *loop;
347
};
348
349
static int
350
logrotate_cb(struct coio_task *ptr)
351
0
{
352
0
  struct rotate_task *task = (struct rotate_task *) ptr;
353
0
  struct log *log = task->log;
354
0
  if (log_rotate(log) < 0)
355
0
    diag_log();
356
0
  tt_pthread_mutex_lock(&log->rotate_mutex);
357
0
  assert(log->rotating_threads > 0);
358
0
  log->rotating_threads--;
359
0
  if (log->rotating_threads == 0)
360
0
    tt_pthread_cond_signal(&log->rotate_cond);
361
0
  tt_pthread_mutex_unlock(&log->rotate_mutex);
362
0
  return 0;
363
0
}
364
365
static int
366
logrotate_cleanup_cb(struct coio_task *ptr)
367
0
{
368
0
  struct rotate_task *task = (struct rotate_task *) ptr;
369
0
  coio_task_destroy(&task->base);
370
0
  free(task);
371
0
  return 0;
372
0
}
373
374
void
375
say_logrotate(struct ev_loop *loop, struct ev_signal *w, int revents)
376
0
{
377
0
  (void) loop;
378
0
  (void) w;
379
0
  (void) revents;
380
0
  int saved_errno = errno;
381
0
  struct log *log;
382
0
  rlist_foreach_entry(log, &log_rotate_list, in_log_list) {
383
0
    struct rotate_task *task =
384
0
      (struct rotate_task *) calloc(1, sizeof(*task));
385
0
    if (task == NULL) {
386
0
      diag_set(OutOfMemory, sizeof(*task), "malloc",
387
0
         "say_logrotate");
388
0
      diag_log();
389
0
      continue;
390
0
    }
391
0
    tt_pthread_mutex_lock(&log->rotate_mutex);
392
0
    log->rotating_threads++;
393
0
    tt_pthread_mutex_unlock(&log->rotate_mutex);
394
0
    coio_task_create(&task->base, logrotate_cb, logrotate_cleanup_cb);
395
0
    task->log = log;
396
0
    task->loop = loop();
397
0
    coio_task_post(&task->base);
398
0
  }
399
0
  errno = saved_errno;
400
0
}
401
402
/**
403
 * Initialize the logger pipe: a standalone
404
 * process which is fed all log messages.
405
 */
406
static int
407
log_pipe_init(struct log *log, const char *init_str)
408
0
{
409
0
  int pipefd[2];
410
0
  char cmd[] = { "/bin/sh" };
411
0
  char args[] = { "-c" };
412
0
  char *argv[] = { cmd, args, (char *) init_str, NULL };
413
0
  log->type = SAY_LOGGER_PIPE;
414
0
  sigset_t mask;
415
0
  sigemptyset(&mask);
416
0
  sigaddset(&mask, SIGCHLD);
417
418
0
  if (pthread_sigmask(SIG_BLOCK, &mask, NULL) == -1)
419
0
    say_syserror("pthread_sigmask");
420
421
0
  if (pipe(pipefd) == -1) {
422
0
    diag_set(SystemError, "failed to create pipe");
423
0
    return -1;
424
0
  }
425
426
  /* flush buffers to avoid multiple output */
427
  /* https://github.com/tarantool/tarantool/issues/366 */
428
0
  fflush(stdout);
429
0
  fflush(stderr);
430
431
0
  log->pid = fork();
432
0
  if (log->pid == -1) {
433
0
    diag_set(SystemError, "failed to create process");
434
0
    return -1;
435
0
  }
436
437
0
  if (log->pid == 0) {
438
0
    pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
439
440
0
    close(pipefd[1]);
441
0
    dup2(pipefd[0], STDIN_FILENO);
442
    /*
443
     * Move to an own process group, to not
444
     * receive signals from the controlling
445
     * tty. This keeps the log open as long as
446
     * the parent is around. When the parent
447
     * dies, we get SIGPIPE and terminate.
448
     */
449
0
    setpgid(0, 0);
450
0
    execv(argv[0], argv); /* does not return */
451
0
    diag_set(SystemError, "can't start logger: %s", init_str);
452
0
    return -1;
453
0
  }
454
0
#if !TARGET_OS_DARWIN
455
  /*
456
   * A courtesy to a DBA who might have
457
   * misconfigured the logger option: check whether
458
   * or not the logger process has started, and if
459
   * it didn't, abort. Notice, that if the logger
460
   * makes a slow start this is futile.
461
   */
462
0
  struct timespec timeout;
463
0
  timeout.tv_sec = 0;
464
0
  timeout.tv_nsec = 1; /* Mostly to trigger preemption. */
465
#if defined(__OpenBSD__)
466
  int sig = 0;
467
  sigwait(&mask, &sig);
468
  if (sig ==SIGCHLD) {
469
    diag_set(IllegalParams, "logger process died");
470
    return -1;
471
  }
472
#else
473
0
  if (sigtimedwait(&mask, NULL, &timeout) == SIGCHLD) {
474
0
    diag_set(IllegalParams, "logger process died");
475
0
    return -1;
476
0
  }
477
0
#endif
478
0
#endif
479
  /* OK, let's hope for the best. */
480
0
  pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
481
0
  close(pipefd[0]);
482
0
  log->fd = pipefd[1];
483
0
  return 0;
484
0
}
485
486
/**
487
 * Initialize logging to a file and set up a log
488
 * rotation signal.
489
 */
490
static int
491
log_file_init(struct log *log, const char *init_str)
492
0
{
493
0
  int fd;
494
0
  log->path = abspath(init_str);
495
0
  log->type = SAY_LOGGER_FILE;
496
0
  if (log->path == NULL) {
497
0
    diag_set(OutOfMemory, strlen(init_str), "malloc", "abspath");
498
0
    return -1;
499
0
  }
500
0
  fd = open(log->path, O_WRONLY | O_APPEND | O_CREAT,
501
0
            S_IRUSR | S_IWUSR | S_IRGRP);
502
0
  if (fd < 0) {
503
0
    diag_set(SystemError, "can't open log file: %s", log->path);
504
0
    return -1;
505
0
  }
506
0
  log->fd = fd;
507
0
  return 0;
508
0
}
509
510
/**
511
 * Connect to syslogd using UNIX socket.
512
 * @param path UNIX socket path.
513
 * @retval not 0 Socket descriptor.
514
 * @retval    -1 Socket error.
515
 */
516
static inline int
517
syslog_connect_unix(const char *path)
518
0
{
519
0
  int fd = socket(PF_UNIX, SOCK_DGRAM, 0);
520
0
  if (fd < 0) {
521
0
    diag_set(SystemError, "socket");
522
0
    return -1;
523
0
  }
524
0
  struct sockaddr_un un;
525
0
  memset(&un, 0, sizeof(un));
526
0
  snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
527
0
  un.sun_family = AF_UNIX;
528
0
  if (connect(fd, (struct sockaddr *) &un, sizeof(un)) != 0) {
529
0
    diag_set(SystemError, "connect");
530
0
    close(fd);
531
0
    return -1;
532
0
  }
533
0
  return fd;
534
0
}
535
536
/**
537
 * Connect to remote syslogd using server:port.
538
 * @param server_address address of remote host.
539
 * @retval not 0 Socket descriptor.
540
 * @retval    -1 Socket error.
541
 */
542
static int
543
syslog_connect_remote(const char *server_address)
544
0
{
545
0
  struct addrinfo *inf, hints, *ptr;
546
0
  char *remote;
547
0
  char buf[10];
548
0
  char *portnum, *copy;
549
0
  int fd = -1;
550
0
  int ret;
551
552
0
  copy = strdup(server_address);
553
0
  if (copy == NULL) {
554
0
    diag_set(OutOfMemory, strlen(server_address), "malloc",
555
0
       "stslog server address");
556
0
    return fd;
557
0
  }
558
0
  portnum = copy;
559
0
  remote = strsep(&portnum, ":");
560
0
  if (portnum == NULL) {
561
0
    snprintf(buf, sizeof(buf), "%d", SAY_SYSLOG_DEFAULT_PORT);
562
0
    portnum = buf;
563
0
  }
564
0
  memset(&hints, 0, sizeof(hints));
565
0
  hints.ai_family = AF_INET;
566
0
  hints.ai_socktype = SOCK_DGRAM;
567
0
  hints.ai_protocol = IPPROTO_UDP;
568
569
0
  ret = getaddrinfo(remote, portnum, &hints, &inf);
570
0
  if (ret != 0) {
571
0
    errno = EIO;
572
0
    diag_set(SystemError, "getaddrinfo: %s",
573
0
       gai_strerror(ret));
574
0
    goto out;
575
0
  }
576
0
  for (ptr = inf; ptr; ptr = ptr->ai_next) {
577
0
    fd = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
578
0
    if (fd < 0) {
579
0
      diag_set(SystemError, "socket");
580
0
      continue;
581
0
    }
582
0
    if (connect(fd, inf->ai_addr, inf->ai_addrlen) != 0) {
583
0
      close(fd);
584
0
      fd = -1;
585
0
      diag_set(SystemError, "connect");
586
0
      continue;
587
0
    }
588
0
    break;
589
0
  }
590
0
  freeaddrinfo(inf);
591
0
out:
592
0
  free(copy);
593
0
  return fd;
594
0
}
595
596
static inline int
597
log_syslog_connect(struct log *log)
598
0
{
599
  /*
600
   * If server option is not set use '/dev/log' for Linux and
601
   * '/var/run/syslog' for Mac.
602
   */
603
0
  switch (log->syslog_server_type) {
604
0
  case SAY_SYSLOG_UNIX:
605
0
    log->fd = syslog_connect_unix(log->path);
606
0
    break;
607
0
  case SAY_SYSLOG_REMOTE:
608
0
    log->fd = syslog_connect_remote(log->path);
609
0
    break;
610
0
  default:
611
0
    log->fd = syslog_connect_unix("/dev/log");
612
0
    if (log->fd < 0)
613
0
      log->fd = syslog_connect_unix("/var/run/syslog");
614
615
0
  }
616
0
  return log->fd;
617
0
}
618
619
/** Initialize logging to syslog */
620
static int
621
log_syslog_init(struct log *log, const char *init_str)
622
0
{
623
0
  struct say_syslog_opts opts;
624
0
  log->type = SAY_LOGGER_SYSLOG;
625
626
0
  if (say_parse_syslog_opts(init_str, &opts) < 0)
627
0
    return -1;
628
629
0
  log->syslog_server_type = opts.server_type;
630
0
  if (log->syslog_server_type != SAY_SYSLOG_DEFAULT) {
631
0
    log->path = strdup(opts.server_path);
632
0
    if (log->path == NULL) {
633
0
      diag_set(OutOfMemory, strlen(opts.server_path),
634
0
         "malloc", "server address");
635
0
      return -1;
636
0
    }
637
0
  }
638
0
  if (opts.identity == NULL)
639
0
    log->syslog_ident = strdup("tarantool");
640
0
  else
641
0
    log->syslog_ident = strdup(opts.identity);
642
0
  if (log->syslog_ident == NULL) {
643
0
    diag_set(OutOfMemory, strlen(opts.identity), "malloc",
644
0
             "log->syslog_ident");
645
0
    return -1;
646
0
  }
647
648
0
  if (opts.facility == syslog_facility_MAX)
649
0
    log->syslog_facility = SYSLOG_LOCAL7;
650
0
  else
651
0
    log->syslog_facility = opts.facility;
652
0
  say_free_syslog_opts(&opts);
653
0
  log->fd = log_syslog_connect(log);
654
0
  if (log->fd < 0) {
655
0
    diag_log();
656
    /* syslog indent is freed in atexit(). */
657
0
    diag_set(SystemError, "syslog logger");
658
0
    return -1;
659
0
  }
660
0
  return 0;
661
0
}
662
663
/**
664
 * Initialize logging subsystem to use in daemon mode.
665
 */
666
int
667
log_create(struct log *log, const char *init_str, int nonblock)
668
0
{
669
0
  log->pid = 0;
670
0
  log->syslog_ident = NULL;
671
0
  log->path = NULL;
672
0
  log->format_func = say_format_plain;
673
0
  log->level = S_INFO;
674
0
  log->rotating_threads = 0;
675
0
  tt_pthread_mutex_init(&log->rotate_mutex, NULL);
676
0
  tt_pthread_cond_init(&log->rotate_cond, NULL);
677
0
  setvbuf(stderr, NULL, _IONBF, 0);
678
679
0
  if (init_str != NULL) {
680
0
    enum say_logger_type type;
681
0
    if (say_parse_logger_type(&init_str, &type))
682
0
      return -1;
683
684
0
    int rc;
685
0
    switch (type) {
686
0
    case SAY_LOGGER_PIPE:
687
0
      log->nonblock = (nonblock >= 0)? nonblock: true;
688
0
      rc = log_pipe_init(log, init_str);
689
0
      break;
690
0
    case SAY_LOGGER_SYSLOG:
691
0
      log->nonblock = (nonblock >= 0)? nonblock: true;
692
0
      rc = log_syslog_init(log, init_str);
693
0
      break;
694
0
    case SAY_LOGGER_FILE:
695
0
    default:
696
0
      log->nonblock = (nonblock >= 0)? nonblock: false;
697
0
      rc = log_file_init(log, init_str);
698
0
      break;
699
0
    }
700
0
    if (rc < 0) {
701
0
      return -1;
702
0
    }
703
    /*
704
     * Set non-blocking mode if a non-default log
705
     * output is set. Avoid setting stdout to
706
     * non-blocking: this will garble interactive
707
     * console output.
708
     */
709
0
    log_set_nonblock(log);
710
0
  } else {
711
0
    log->type = SAY_LOGGER_STDERR;
712
0
    log->fd = STDERR_FILENO;
713
0
  }
714
0
  if (log->type == SAY_LOGGER_FILE)
715
0
    rlist_add_entry(&log_rotate_list, log, in_log_list);
716
0
  else
717
0
    rlist_create(&log->in_log_list);
718
0
  return 0;
719
0
}
720
721
bool
722
say_logger_initialized(void)
723
0
{
724
0
  return log_default == &log_std;
725
0
}
726
727
void
728
say_logger_init(const char *init_str, int level, int nonblock,
729
    const char *format)
730
0
{
731
  /*
732
   * The logger may be early configured
733
   * by hands without configuing the whole box.
734
   */
735
0
  if (say_logger_initialized()) {
736
0
    say_set_log_level(level);
737
0
    say_set_log_format(say_format_by_name(format));
738
0
    return;
739
0
  }
740
741
0
  if (log_create(&log_std, init_str, nonblock) < 0)
742
0
    goto fail;
743
744
0
  log_default = &log_std;
745
746
0
  switch (log_default->type) {
747
0
  case SAY_LOGGER_PIPE:
748
0
    fprintf(stderr, "started logging into a pipe,"
749
0
      " SIGHUP log rotation disabled\n");
750
0
    break;
751
0
  case SAY_LOGGER_SYSLOG:
752
0
    fprintf(stderr, "started logging into a syslog,"
753
0
      " SIGHUP log rotation disabled\n");
754
0
  default:
755
0
    break;
756
0
  }
757
0
  _say = say_default;
758
0
  say_set_log_level(level);
759
0
  log_pid = log_default->pid;
760
0
  say_set_log_format(say_format_by_name(format));
761
762
0
  return;
763
0
fail:
764
0
  diag_log();
765
0
  panic("failed to initialize logging subsystem");
766
0
}
767
768
int
769
say_set_background(void)
770
0
{
771
0
  assert(say_logger_initialized());
772
773
0
  if (log_background)
774
0
    return 0;
775
776
0
  log_background = true;
777
778
0
  fflush(stderr);
779
0
  fflush(stdout);
780
781
0
  int fd;
782
0
  int fd_null = -1;
783
0
  if (log_default->fd == STDERR_FILENO) {
784
0
    fd_null = open("/dev/null", O_WRONLY);
785
0
    if (fd_null < 0) {
786
0
      diag_set(SystemError, "open(/dev/null)");
787
0
      return -1;
788
0
    }
789
0
    fd = fd_null;
790
0
  } else {
791
0
    fd = log_default->fd;
792
0
  }
793
794
0
  dup2(fd, STDERR_FILENO);
795
0
  dup2(fd, STDOUT_FILENO);
796
0
  if (fd_null != -1)
797
0
    close(fd_null);
798
799
0
  return 0;
800
0
}
801
802
void
803
say_logger_free(void)
804
0
{
805
0
  if (say_logger_initialized())
806
0
    log_destroy(&log_std);
807
0
}
808
809
/** {{{ Formatters */
810
811
/**
812
 * Format the log message in compact form:
813
 * MESSAGE: ERROR
814
 *
815
 * Used during boot time, e.g. without box.cfg().
816
 */
817
static int
818
say_format_boot(struct log *log, char *buf, int len, int level,
819
    const char *module, const char *filename, int line,
820
    const char *error, const char *format, va_list ap)
821
0
{
822
0
  (void)log;
823
0
  (void)module;
824
0
  (void)filename;
825
0
  (void)line;
826
0
  (void)level;
827
0
  int total = 0;
828
0
  SNPRINT(total, vsnprintf, buf, len, format, ap);
829
0
  if (error != NULL)
830
0
    SNPRINT(total, snprintf, buf, len, ": %s", error);
831
0
  SNPRINT(total, snprintf, buf, len, "\n");
832
0
  return total;
833
0
}
834
835
/**
836
 * Format the log message in Tarantool format:
837
 * YYYY-MM-DD hh:mm:ss.ms [PID]: CORD/FID/FIBERNAME/MODULENAME LEVEL> MSG
838
 */
839
int
840
say_format_plain(struct log *log, char *buf, int len, int level,
841
     const char *module, const char *filename, int line,
842
     const char *error, const char *format, va_list ap)
843
0
{
844
0
  int total = 0;
845
846
  /*
847
   * Every message written to syslog has a header that contains
848
   * the current time and pid (see format_syslog_header) so we
849
   * exclude them from the message body.
850
   */
851
0
  if (log->type != SAY_LOGGER_SYSLOG) {
852
0
    struct tm tm;
853
0
    double tm_sec;
854
0
    get_current_time(&tm, &tm_sec);
855
    /* Print time in format 2012-08-07 18:30:00.634 */
856
0
    SNPRINT(total, strftime, buf, len, "%F %H:%M", &tm);
857
0
    SNPRINT(total, snprintf, buf, len, ":%06.3f ", tm_sec);
858
    /* Print pid */
859
0
    SNPRINT(total, snprintf, buf, len, "[%i] ", getpid());
860
0
  }
861
862
0
  SNPRINT(total, snprintf, buf, len, "%s", cord()->name);
863
0
  if (fiber() && fiber()->fid != FIBER_ID_SCHED) {
864
0
    SNPRINT(total, snprintf, buf, len, "/%llu/%s",
865
0
      (long long)fiber()->fid, fiber_name(fiber()));
866
0
  }
867
868
0
  if (module != NULL)
869
0
    SNPRINT(total, snprintf, buf, len, "/%s", module);
870
871
0
  if (level == S_WARN || level == S_ERROR || level == S_SYSERROR) {
872
    /* Primitive basename(filename) */
873
0
    if (filename) {
874
0
      for (const char *f = filename; *f; f++)
875
0
        if (*f == '/' && *(f + 1) != '\0')
876
0
          filename = f + 1;
877
0
      SNPRINT(total, snprintf, buf, len, " %s:%i", filename,
878
0
        line);
879
0
    }
880
0
  }
881
882
0
  SNPRINT(total, snprintf, buf, len, " %c> ", level_chars[level]);
883
884
0
  SNPRINT(total, vsnprintf, buf, len, format, ap);
885
0
  if (error != NULL)
886
0
    SNPRINT(total, snprintf, buf, len, ": %s", error);
887
888
0
  SNPRINT(total, snprintf, buf, len, "\n");
889
0
  return total;
890
0
}
891
892
/**
893
 * Format log message in json format:
894
 * {"time": 1507026445.23232, "level": "WARN", "message": <message>,
895
 * "pid": <pid>, "cord_name": <name>, "fiber_id": <id>,
896
 * "fiber_name": <fiber_name>, file": <filename>, "line": <fds>,
897
 * "module": <module_name>}
898
 */
899
int
900
say_format_json(struct log *log, char *buf, int len, int level,
901
    const char *module, const char *filename, int line,
902
    const char *error, const char *format, va_list ap)
903
0
{
904
0
  (void) log;
905
0
  int total = 0;
906
907
0
  SNPRINT(total, snprintf, buf, len, "{\"time\": \"");
908
909
0
  struct tm tm;
910
0
  double tm_sec;
911
0
  get_current_time(&tm, &tm_sec);
912
0
  int written = strftime(buf, len, "%FT%H:%M", &tm);
913
0
  buf += written, len -= written, total += written;
914
0
  SNPRINT(total, snprintf, buf, len, ":%06.3f", tm_sec);
915
0
  written = strftime(buf, len, "%z", &tm);
916
0
  buf += written, len -= written, total += written;
917
0
  SNPRINT(total, snprintf, buf, len, "\", ");
918
919
0
  SNPRINT(total, snprintf, buf, len, "\"level\": \"%s\", ",
920
0
      level_strs[level]);
921
922
0
  if (strncmp(format, "json", sizeof("json")) == 0) {
923
    /*
924
     * Message is already JSON-formatted.
925
     * Get rid of {} brackets and append to the output buffer.
926
     */
927
0
    const char *str = va_arg(ap, const char *);
928
0
    assert(str != NULL);
929
0
    int str_len = strlen(str);
930
0
    assert(str_len > 2 && str[0] == '{' && str[str_len - 1] == '}');
931
0
    SNPRINT(total, snprintf, buf, len, "%.*s, ",
932
0
      str_len - 2, str + 1);
933
0
  } else {
934
    /* Format message */
935
0
    char *tmp = tt_static_buf();
936
0
    if (vsnprintf(tmp, TT_STATIC_BUF_LEN, format, ap) < 0)
937
0
      return -1;
938
0
    SNPRINT(total, snprintf, buf, len, "\"message\": \"");
939
    /* Escape and print message */
940
0
    SNPRINT(total, json_escape, buf, len, tmp);
941
0
    SNPRINT(total, snprintf, buf, len, "\", ");
942
0
  }
943
944
  /* in case of system errors */
945
0
  if (error) {
946
0
    SNPRINT(total, snprintf, buf, len, "\"error\": \"");
947
0
    SNPRINT(total, json_escape, buf, len, error);
948
0
    SNPRINT(total, snprintf, buf, len, "\", ");
949
0
  }
950
951
0
  SNPRINT(total, snprintf, buf, len, "\"pid\": %i ", getpid());
952
0
  SNPRINT(total, snprintf, buf, len, ", \"cord_name\": \"");
953
0
  SNPRINT(total, json_escape, buf, len, cord()->name);
954
0
  SNPRINT(total, snprintf, buf, len, "\"");
955
0
  if (fiber() && fiber()->fid != FIBER_ID_SCHED) {
956
0
    SNPRINT(total, snprintf, buf, len, ", \"fiber_id\": %llu, ",
957
0
      (long long)fiber()->fid);
958
0
    SNPRINT(total, snprintf, buf, len, "\"fiber_name\": \"");
959
0
    SNPRINT(total, json_escape, buf, len, fiber()->name);
960
0
    SNPRINT(total, snprintf, buf, len, "\"");
961
0
  }
962
963
0
  if (filename) {
964
0
    SNPRINT(total, snprintf, buf, len, ", \"file\": \"");
965
0
    SNPRINT(total, json_escape, buf, len, filename);
966
0
    SNPRINT(total, snprintf, buf, len, "\", \"line\": %i", line);
967
0
  }
968
0
  if (module != NULL) {
969
0
    SNPRINT(total, snprintf, buf, len, ", \"module\": \"");
970
0
    SNPRINT(total, json_escape, buf, len, module);
971
0
    SNPRINT(total, snprintf, buf, len, "\"");
972
0
  }
973
0
  SNPRINT(total, snprintf, buf, len, "}\n");
974
0
  return total;
975
0
}
976
977
/** Wrapper around log->format_func to be used with SNPRINT. */
978
static int
979
format_func_adapter(char *buf, int len, struct log *log, int level,
980
        const char *module, const char *filename, int line,
981
        const char *error, const char *format, va_list ap)
982
0
{
983
0
  return log->format_func(log, buf, len, level, module, filename, line,
984
0
        error, format, ap);
985
0
}
986
987
/**
988
 * Format the header of a log message in syslog format.
989
 *
990
 * See RFC 5424 and RFC 3164. RFC 3164 is compatible with RFC 5424,
991
 * so it is implemented.
992
 * Protocol:
993
 * <PRIORITY_VALUE>TIMESTAMP IDENTATION[PID]: CORD/FID/FIBERNAME LEVEL> MSG
994
 * - Priority value is encoded as message subject * 8 and bitwise
995
 *   OR with message level;
996
 * - Timestamp must be encoded in the format: Mmm dd hh:mm:ss;
997
 *   Mmm - moth abbreviation;
998
 * - Identation is application name. By default it is "tarantool";
999
 */
1000
static int
1001
format_syslog_header(char *buf, int len, int level,
1002
         enum syslog_facility facility, const char *ident)
1003
0
{
1004
0
  struct tm tm;
1005
0
  double tm_sec;
1006
0
  get_current_time(&tm, &tm_sec);
1007
1008
0
  int total = 0;
1009
1010
  /* Format syslog header according to RFC */
1011
0
  int prio = (facility << 3) | level_to_syslog_priority(level);
1012
0
  SNPRINT(total, snprintf, buf, len, "<%d>", prio);
1013
0
  SNPRINT(total, strftime, buf, len, "%h %e %T ", &tm);
1014
0
  SNPRINT(total, snprintf, buf, len, "%s[%d]: ", ident,
1015
0
    getpid());
1016
0
  return total;
1017
0
}
1018
1019
/** Formatters }}} */
1020
1021
/** {{{ Loggers */
1022
1023
/*
1024
 * From pipe(7):
1025
 * POSIX.1 says that write(2)s of less than PIPE_BUF bytes must be atomic:
1026
 * the output data is written to the pipe as a contiguous sequence. Writes
1027
 * of more than PIPE_BUF bytes may be nonatomic: the kernel may interleave
1028
 * the data with data written by other processes. PIPE_BUF is 4k on Linux.
1029
 *
1030
 * Nevertheless, let's ignore the fact that messages can be interleaved in
1031
 * some situations and set SAY_BUF_LEN_MAX to 16k for now.
1032
 */
1033
enum { SAY_BUF_LEN_MAX = 16 * 1024 };
1034
static __thread char say_buf[SAY_BUF_LEN_MAX];
1035
1036
/**
1037
 * Wrapper over write which ensures, that writes not more than buffer size.
1038
 */
1039
static ssize_t
1040
safe_write(int fd, const char *buf, int size)
1041
0
{
1042
0
  assert(size >= 0);
1043
  /* Writes at most SAY_BUF_LEN_MAX - 1
1044
   * (1 byte was taken for 0 byte in vsnprintf).
1045
   */
1046
0
  return write(fd, buf, MIN(size, SAY_BUF_LEN_MAX - 1));
1047
0
}
1048
1049
/**
1050
 * Common part of say_default() and say_from_lua().
1051
 */
1052
static void
1053
say_internal(int level, bool check_level, const char *module,
1054
       const char *filename, int line, const char *error,
1055
       const char *format, va_list ap)
1056
0
{
1057
0
  int errsv = errno;
1058
0
  int total = log_vsay(log_default, level, check_level, module, filename,
1059
0
           line, error, format, ap);
1060
0
  if (total > 0 &&
1061
0
      level == S_FATAL && log_default->fd != STDERR_FILENO) {
1062
0
    ssize_t r = safe_write(STDERR_FILENO, say_buf, total);
1063
0
    (void)r;
1064
0
  }
1065
0
  errno = errsv; /* Preserve the errno. */
1066
0
}
1067
1068
/**
1069
 * Default say function.
1070
 */
1071
static void
1072
say_default(int level, const char *filename, int line, const char *error,
1073
      const char *format, ...)
1074
0
{
1075
0
  va_list ap;
1076
0
  va_start(ap, format);
1077
0
  if (level <= log_level_flightrec) {
1078
0
    assert(log_write_flightrec != NULL);
1079
0
    int errsv = errno;
1080
0
    va_list ap_copy;
1081
0
    va_copy(ap_copy, ap);
1082
0
    log_write_flightrec(level, filename, line, error, format,
1083
0
            ap_copy);
1084
0
    va_end(ap_copy);
1085
0
    errno = errsv; /* Preserve the errno. */
1086
0
  }
1087
0
  say_internal(level, true, NULL, filename, line, error, format, ap);
1088
0
  va_end(ap);
1089
0
}
1090
1091
/**
1092
 * Format and print a message to the default Tarantool log.
1093
 * This function is used by Lua say().
1094
 * Unlike say_default(), it doesn't compare level against log->level, the check
1095
 * is performed in Lua, because each module can have its own log level.
1096
 * Also it takes module name, and doesn't take an error argument.
1097
 */
1098
void
1099
say_from_lua(int level, const char *module, const char *filename, int line,
1100
       const char *format, ...)
1101
0
{
1102
0
  va_list ap;
1103
0
  va_start(ap, format);
1104
0
  say_internal(level, false, module, filename, line, NULL, format, ap);
1105
0
  va_end(ap);
1106
0
}
1107
1108
/**
1109
 * A variadic wrapper over log_write_flightrec(), used by Lua say().
1110
 */
1111
void
1112
log_write_flightrec_from_lua(int level, const char *filename, int line, ...)
1113
0
{
1114
0
  assert(log_write_flightrec != NULL);
1115
0
  int errsv = errno;
1116
0
  va_list ap;
1117
0
  va_start(ap, line);
1118
  /* ap contains a single string, which is already formatted. */
1119
0
  log_write_flightrec(level, filename, line, NULL, "%s", ap);
1120
0
  errno = errsv; /* Preserve the errno. */
1121
0
  va_end(ap);
1122
0
}
1123
1124
/**
1125
 * File and pipe logger
1126
 */
1127
static void
1128
write_to_file(struct log *log, int total)
1129
0
{
1130
0
  assert(log->type == SAY_LOGGER_FILE ||
1131
0
         log->type == SAY_LOGGER_PIPE ||
1132
0
         log->type == SAY_LOGGER_STDERR);
1133
0
  assert(total >= 0);
1134
0
  ssize_t r = safe_write(log->fd, say_buf, total);
1135
0
  (void) r;                               /* silence gcc warning */
1136
0
}
1137
1138
/**
1139
 * Syslog logger
1140
 */
1141
static void
1142
write_to_syslog(struct log *log, int total)
1143
0
{
1144
0
  assert(log->type == SAY_LOGGER_SYSLOG);
1145
0
  assert(total >= 0);
1146
0
  if (log->fd < 0 || safe_write(log->fd, say_buf, total) <= 0) {
1147
    /*
1148
     * Try to reconnect, if write to syslog has
1149
     * failed. Syslog write can fail, if, for example,
1150
     * syslogd is restarted. In such a case write to
1151
     * UNIX socket starts return -1 even for UDP.
1152
     */
1153
0
    if (log->fd >= 0)
1154
0
      close(log->fd);
1155
0
    log->fd = log_syslog_connect(log);
1156
0
    if (log->fd >= 0) {
1157
0
      log_set_nonblock(log);
1158
      /*
1159
       * In a case or error the log message is
1160
       * lost. We can not wait for connection -
1161
       * it would block thread. Try to reconnect
1162
       * on next vsay().
1163
       */
1164
0
      ssize_t r = safe_write(log->fd, say_buf, total);
1165
0
      (void) r;               /* silence gcc warning */
1166
0
    }
1167
0
  }
1168
0
}
1169
1170
/** Loggers }}} */
1171
1172
/*
1173
 * Init string parser(s)
1174
 */
1175
1176
/**
1177
 * @retval string after prefix if a prefix is found,
1178
 *         *str also is advanced to the prefix
1179
 *     NULL a prefix is not found, str is left intact
1180
 */
1181
static const char *
1182
say_parse_prefix(const char **str, const char *prefix)
1183
0
{
1184
0
  size_t len = strlen(prefix);
1185
0
  if (strncmp(*str, prefix, len) == 0) {
1186
0
    *str = *str + len;
1187
0
    return *str;
1188
0
  }
1189
0
  return NULL;
1190
0
}
1191
1192
int
1193
say_parse_logger_type(const char **str, enum say_logger_type *type)
1194
0
{
1195
0
  if (say_parse_prefix(str, "|"))
1196
0
    *type = SAY_LOGGER_PIPE;
1197
0
  else if (say_parse_prefix(str, "file:"))
1198
0
    *type = SAY_LOGGER_FILE;
1199
0
  else if (say_parse_prefix(str, "pipe:"))
1200
0
    *type = SAY_LOGGER_PIPE;
1201
0
  else if (say_parse_prefix(str, "syslog:"))
1202
0
    *type = SAY_LOGGER_SYSLOG;
1203
0
  else if (strchr(*str, ':') == NULL)
1204
0
    *type = SAY_LOGGER_FILE;
1205
0
  else {
1206
0
    diag_set(IllegalParams, logger_syntax_reminder);
1207
0
    return -1;
1208
0
  }
1209
0
  return 0;
1210
0
}
1211
1212
static const char *syslog_facility_strs[] = {
1213
  [SYSLOG_KERN] = "kern",
1214
  [SYSLOG_USER] = "user",
1215
  [SYSLOG_MAIL] = "mail",
1216
  [SYSLOG_DAEMON] = "daemon",
1217
  [SYSLOG_AUTH] = "auth",
1218
  [SYSLOG_INTERN] = "intern",
1219
  [SYSLOG_LPR] = "lpr",
1220
  [SYSLOG_NEWS] = "news",
1221
  [SYSLOG_UUCP] = "uucp",
1222
  [SYSLOG_CLOCK] = "clock",
1223
  [SYSLOG_AUTHPRIV] = "authpriv",
1224
  [SYSLOG_FTP] = "ftp",
1225
  [SYSLOG_NTP] = "ntp",
1226
  [SYSLOG_AUDIT] = "audit",
1227
  [SYSLOG_ALERT] = "alert",
1228
  [SYSLOG_CRON] = "cron",
1229
  [SYSLOG_LOCAL0] = "local0",
1230
  [SYSLOG_LOCAL1] = "local1",
1231
  [SYSLOG_LOCAL2] = "local2",
1232
  [SYSLOG_LOCAL3] = "local3",
1233
  [SYSLOG_LOCAL4] = "local4",
1234
  [SYSLOG_LOCAL5] = "local5",
1235
  [SYSLOG_LOCAL6] = "local6",
1236
  [SYSLOG_LOCAL7] = "local7",
1237
  [syslog_facility_MAX] = "unknown",
1238
};
1239
1240
enum syslog_facility
1241
say_syslog_facility_by_name(const char *facility)
1242
0
{
1243
0
  return STR2ENUM(syslog_facility, facility);
1244
0
}
1245
1246
int
1247
say_parse_syslog_opts(const char *init_str, struct say_syslog_opts *opts)
1248
0
{
1249
0
  opts->server_path = NULL;
1250
0
  opts->server_type = SAY_SYSLOG_DEFAULT;
1251
0
  opts->identity = NULL;
1252
0
  opts->facility = syslog_facility_MAX;
1253
0
  opts->copy = strdup(init_str);
1254
0
  if (opts->copy == NULL) {
1255
0
    diag_set(OutOfMemory, strlen(init_str), "malloc", "opts->copy");
1256
0
    return -1;
1257
0
  }
1258
0
  char *ptr = opts->copy;
1259
0
  const char *option, *value;
1260
1261
  /* strsep() overwrites the separator with '\0' */
1262
0
  while ((option = strsep(&ptr, ","))) {
1263
0
    if (*option == '\0')
1264
0
      break;
1265
1266
0
    value = option;
1267
0
    if (say_parse_prefix(&value, "server=")) {
1268
0
      if (opts->server_path != NULL ||
1269
0
          opts->server_type != SAY_SYSLOG_DEFAULT)
1270
0
        goto duplicate;
1271
0
      if (say_parse_prefix(&value, "unix:")) {
1272
0
        opts->server_type = SAY_SYSLOG_UNIX;
1273
0
        opts->server_path = value;
1274
0
      } else {
1275
0
        opts->server_type = SAY_SYSLOG_REMOTE;
1276
0
        opts->server_path = value;
1277
0
      }
1278
0
    } else if (say_parse_prefix(&value, "identity=")) {
1279
0
      if (opts->identity != NULL)
1280
0
        goto duplicate;
1281
0
      opts->identity = value;
1282
0
    } else if (say_parse_prefix(&value, "facility=")) {
1283
0
      if (opts->facility != syslog_facility_MAX)
1284
0
        goto duplicate;
1285
0
      opts->facility = say_syslog_facility_by_name(value);
1286
0
      if (opts->facility == syslog_facility_MAX) {
1287
0
        diag_set(IllegalParams, "bad syslog facility option '%s'",
1288
0
           value);
1289
0
        goto error;
1290
0
      }
1291
0
    } else {
1292
0
      diag_set(IllegalParams, "bad option '%s'", option);
1293
0
      goto error;
1294
0
    }
1295
0
  }
1296
0
  return 0;
1297
0
duplicate:
1298
  /* Terminate the "bad" option, by overwriting '=' sign */
1299
0
  ((char *)value)[-1] = '\0';
1300
0
  diag_set(IllegalParams, "duplicate option '%s'", option);
1301
0
error:
1302
0
  free(opts->copy); opts->copy = NULL;
1303
0
  return -1;
1304
0
}
1305
1306
void
1307
say_free_syslog_opts(struct say_syslog_opts *opts)
1308
0
{
1309
0
  free(opts->copy);
1310
0
  opts->copy = NULL;
1311
0
}
1312
1313
void
1314
log_destroy(struct log *log)
1315
0
{
1316
0
  assert(log != NULL);
1317
0
  tt_pthread_mutex_lock(&log->rotate_mutex);
1318
0
  while(log->rotating_threads > 0)
1319
0
    tt_pthread_cond_wait(&log->rotate_cond, &log->rotate_mutex);
1320
0
  tt_pthread_mutex_unlock(&log->rotate_mutex);
1321
0
  pm_atomic_store(&log->type, SAY_LOGGER_BOOT);
1322
1323
0
  if (log->fd != -1)
1324
0
    close(log->fd);
1325
0
  free(log->syslog_ident);
1326
0
  free(log->path);
1327
0
  rlist_del_entry(log, in_log_list);
1328
0
  tt_pthread_mutex_destroy(&log->rotate_mutex);
1329
0
  tt_pthread_cond_destroy(&log->rotate_cond);
1330
0
}
1331
1332
/**
1333
 * Format a line of log.
1334
 */
1335
static int
1336
format_log_entry(struct log *log, int level, const char *module,
1337
     const char *filename, int line, const char *error,
1338
     const char *format, va_list ap)
1339
0
{
1340
0
  int total = 0;
1341
0
  char *buf = say_buf;
1342
0
  int len = SAY_BUF_LEN_MAX;
1343
1344
0
  if (log->type == SAY_LOGGER_SYSLOG) {
1345
0
    SNPRINT(total, format_syslog_header, buf, len,
1346
0
      level, log->syslog_facility, log->syslog_ident);
1347
0
  }
1348
0
  SNPRINT(total, format_func_adapter, buf, len, log, level, module,
1349
0
    filename, line, error, format, ap);
1350
1351
0
  return total;
1352
0
}
1353
1354
int
1355
log_vsay(struct log *log, int level, bool check_level, const char *module,
1356
   const char *filename, int line, const char *error, const char *format,
1357
   va_list ap)
1358
0
{
1359
0
  int errsv = errno;
1360
0
  int total = 0;
1361
1362
0
  assert(level >= 0 && level < say_level_MAX);
1363
1364
0
  if (check_level && level > log->level)
1365
0
    goto out;
1366
1367
0
  total = format_log_entry(log, level, module, filename, line, error,
1368
0
         format, ap);
1369
0
  if (total <= 0)
1370
0
    goto out;
1371
1372
0
  switch (log->type) {
1373
0
  case SAY_LOGGER_FILE:
1374
0
  case SAY_LOGGER_PIPE:
1375
0
    write_to_file(log, total);
1376
0
    break;
1377
0
  case SAY_LOGGER_STDERR:
1378
0
    if (before_stderr_callback != NULL)
1379
0
      before_stderr_callback();
1380
0
    write_to_file(log, total);
1381
0
    if (after_stderr_callback != NULL)
1382
0
      after_stderr_callback();
1383
0
    break;
1384
0
  case SAY_LOGGER_SYSLOG:
1385
0
    write_to_syslog(log, total);
1386
0
    if (level == S_FATAL && log->fd != STDERR_FILENO)
1387
0
      (void)safe_write(STDERR_FILENO, say_buf, total);
1388
0
    break;
1389
0
  case SAY_LOGGER_BOOT:
1390
0
  {
1391
0
    if (before_stderr_callback != NULL)
1392
0
      before_stderr_callback();
1393
0
    ssize_t r = safe_write(STDERR_FILENO, say_buf, total);
1394
0
    (void) r;                       /* silence gcc warning */
1395
0
    if (after_stderr_callback != NULL)
1396
0
      after_stderr_callback();
1397
0
    break;
1398
0
  }
1399
0
  default:
1400
0
    unreachable();
1401
0
  }
1402
0
out:
1403
0
  errno = errsv; /* Preserve the errno. */
1404
0
  return total;
1405
0
}
1406
1407
void
1408
say_set_stderr_callback(say_stderr_callback_t before,
1409
      say_stderr_callback_t after)
1410
0
{
1411
0
  before_stderr_callback = before;
1412
0
  after_stderr_callback = after;
1413
0
}