trace.c 7.6 KB
Newer Older
M
 
Marc G. Fournier 已提交
1 2
/*-------------------------------------------------------------------------
 *
3
 * trace.c
M
 
Marc G. Fournier 已提交
4
 *
5
 *	  Conditional trace and logging functions.
M
 
Marc G. Fournier 已提交
6
 *
7
 *	  Massimo Dal Zotto <dz@cs.unitn.it>
M
 
Marc G. Fournier 已提交
8 9 10 11
 *
 *-------------------------------------------------------------------------
 */

12 13
#include "postgres.h"

M
 
Marc G. Fournier 已提交
14 15
#include <unistd.h>
#include <signal.h>
M
 
Marc G. Fournier 已提交
16
#include <sys/time.h>
M
 
Marc G. Fournier 已提交
17 18 19 20 21 22 23 24 25 26
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef USE_SYSLOG
#include <syslog.h>
#endif

#include "miscadmin.h"
#include "utils/trace.h"

27 28 29 30 31 32 33
/*
 * We could support trace messages of indefinite length, as elog() does,
 * but it's probably not worth the trouble.  Instead limit trace message
 * length to this.
 */
#define TRACEMSG_MAXLEN		1024

M
 
Marc G. Fournier 已提交
34 35 36 37
#ifdef USE_SYSLOG
/*
 * Global option to control the use of syslog(3) for logging:
 *
38 39 40
 *		0	stdout/stderr only
 *		1	stdout/stderr + syslog
 *		2	syslog only
M
 
Marc G. Fournier 已提交
41
 */
42 43
#define UseSyslog		pg_options[OPT_SYSLOG]
#define PG_LOG_FACILITY LOG_LOCAL0
M
 
Marc G. Fournier 已提交
44 45 46 47 48 49 50 51 52
#define PG_LOG_IDENT	"postgres"
#else
#define UseSyslog 0
#endif

/*
 * Trace option names, must match the constants in trace_opts[].
 */
static char *opt_names[] = {
M
 
Marc G. Fournier 已提交
53
	"all",						/* 0=trace some, 1=trace all, -1=trace none */
M
 
Marc G. Fournier 已提交
54 55 56 57 58
	"verbose",
	"query",
	"plan",
	"parse",
	"rewritten",
J
Jan Wieck 已提交
59 60 61
	"pretty_plan",
	"pretty_parse",
	"pretty_rewritten",
M
 
Marc G. Fournier 已提交
62 63 64
	"parserstats",
	"plannerstats",
	"executorstats",
65
	"shortlocks",				/* currently unused but needed, see lock.c */
M
 
Marc G. Fournier 已提交
66 67 68 69 70 71 72 73
	"locks",
	"userlocks",
	"spinlocks",
	"notify",
	"malloc",
	"palloc",
	"lock_debug_oidmin",
	"lock_debug_relid",
74 75 76 77 78
	"lock_read_priority",		/* lock priority, see lock.c */
	"deadlock_timeout",			/* deadlock timeout, see proc.c */
	"syslog",					/* use syslog for error messages */
	"hostlookup",				/* enable hostname lookup in ps_status */
	"showportnumber",			/* show port number in ps_status */
M
 
Marc G. Fournier 已提交
79 80

	/* NUM_PG_OPTIONS */		/* must be the last item of enum */
M
 
Marc G. Fournier 已提交
81 82 83 84 85
};

/*
 * Array of trace flags which can be set or reset independently.
 */
86
int			pg_options[NUM_PG_OPTIONS] = {0};
M
 
Marc G. Fournier 已提交
87 88 89 90 91 92

/*
 * Print a timestamp and a message to stdout if the trace flag
 * indexed by the flag value is set.
 */
int
93
tprintf(int flag, const char *fmt,...)
M
 
Marc G. Fournier 已提交
94 95
{
	va_list		ap;
96
	char		line[TRACEMSG_MAXLEN + TIMESTAMP_SIZE + 1];
M
 
Marc G. Fournier 已提交
97
#ifdef USE_SYSLOG
98
	int			log_level;
M
 
Marc G. Fournier 已提交
99 100
#endif

101 102
	if ((flag == TRACE_ALL) || (pg_options[TRACE_ALL] > 0))
	{
103
		/* unconditional trace or trace all option set */
104 105 106 107
	}
	else if (pg_options[TRACE_ALL] == 0)
	{
		if ((flag < 0) || (flag >= NUM_PG_OPTIONS) || (!pg_options[flag]))
M
 
Marc G. Fournier 已提交
108 109
			return 0;
	}
110 111
	else if (pg_options[TRACE_ALL] < 0)
		return 0;
M
 
Marc G. Fournier 已提交
112 113 114 115

#ifdef ELOG_TIMESTAMPS
	strcpy(line, tprintf_timestamp());
#endif
116 117
	va_start(ap, fmt);
	vsnprintf(line + TIMESTAMP_SIZE, TRACEMSG_MAXLEN, fmt, ap);
M
 
Marc G. Fournier 已提交
118 119 120 121
	va_end(ap);

#ifdef USE_SYSLOG
	log_level = ((flag == TRACE_ALL) ? LOG_INFO : LOG_DEBUG);
122
	write_syslog(log_level, line + TIMESTAMP_SIZE);
M
 
Marc G. Fournier 已提交
123 124
#endif

125 126
	if (UseSyslog <= 1)
	{
M
 
Marc G. Fournier 已提交
127 128 129 130 131 132 133
		puts(line);
		fflush(stdout);
	}

	return 1;
}

