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:

Previous
From: Bruce Momjian
Date:
Subject: Re: build infrastructure for extensions v3
Next
From: Bruce Momjian
Date:
Subject: Re: add missing options to pg_dumpall