Add support for process-level control for overriding log levels.
authorPavan Deolasee <[email protected]>
Fri, 4 Mar 2016 06:51:18 +0000 (12:21 +0530)
committerPavan Deolasee <[email protected]>
Fri, 4 Mar 2016 06:51:18 +0000 (12:21 +0530)
This patch changes the behaviour of pg_msgmodule_set/change() functions. These
functions now only change the log levels for various messages, but the actual
logging won't start until one of the following enable() function is called.

This patch adds a few more functions:

- pg_msgmodule_enable(pid) - the given pid will start logging as per the
  current settings for various msgs.

- pg_msgmodule_disable(pid) - the given pid will stop logging and use the
  compile time settings

- pg_msgmodule_enable_all(persistent) - all current processes will start
  logging as per the current setting. If "persistent" is set to true then all
  new processes will also log as per the setting

- pg_msgmodule_disable_all() - all current and future processes will stop
  logging and only use compile time settings.

src/backend/tcop/postgres.c
src/backend/utils/error/elog.c
src/include/catalog/pg_proc.h
src/include/utils/builtins.h
src/include/utils/elog.h

index a7ee658a5d5aa4df44cf44f64d5481f6af1647e9..1edd77d944d3178d1204fddf7300af779636fe83 100644 (file)
@@ -4310,6 +4310,10 @@ PostgresMain(int argc, char *argv[],
                prev_ParseAnalyze_callback = post_parse_analyze_hook;
        post_parse_analyze_hook = ParseAnalyze_callback;
 
+#ifdef USE_MODULE_MSGIDS
+       AtProcStart_MsgModule();
+#endif
+
        /* if we exit, try to release cluster lock properly */
        on_shmem_exit(PGXCCleanClusterLock, 0);
 
index dabe5c2c6020c0a64ef4d8d404bd2b5078b3556f..909e2667e6f855c468f991d80a13907906f9cfd6 100644 (file)
@@ -73,7 +73,9 @@
 #include "postmaster/syslogger.h"
 #include "storage/ipc.h"
 #include "storage/proc.h"
+#include "storage/procarray.h"
 #include "tcop/tcopprot.h"
+#include "utils/builtins.h"
 #include "utils/guc.h"
 #include "utils/memutils.h"
 #include "utils/ps_status.h"
 
 static const char *err_gettext(const char *str) pg_attribute_format_arg(1);
 static void set_errdata_field(MemoryContextData *cxt, char **ptr, const char *str);
+#ifdef USE_MODULE_MSGIDS
+static void AtProcExit_MsgModule(int code, Datum arg);
+static bool pg_msgmodule_enable_disable(int32 pid, bool enable);
+#endif
 
 /* Global variables */
 ErrorContextCallback *error_context_stack = NULL;
@@ -189,7 +195,27 @@ static void setup_formatted_log_time(void);
 static void setup_formatted_start_time(void);
 
 #ifdef USE_MODULE_MSGIDS
-char *MsgModuleCtl;
+typedef struct MsgModuleCtlStruct
+{
+       bool    mm_enabled;
+       bool    mm_persistent;
+       char    mm_flags[FLEXIBLE_ARRAY_MEMBER];
+} MsgModuleCtlStruct;
+
+#define StartOfBackendFlags    \
+       ( \
+         PGXL_MSG_MAX_MODULES * \
+         PGXL_MSG_MAX_FILEIDS_PER_MODULE * \
+         PGXL_MSG_MAX_MSGIDS_PER_FILE \
+       )
+
+#define SizeOfMsgModuleCtlStruct       \
+       ( \
+         offsetof(MsgModuleCtlStruct, mm_flags) + \
+         StartOfBackendFlags + \
+         MaxBackends \
+       )
+static MsgModuleCtlStruct *MsgModuleCtl;
 #endif
 
 /*
@@ -3747,7 +3773,7 @@ write_stderr(const char *fmt,...)
 
 #ifdef USE_MODULE_MSGIDS
 static int
-get_overriden_log_level(int moduleid, int fileid, int msgid, int origlevel)
+get_overridden_log_level(int moduleid, int fileid, int msgid, int origlevel)
 {
        uint32 position;
        int value, relative, change, elevel;
@@ -3759,6 +3785,9 @@ get_overriden_log_level(int moduleid, int fileid, int msgid, int origlevel)
        if (!IsPostmasterEnvironment || IsInitProcessingMode())
                return origlevel;
 
+       if (!MsgModuleCtl->mm_enabled)
+               return origlevel;
+
        /*
         * Reject invalid bounds
         */
@@ -3770,6 +3799,9 @@ get_overriden_log_level(int moduleid, int fileid, int msgid, int origlevel)
        if (origlevel < DEBUG5 || origlevel >= LOG)
                return origlevel;
 
+       if (!(MsgModuleCtl->mm_flags[StartOfBackendFlags + MyBackendId]))
+               return origlevel;
+
        elevel = origlevel;
 
        /*
@@ -3781,7 +3813,7 @@ get_overriden_log_level(int moduleid, int fileid, int msgid, int origlevel)
                        (msgid - 1);
        
        /* Read once */
-       value = MsgModuleCtl[position];
+       value = MsgModuleCtl->mm_flags[position];
 
        relative = value & 0x80;
        change = value & 0x7f;
@@ -3836,7 +3868,7 @@ is_log_level_output(int elevel,
         * especially be useful to turn some specific ERROR messages into FATAL or
         * PANIC to be able to get a core dump for analysis.
         */
-       elevel = get_overriden_log_level(moduleid, fileid, msgid,
+       elevel = get_overridden_log_level(moduleid, fileid, msgid,
                        elevel);
 #endif
 
@@ -3887,8 +3919,6 @@ trace_recovery(int trace_level)
 Size
 MsgModuleShmemSize(void)
 {
-       Size mm_size;
-
        /*
         * One byte per message to store overridden log level.
         * !!TODO We don't really need a byte and a few bits would be enough. So
@@ -3901,14 +3931,12 @@ MsgModuleShmemSize(void)
         * to the largest value that any one module uses, but the actual values are
         * much smaller
         *
-        * In theory, we could also have separate area for each backend so that
-        * logging can be controlled at a backend level. But the current
-        * representation is not at all efficient to do that.
+        * Also have a separate area for MaxBackends so that caller can selectively
+        * change logging for individual backends. Note that we don't support
+        * having different logging levels for different backends. So either a
+        * backend honours the module/file/msg level overrides or it does not.
         */
-       mm_size = mul_size(PGXL_MSG_MAX_MODULES, PGXL_MSG_MAX_FILEIDS_PER_MODULE);
-       mm_size = mul_size(mm_size, PGXL_MSG_MAX_MSGIDS_PER_FILE);
-
-       return mm_size;
+       return SizeOfMsgModuleCtlStruct;
 }
 
 void
@@ -3917,12 +3945,20 @@ MsgModuleShmemInit(void)
        bool found;
 
        MsgModuleCtl = ShmemInitStruct("Message Module Struct",
-                                                                  (PGXL_MSG_MAX_MODULES *
-                                                                   PGXL_MSG_MAX_FILEIDS_PER_MODULE *
-                                                                   PGXL_MSG_MAX_MSGIDS_PER_FILE),
+                                                                  SizeOfMsgModuleCtlStruct,
                                                                   &found);
 }
 
+void
+AtProcStart_MsgModule(void)
+{
+       if (MsgModuleCtl->mm_persistent)
+               MsgModuleCtl->mm_flags[StartOfBackendFlags + MyBackendId] = true;
+       else
+               MsgModuleCtl->mm_flags[StartOfBackendFlags + MyBackendId] = false;
+       before_shmem_exit(AtProcExit_MsgModule, 0);
+}
+
 static bool
 pg_msgmodule_internal(int32 moduleid, int32 fileid, int32 msgid, char value)
 {
@@ -3947,8 +3983,8 @@ pg_msgmodule_internal(int32 moduleid, int32 fileid, int32 msgid, char value)
                 */
                len = PGXL_MSG_MAX_FILEIDS_PER_MODULE * PGXL_MSG_MAX_MSGIDS_PER_FILE;
                start_position = (moduleid - 1) * len;
-               memset(MsgModuleCtl + start_position, value, len);
-               return true;
+               memset(MsgModuleCtl->mm_flags + start_position, value, len);
+               goto success;
        }
        else
        {
@@ -3965,8 +4001,8 @@ pg_msgmodule_internal(int32 moduleid, int32 fileid, int32 msgid, char value)
                        len = PGXL_MSG_MAX_MSGIDS_PER_FILE;
                        start_position = ((moduleid - 1) * PGXL_MSG_MAX_FILEIDS_PER_MODULE * PGXL_MSG_MAX_MSGIDS_PER_FILE) +
                                                (fileid - 1) * PGXL_MSG_MAX_MSGIDS_PER_FILE;
-                       memset(MsgModuleCtl + start_position, value, len);
-                       return true;
+                       memset(MsgModuleCtl->mm_flags + start_position, value, len);
+                       goto success;
                }
 
                if (msgid <= 0 || msgid >= PGXL_MSG_MAX_MSGIDS_PER_FILE)
@@ -3980,9 +4016,11 @@ pg_msgmodule_internal(int32 moduleid, int32 fileid, int32 msgid, char value)
                start_position = ((moduleid - 1) * PGXL_MSG_MAX_FILEIDS_PER_MODULE * PGXL_MSG_MAX_MSGIDS_PER_FILE) +
                        ((fileid - 1) * PGXL_MSG_MAX_MSGIDS_PER_FILE) +
                        (msgid - 1);
-               memset(MsgModuleCtl + start_position, value, len);
-               return true;
+               memset(MsgModuleCtl->mm_flags + start_position, value, len);
+               goto success;
        }
+
+success:
        return true;
 }
 
