Magnus Hagander wrote:
Since I believe that retrieving the logs easily without server file access is a feature that's welcomed by many users, here's my proposal.Specifically about the logs, I still think there is a lot of value to being able to read the logs remotely even if you can't restart postmaster.
The attached diff will
- add a guc-variable log_filename
- extend log_destination to accept the keyword 'file'
- elog to that file if configured
- provide two functions pg_logfile_length() and pg_logfile to obtain the contents.
int4 pg_logfile_length()
cstring pg_logfile(int4 size, int4 position)
size (may be null meaning max) is the chunk size (max: currently 50000)
position (may be null meaning -size) is the start position; positive counting from log file start, negative from end.
Regards, Andreas
Index: backend/postmaster/postmaster.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/postmaster/postmaster.c,v
retrieving revision 1.402
diff -u -r1.402 postmaster.c
--- backend/postmaster/postmaster.c 3 Jun 2004 02:08:03 -0000 1.402
+++ backend/postmaster/postmaster.c 8 Jun 2004 18:07:30 -0000
@@ -532,6 +532,9 @@
/* If timezone is not set, determine what the OS uses */
pg_timezone_initialize();
+ /* open alternate logfile, if any */
+ LogFileOpen();
+
#ifdef EXEC_BACKEND
write_nondefault_variables(PGC_POSTMASTER);
#endif
Index: backend/storage/ipc/ipc.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/storage/ipc/ipc.c,v
retrieving revision 1.87
diff -u -r1.87 ipc.c
--- backend/storage/ipc/ipc.c 12 Dec 2003 18:45:09 -0000 1.87
+++ backend/storage/ipc/ipc.c 8 Jun 2004 18:07:31 -0000
@@ -111,6 +111,8 @@
on_proc_exit_list[on_proc_exit_index].arg);
elog(DEBUG3, "exit(%d)", code);
+
+ LogFileClose();
exit(code);
}
Index: backend/utils/adt/misc.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/misc.c,v
retrieving revision 1.34
diff -u -r1.34 misc.c
--- backend/utils/adt/misc.c 2 Jun 2004 21:29:29 -0000 1.34
+++ backend/utils/adt/misc.c 8 Jun 2004 18:07:36 -0000
@@ -103,3 +103,64 @@
{
PG_RETURN_INT32(pg_signal_backend(PG_GETARG_INT32(0),SIGINT));
}
+
+Datum pg_logfile_length(PG_FUNCTION_ARGS)
+{
+ extern FILE *logfile; // in elog.c
+
+ if (logfile)
+ PG_RETURN_INT32(ftell(logfile));
+ PG_RETURN_INT32(0);
+}
+
+
+#define MAXLOGFILECHUNK 50000
+Datum pg_logfile(PG_FUNCTION_ARGS)
+{
+ size_t size=MAXLOGFILECHUNK;
+ char *buf=0;
+ size_t nbytes;
+
+ char *filename = LogFileName();
+ if (filename)
+ {
+ if (!PG_ARGISNULL(0))
+ size = PG_GETARG_INT32(0);
+ if (size > MAXLOGFILECHUNK)
+ {
+ size = MAXLOGFILECHUNK;
+ ereport(WARNING,
+ (errcode(ERRCODE_OUT_OF_MEMORY),
+ errmsg("Maximum size is %d.",
MAXLOGFILECHUNK)));
+ }
+
+ FILE *f=fopen(filename, "r");
+ if (f)
+ {
+ if (PG_ARGISNULL(1))
+ fseek(f, -size, SEEK_END);
+ else
+ {
+ long pos = PG_GETARG_INT32(1);
+ if (pos >= 0)
+ fseek(f, pos, SEEK_SET);
+ else
+ fseek(f, pos, SEEK_END);
+ }
+ buf = palloc(size+1);
+ nbytes = fread(buf, 1, size, f);
+ buf[nbytes] = 0;
+
+ fclose(f);
+ }
+ else
+ {
+ ereport(WARNING,
+ (errcode(ERRCODE_NO_DATA),
+ errmsg("Could not open log file %s.",
filename)));
+ }
+ free(filename);
+ }
+
+ PG_RETURN_CSTRING(buf);
+}
Index: backend/utils/error/elog.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/error/elog.c,v
retrieving revision 1.140
diff -u -r1.140 elog.c
--- backend/utils/error/elog.c 3 Jun 2004 02:08:04 -0000 1.140
+++ backend/utils/error/elog.c 8 Jun 2004 18:07:39 -0000
@@ -71,8 +71,10 @@
PGErrorVerbosity Log_error_verbosity = PGERROR_VERBOSE;
char *Log_line_prefix = NULL; /* format for extra log line info */
unsigned int Log_destination = LOG_DESTINATION_STDERR;
+char *Log_filename = NULL;
bool in_fatal_exit = false;
+FILE *logfile = NULL;
#ifdef HAVE_SYSLOG
char *Syslog_facility; /* openlog() parameters */
@@ -936,6 +938,69 @@
/*
+ * Name of configured log file, or NULL
+ * must be freed after usage
+ */
+char*
+LogFileName(void)
+{
+ if (Log_filename && (Log_destination & LOG_DESTINATION_FILE))
+ {
+ if (is_absolute_path(Log_filename))
+ return strdup(Log_filename);
+ else
+ {
+ char *buf = malloc(strlen(DataDir) + strlen(Log_filename) +2);
+ if (!buf)
+ ereport(FATAL,
+ (errcode(ERRCODE_OUT_OF_MEMORY),
+ errmsg("out of memory")));
+
+ sprintf(buf, "%s/%s", DataDir, Log_filename);
+
+ return buf;
+ }
+ }
+ return NULL;
+}
+
+
+/*
+ * Open log file, if configured.
+ */
+void
+LogFileOpen(void)
+{
+ char *filename = LogFileName();
+
+ if (filename)
+ {
+ LogFileClose();
+
+ logfile = fopen(filename, "at");
+
+ if (!logfile)
+ ereport(WARNING,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("could not open log file %s",
filename)));
+
+ free(filename);
+ }
+}
+
+
+/*
+ * Close log file, if open.
+ */
+void
+LogFileClose(void)
+{
+ if (logfile)
+ fclose(logfile);
+ logfile = NULL;
+}
+
+/*
* Initialization of error output file
*/
void
@@ -1445,6 +1510,11 @@
if ((Log_destination & LOG_DESTINATION_STDERR) || whereToSendOutput == Debug)
{
fprintf(stderr, "%s", buf.data);
+ }
+
+ if (logfile && (Log_destination & LOG_DESTINATION_FILE))
+ {
+ fprintf(logfile, "%s", buf.data);
}
pfree(buf.data);
Index: backend/utils/misc/guc.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/misc/guc.c,v
retrieving revision 1.210
diff -u -r1.210 guc.c
--- backend/utils/misc/guc.c 30 May 2004 23:40:38 -0000 1.210
+++ backend/utils/misc/guc.c 8 Jun 2004 18:07:47 -0000
@@ -76,6 +76,8 @@
static const char *assign_log_destination(const char *value,
bool doit, GucSource source);
+extern char *Log_filename;
+
#ifdef HAVE_SYSLOG
extern char *Syslog_facility;
extern char *Syslog_ident;
@@ -1644,13 +1646,23 @@
{
{"log_destination", PGC_POSTMASTER, LOGGING_WHERE,
gettext_noop("Sets the target for log output."),
- gettext_noop("Valid values are combinations of stderr, syslog "
+ gettext_noop("Valid values are combinations of stderr, file, syslog "
"and eventlog, depending on platform."),
GUC_LIST_INPUT | GUC_REPORT
},
&log_destination_string,
"stderr", assign_log_destination, NULL
},
+ {
+ {"log_filename", PGC_POSTMASTER, LOGGING_WHERE,
+ gettext_noop("Sets the target filename for log output."),
+ gettext_noop("May be specified as relative to the cluster directory "
+ "or as absolute path."),
+ GUC_LIST_INPUT | GUC_REPORT
+ },
+ &Log_filename,
+ "postgresql.log", NULL, NULL
+ },
#ifdef HAVE_SYSLOG
{
@@ -4775,6 +4787,8 @@
if (pg_strcasecmp(tok,"stderr") == 0)
newlogdest |= LOG_DESTINATION_STDERR;
+ else if (pg_strcasecmp(tok,"file") == 0)
+ newlogdest |= LOG_DESTINATION_FILE;
#ifdef HAVE_SYSLOG
else if (pg_strcasecmp(tok,"syslog") == 0)
newlogdest |= LOG_DESTINATION_SYSLOG;
Index: backend/utils/misc/postgresql.conf.sample
===================================================================
RCS file:
/projects/cvsroot/pgsql-server/src/backend/utils/misc/postgresql.conf.sample,v
retrieving revision 1.113
diff -u -r1.113 postgresql.conf.sample
--- backend/utils/misc/postgresql.conf.sample 7 Apr 2004 05:05:50 -0000 1.113
+++ backend/utils/misc/postgresql.conf.sample 8 Jun 2004 18:07:48 -0000
@@ -147,9 +147,10 @@
# - Where to Log -
-#log_destination = 'stderr' # Valid values are combinations of stderr,
+#log_destination = 'stderr' # Valid values are combinations of stderr, file,
# syslog and eventlog, depending on
# platform.
+#log_filename = 'pgsql.log'
#syslog_facility = 'LOCAL0'
#syslog_ident = 'postgres'
Index: include/catalog/pg_proc.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/include/catalog/pg_proc.h,v
retrieving revision 1.334
diff -u -r1.334 pg_proc.h
--- include/catalog/pg_proc.h 2 Jun 2004 21:29:29 -0000 1.334
+++ include/catalog/pg_proc.h 8 Jun 2004 18:08:03 -0000
@@ -3588,6 +3588,12 @@
DATA(insert OID = 2243 ( bit_or
PGNSP PGUID 12 t f f f i 1 1560 "1560" _null_ aggregate_dummy - _null_));
DESCR("bitwise-or bit aggregate");
+DATA(insert OID = 2550( pg_logfile_length PGNSP PGUID 12 f f f f
v 0 23 "" _null_ pg_logfile_length - _null_ ));
+DESCR("length of log file");
+DATA(insert OID = 2551( pg_logfile PGNSP PGUID 12 f f f f
v 2 2275 "23 23" _null_ pg_logfile - _null_ ));
+DESCR("return log file contents");
+
+
/*
* Symbolic values for provolatile column: these indicate whether the result
* of a function is dependent *only* on the values of its explicit arguments,
Index: include/utils/builtins.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/include/utils/builtins.h,v
retrieving revision 1.241
diff -u -r1.241 builtins.h
--- include/utils/builtins.h 2 Jun 2004 21:29:29 -0000 1.241
+++ include/utils/builtins.h 8 Jun 2004 18:08:05 -0000
@@ -356,6 +356,8 @@
extern Datum current_database(PG_FUNCTION_ARGS);
extern Datum pg_terminate_backend(PG_FUNCTION_ARGS);
extern Datum pg_cancel_backend(PG_FUNCTION_ARGS);
+extern Datum pg_logfile_length(PG_FUNCTION_ARGS);
+extern Datum pg_logfile(PG_FUNCTION_ARGS);
/* not_in.c */
extern Datum int4notin(PG_FUNCTION_ARGS);
Index: include/utils/elog.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/include/utils/elog.h,v
retrieving revision 1.68
diff -u -r1.68 elog.h
--- include/utils/elog.h 5 Apr 2004 03:02:10 -0000 1.68
+++ include/utils/elog.h 8 Jun 2004 18:08:06 -0000
@@ -182,8 +182,12 @@
#define LOG_DESTINATION_STDERR 1
#define LOG_DESTINATION_SYSLOG 2
#define LOG_DESTINATION_EVENTLOG 4
+#define LOG_DESTINATION_FILE 8
/* Other exported functions */
extern void DebugFileOpen(void);
+extern char *LogFileName(void);
+extern void LogFileOpen(void);
+extern void LogFileClose(void);
#endif /* ELOG_H */
---------------------------(end of broadcast)--------------------------- TIP 7: don't forget to increase your free space map settings
