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