@@ -4050,6 +4088,153 @@ pg_msgmodule_change(PG_FUNCTION_ARGS)
 
        PG_RETURN_BOOL(pg_msgmodule_internal(moduleid, fileid, msgid, level));
 }
+
+static bool
+pg_msgmodule_enable_disable(int32 pid, bool enable)
+{
+       BackendId backendId;
+       /*
+        * pid == -1 implies the action is applied for all backends
+        */
+       if (pid != -1)
+       {
+               volatile PGPROC *proc = BackendPidGetProc(pid);
+               if (proc == NULL)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_INTERNAL_ERROR),
+                                        (errmsg("PID %d is not a PostgreSQL server process", pid))));
+               backendId = proc->backendId;
+               MsgModuleCtl->mm_flags[StartOfBackendFlags + backendId] = enable ? true :
+                       false;
+       }
+       else
+       {
+               /*
+                * All backends should not honour the current settings
+                */
+               memset(MsgModuleCtl->mm_flags + StartOfBackendFlags, true,
+                               MaxBackends);
+       }
+
+       /*
+        * If we are disabling the last backend and no new backends are going to
+        * participate in the facility, then just disable the entire facility so
+        * that subsequent backends can quickly bail out
+        *
+        * XXX There is a race possible here if another call to turn on the logging
+        * comes just after we had passed over tje slot. We should possibly protect
+        * access to the shared memory, but doesn't seem like worth the effort
+        * right now
+        */
+       if (!enable && !MsgModuleCtl->mm_persistent)
+       {
+               int i;
+               for (i = 0; i < MaxBackends; i++)
+                       if (MsgModuleCtl->mm_flags[StartOfBackendFlags + i])
+                               break;
+               if (i == MaxBackends)
+                       MsgModuleCtl->mm_enabled = false;
+       }
+       else
+               MsgModuleCtl->mm_enabled = true;
+
+       return true;
+}
+
+Datum
+pg_msgmodule_enable(PG_FUNCTION_ARGS)
+{
+       int32 pid = PG_GETARG_INT32(0);
+
+       if (!superuser())
+               ereport(ERROR,
+                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                        (errmsg("must be superuser to change elog message level"))));
+
+       PG_RETURN_BOOL(pg_msgmodule_enable_disable(pid, true));
+}
+
+Datum
+pg_msgmodule_disable(PG_FUNCTION_ARGS)
+{
+       int32 pid = PG_GETARG_INT32(0);
+
+       if (!superuser())
+               ereport(ERROR,
+                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                        (errmsg("must be superuser to change elog message level"))));
+
+       PG_RETURN_BOOL(pg_msgmodule_enable_disable(pid, false));
+}
+
+/*
+ * pg_msgmodule_enable_all(bool persistent)
+ *
+ * All processes to start honouring the current settings of overridden log
+ * levels. If "persistent" is set to true, then all future processes will also
+ * honour the settings.
+ */
+Datum
+pg_msgmodule_enable_all(PG_FUNCTION_ARGS)
+{
+       bool persistent = PG_GETARG_BOOL(0);
+
+       if (!superuser())
+               ereport(ERROR,
+                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                        (errmsg("must be superuser to change elog message level"))));
+
+       MsgModuleCtl->mm_persistent = persistent;
+       if (persistent)
+       {
+               MsgModuleCtl->mm_enabled = true;
+               memset(MsgModuleCtl->mm_flags + StartOfBackendFlags, true,
+                               MaxBackends);
+               PG_RETURN_BOOL(true);
+       }
+       else
+               PG_RETURN_BOOL(pg_msgmodule_enable_disable(-1, true));
+}
+
+/*
+ * Disable all current and future processes from honouring the overridden log
+ * levels
+ */
+Datum
+pg_msgmodule_disable_all(PG_FUNCTION_ARGS)
+{
+       if (!superuser())
+               ereport(ERROR,
+                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                        (errmsg("must be superuser to change elog message level"))));
+
+       MsgModuleCtl->mm_enabled = false;
+       MsgModuleCtl->mm_persistent = false;
+       memset(MsgModuleCtl->mm_flags + StartOfBackendFlags, false,
+                       MaxBackends);
+       PG_RETURN_BOOL(true);
+}
+
+/*
+ * Handle proc exit. If persistent flag is not set then also check if we are
+ * the last process using the facility and if so, disable it. The current log
+ * settings are retained and will be used when newer processes are enabled for
+ * the facility
+ */
+static void
+AtProcExit_MsgModule(int code, Datum arg)
+{
+       MsgModuleCtl->mm_flags[StartOfBackendFlags + MyBackendId] = false;
+       if (!MsgModuleCtl->mm_persistent)
+       {
+               int i;
+               for (i = 0; i < MaxBackends; i++)
+                       if (MsgModuleCtl->mm_flags[StartOfBackendFlags + i])
+                               break;
+               if (i == MaxBackends)
+                       MsgModuleCtl->mm_enabled = false;
+       }
+}
 #else
 Datum
 pg_msgmodule_set(PG_FUNCTION_ARGS)
