PostgreSQL Source Code  git master
logging.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  * Logging framework for frontend programs
3  *
4  * Copyright (c) 2018-2019, PostgreSQL Global Development Group
5  *
6  * src/common/logging.c
7  *
8  *-------------------------------------------------------------------------
9  */
10 #include "postgres_fe.h"
11 
12 #include <unistd.h>
13 
14 #include "common/logging.h"
15 
17 
18 static const char *progname;
19 static int log_flags;
20 
21 static void (*log_pre_callback) (void);
22 static void (*log_locus_callback) (const char **, uint64 *);
23 
24 static const char *sgr_error = NULL;
25 static const char *sgr_warning = NULL;
26 static const char *sgr_locus = NULL;
27 
28 #define SGR_ERROR_DEFAULT "01;31"
29 #define SGR_WARNING_DEFAULT "01;35"
30 #define SGR_LOCUS_DEFAULT "01"
31 
32 #define ANSI_ESCAPE_FMT "\x1b[%sm"
33 #define ANSI_ESCAPE_RESET "\x1b[0m"
34 
35 /*
36  * This should be called before any output happens.
37  */
38 void
39 pg_logging_init(const char *argv0)
40 {
41  const char *pg_color_env = getenv("PG_COLOR");
42  bool log_color = false;
43 
44  /* usually the default, but not on Windows */
45  setvbuf(stderr, NULL, _IONBF, 0);
46 
47  progname = get_progname(argv0);
49 
50  if (pg_color_env)
51  {
52  if (strcmp(pg_color_env, "always") == 0 ||
53  (strcmp(pg_color_env, "auto") == 0 && isatty(fileno(stderr))))
54  log_color = true;
55  }
56 
57  if (log_color)
58  {
59  const char *pg_colors_env = getenv("PG_COLORS");
60 
61  if (pg_colors_env)
62  {
63  char *colors = strdup(pg_colors_env);
64 
65  if (colors)
66  {
67  for (char *token = strtok(colors, ":"); token; token = strtok(NULL, ":"))
68  {
69  char *e = strchr(token, '=');
70 
71  if (e)
72  {
73  char *name;
74  char *value;
75 
76  *e = '\0';
77  name = token;
78  value = e + 1;
79 
80  if (strcmp(name, "error") == 0)
81  sgr_error = strdup(value);
82  if (strcmp(name, "warning") == 0)
83  sgr_warning = strdup(value);
84  if (strcmp(name, "locus") == 0)
85  sgr_locus = strdup(value);
86  }
87  }
88 
89  free(colors);
90  }
91  }
92  else
93  {
97  }
98  }
99 }
100 
101 void
102 pg_logging_config(int new_flags)
103 {
104  log_flags = new_flags;
105 }
106 
107 void
109 {
110  __pg_log_level = new_level;
111 }
112 
113 void
114 pg_logging_set_pre_callback(void (*cb) (void))
115 {
116  log_pre_callback = cb;
117 }
118 
119 void
120 pg_logging_set_locus_callback(void (*cb) (const char **filename, uint64 *lineno))
121 {
122  log_locus_callback = cb;
123 }
124 
125 void
126 pg_log_generic(enum pg_log_level level, const char *pg_restrict fmt,...)
127 {
128  va_list ap;
129 
130  va_start(ap, fmt);
131  pg_log_generic_v(level, fmt, ap);
132  va_end(ap);
133 }
134 
135 void
136 pg_log_generic_v(enum pg_log_level level, const char *pg_restrict fmt, va_list ap)
137 {
138  int save_errno = errno;
139  const char *filename = NULL;
140  uint64 lineno = 0;
141  va_list ap2;
142  size_t required_len;
143  char *buf;
144 
145  Assert(progname);
146  Assert(level);
147  Assert(fmt);
148  Assert(fmt[strlen(fmt) - 1] != '\n');
149 
150  /*
151  * Flush stdout before output to stderr, to ensure sync even when stdout
152  * is buffered.
153  */
154  fflush(stdout);
155 
156  if (log_pre_callback)
158 
159  if (log_locus_callback)
160  log_locus_callback(&filename, &lineno);
161 
162  fmt = _(fmt);
163 
164  if (!(log_flags & PG_LOG_FLAG_TERSE) || filename)
165  {
166  if (sgr_locus)
168  if (!(log_flags & PG_LOG_FLAG_TERSE))
169  fprintf(stderr, "%s:", progname);
170  if (filename)
171  {
172  fprintf(stderr, "%s:", filename);
173  if (lineno > 0)
174  fprintf(stderr, UINT64_FORMAT ":", lineno);
175  }
176  fprintf(stderr, " ");
177  if (sgr_locus)
178  fprintf(stderr, ANSI_ESCAPE_RESET);
179  }
180 
181  if (!(log_flags & PG_LOG_FLAG_TERSE))
182  {
183  switch (level)
184  {
185  case PG_LOG_FATAL:
186  if (sgr_error)
188  fprintf(stderr, _("fatal: "));
189  if (sgr_error)
190  fprintf(stderr, ANSI_ESCAPE_RESET);
191  break;
192  case PG_LOG_ERROR:
193  if (sgr_error)
195  fprintf(stderr, _("error: "));
196  if (sgr_error)
197  fprintf(stderr, ANSI_ESCAPE_RESET);
198  break;
199  case PG_LOG_WARNING:
200  if (sgr_warning)
202  fprintf(stderr, _("warning: "));
203  if (sgr_warning)
204  fprintf(stderr, ANSI_ESCAPE_RESET);
205  break;
206  default:
207  break;
208  }
209  }
210 
211  errno = save_errno;
212 
213  va_copy(ap2, ap);
214  required_len = vsnprintf(NULL, 0, fmt, ap2) + 1;
215  va_end(ap2);
216 
217  buf = pg_malloc_extended(required_len, MCXT_ALLOC_NO_OOM);
218 
219  errno = save_errno; /* malloc might change errno */
220 
221  if (!buf)
222  {
223  /* memory trouble, just print what we can and get out of here */
224  vfprintf(stderr, fmt, ap);
225  return;
226  }
227 
228  vsnprintf(buf, required_len, fmt, ap);
229 
230  /* strip one newline, for PQerrorMessage() */
231  if (required_len >= 2 && buf[required_len - 2] == '\n')
232  buf[required_len - 2] = '\0';
233 
234  fprintf(stderr, "%s\n", buf);
235 
236  free(buf);
237 }
static void(* log_locus_callback)(const char **, uint64 *)
Definition: logging.c:22
static char * argv0
Definition: pg_ctl.c:97
#define ANSI_ESCAPE_RESET
Definition: logging.c:33
const char * get_progname(const char *argv0)
Definition: path.c:453
void pg_logging_init(const char *argv0)
Definition: logging.c:39
pg_log_level
Definition: logging.h:16
void pg_logging_set_pre_callback(void(*cb)(void))
Definition: logging.c:114
static struct @145 value
#define MCXT_ALLOC_NO_OOM
Definition: fe_memutils.h:18
#define fprintf
Definition: port.h:196
#define ANSI_ESCAPE_FMT
Definition: logging.c:32
#define SGR_LOCUS_DEFAULT
Definition: logging.c:30
static void(* log_pre_callback)(void)
Definition: logging.c:21
#define vsnprintf
Definition: port.h:191
static const char * sgr_error
Definition: logging.c:24
static char * buf
Definition: pg_test_fsync.c:67
void * pg_malloc_extended(size_t size, int flags)
Definition: fe_memutils.c:59
static const char * sgr_warning
Definition: logging.c:25
void pg_logging_set_locus_callback(void(*cb)(const char **filename, uint64 *lineno))
Definition: logging.c:120
enum pg_log_level __pg_log_level
Definition: logging.c:16
static int log_flags
Definition: logging.c:19
static const char * progname
Definition: logging.c:18
void pg_log_generic(enum pg_log_level level, const char *pg_restrict fmt,...)
Definition: logging.c:126
#define free(a)
Definition: header.h:65
#define Assert(condition)
Definition: c.h:739
void pg_logging_config(int new_flags)
Definition: logging.c:102
void pg_log_generic_v(enum pg_log_level level, const char *pg_restrict fmt, va_list ap)
Definition: logging.c:136
#define SGR_ERROR_DEFAULT
Definition: logging.c:28
const char * name
Definition: encode.c:521
static char * filename
Definition: pg_dumpall.c:90
e
Definition: preproc-init.c:82
#define PG_LOG_FLAG_TERSE
Definition: logging.h:64
void pg_logging_set_level(enum pg_log_level new_level)
Definition: logging.c:108
#define vfprintf
Definition: port.h:195
static const char * sgr_locus
Definition: logging.c:26
#define _(x)
Definition: elog.c:87
#define UINT64_FORMAT
Definition: c.h:402
#define SGR_WARNING_DEFAULT
Definition: logging.c:29