summaryrefslogtreecommitdiff
path: root/src/backend/utils/error/elog.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/error/elog.c')
-rw-r--r--src/backend/utils/error/elog.c214
1 files changed, 178 insertions, 36 deletions
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index ce6cbac4bb1..19c107ddb6e 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.58 2000/05/30 00:49:55 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.59 2000/05/31 00:28:32 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -24,8 +24,10 @@
#include <errno.h>
#include <unistd.h>
#include <signal.h>
-#ifdef USE_SYSLOG
-#include <syslog.h>
+#include <sys/time.h>
+#include <ctype.h>
+#ifdef ENABLE_SYSLOG
+# include <syslog.h>
#endif
#include "libpq/libpq.h"
@@ -40,20 +42,31 @@ extern int sys_nerr;
extern CommandDest whereToSendOutput;
-#ifdef USE_SYSLOG
+#ifdef ENABLE_SYSLOG
/*
- * Global option to control the use of syslog(3) for logging:
- *
- * 0 stdout/stderr only
- * 1 stdout/stderr + syslog
- * 2 syslog only
+ * 0 = only stdout/stderr
+ * 1 = stdout+stderr and syslog
+ * 2 = syslog only
+ * ... in theory anyway
*/
-#define UseSyslog pg_options[OPT_SYSLOG]
-#define PG_LOG_FACILITY LOG_LOCAL0
+int Use_syslog = 0;
+
+static void write_syslog(int level, const char *line);
+
+#else
+# define Use_syslog 0
+#endif
+
+
+#ifdef ELOG_TIMESTAMPS
+static const char * print_timestamp(void);
+# define TIMESTAMP_SIZE 28
#else
-#define UseSyslog 0
+# define TIMESTAMP_SIZE 0
#endif
+
+
static int Debugfile = -1;
static int Err_file = -1;
static int ElogDebugIndentLevel = 0;
@@ -182,7 +195,7 @@ elog(int lev, const char *fmt,...)
}
}
#ifdef ELOG_TIMESTAMPS
- strcpy(fmt_buf, tprintf_timestamp());
+ strcpy(fmt_buf, print_timestamp());
strcat(fmt_buf, prefix);
#else
strcpy(fmt_buf, prefix);
@@ -265,7 +278,7 @@ elog(int lev, const char *fmt,...)
msg_buf = msg_fixedbuf;
lev = REALLYFATAL;
#ifdef ELOG_TIMESTAMPS
- strcpy(msg_buf, tprintf_timestamp());
+ strcpy(msg_buf, print_timestamp());
strcat(msg_buf, "FATAL: elog: out of memory");
#else
strcpy(msg_buf, "FATAL: elog: out of memory");
@@ -278,35 +291,43 @@ elog(int lev, const char *fmt,...)
* Message prepared; send it where it should go
*/
-#ifdef USE_SYSLOG
- switch (lev)
+#ifdef ENABLE_SYSLOG
+ if (Use_syslog >= 1)
{
- case NOIND:
- log_level = LOG_DEBUG;
- break;
- case DEBUG:
- log_level = LOG_DEBUG;
- break;
- case NOTICE:
- log_level = LOG_NOTICE;
- break;
- case ERROR:
- log_level = LOG_WARNING;
- break;
- case FATAL:
- default:
- log_level = LOG_ERR;
- break;
+ int syslog_level;
+
+ switch (lev)
+ {
+ case NOIND:
+ syslog_level = LOG_DEBUG;
+ break;
+ case DEBUG:
+ syslog_level = LOG_DEBUG;
+ break;
+ case NOTICE:
+ syslog_level = LOG_NOTICE;
+ break;
+ case ERROR:
+ syslog_level = LOG_WARNING;
+ break;
+ case FATAL:
+ syslog_level = LOG_ERR;
+ break;
+ case REALLYFATAL:
+ default:
+ syslog_level = LOG_CRIT;
+ }
+
+ write_syslog(syslog_level, msg_buf + TIMESTAMP_SIZE);
}
- write_syslog(log_level, msg_buf + TIMESTAMP_SIZE);
-#endif
+#endif /* ENABLE_SYSLOG */
/* syslog doesn't want a trailing newline, but other destinations do */
strcat(msg_buf, "\n");
len = strlen(msg_buf);
- if (Debugfile >= 0 && UseSyslog <= 1)
+ if (Debugfile >= 0 && Use_syslog <= 1)
write(Debugfile, msg_buf, len);
/*
@@ -321,7 +342,7 @@ elog(int lev, const char *fmt,...)
* does anyone still use ultrix?)
*/
if (lev > DEBUG && Err_file >= 0 &&
- Debugfile != Err_file && UseSyslog <= 1)
+ Debugfile != Err_file && Use_syslog <= 1)
{
if (write(Err_file, msg_buf, len) < 0)
{
@@ -502,3 +523,124 @@ DebugFileOpen(void)
}
#endif
+
+
+#ifdef ELOG_TIMESTAMPS
+/*
+ * Return a timestamp string like "980119.17:25:59.902 [21974] "
+ */
+static const char *
+print_timestamp()
+{
+ struct timeval tv;
+ struct timezone tz = { 0, 0 };
+ struct tm *time;
+ time_t tm;
+ static char timestamp[32],
+ pid[8];
+
+ gettimeofday(&tv, &tz);
+ tm = tv.tv_sec;
+ time = localtime(&tm);
+
+ sprintf(pid, "[%d]", MyProcPid);
+ sprintf(timestamp, "%02d%02d%02d.%02d:%02d:%02d.%03d %7s ",
+ time->tm_year % 100, time->tm_mon + 1, time->tm_mday,
+ time->tm_hour, time->tm_min, time->tm_sec,
+ (int) (tv.tv_usec/1000), pid);
+
+ return timestamp;
+}
+#endif
+
+
+#ifdef ENABLE_SYSLOG
+
+/*
+ * Write a message line to syslog if the syslog option is set.
+ *
+ * Our problem here is that many syslog implementations don't handle
+ * long messages in an acceptable manner. While this function doesn't
+ * help that fact, it does work around by splitting up messages into
+ * smaller pieces.
+ */
+static void
+write_syslog(int level, const char *line)
+{
+#ifndef PG_SYSLOG_LIMIT
+# define PG_SYSLOG_LIMIT 128
+#endif
+
+ static bool openlog_done = false;
+ static unsigned long seq = 0;
+ int len = strlen(line);
+
+ if (Use_syslog == 0)
+ return;
+
+ if (!openlog_done)
+ {
+ openlog("postgres", LOG_PID | LOG_NDELAY, LOG_LOCAL0);
+ openlog_done = true;
+ }
+
+ /*
+ * We add a sequence number to each log message to suppress "same"
+ * messages.
+ */
+ seq++;
+
+ /* divide into multiple syslog() calls if message is too long */
+ if (len > PG_SYSLOG_LIMIT)
+ {
+ static char buf[PG_SYSLOG_LIMIT+1];
+ int chunk_nr = 0;
+ int buflen;
+
+ while (len > 0)
+ {
+ int l;
+ int i;
+
+ strncpy(buf, line, PG_SYSLOG_LIMIT);
+ buf[PG_SYSLOG_LIMIT] = '\0';
+
+ l = strlen(buf);
+#ifdef MULTIBYTE
+ /* trim to multibyte letter boundary */
+ buflen = pg_mbcliplen(buf, l, l);
+ buf[buflen] = '\0';
+ l = strlen(buf);
+#endif
+ /* already word boundary? */
+ if (isspace(line[l]) || line[l] == '\0')
+ buflen = l;
+ else
+ {
+ /* try to divide in word boundary */
+ i = l - 1;
+ while(i > 0 && !isspace(buf[i]))
+ i--;
+
+ if (i <= 0) /* couldn't divide word boundary */
+ buflen = l;
+ else
+ {
+ buflen = i;
+ buf[i] = '\0';
+ }
+ }
+
+ chunk_nr++;
+
+ syslog(level, "[%lu-%d] %s", seq, chunk_nr, buf);
+ line += buflen;
+ len -= buflen;
+ }
+ }
+ /* message short enough */
+ else
+ syslog(level, "[%lu] %s", seq, line);
+}
+
+#endif /* ENABLE_SYSLOG */