@@ -4063,4 +4248,28 @@ pg_msgmodule_change(PG_FUNCTION_ARGS)
        ereport(ERROR, (errmsg_internal("Module msgid support not available. "
                                        "Please recompile with --enable-genmsgids")));
 }
+Datum
+pg_msgmodule_enable(PG_FUNCTION_ARGS)
+{
+       ereport(ERROR, (errmsg_internal("Module msgid support not available. "
+                                       "Please recompile with --enable-genmsgids")));
+}
+Datum
+pg_msgmodule_disable(PG_FUNCTION_ARGS)
+{
+       ereport(ERROR, (errmsg_internal("Module msgid support not available. "
+                                       "Please recompile with --enable-genmsgids")));
+}
+Datum
+pg_msgmodule_enable_all(PG_FUNCTION_ARGS)
+{
+       ereport(ERROR, (errmsg_internal("Module msgid support not available. "
+                                       "Please recompile with --enable-genmsgids")));
+}
+Datum
+pg_msgmodule_disable_all(PG_FUNCTION_ARGS)
+{
+       ereport(ERROR, (errmsg_internal("Module msgid support not available. "
+                                       "Please recompile with --enable-genmsgids")));
+}
 #endif
index 0dd124d0ec0aa420e2e0c8eb1fff53a2975bfcaf..ede11ebc18abde8df447318b83282e7ee6f189c8 100644 (file)
@@ -5381,6 +5381,14 @@ DATA(insert OID = 6015 ( pg_msgmodule_set PGNSP PGUID 12 1 1 0 0 f f f f t t i 4
 DESCR("set debugging level for module/file/msg");
 DATA(insert OID = 6016 ( pg_msgmodule_change PGNSP PGUID 12 1 1 0 0 f f f f t t i 4 0 16 "20 20 20 20" _null_ _null_ _null_ _null_ _null_ pg_msgmodule_change _null_ _null_ _null_ ));
 DESCR("change debugging level for module/file/msg");
+DATA(insert OID = 6017 ( pg_msgmodule_enable PGNSP PGUID 12 1 1 0 0 f f f f t t i 1 0 16 "20" _null_ _null_ _null_ _null_ _null_ pg_msgmodule_enable _null_ _null_ _null_ ));
+DESCR("pid to honour overriden log levels");
+DATA(insert OID = 6018 ( pg_msgmodule_disable PGNSP PGUID 12 1 1 0 0 f f f f t t i 1 0 16 "20" _null_ _null_ _null_ _null_ _null_ pg_msgmodule_disable _null_ _null_ _null_ ));
+DESCR("pid to ignore overriden log levels");
+DATA(insert OID = 6019 ( pg_msgmodule_enable_all PGNSP PGUID 12 1 1 0 0 f f f f t t i 1 0 16 "16" _null_ _null_ _null_ _null_ _null_ pg_msgmodule_enable_all _null_ _null_ _null_ ));
+DESCR("all current/future processes to honour overriden log levels");
+DATA(insert OID = 6020 ( pg_msgmodule_disable_all PGNSP PGUID 12 1 1 0 0 f f f f t t 0 0 0 16 "" _null_ _null_ _null_ _null_ _null_ pg_msgmodule_disable_all _null_ _null_ _null_ ));
+DESCR("all processes to ignore overriden log levels");
 #endif
 
 /*
index 4c7638294f605985f01ac20476c16568875a69ec..5b0033cc80e99361b424456585f6a53ab53e9e51 100644 (file)
@@ -1325,5 +1325,10 @@ extern Datum pgxc_is_inprogress(PG_FUNCTION_ARGS);
 #endif
 #ifdef USE_MODULE_MSGIDS
 extern Datum pg_msgmodule_set(PG_FUNCTION_ARGS);
+extern Datum pg_msgmodule_change(PG_FUNCTION_ARGS);
+extern Datum pg_msgmodule_enable(PG_FUNCTION_ARGS);
+extern Datum pg_msgmodule_disable(PG_FUNCTION_ARGS);
+extern Datum pg_msgmodule_enable_all(PG_FUNCTION_ARGS);
+extern Datum pg_msgmodule_disable_all(PG_FUNCTION_ARGS);
 #endif
 #endif   /* BUILTINS_H */
index 0f7c7736623d71e57fe0a9bfbbad78f4b0750e07..8e5d2c1f350a143f105dae97d937cafe374d7fa7 100644 (file)
@@ -440,9 +440,9 @@ typedef struct ErrorData
 #define PGXL_MSG_MAX_FILEIDS_PER_MODULE        100
 #define PGXL_MSG_MAX_MSGIDS_PER_FILE   300
 
-extern char *MsgModuleCtl;
 extern Size MsgModuleShmemSize(void);
 extern void MsgModuleShmemInit(void);
+extern void AtProcStart_MsgModule(void);
 #endif
 
 extern void EmitErrorReport(void);