Re: serverlog rotation/functions - Mailing list pgsql-patches
From | Bruce Momjian |
---|---|
Subject | Re: serverlog rotation/functions |
Date | |
Msg-id | 200407151456.i6FEuWo28145@candle.pha.pa.us Whole thread Raw |
In response to | Re: serverlog rotation/functions (Andreas Pflug <pgadmin@pse-consulting.de>) |
List | pgsql-patches |
Path withdrawn by author. --------------------------------------------------------------------------- Andreas Pflug wrote: > Updated version. > > Only timestamp of fresh logfile in shared mem, with sanity checks. > On SIGHUP, timestamp is checked if rotation was issued, as well as > changed log_filename setting from postgresql.conf. > > Regards, > Andreas > > > > Index: src/backend/postmaster/postmaster.c > =================================================================== > RCS file: /projects/cvsroot/pgsql-server/src/backend/postmaster/postmaster.c,v > retrieving revision 1.405 > diff -u -r1.405 postmaster.c > --- src/backend/postmaster/postmaster.c 24 Jun 2004 21:02:55 -0000 1.405 > +++ src/backend/postmaster/postmaster.c 6 Jul 2004 22:12:22 -0000 > @@ -729,6 +729,11 @@ > reset_shared(PostPortNumber); > > /* > + * Opens alternate log file > + */ > + LogFileInit(); > + > + /* > * Estimate number of openable files. This must happen after setting > * up semaphores, because on some platforms semaphores count as open > * files. > Index: src/backend/utils/adt/misc.c > =================================================================== > RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/misc.c,v > retrieving revision 1.35 > diff -u -r1.35 misc.c > --- src/backend/utils/adt/misc.c 2 Jul 2004 18:59:22 -0000 1.35 > +++ src/backend/utils/adt/misc.c 6 Jul 2004 22:12:34 -0000 > @@ -202,3 +202,137 @@ > FreeDir(fctx->dirdesc); > SRF_RETURN_DONE(funcctx); > } > + > + > +extern FILE *logfile; // in elog.c > +#define MAXLOGFILECHUNK 50000 > + > +static char *absClusterPath(text *arg) > +{ > + char *filename; > + > + if (is_absolute_path(VARDATA(arg))) > + filename=VARDATA(arg); > + else > + { > + filename = palloc(strlen(DataDir)+VARSIZE(arg)+2); > + sprintf(filename, "%s/%s", DataDir, VARDATA(arg)); > + } > + return filename; > +} > + > + > +Datum pg_logfile_get(PG_FUNCTION_ARGS) > +{ > + size_t size=MAXLOGFILECHUNK; > + char *buf=0; > + size_t nbytes; > + FILE *f; > + > + 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.", size))); > + } > + > + if (PG_ARGISNULL(2)) > + f = logfile; > + else > + { > + /* explicitely named logfile */ > + char *filename = absClusterPath(PG_GETARG_TEXT_P(2)); > + f = fopen(filename, "r"); > + if (!f) > + { > + ereport(WARNING, > + (errcode_for_file_access(), > + errmsg("file not found %s", filename))); > + PG_RETURN_NULL(); > + } > + } > + > + 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; > + > + fseek(f, 0, SEEK_END); > + > + if (!PG_ARGISNULL(2)) > + fclose(f); > + } > + > + if (buf) > + PG_RETURN_CSTRING(buf); > + else > + PG_RETURN_NULL(); > +} > + > + > +Datum pg_logfile_length(PG_FUNCTION_ARGS) > +{ > + if (PG_ARGISNULL(0)) > + { > + if (logfile) > + { > + fflush(logfile); > + PG_RETURN_INT32(ftell(logfile)); > + } > + } > + else > + { > + struct stat fst; > + fst.st_size=0; > + stat(absClusterPath(PG_GETARG_TEXT_P(0)), &fst); > + > + PG_RETURN_INT32(fst.st_size); > + } > + PG_RETURN_INT32(0); > +} > + > + > +Datum pg_logfile_name(PG_FUNCTION_ARGS) > +{ > + char *filename=LogFileName(); > + if (filename) > + { > + if (strncmp(filename, DataDir, strlen(DataDir))) > + PG_RETURN_CSTRING(filename); > + else > + PG_RETURN_CSTRING(filename+strlen(DataDir)+1); > + } > + PG_RETURN_NULL(); > +} > + > + > +Datum pg_logfile_rotate(PG_FUNCTION_ARGS) > +{ > + char *renamedFile = LogFileRotate(); > + > + if (renamedFile) > + { > + if (strncmp(renamedFile, DataDir, strlen(DataDir))) > + PG_RETURN_CSTRING(renamedFile); > + else > + PG_RETURN_CSTRING(renamedFile+strlen(DataDir)+1); > + } > + else > + PG_RETURN_NULL(); > +} > + > Index: src/backend/utils/error/elog.c > =================================================================== > RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/error/elog.c,v > retrieving revision 1.142 > diff -u -r1.142 elog.c > --- src/backend/utils/error/elog.c 24 Jun 2004 21:03:13 -0000 1.142 > +++ src/backend/utils/error/elog.c 6 Jul 2004 22:12:37 -0000 > @@ -63,7 +63,6 @@ > #include "utils/memutils.h" > #include "utils/guc.h" > > - > /* Global variables */ > ErrorContextCallback *error_context_stack = NULL; > > @@ -71,9 +70,17 @@ > 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; /* the logfile we're writing to */ > +static char logfileName[MAXPGPATH]; /* current filename */ > +static pg_time_t logfileTimestamp=0; /* logfile version this backend is currently using */ > + > +static pg_time_t *globalLogfileTimestamp = NULL; /* logfile version the backend should be using (shared mem) */ > + > + > #ifdef HAVE_SYSLOG > char *Syslog_facility; /* openlog() parameters */ > char *Syslog_ident; > @@ -140,6 +147,9 @@ > static const char *error_severity(int elevel); > static void append_with_tabs(StringInfo buf, const char *str); > > +static char *logfile_getname(pg_time_t timestamp); > +static void logfile_reopen(void); > + > > /* > * errstart --- begin an error-reporting cycle > @@ -931,11 +941,181 @@ > /* > * And let errfinish() finish up. > */ > + > errfinish(0); > } > > > /* > + * Initialize shared mem for logfile rotation > + */ > + > +void > +LogFileInit(void) > +{ > + if (!globalLogfileTimestamp && Log_filename && (Log_destination & LOG_DESTINATION_FILE)) > + { > + /* allocate logfile version shared memory segment for rotation signaling */ > + globalLogfileTimestamp = ShmemAlloc(sizeof(pg_time_t)); > + if (!globalLogfileTimestamp) > + { > + ereport(FATAL, > + (errcode(ERRCODE_OUT_OF_MEMORY), > + errmsg("Out of shared memory"))); > + return; > + } > + > + *globalLogfileTimestamp = time(NULL); > + > + /* open logfile after we successfully initialized */ > + logfile_reopen(); > + } > +} > + > + > +/* > + * Rotate log file > + */ > +char * > +LogFileRotate(void) > +{ > + char *filename; > + char *oldFilename; > + pg_time_t now; > + > + if (!globalLogfileTimestamp || !logfileName || !(Log_destination & LOG_DESTINATION_FILE)) > + return NULL; > + > + now = time(NULL); > + > + filename = logfile_getname(now); > + if (!filename) > + return NULL; > + > + if (!strcmp(filename, logfileName)) > + { > + ereport(ERROR, > + (errcode(ERRCODE_CONFIG_FILE_ERROR), > + errmsg("Log_filename not suitable for rotation."))); > + return NULL; > + } > + > + oldFilename = pstrdup(logfileName); > + *globalLogfileTimestamp = now; > + > + ereport(NOTICE, > + (errcode(ERRCODE_WARNING), > + errmsg("Opened new log file %s; previous logfile %s", filename, oldFilename))); > + > + return oldFilename; > +} > + > + > +/* > + * return current log file name > + */ > +char* > +LogFileName(void) > +{ > + if (logfileName) > + return pstrdup(logfileName); > + return NULL; > +} > + > + > +/* > + * check if logfile has to be reopened > + * if called from ProcessConfigFile after SIGHUP, also check for filename template change > + */ > +void LogFileCheckReopen(bool fromSIGHUP) > +{ > + if (globalLogfileTimestamp) > + { > + if (*globalLogfileTimestamp != logfileTimestamp) > + { > + /* sanity check: if it's in the future, shmem probably corrupted */ > + pg_time_t now=time(NULL); > + if (*globalLogfileTimestamp > now) > + *globalLogfileTimestamp = now; > + > + logfile_reopen(); > + } > + else if (fromSIGHUP) > + { > + char *filename = logfile_getname(logfileTimestamp); > + if (filename && strcmp(filename, logfileName)) > + { > + /* template for logfile was changed */ > + logfile_reopen(); > + pfree(filename); > + } > + } > + } > +} > + > + > +/* > + * creates logfile name using timestamp information > + */ > +static char* > +logfile_getname(pg_time_t timestamp) > +{ > + char *filetemplate; > + char *filename; > + > + if (is_absolute_path(Log_filename)) > + filetemplate = pstrdup(Log_filename); > + else > + { > + filetemplate = palloc(strlen(DataDir) + strlen(Log_filename) + 2); > + sprintf(filetemplate, "%s/%s", DataDir, Log_filename); > + } > + filename = palloc(MAXPGPATH); > + pg_strftime(filename, MAXPGPATH, filetemplate, pg_localtime(×tamp)); > + > + pfree(filetemplate); > + > + return filename; > +} > + > + > +/* > + * reopen log file. > + */ > +static void > +logfile_reopen(void) > +{ > + if (logfile) > + { > + fclose(logfile); > + logfile = NULL; > + } > + > + if ((Log_destination & LOG_DESTINATION_FILE) && globalLogfileTimestamp) > + { > + char *fn; > + > + logfileTimestamp = *globalLogfileTimestamp; > + > + fn=logfile_getname(logfileTimestamp); > + > + if (fn) > + { > + logfile = fopen(fn, "a+"); > + > + if (!logfile) > + ereport(ERROR, > + (errcode_for_file_access(), > + errmsg("failed to open log file %s", fn))); > + > + strcpy(logfileName, fn); > + pfree(fn); > + } > + } > +} > + > + > +/* > * Initialization of error output file > */ > void > @@ -1455,6 +1635,20 @@ > if ((Log_destination & LOG_DESTINATION_STDERR) || whereToSendOutput == Debug) > { > fprintf(stderr, "%s", buf.data); > + } > + > + /* Write to file, if enabled */ > + if (logfile && (Log_destination & LOG_DESTINATION_FILE)) > + { > + /* check if logfile changed */ > + LogFileCheckReopen(false); > + > + if (logfile) > + { > + fseek(logfile, 0, SEEK_END); > + fprintf(logfile, "%s", buf.data); > + fflush(logfile); > + } > } > > pfree(buf.data); > Index: src/backend/utils/misc/guc-file.l > =================================================================== > RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/misc/guc-file.l,v > retrieving revision 1.22 > diff -u -r1.22 guc-file.l > --- src/backend/utils/misc/guc-file.l 26 May 2004 15:07:38 -0000 1.22 > +++ src/backend/utils/misc/guc-file.l 6 Jul 2004 22:12:38 -0000 > @@ -276,6 +276,9 @@ > set_config_option(item->name, item->value, context, > PGC_S_FILE, false, true); > > + if (context == PGC_SIGHUP) > + LogFileCheckReopen(true); > + > cleanup_exit: > free_name_value_list(head); > return; > Index: src/backend/utils/misc/guc.c > =================================================================== > RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/misc/guc.c,v > retrieving revision 1.213 > diff -u -r1.213 guc.c > --- src/backend/utils/misc/guc.c 5 Jul 2004 23:14:14 -0000 1.213 > +++ src/backend/utils/misc/guc.c 6 Jul 2004 22:12:46 -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; > @@ -1606,13 +1608,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 > }, > &log_destination_string, > "stderr", assign_log_destination, NULL > }, > + { > + {"log_filename", PGC_SIGHUP, 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.%Y-%m-%d_%H%M%S", NULL, NULL > + }, > > #ifdef HAVE_SYSLOG > { > @@ -5033,6 +5045,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: src/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 > --- src/backend/utils/misc/postgresql.conf.sample 7 Apr 2004 05:05:50 -0000 1.113 > +++ src/backend/utils/misc/postgresql.conf.sample 6 Jul 2004 22:12:47 -0000 > @@ -147,9 +147,12 @@ > > # - 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 = 'postgresql.log.%Y-%m-%d_%H%M%S' # filename if > + # 'file' log_destination is used. > + > #syslog_facility = 'LOCAL0' > #syslog_ident = 'postgres' > > Index: src/include/catalog/pg_proc.h > =================================================================== > RCS file: /projects/cvsroot/pgsql-server/src/include/catalog/pg_proc.h,v > retrieving revision 1.341 > diff -u -r1.341 pg_proc.h > --- src/include/catalog/pg_proc.h 2 Jul 2004 22:49:48 -0000 1.341 > +++ src/include/catalog/pg_proc.h 6 Jul 2004 22:13:02 -0000 > @@ -3595,6 +3595,14 @@ > DATA(insert OID = 2556 ( pg_tablespace_databases PGNSP PGUID 12 f f t t s 1 26 "26" _null_ pg_tablespace_databases- _null_)); > DESCR("returns database oids in a tablespace"); > > +DATA(insert OID = 2557( pg_logfile_get PGNSP PGUID 12 f f f f v 3 2275 "23 23 25" _null_ pg_logfile_get- _null_ )); > +DESCR("return log file contents"); > +DATA(insert OID = 2558( pg_logfile_length PGNSP PGUID 12 f f f f v 1 23 "25" _null_ pg_logfile_length -_null_ )); > +DESCR("name of log file"); > +DATA(insert OID = 2559( pg_logfile_name PGNSP PGUID 12 f f f f v 0 2275 "" _null_ pg_logfile_name - _null_)); > +DESCR("length of log file"); > +DATA(insert OID = 2560( pg_logfile_rotate PGNSP PGUID 12 f f f f v 0 2275 "" _null_ pg_logfile_rotate -_null_ )); > +DESCR("rotate log file"); > > /* > * Symbolic values for provolatile column: these indicate whether the result > Index: src/include/utils/builtins.h > =================================================================== > RCS file: /projects/cvsroot/pgsql-server/src/include/utils/builtins.h,v > retrieving revision 1.245 > diff -u -r1.245 builtins.h > --- src/include/utils/builtins.h 2 Jul 2004 18:59:25 -0000 1.245 > +++ src/include/utils/builtins.h 6 Jul 2004 22:13:05 -0000 > @@ -358,6 +358,11 @@ > extern Datum pg_cancel_backend(PG_FUNCTION_ARGS); > extern Datum pg_tablespace_databases(PG_FUNCTION_ARGS); > > +extern Datum pg_logfile_get(PG_FUNCTION_ARGS); > +extern Datum pg_logfile_length(PG_FUNCTION_ARGS); > +extern Datum pg_logfile_name(PG_FUNCTION_ARGS); > +extern Datum pg_logfile_rotate(PG_FUNCTION_ARGS); > + > /* not_in.c */ > extern Datum int4notin(PG_FUNCTION_ARGS); > extern Datum oidnotin(PG_FUNCTION_ARGS); > Index: src/include/utils/elog.h > =================================================================== > RCS file: /projects/cvsroot/pgsql-server/src/include/utils/elog.h,v > retrieving revision 1.69 > diff -u -r1.69 elog.h > --- src/include/utils/elog.h 24 Jun 2004 21:03:42 -0000 1.69 > +++ src/include/utils/elog.h 6 Jul 2004 22:13:05 -0000 > @@ -182,10 +182,14 @@ > #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 void LogFileInit(void); > +extern void LogFileCheckReopen(bool fromSIGHUP); > +extern char *LogFileRotate(void); > +extern char *LogFileName(void); > /* > * Write errors to stderr (or by equal means when stderr is > * not available). Used before ereport/elog can be used -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square, Pennsylvania 19073
pgsql-patches by date: