]> granicus.if.org Git - postgresql/blob - src/backend/utils/misc/trace.c
Massimo's SET FSYNC and SHOW PG_OPTIONS changes, without SET QUERY_LIMIT.
[postgresql] / src / backend / utils / misc / trace.c
1 /*-------------------------------------------------------------------------
2  *
3  * trace.c
4  *
5  *        Conditional trace and logging functions.
6  *
7  *        Massimo Dal Zotto <dz@cs.unitn.it>
8  *
9  *-------------------------------------------------------------------------
10  */
11
12 #include "postgres.h"
13
14 #include <unistd.h>
15 #include <signal.h>
16 #include <sys/time.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #ifdef USE_SYSLOG
21 #include <syslog.h>
22 #endif
23
24 #include "miscadmin.h"
25 #include "utils/trace.h"
26
27 /*
28  * We could support trace messages of indefinite length, as elog() does,
29  * but it's probably not worth the trouble.  Instead limit trace message
30  * length to this.
31  */
32 #define TRACEMSG_MAXLEN         1024
33
34 #ifdef USE_SYSLOG
35 /*
36  * Global option to control the use of syslog(3) for logging:
37  *
38  *              0       stdout/stderr only
39  *              1       stdout/stderr + syslog
40  *              2       syslog only
41  */
42 #define UseSyslog               pg_options[OPT_SYSLOG]
43 #define PG_LOG_FACILITY LOG_LOCAL0
44 #define PG_LOG_IDENT    "postgres"
45 #else
46 #define UseSyslog 0
47 #endif
48
49 /*
50  * Trace option names, must match the constants in trace_opts[].
51  */
52 static char *opt_names[] = {
53         "all",                                          /* 0=trace some, 1=trace all, -1=trace none */
54         "verbose",
55         "query",
56         "plan",
57         "parse",
58         "rewritten",
59         "pretty_plan",
60         "pretty_parse",
61         "pretty_rewritten",
62         "parserstats",
63         "plannerstats",
64         "executorstats",
65         "shortlocks",                           /* currently unused but needed, see lock.c */
66         "locks",
67         "userlocks",
68         "spinlocks",
69         "notify",
70         "malloc",
71         "palloc",
72         "lock_debug_oidmin",
73         "lock_debug_relid",
74         "lock_read_priority",           /* lock priority, see lock.c */
75         "deadlock_timeout",                     /* deadlock timeout, see proc.c */
76         "nofsync",                                      /* turn fsync off */
77         "syslog",                                       /* use syslog for error messages */
78         "hostlookup",                           /* enable hostname lookup in ps_status */
79         "showportnumber",                       /* show port number in ps_status */
80
81         /* NUM_PG_OPTIONS */            /* must be the last item of enum */
82 };
83
84 /*
85  * Array of trace flags which can be set or reset independently.
86  */
87 int                     pg_options[NUM_PG_OPTIONS] = {0};
88
89 /*
90  * Print a timestamp and a message to stdout if the trace flag
91  * indexed by the flag value is set.
92  */
93 int
94 tprintf(int flag, const char *fmt,...)
95 {
96         va_list         ap;
97         char            line[TRACEMSG_MAXLEN + TIMESTAMP_SIZE + 1];
98 #ifdef USE_SYSLOG
99         int                     log_level;
100 #endif
101
102         if ((flag == TRACE_ALL) || (pg_options[TRACE_ALL] > 0))
103         {
104                 /* unconditional trace or trace all option set */
105         }
106         else if (pg_options[TRACE_ALL] == 0)
107         {
108                 if ((flag < 0) || (flag >= NUM_PG_OPTIONS) || (!pg_options[flag]))
109                         return 0;
110         }
111         else if (pg_options[TRACE_ALL] < 0)
112                 return 0;
113
114 #ifdef ELOG_TIMESTAMPS
115         strcpy(line, tprintf_timestamp());
116 #endif
117         va_start(ap, fmt);
118         vsnprintf(line + TIMESTAMP_SIZE, TRACEMSG_MAXLEN, fmt, ap);
119         va_end(ap);
120
121 #ifdef USE_SYSLOG
122         log_level = ((flag == TRACE_ALL) ? LOG_INFO : LOG_DEBUG);
123         write_syslog(log_level, line + TIMESTAMP_SIZE);
124 #endif
125
126         if (UseSyslog <= 1)
127         {
128                 puts(line);
129                 fflush(stdout);
130         }
131
132         return 1;
133 }
134
135 /*
136  * Print a timestamp and a message to stdout or to syslog.
137  */
138 #ifdef NOT_USED
139 int
140 tprintf1(const char *fmt,...)
141 {
142         va_list         ap;
143         char            line[TRACEMSG_MAXLEN + TIMESTAMP_SIZE + 1];
144
145 #ifdef ELOG_TIMESTAMPS
146         strcpy(line, tprintf_timestamp());
147 #endif
148         va_start(ap, fmt);
149         vsnprintf(line + TIMESTAMP_SIZE, TRACEMSG_MAXLEN, fmt, ap);
150         va_end(ap);
151
152 #ifdef USE_SYSLOG
153         write_syslog(LOG_INFO, line + TIMESTAMP_SIZE);
154 #endif
155
156         if (UseSyslog <= 1)
157         {
158                 puts(line);
159                 fflush(stdout);
160         }
161
162         return 1;
163 }
164 #endif
165
166 /*
167  * Print a timestamp and a message to stderr.
168  */
169 int
170 eprintf(const char *fmt,...)
171 {
172         va_list         ap;
173         char            line[TRACEMSG_MAXLEN + TIMESTAMP_SIZE + 1];
174
175 #ifdef ELOG_TIMESTAMPS
176         strcpy(line, tprintf_timestamp());
177 #endif
178         va_start(ap, fmt);
179         vsnprintf(line + TIMESTAMP_SIZE, TRACEMSG_MAXLEN, fmt, ap);
180         va_end(ap);
181
182 #ifdef USE_SYSLOG
183         write_syslog(LOG_ERR, line + TIMESTAMP_SIZE);
184 #endif
185
186         if (UseSyslog <= 1)
187         {
188                 fputs(line, stderr);
189                 fputc('\n', stderr);
190                 fflush(stderr);
191         }
192
193         return 1;
194 }
195
196 #ifdef USE_SYSLOG
197 /*
198  * Write a message line to syslog if the syslog option is set.
199  */
200 void
201 write_syslog(int level, char *line)
202 {
203         static int      openlog_done = 0;
204
205         if (UseSyslog >= 1)
206         {
207                 if (!openlog_done)
208                 {
209                         openlog_done = 1;
210                         openlog(PG_LOG_IDENT, LOG_PID | LOG_NDELAY, PG_LOG_FACILITY);
211                 }
212                 syslog(level, "%s", line);
213         }
214 }
215 #endif
216
217 #ifdef ELOG_TIMESTAMPS
218 /*
219  * Return a timestamp string like "980119.17:25:59.902 [21974] "
220  */
221 char *
222 tprintf_timestamp()
223 {
224         struct timeval tv;
225         struct timezone tz = { 0, 0 };
226         struct tm  *time;
227         time_t          tm;
228         static char timestamp[32],
229                                 pid[8];
230
231         gettimeofday(&tv, &tz);
232         tm = tv.tv_sec;
233         time = localtime(&tm);
234
235         sprintf(pid, "[%d]", MyProcPid);
236         sprintf(timestamp, "%02d%02d%02d.%02d:%02d:%02d.%03d %7s ",
237                         time->tm_year, time->tm_mon + 1, time->tm_mday,
238                         time->tm_hour, time->tm_min, time->tm_sec,
239                         (int) (tv.tv_usec/1000), pid);
240
241         return timestamp;
242 }
243 #endif
244
245 #ifdef NOT_USED
246 static int
247 option_flag(int flag)
248 {
249         if ((flag < 0) || (flag >= NUM_PG_OPTIONS))
250                 return 0;
251         return pg_options[flag];
252 }
253
254 int
255 set_option_flag(int flag, int value)
256 {
257         if ((flag < 0) || (flag >= NUM_PG_OPTIONS))
258                 return -1;
259
260         pg_options[flag] = value;
261         return value;
262 }
263 #endif
264
265 /*
266  * Parse an option string like "name,name+,name-,name=value".
267  * Single options are delimited by ',',space,tab,newline or cr.
268  *
269  * If 'secure' is false, the option string came from a remote client via
270  * connection "debug options" field --- do not obey any requests that
271  * might potentially be security loopholes.
272  */
273 void
274 parse_options(char *str, bool secure)
275 {
276         char       *s,
277                            *name;
278         int                     i,
279                                 len,
280                                 val,
281                                 is_comment;
282
283         Assert((sizeof(opt_names) / sizeof(char *)) == NUM_PG_OPTIONS);
284
285         str = strdup(str);
286         for (s = str; *s;)
287         {
288                 is_comment = 0;
289                 name = s;
290                 val = 1;
291                 for (; *s; s++)
292                 {
293                         switch (*s)
294                         {
295                                 case '#':
296                                         is_comment = 1;
297                                         break;
298                                 case '=':
299                                         *s++ = '\0';
300                                         val = strtol(s, &s, 10);
301                                         goto setval;
302                                 case '-':
303                                         *s++ = '\0';
304                                         val = 0;
305                                         goto setval;
306                                 case '+':
307                                         *s++ = '\0';
308                                         val = 1;
309                                         goto setval;
310                                 case ' ':
311                                 case ',':
312                                 case '\t':
313                                 case '\n':
314                                 case '\r':
315                                         *s = ',';
316                                         val = 1;
317                                         goto setval;
318                         }
319                 }
320 setval:
321                 for (; *s; s++)
322                 {
323                         if (*s == ',')
324                         {
325                                 *s++ = '\0';
326                                 break;
327                         }
328                 }
329                 len = strlen(name);
330                 if (len == 0)
331                         continue;
332                 for (i = 0; i < NUM_PG_OPTIONS; i++)
333                 {
334                         if (strncmp(name, opt_names[i], len) == 0)
335                         {
336                                 pg_options[i] = val;
337                                 break;
338                         }
339                 }
340                 if (!is_comment && (i >= NUM_PG_OPTIONS))
341                         fprintf(stderr, "invalid option: %s\n", name);
342         }
343         free(str);
344 }
345
346 #define BUF_SIZE 4096
347
348 void
349 read_pg_options(SIGNAL_ARGS)
350 {
351         int                     fd;
352         int                     n;
353         int                     verbose;
354         char            buffer[BUF_SIZE];
355         char            c;
356         char       *s,
357                            *p;
358
359         if (!DataDir)
360         {
361                 fprintf(stderr, "read_pg_options: DataDir not defined\n");
362                 return;
363         }
364
365         snprintf(buffer, BUF_SIZE - 1, "%s/%s", DataDir, "pg_options");
366 #ifndef __CYGWIN32__
367         if ((fd = open(buffer, O_RDONLY)) < 0)
368 #else
369         if ((fd = open(buffer, O_RDONLY | O_BINARY)) < 0)
370 #endif
371                 return;
372
373         if ((n = read(fd, buffer, BUF_SIZE - 1)) > 0)
374         {
375                 /* collpse buffer in place removing comments and spaces */
376                 for (s = buffer, p = buffer, c = '\0'; s < (buffer + n);)
377                 {
378                         switch (*s)
379                         {
380                                 case '#':
381                                         while ((s < (buffer + n)) && (*s++ != '\n'));
382                                         break;
383                                 case ' ':
384                                 case '\t':
385                                 case '\n':
386                                 case '\r':
387                                         if (c != ',')
388                                                 c = *p++ = ',';
389                                         s++;
390                                         break;
391                                 default:
392                                         c = *p++ = *s++;
393                                         break;
394                         }
395                 }
396                 if (c == ',')
397                         p--;
398                 *p = '\0';
399                 verbose = pg_options[TRACE_VERBOSE];
400                 parse_options(buffer, true);
401                 verbose |= pg_options[TRACE_VERBOSE];
402                 if (verbose || postgres_signal_arg == SIGHUP)
403                         tprintf(TRACE_ALL, "read_pg_options: %s", buffer);
404         }
405
406         close(fd);
407 }
408
409 void
410 show_options(void)
411 {
412         int             i;
413
414         for (i=0; i<NUM_PG_OPTIONS; i++) {
415                 elog(NOTICE, "%s=%d", opt_names[i], pg_options[i]);
416         }
417 }
418   
419 /*
420  * Local variables:
421  *      tab-width: 4
422  *      c-indent-level: 4
423  *      c-basic-offset: 4
424  * End:
425  */