Hi All, On Mon, Jul 13, 2015 at 2:12 PM, Tom Lane <t...@sss.pgh.pa.us> wrote:
> Jim Nasby <jim.na...@bluetreble.com> writes: > > On 7/13/15 3:39 PM, dinesh kumar wrote: > >> Ah. It's' my bad interpretation. Let me work on it, and will send a new > >> patch as a wrapper sql function for ereport. > > > You might want to present a plan for that; it's not as trivial as it > > sounds due to how ereport works. In particular, I'd want to see (at > > minimum) the same functionality that plpgsql's RAISE command now > > provides (errdetail, errhint, etc). > > Jim, For now, I worked on (ERROR Level, ERROR Message, HIDE ERROR Stmt). In our to do item description, I found this wrapper needs to return "Anyelement". But, I believe, return "VOID" is enough for this function. Let me know if I erred here. In design phase, 1. I took a CustomDataType with the elevel code, elevel text 2. Populated this CDT with all existing pre-processors, except {FATAL, PANIC}. Since, we don't expose these to client. 3. By matching the user elevel text, processing the report log function. Find the attached patch with implementation. > The real question is why the existing functionality in plpgsql isn't > sufficient. Somebody who wants a "log from SQL" function can easily > write a simple plpgsql function that does exactly what they want, > with no more or fewer bells-n-whistles than they need. If we try > to create a SQL function that does all that, it's likely to be a mess > to use, even with named arguments. > > I'm not necessarily against the basic idea, but I think inventing > something that actually offers an increment in usability compared > to the existing alternative is going to be harder than it sounds. > > Tom, I agree with your inputs. We can build pl/pgsql function as alternative for this. My initial proposal, and implementation was, logging messages to log file irrespectively of our log settings. I was not sure we can do this with some pl/perlu. And then, I started working on our to do item, ereport, wrapper callable from SQL, and found it can be useful to have a direct function call with required log level. Thanks. Regards, Dinesh manojadinesh.blogspot.com regards, tom lane >
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 76f77cb..43dbaec 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -17850,6 +17850,15 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); Return information about a file. </entry> </row> + <row> + <entry> + <literal><function>pg_report_log(<parameter>elevel</><type>text</>, <parameter>message</> <type>anyelement</type>, <parameter>ishidestmt</><type>boolean</>)</function></literal> + </entry> + <entry><type>void</type></entry> + <entry> + Write message into log file as per log level. + </entry> + </row> </tbody> </tgroup> </table> @@ -17918,6 +17927,24 @@ SELECT (pg_stat_file('filename')).modification; </programlisting> </para> + <indexterm> + <primary>pg_report_log</primary> + </indexterm> + <para> + <function>pg_report_log</> is useful to write custom messages + into current log destination and returns <type>void</type>. + This function don't support the PANIC, FATAL log levels due to their unique internal DB usage, which may cause the database instability. Using <parameter>ishidestmt</>, function can write or ignore the current SQL statement into the log file. + Typical usages include: +<programlisting> +postgres=# SELECT pg_report_log('NOTICE', 'Custom Message', true); +NOTICE: Custom Message + pg_report_log +--------------- + +(1 row) +</programlisting> + </para> + </sect2> <sect2 id="functions-advisory-locks"> diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index c0495d9..1c7c263 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -76,6 +76,91 @@ current_query(PG_FUNCTION_ARGS) } /* + * pg_report_log() + * + * Printing custom log messages in log file. + */ + +typedef struct +{ + int ecode; + char *level; +} errorlevels; + +Datum +pg_report_log(PG_FUNCTION_ARGS) +{ + + /* + * Do not add FATAL, PANIC log levels to the below list. + */ + errorlevels elevels[]={ + {DEBUG5, "DEBUG5"}, {DEBUG4, "DEBUG4"}, {DEBUG3, "DEBUG3"}, + {DEBUG2, "DEBUG2"}, {DEBUG1, "DEBUG1"}, {LOG, "LOG"}, + {COMMERROR, "COMMERROR"}, {INFO, "INFO"}, {NOTICE, "NOTICE"}, + {WARNING, "WARNING"}, {ERROR, "ERROR"} + /* + * Adding PGERROR to elevels if WIN32 + */ + #ifdef WIN32 + ,{PGERROR, "PGERROR"} + #endif + }; + + int itr = 0; + bool ishidestmt = false; + int noelevel = (int) sizeof(elevels)/sizeof(*elevels); + char *level; + + level = text_to_cstring(PG_GETARG_TEXT_P(0)); + ishidestmt = PG_GETARG_BOOL(2); + + /* + * Do not expose FATAL, PANIC log levels to outer world. + */ + if(pg_strcasecmp("FATAL", level) == 0) + ereport(ERROR, + (errmsg("%s is an unsupported report log level.", level))); + + else if(pg_strcasecmp("PANIC", level) == 0) + ereport(ERROR, + (errmsg("%s is an unsupported report log level.", level))); + else + { + while (itr < noelevel) + { + if (pg_strcasecmp(elevels[itr].level, level) == 0) + { + /* + * Is errhide statement true + */ + if (ishidestmt == true) + { + ereport(elevels[itr].ecode, + (errmsg("%s", text_to_cstring(PG_GETARG_TEXT_P(1))), + errhidestmt(true))); + break; + } + else + { + ereport(elevels[itr].ecode,_ + (errmsg("%s", text_to_cstring(PG_GETARG_TEXT_P(1))))); + break; + } + } + itr++; + } + + /* Invalid log level */ + if (itr == noelevel) + ereport(ERROR, + (errmsg("Unknown log level \"%s\"", level))); + else + PG_RETURN_VOID(); + } +} + +/* * Send a signal to another backend. * * The signal is delivered if the user is either a superuser or the same diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 6fd1278..b745d80 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -5344,6 +5344,14 @@ DESCR("tsm_bernoulli_reset(internal)"); DATA(insert OID = 3346 ( tsm_bernoulli_cost PGNSP PGUID 12 1 0 0 0 f f f f t f v 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ tsm_bernoulli_cost _null_ _null_ _null_ )); DESCR("tsm_bernoulli_cost(internal)"); +/* Logging function */ + +DATA(insert OID = 6015 ( pg_report_log PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 2278 "25 25 16" _null_ _null_ _null_ _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 t f s 3 0 2278 "25 2283 16" _null_ _null_ _null_ _null_ _null_ "SELECT pg_report_log($1::pg_catalog.text, $2::pg_catalog.text, $3::boolean)" _null_ _null_ _null_ )); +DESCR("write message to log file"); + + /* * Symbolic values for provolatile column: these indicate whether the result * of a function is dependent *only* on the values of its explicit arguments, diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index fcb0bf0..3a2164b 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 <setjmp.h> +/* + * 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. */
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers