diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index b3b78d2..ff20a9f 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -17925,6 +17925,15 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup());
Return information about a file.
+
+
+ pg_report_log(elevel>text>, message> anyelement, ishidestmt>boolean>, detail> text, hint> text, context> text)
+
+ void
+
+ Write message into log file as per log level.
+
+
@@ -17993,6 +18002,24 @@ SELECT (pg_stat_file('filename')).modification;
+
+ pg_report_log
+
+
+ pg_report_log> is useful to write custom messages
+ into current log destination and returns void.
+ This function don't support the PANIC, FATAL log levels due to their unique internal DB usage, which may cause the database instability. Using ishidestmt>, function can write or ignore the current SQL statement into the log file. Also, we can have DETAIL, HINT, CONTEXT log messages by provding detail>, hint> and context> as function arguments. By default, all these parameter values are NULL.
+ Typical usages include:
+
+postgres=# SELECT pg_report_log('NOTICE', 'Custom Message', true);
+NOTICE: Custom Message
+ pg_report_log
+---------------
+
+(1 row)
+
+
+
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index ccc030f..cd6cc0f 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -940,3 +940,18 @@ RETURNS jsonb
LANGUAGE INTERNAL
STRICT IMMUTABLE
AS 'jsonb_set';
+
+CREATE OR REPLACE FUNCTION pg_report_log(elevel TEXT, message TEXT, ishidestmt BOOLEAN DEFAULT TRUE, detail TEXT DEFAULT NULL, hint TEXT DEFAULT NULL, context TEXT DEFAULT NULL)
+RETURNS VOID
+LANGUAGE INTERNAL
+VOLATILE
+AS 'pg_report_log';
+
+CREATE OR REPLACE FUNCTION pg_report_log(elevel TEXT, message anyelement, ishidestmt BOOLEAN DEFAULT TRUE, detail TEXT DEFAULT NULL, hint TEXT DEFAULT NULL, context TEXT DEFAULT NULL)
+RETURNS VOID
+VOLATILE
+AS
+$$
+SELECT pg_report_log($1::pg_catalog.text, $2::pg_catalog.text, $3::pg_catalog.bool, $4::pg_catalog.text, $5::pg_catalog.text, $6::pg_catalog.text)
+$$
+LANGUAGE SQL;
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index c0495d9..99f99e0 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -75,6 +75,100 @@ current_query(PG_FUNCTION_ARGS)
PG_RETURN_NULL();
}
+
+/*
+ * Parsing error levels
+ */
+typedef struct
+{
+ int ecode;
+ char *level;
+} errorlevels;
+
+static int parse_error_level(const char* elevel)
+{
+ errorlevels elevels[]={
+ {DEBUG5, "DEBUG5"}, {DEBUG4, "DEBUG4"}, {DEBUG3, "DEBUG3"},
+ {DEBUG2, "DEBUG2"}, {DEBUG1, "DEBUG1"}, {LOG, "LOG"},
+ {COMMERROR, "COMMERROR"}, {INFO, "INFO"}, {NOTICE, "NOTICE"},
+ {WARNING, "WARNING"}, {ERROR, "ERROR"}, {FATAL, "FATAL"}, {PANIC, "PANIC"}
+ /*
+ * Adding PGERROR to elevels if WIN32
+ */
+ #ifdef WIN32
+ ,{PGERROR, "PGERROR"}
+ #endif
+ };
+ int noelevel = (int) sizeof(elevels)/sizeof(*elevels);
+ int itr = 0;
+
+ while (itr < noelevel)
+ {
+ if (pg_strcasecmp(elevels[itr].level, elevel) == 0)
+ break;
+ itr++;
+ }
+
+ if (itr != noelevel)
+ return elevels[itr].ecode;
+
+ else
+ /* Invalid log level */
+ return 0;
+}
+
+/*
+ * pg_report_log()
+ *
+ * Printing custom log messages in log file.
+ */
+
+Datum
+pg_report_log(PG_FUNCTION_ARGS)
+{
+ int elevel;
+ bool ishidestmt = false;
+ char *loglevel, *detail, *hint, *cntxt;
+
+ loglevel = PG_ARGISNULL(0) ? NULL : text_to_cstring(PG_GETARG_TEXT_P(0));
+ detail = PG_ARGISNULL(3) ? NULL : text_to_cstring(PG_GETARG_TEXT_P(3));
+ hint = PG_ARGISNULL(4) ? NULL : text_to_cstring(PG_GETARG_TEXT_P(4));
+ cntxt = PG_ARGISNULL(5) ? NULL : text_to_cstring(PG_GETARG_TEXT_P(5));
+ ishidestmt = PG_GETARG_BOOL(2);
+
+ if(!loglevel)
+ ereport(ERROR,
+ (errmsg("NULL is an unsupported report log level.")));
+
+ elevel = parse_error_level(loglevel);
+
+ /*
+ * Do not expose FATAL, PANIC log levels to outer world.
+ */
+ if(elevel && elevel==FATAL)
+ ereport(ERROR,
+ (errmsg("%s is an unsupported report log level.", loglevel)));
+
+ else if(elevel && elevel==PANIC)
+ ereport(ERROR,
+ (errmsg("%s is an unsupported report log level.", loglevel)));
+
+ else if(elevel)
+ ereport(elevel,
+ ((elevel>=ERROR) ? errcode(ERRCODE_RAISE_EXCEPTION) : 0,
+ (errmsg("%s", PG_ARGISNULL(1) ? "" : text_to_cstring(PG_GETARG_TEXT_P(1))),
+ detail ? errdetail("%s", detail) : 0,
+ hint ? errhint("%s", hint) : 0,
+ cntxt ? errcontext_msg("%s", cntxt) : 0,
+ errhidestmt(ishidestmt)
+ )));
+ else
+ ereport(ERROR,
+ (errmsg("%s is an unknown report log level.", loglevel)));
+
+ PG_RETURN_VOID();
+}
+
/*
* Send a signal to another backend.
*
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index ddf7c67..7c4fe87 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -5349,6 +5349,13 @@ DESCR("row security for current context active on table by table oid");
DATA(insert OID = 3299 ( row_security_active PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 16 "25" _null_ _null_ _null_ _null_ _null_ row_security_active_name _null_ _null_ _null_ ));
DESCR("row security for current context active on table by table name");
+/* Logging function */
+
+DATA(insert OID = 6015 ( pg_report_log PGNSP PGUID 12 1 0 0 0 f f f f f f v 6 0 2278 "25 25 16 25 25 25" _null_ _null_ "{elevel, message, ishidestmt, detail, hint, context}" _null_ _null_ pg_report_log _null_ _null_ _null_ ));
+DESCR("write message to log file");
+DATA(insert OID = 6016 ( pg_report_log PGNSP PGUID 14 1 0 0 0 f f f f f f v 6 0 2278 "25 2283 16 25 25 25" _null_ _null_ "{elevel, message, ishidestmt, detail, hint, context}" _null_ _null_ "SELECT pg_report_log($1::pg_catalog.text, $2::pg_catalog.text, $3::pg_catalog.bool, $4::pg_catalog.text, $5::pg_catalog.text, $6::pg_catalog.text)" _null_ _null_ _null_ ));
+DESCR("write message to log file");
+
/*
* Symbolic values for proargmodes column. Note that these must agree with
* the FunctionParameterMode enum in parsenodes.h; we declare them here to
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index fc1679e..0dd1425 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -495,6 +495,7 @@ extern Datum pg_typeof(PG_FUNCTION_ARGS);
extern Datum pg_collation_for(PG_FUNCTION_ARGS);
extern Datum pg_relation_is_updatable(PG_FUNCTION_ARGS);
extern Datum pg_column_is_updatable(PG_FUNCTION_ARGS);
+extern Datum pg_report_log(PG_FUNCTION_ARGS);
/* oid.c */
extern Datum oidin(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 7684717..fcb7218 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -16,6 +16,13 @@
#include
+/*
+ * XXX
+ * If you are adding another elevel, make sure you update the
+ * pg_report_log() in src/backend/utils/adt/misc.c, with the
+ * new elevel
+ */
+
/* Error level codes */
#define DEBUG5 10 /* Debugging messages, in categories of
* decreasing detail. */
diff --git a/src/test/regress/expected/reportlog.out b/src/test/regress/expected/reportlog.out
new file mode 100644
index 0000000..fd639b4
--- /dev/null
+++ b/src/test/regress/expected/reportlog.out
@@ -0,0 +1,84 @@
+--
+-- Test for Report Log With WARNING
+--
+SELECT pg_catalog.pg_report_log('WARNING', 'Custom Message'); --OK
+WARNING: Custom Message
+ pg_report_log
+---------------
+
+(1 row)
+
+--
+-- Test for ERROR with default ishidestmt
+--
+SELECT pg_catalog.pg_report_log('ERROR', 'Custom Message'); --ERROR
+ERROR: Custom Message
+--
+-- Test for ERROR with ishidestmt
+--
+SELECT pg_catalog.pg_report_log('ERROR', 'Custom Message', true); --ERROR
+ERROR: Custom Message
+--
+-- Test for anyelement
+--
+SELECT pg_catalog.pg_report_log('WARNING', -1234.34); --OK
+WARNING: -1234.34
+ pg_report_log
+---------------
+
+(1 row)
+
+--
+-- Test for denial of FATAL
+--
+SELECT pg_catalog.pg_report_log('FATAL', 'Fatal Message'); --OK
+ERROR: FATAL is an unsupported report log level.
+--
+-- Test for optional arguements
+--
+SELECT pg_catalog.pg_report_log('WARNING', 'Warning Message', true, 'WARNING DETAIL'); --OK
+WARNING: Warning Message
+DETAIL: WARNING DETAIL
+ pg_report_log
+---------------
+
+(1 row)
+
+--
+-- Test for NULL elevel
+--
+SELECT pg_catalog.pg_report_log(NULL, NULL); --ERROR
+ERROR: NULL is an unsupported report log level.
+--
+-- Test for NULL Message
+--
+SELECT pg_catalog.pg_report_log('NOTICE', NULL); --OK
+NOTICE:
+ pg_report_log
+---------------
+
+(1 row)
+
+--
+-- Test for all NULL inputs, except elevel
+--
+SELECT pg_catalog.pg_report_log('WARNING', NULL, NULL, NULL, NULL, NULL); --OK
+WARNING:
+ pg_report_log
+---------------
+
+(1 row)
+
+--
+-- Test for all NOT NULL arguments
+--
+SELECT pg_catalog.pg_report_log('WARNING', 'Warning Message', true, 'DETAIL', 'HINT', 'CONTEXT'); --OK
+WARNING: Warning Message
+DETAIL: DETAIL
+HINT: HINT
+CONTEXT: CONTEXT
+ pg_report_log
+---------------
+
+(1 row)
+
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 6fc5d1e..4cd193d 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -97,7 +97,7 @@ test: rules
# ----------
# Another group of parallel tests
# ----------
-test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts foreign_data window xmlmap functional_deps advisory_lock json jsonb indirect_toast equivclass
+test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts foreign_data window xmlmap functional_deps advisory_lock json jsonb indirect_toast reportlog equivclass
# ----------
# Another group of parallel tests
# NB: temp.sql does a reconnect which transiently uses 2 connections,
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 2ae51cf..6c9f5c3 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -158,3 +158,4 @@ test: with
test: xml
test: event_trigger
test: stats
+test: reportlog
diff --git a/src/test/regress/sql/reportlog.sql b/src/test/regress/sql/reportlog.sql
new file mode 100644
index 0000000..153f03e
--- /dev/null
+++ b/src/test/regress/sql/reportlog.sql
@@ -0,0 +1,51 @@
+--
+-- Test for Report Log With WARNING
+--
+SELECT pg_catalog.pg_report_log('WARNING', 'Custom Message'); --OK
+
+--
+-- Test for ERROR with default ishidestmt
+--
+SELECT pg_catalog.pg_report_log('ERROR', 'Custom Message'); --ERROR
+
+--
+-- Test for ERROR with ishidestmt
+--
+SELECT pg_catalog.pg_report_log('ERROR', 'Custom Message', true); --ERROR
+
+--
+-- Test for anyelement
+--
+SELECT pg_catalog.pg_report_log('WARNING', -1234.34); --OK
+
+--
+-- Test for denial of FATAL
+--
+SELECT pg_catalog.pg_report_log('FATAL', 'Fatal Message'); --OK
+
+--
+-- Test for optional arguements
+--
+SELECT pg_catalog.pg_report_log('WARNING', 'Warning Message', true, 'WARNING DETAIL'); --OK
+
+--
+-- Test for NULL elevel
+--
+SELECT pg_catalog.pg_report_log(NULL, NULL); --ERROR
+
+
+--
+-- Test for NULL Message
+--
+SELECT pg_catalog.pg_report_log('NOTICE', NULL); --OK
+
+
+--
+-- Test for all NULL inputs, except elevel
+--
+SELECT pg_catalog.pg_report_log('WARNING', NULL, NULL, NULL, NULL, NULL); --OK
+
+--
+-- Test for all NOT NULL arguments
+--
+SELECT pg_catalog.pg_report_log('WARNING', 'Warning Message', true, 'DETAIL', 'HINT', 'CONTEXT'); --OK