LCOV - differential code coverage report
Current view: top level - src/backend/utils/error - csvlog.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 88.0 % 108 95 13 95
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 2 2 2
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * csvlog.c
       4                 :  *    CSV logging
       5                 :  *
       6                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
       7                 :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :  *
       9                 :  *
      10                 :  * IDENTIFICATION
      11                 :  *    src/backend/utils/error/csvlog.c
      12                 :  *
      13                 :  *-------------------------------------------------------------------------
      14                 :  */
      15                 : 
      16                 : #include "postgres.h"
      17                 : 
      18                 : #include "access/xact.h"
      19                 : #include "libpq/libpq.h"
      20                 : #include "lib/stringinfo.h"
      21                 : #include "miscadmin.h"
      22                 : #include "postmaster/bgworker.h"
      23                 : #include "postmaster/syslogger.h"
      24                 : #include "storage/lock.h"
      25                 : #include "storage/proc.h"
      26                 : #include "tcop/tcopprot.h"
      27                 : #include "utils/backend_status.h"
      28                 : #include "utils/elog.h"
      29                 : #include "utils/guc.h"
      30                 : #include "utils/ps_status.h"
      31                 : 
      32                 : 
      33                 : /*
      34                 :  * append a CSV'd version of a string to a StringInfo
      35                 :  * We use the PostgreSQL defaults for CSV, i.e. quote = escape = '"'
      36                 :  * If it's NULL, append nothing.
      37                 :  */
      38                 : static inline void
      39 CBC         169 : appendCSVLiteral(StringInfo buf, const char *data)
      40                 : {
      41             169 :     const char *p = data;
      42                 :     char        c;
      43                 : 
      44                 :     /* avoid confusing an empty string with NULL */
      45             169 :     if (p == NULL)
      46              80 :         return;
      47                 : 
      48              89 :     appendStringInfoCharMacro(buf, '"');
      49            1738 :     while ((c = *p++) != '\0')
      50                 :     {
      51            1649 :         if (c == '"')
      52               6 :             appendStringInfoCharMacro(buf, '"');
      53            1649 :         appendStringInfoCharMacro(buf, c);
      54                 :     }
      55              89 :     appendStringInfoCharMacro(buf, '"');
      56                 : }
      57                 : 
      58                 : /*
      59                 :  * write_csvlog -- Generate and write CSV log entry
      60                 :  *
      61                 :  * Constructs the error message, depending on the Errordata it gets, in a CSV
      62                 :  * format which is described in doc/src/sgml/config.sgml.
      63                 :  */
      64                 : void
      65              20 : write_csvlog(ErrorData *edata)
      66                 : {
      67                 :     StringInfoData buf;
      68              20 :     bool        print_stmt = false;
      69                 : 
      70                 :     /* static counter for line numbers */
      71                 :     static long log_line_number = 0;
      72                 : 
      73                 :     /* has counter been reset in current process? */
      74                 :     static int  log_my_pid = 0;
      75                 : 
      76                 :     /*
      77                 :      * This is one of the few places where we'd rather not inherit a static
      78                 :      * variable's value from the postmaster.  But since we will, reset it when
      79                 :      * MyProcPid changes.
      80                 :      */
      81              20 :     if (log_my_pid != MyProcPid)
      82                 :     {
      83              11 :         log_line_number = 0;
      84              11 :         log_my_pid = MyProcPid;
      85              11 :         reset_formatted_start_time();
      86                 :     }
      87              20 :     log_line_number++;
      88                 : 
      89              20 :     initStringInfo(&buf);
      90                 : 
      91                 :     /* timestamp with milliseconds */
      92              20 :     appendStringInfoString(&buf, get_formatted_log_time());
      93              20 :     appendStringInfoChar(&buf, ',');
      94                 : 
      95                 :     /* username */
      96              20 :     if (MyProcPort)
      97               9 :         appendCSVLiteral(&buf, MyProcPort->user_name);
      98              20 :     appendStringInfoChar(&buf, ',');
      99                 : 
     100                 :     /* database name */
     101              20 :     if (MyProcPort)
     102               9 :         appendCSVLiteral(&buf, MyProcPort->database_name);
     103              20 :     appendStringInfoChar(&buf, ',');
     104                 : 
     105                 :     /* Process id  */
     106              20 :     if (MyProcPid != 0)
     107              20 :         appendStringInfo(&buf, "%d", MyProcPid);
     108              20 :     appendStringInfoChar(&buf, ',');
     109                 : 
     110                 :     /* Remote host and port */
     111              20 :     if (MyProcPort && MyProcPort->remote_host)
     112                 :     {
     113               9 :         appendStringInfoChar(&buf, '"');
     114               9 :         appendStringInfoString(&buf, MyProcPort->remote_host);
     115               9 :         if (MyProcPort->remote_port && MyProcPort->remote_port[0] != '\0')
     116                 :         {
     117 UBC           0 :             appendStringInfoChar(&buf, ':');
     118               0 :             appendStringInfoString(&buf, MyProcPort->remote_port);
     119                 :         }
     120 CBC           9 :         appendStringInfoChar(&buf, '"');
     121                 :     }
     122              20 :     appendStringInfoChar(&buf, ',');
     123                 : 
     124                 :     /* session id */
     125              20 :     appendStringInfo(&buf, "%lx.%x", (long) MyStartTime, MyProcPid);
     126              20 :     appendStringInfoChar(&buf, ',');
     127                 : 
     128                 :     /* Line number */
     129              20 :     appendStringInfo(&buf, "%ld", log_line_number);
     130              20 :     appendStringInfoChar(&buf, ',');
     131                 : 
     132                 :     /* PS display */
     133              20 :     if (MyProcPort)
     134                 :     {
     135                 :         StringInfoData msgbuf;
     136                 :         const char *psdisp;
     137                 :         int         displen;
     138                 : 
     139               9 :         initStringInfo(&msgbuf);
     140                 : 
     141               9 :         psdisp = get_ps_display(&displen);
     142               9 :         appendBinaryStringInfo(&msgbuf, psdisp, displen);
     143               9 :         appendCSVLiteral(&buf, msgbuf.data);
     144                 : 
     145               9 :         pfree(msgbuf.data);
     146                 :     }
     147              20 :     appendStringInfoChar(&buf, ',');
     148                 : 
     149                 :     /* session start timestamp */
     150              20 :     appendStringInfoString(&buf, get_formatted_start_time());
     151              20 :     appendStringInfoChar(&buf, ',');
     152                 : 
     153                 :     /* Virtual transaction id */
     154                 :     /* keep VXID format in sync with lockfuncs.c */
     155              20 :     if (MyProc != NULL && MyProc->backendId != InvalidBackendId)
     156               9 :         appendStringInfo(&buf, "%d/%u", MyProc->backendId, MyProc->lxid);
     157              20 :     appendStringInfoChar(&buf, ',');
     158                 : 
     159                 :     /* Transaction id */
     160              20 :     appendStringInfo(&buf, "%u", GetTopTransactionIdIfAny());
     161              20 :     appendStringInfoChar(&buf, ',');
     162                 : 
     163                 :     /* Error severity */
     164              20 :     appendStringInfoString(&buf, _(error_severity(edata->elevel)));
     165              20 :     appendStringInfoChar(&buf, ',');
     166                 : 
     167                 :     /* SQL state code */
     168              20 :     appendStringInfoString(&buf, unpack_sql_state(edata->sqlerrcode));
     169              20 :     appendStringInfoChar(&buf, ',');
     170                 : 
     171                 :     /* errmessage */
     172              20 :     appendCSVLiteral(&buf, edata->message);
     173              20 :     appendStringInfoChar(&buf, ',');
     174                 : 
     175                 :     /* errdetail or errdetail_log */
     176              20 :     if (edata->detail_log)
     177 UBC           0 :         appendCSVLiteral(&buf, edata->detail_log);
     178                 :     else
     179 CBC          20 :         appendCSVLiteral(&buf, edata->detail);
     180              20 :     appendStringInfoChar(&buf, ',');
     181                 : 
     182                 :     /* errhint */
     183              20 :     appendCSVLiteral(&buf, edata->hint);
     184              20 :     appendStringInfoChar(&buf, ',');
     185                 : 
     186                 :     /* internal query */
     187              20 :     appendCSVLiteral(&buf, edata->internalquery);
     188              20 :     appendStringInfoChar(&buf, ',');
     189                 : 
     190                 :     /* if printed internal query, print internal pos too */
     191              20 :     if (edata->internalpos > 0 && edata->internalquery != NULL)
     192 UBC           0 :         appendStringInfo(&buf, "%d", edata->internalpos);
     193 CBC          20 :     appendStringInfoChar(&buf, ',');
     194                 : 
     195                 :     /* errcontext */
     196              20 :     if (!edata->hide_ctx)
     197              20 :         appendCSVLiteral(&buf, edata->context);
     198              20 :     appendStringInfoChar(&buf, ',');
     199                 : 
     200                 :     /* user query --- only reported if not disabled by the caller */
     201              20 :     print_stmt = check_log_of_query(edata);
     202              20 :     if (print_stmt)
     203               2 :         appendCSVLiteral(&buf, debug_query_string);
     204              20 :     appendStringInfoChar(&buf, ',');
     205              20 :     if (print_stmt && edata->cursorpos > 0)
     206               1 :         appendStringInfo(&buf, "%d", edata->cursorpos);
     207              20 :     appendStringInfoChar(&buf, ',');
     208                 : 
     209                 :     /* file error location */
     210              20 :     if (Log_error_verbosity >= PGERROR_VERBOSE)
     211                 :     {
     212                 :         StringInfoData msgbuf;
     213                 : 
     214 UBC           0 :         initStringInfo(&msgbuf);
     215                 : 
     216               0 :         if (edata->funcname && edata->filename)
     217               0 :             appendStringInfo(&msgbuf, "%s, %s:%d",
     218                 :                              edata->funcname, edata->filename,
     219                 :                              edata->lineno);
     220               0 :         else if (edata->filename)
     221               0 :             appendStringInfo(&msgbuf, "%s:%d",
     222                 :                              edata->filename, edata->lineno);
     223               0 :         appendCSVLiteral(&buf, msgbuf.data);
     224               0 :         pfree(msgbuf.data);
     225                 :     }
     226 CBC          20 :     appendStringInfoChar(&buf, ',');
     227                 : 
     228                 :     /* application name */
     229              20 :     if (application_name)
     230              20 :         appendCSVLiteral(&buf, application_name);
     231                 : 
     232              20 :     appendStringInfoChar(&buf, ',');
     233                 : 
     234                 :     /* backend type */
     235              20 :     appendCSVLiteral(&buf, get_backend_type_for_log());
     236              20 :     appendStringInfoChar(&buf, ',');
     237                 : 
     238                 :     /* leader PID */
     239              20 :     if (MyProc)
     240                 :     {
     241              13 :         PGPROC     *leader = MyProc->lockGroupLeader;
     242                 : 
     243                 :         /*
     244                 :          * Show the leader only for active parallel workers.  This leaves out
     245                 :          * the leader of a parallel group.
     246                 :          */
     247              13 :         if (leader && leader->pid != MyProcPid)
     248 UBC           0 :             appendStringInfo(&buf, "%d", leader->pid);
     249                 :     }
     250 CBC          20 :     appendStringInfoChar(&buf, ',');
     251                 : 
     252                 :     /* query id */
     253              20 :     appendStringInfo(&buf, "%lld", (long long) pgstat_get_my_query_id());
     254                 : 
     255              20 :     appendStringInfoChar(&buf, '\n');
     256                 : 
     257                 :     /* If in the syslogger process, try to write messages direct to file */
     258              20 :     if (MyBackendType == B_LOGGER)
     259 UBC           0 :         write_syslogger_file(buf.data, buf.len, LOG_DESTINATION_CSVLOG);
     260                 :     else
     261 CBC          20 :         write_pipe_chunks(buf.data, buf.len, LOG_DESTINATION_CSVLOG);
     262                 : 
     263              20 :     pfree(buf.data);
     264              20 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a