134 135 136
/*
 * Print a timestamp and a message to stdout or to syslog.
 */
137
#ifdef NOT_USED
138
int
B
Bruce Momjian 已提交
139
tprintf1(const char *fmt,...)
140 141
{
	va_list		ap;
142
	char		line[TRACEMSG_MAXLEN + TIMESTAMP_SIZE + 1];
143 144 145 146

#ifdef ELOG_TIMESTAMPS
	strcpy(line, tprintf_timestamp());
#endif
147 148
	va_start(ap, fmt);
	vsnprintf(line + TIMESTAMP_SIZE, TRACEMSG_MAXLEN, fmt, ap);
149 150 151
	va_end(ap);

#ifdef USE_SYSLOG
B
Bruce Momjian 已提交
152
	write_syslog(LOG_INFO, line + TIMESTAMP_SIZE);
153 154
#endif

B
Bruce Momjian 已提交
155 156
	if (UseSyslog <= 1)
	{
157 158 159 160 161 162
		puts(line);
		fflush(stdout);
	}

	return 1;
}
163
#endif
164

M
 
Marc G. Fournier 已提交
165 166 167 168
/*
 * Print a timestamp and a message to stderr.
 */
int
169
eprintf(const char *fmt,...)
M
 
Marc G. Fournier 已提交
170 171
{
	va_list		ap;
172
	char		line[TRACEMSG_MAXLEN + TIMESTAMP_SIZE + 1];
M
 
Marc G. Fournier 已提交
173 174 175 176

#ifdef ELOG_TIMESTAMPS
	strcpy(line, tprintf_timestamp());
#endif
177 178
	va_start(ap, fmt);
	vsnprintf(line + TIMESTAMP_SIZE, TRACEMSG_MAXLEN, fmt, ap);
M
 
Marc G. Fournier 已提交
179 180 181
	va_end(ap);

#ifdef USE_SYSLOG
182
	write_syslog(LOG_ERR, line + TIMESTAMP_SIZE);
M
 
Marc G. Fournier 已提交
183 184
#endif

185 186
	if (UseSyslog <= 1)
	{
M
 
Marc G. Fournier 已提交
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
		fputs(line, stderr);
		fputc('\n', stderr);
		fflush(stderr);
	}

	return 1;
}

#ifdef USE_SYSLOG
/*
 * Write a message line to syslog if the syslog option is set.
 */
void
write_syslog(int level, char *line)
{
B
Bruce Momjian 已提交
202
	static int	openlog_done = 0;
T
Tom Lane 已提交
203

204 205 206 207
	if (UseSyslog >= 1)
	{
		if (!openlog_done)
		{
M
 
Marc G. Fournier 已提交
208
			openlog_done = 1;
209
			openlog(PG_LOG_IDENT, LOG_PID | LOG_NDELAY, PG_LOG_FACILITY);
M
 
Marc G. Fournier 已提交
210 211 212 213 214 215 216 217 218 219 220 221 222
		}
		syslog(level, "%s", line);
	}
}
#endif

#ifdef ELOG_TIMESTAMPS
/*
 * Return a timestamp string like "980119.17:25:59.902 [21974] "
 */
char *
tprintf_timestamp()
{
223
	struct timeval tv;
M
 
Marc G. Fournier 已提交
224
	struct timezone tz = { 0, 0 };
225 226 227 228
	struct tm  *time;
	time_t		tm;
	static char timestamp[32],
				pid[8];
M
 
Marc G. Fournier 已提交
229

M
 
Marc G. Fournier 已提交
230
	gettimeofday(&tv, &tz);
M
 
Marc G. Fournier 已提交
231 232 233 234 235
	tm = tv.tv_sec;
	time = localtime(&tm);

	sprintf(pid, "[%d]", MyProcPid);
	sprintf(timestamp, "%02d%02d%02d.%02d:%02d:%02d.%03d %7s ",
236
			time->tm_year, time->tm_mon + 1, time->tm_mday,
M
 
Marc G. Fournier 已提交
237
			time->tm_hour, time->tm_min, time->tm_sec,
M
 
Marc G. Fournier 已提交
238
			(int) (tv.tv_usec/1000), pid);
M
 
Marc G. Fournier 已提交
239 240 241 242 243

	return timestamp;
}
#endif

244 245
#ifdef NOT_USED
static int
M
 
Marc G. Fournier 已提交
246 247
option_flag(int flag)
{
248
	if ((flag < 0) || (flag >= NUM_PG_OPTIONS))
M
 
Marc G. Fournier 已提交
249 250 251 252 253 254 255
		return 0;
	return pg_options[flag];
}

int
set_option_flag(int flag, int value)
{
256
	if ((flag < 0) || (flag >= NUM_PG_OPTIONS))
M
 
Marc G. Fournier 已提交
257 258 259 260 261
		return -1;

	pg_options[flag] = value;
	return value;
}
262
#endif
M
 
Marc G. Fournier 已提交
263 264 265 266

/*
 * Parse an option string like "name,name+,name-,name=value".
 * Single options are delimited by ',',space,tab,newline or cr.
267 268 269 270
 *
 * If 'secure' is false, the option string came from a remote client via
 * connection "debug options" field --- do not obey any requests that
 * might potentially be security loopholes.
271
 */
M
 
Marc G. Fournier 已提交
272
void
273
parse_options(char *str, bool secure)
M
 
Marc G. Fournier 已提交
274
{
275 276 277 278 279 280 281 282 283
	char	   *s,
			   *name;
	int			i,
				len,
				val,
				is_comment;

	Assert((sizeof(opt_names) / sizeof(char *)) == NUM_PG_OPTIONS);

M
 
Marc G. Fournier 已提交
284
	str = strdup(str);
285 286
	for (s = str; *s;)
	{
M
 
Marc G. Fournier 已提交
287 288 289
		is_comment = 0;
		name = s;
		val = 1;
290 291 292 293
		for (; *s; s++)
		{
			switch (*s)
			{
M
 
Marc G. Fournier 已提交
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
				case '#':
					is_comment = 1;
					break;
				case '=':
					*s++ = '\0';
					val = strtol(s, &s, 10);
					goto setval;
				case '-':
					*s++ = '\0';
					val = 0;
					goto setval;
				case '+':
					*s++ = '\0';
					val = 1;
					goto setval;
				case ' ':
				case ',':
				case '\t':
				case '\n':
				case '\r':
					*s = ',';
					val = 1;
					goto setval;
			}
		}
319 320 321 322 323
setval:
		for (; *s; s++)
		{
			if (*s == ',')
			{
M
 
Marc G. Fournier 已提交
324 325 326 327 328
				*s++ = '\0';
				break;
			}
		}
		len = strlen(name);
329
		if (len == 0)
M
 
Marc G. Fournier 已提交
330
			continue;
331 332 333 334
		for (i = 0; i < NUM_PG_OPTIONS; i++)
		{
			if (strncmp(name, opt_names[i], len) == 0)
			{
M
 
Marc G. Fournier 已提交
335 336 337 338
				pg_options[i] = val;
				break;
			}
		}
339
		if (!is_comment && (i >= NUM_PG_OPTIONS))
M
 
Marc G. Fournier 已提交
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
			fprintf(stderr, "invalid option: %s\n", name);
	}
	free(str);
}

#define BUF_SIZE 4096

void
read_pg_options(SIGNAL_ARGS)
{
	int			fd;
	int			n;
	int			verbose;
	char		buffer[BUF_SIZE];
	char		c;
355 356
	char	   *s,
			   *p;
M
 
Marc G. Fournier 已提交
357

B
Bruce Momjian 已提交
358 359 360 361
	if (!DataDir)
	{
		fprintf(stderr, "read_pg_options: DataDir not defined\n");
		return;
362 363
	}

364
	snprintf(buffer, BUF_SIZE - 1, "%s/%s", DataDir, "pg_options");
365
#ifndef __CYGWIN32__
366
	if ((fd = open(buffer, O_RDONLY)) < 0)
367 368 369
#else
	if ((fd = open(buffer, O_RDONLY | O_BINARY)) < 0)
#endif
M
 
Marc G. Fournier 已提交
370 371
		return;

372 373
	if ((n = read(fd, buffer, BUF_SIZE - 1)) > 0)
	{
M
 
Marc G. Fournier 已提交
374
		/* collpse buffer in place removing comments and spaces */
375 376 377 378
		for (s = buffer, p = buffer, c = '\0'; s < (buffer + n);)
		{
			switch (*s)
			{
M
 
Marc G. Fournier 已提交
379
				case '#':
380
					while ((s < (buffer + n)) && (*s++ != '\n'));
M
 
Marc G. Fournier 已提交
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
					break;
				case ' ':
				case '\t':
				case '\n':
				case '\r':
					if (c != ',')
						c = *p++ = ',';
					s++;
					break;
				default:
					c = *p++ = *s++;
					break;
			}
		}
		if (c == ',')
			p--;
		*p = '\0';
		verbose = pg_options[TRACE_VERBOSE];
399
		parse_options(buffer, true);
M
 
Marc G. Fournier 已提交
400
		verbose |= pg_options[TRACE_VERBOSE];
401
		if (verbose || postgres_signal_arg == SIGHUP)
M
 
Marc G. Fournier 已提交
402 403 404 405 406 407 408
			tprintf(TRACE_ALL, "read_pg_options: %s", buffer);
	}

	close(fd);
}

/*
B
Bruce Momjian 已提交
409 410 411 412
 * Local variables:
 *	tab-width: 4
 *	c-indent-level: 4
 *	c-basic-offset: 4
M
 
Marc G. Fournier 已提交
413 414
 * End:
 */