1 /*-------------------------------------------------------------------------
6 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/utils/error/csvlog.c
13 *-------------------------------------------------------------------------
18 #include "access/xact.h"
19 #include "lib/stringinfo.h"
20 #include "libpq/libpq-be.h"
21 #include "miscadmin.h"
22 #include "postmaster/syslogger.h"
23 #include "storage/lock.h"
24 #include "storage/proc.h"
25 #include "tcop/tcopprot.h"
26 #include "utils/backend_status.h"
27 #include "utils/guc.h"
28 #include "utils/ps_status.h"
32 * append a CSV'd version of a string to a StringInfo
33 * We use the PostgreSQL defaults for CSV, i.e. quote = escape = '"'
34 * If it's NULL, append nothing.
37 appendCSVLiteral(StringInfo buf
, const char *data
)
42 /* avoid confusing an empty string with NULL */
46 appendStringInfoCharMacro(buf
, '"');
47 while ((c
= *p
++) != '\0')
50 appendStringInfoCharMacro(buf
, '"');
51 appendStringInfoCharMacro(buf
, c
);
53 appendStringInfoCharMacro(buf
, '"');
57 * write_csvlog -- Generate and write CSV log entry
59 * Constructs the error message, depending on the Errordata it gets, in a CSV
60 * format which is described in doc/src/sgml/config.sgml.
63 write_csvlog(ErrorData
*edata
)
66 bool print_stmt
= false;
68 /* static counter for line numbers */
69 static long log_line_number
= 0;
71 /* has counter been reset in current process? */
72 static int log_my_pid
= 0;
75 * This is one of the few places where we'd rather not inherit a static
76 * variable's value from the postmaster. But since we will, reset it when
79 if (log_my_pid
!= MyProcPid
)
82 log_my_pid
= MyProcPid
;
83 reset_formatted_start_time();
89 /* timestamp with milliseconds */
90 appendStringInfoString(&buf
, get_formatted_log_time());
91 appendStringInfoChar(&buf
, ',');
95 appendCSVLiteral(&buf
, MyProcPort
->user_name
);
96 appendStringInfoChar(&buf
, ',');
100 appendCSVLiteral(&buf
, MyProcPort
->database_name
);
101 appendStringInfoChar(&buf
, ',');
105 appendStringInfo(&buf
, "%d", MyProcPid
);
106 appendStringInfoChar(&buf
, ',');
108 /* Remote host and port */
109 if (MyProcPort
&& MyProcPort
->remote_host
)
111 appendStringInfoChar(&buf
, '"');
112 appendStringInfoString(&buf
, MyProcPort
->remote_host
);
113 if (MyProcPort
->remote_port
&& MyProcPort
->remote_port
[0] != '\0')
115 appendStringInfoChar(&buf
, ':');
116 appendStringInfoString(&buf
, MyProcPort
->remote_port
);
118 appendStringInfoChar(&buf
, '"');
120 appendStringInfoChar(&buf
, ',');
123 appendStringInfo(&buf
, "%" INT64_MODIFIER
"x.%x", MyStartTime
, MyProcPid
);
124 appendStringInfoChar(&buf
, ',');
127 appendStringInfo(&buf
, "%ld", log_line_number
);
128 appendStringInfoChar(&buf
, ',');
133 StringInfoData msgbuf
;
137 initStringInfo(&msgbuf
);
139 psdisp
= get_ps_display(&displen
);
140 appendBinaryStringInfo(&msgbuf
, psdisp
, displen
);
141 appendCSVLiteral(&buf
, msgbuf
.data
);
145 appendStringInfoChar(&buf
, ',');
147 /* session start timestamp */
148 appendStringInfoString(&buf
, get_formatted_start_time());
149 appendStringInfoChar(&buf
, ',');
151 /* Virtual transaction id */
152 /* keep VXID format in sync with lockfuncs.c */
153 if (MyProc
!= NULL
&& MyProc
->vxid
.procNumber
!= INVALID_PROC_NUMBER
)
154 appendStringInfo(&buf
, "%d/%u", MyProc
->vxid
.procNumber
, MyProc
->vxid
.lxid
);
155 appendStringInfoChar(&buf
, ',');
158 appendStringInfo(&buf
, "%u", GetTopTransactionIdIfAny());
159 appendStringInfoChar(&buf
, ',');
162 appendStringInfoString(&buf
, _(error_severity(edata
->elevel
)));
163 appendStringInfoChar(&buf
, ',');
166 appendStringInfoString(&buf
, unpack_sql_state(edata
->sqlerrcode
));
167 appendStringInfoChar(&buf
, ',');
170 appendCSVLiteral(&buf
, edata
->message
);
171 appendStringInfoChar(&buf
, ',');
173 /* errdetail or errdetail_log */
174 if (edata
->detail_log
)
175 appendCSVLiteral(&buf
, edata
->detail_log
);
177 appendCSVLiteral(&buf
, edata
->detail
);
178 appendStringInfoChar(&buf
, ',');
181 appendCSVLiteral(&buf
, edata
->hint
);
182 appendStringInfoChar(&buf
, ',');
185 appendCSVLiteral(&buf
, edata
->internalquery
);
186 appendStringInfoChar(&buf
, ',');
188 /* if printed internal query, print internal pos too */
189 if (edata
->internalpos
> 0 && edata
->internalquery
!= NULL
)
190 appendStringInfo(&buf
, "%d", edata
->internalpos
);
191 appendStringInfoChar(&buf
, ',');
194 if (!edata
->hide_ctx
)
195 appendCSVLiteral(&buf
, edata
->context
);
196 appendStringInfoChar(&buf
, ',');
198 /* user query --- only reported if not disabled by the caller */
199 print_stmt
= check_log_of_query(edata
);
201 appendCSVLiteral(&buf
, debug_query_string
);
202 appendStringInfoChar(&buf
, ',');
203 if (print_stmt
&& edata
->cursorpos
> 0)
204 appendStringInfo(&buf
, "%d", edata
->cursorpos
);
205 appendStringInfoChar(&buf
, ',');
207 /* file error location */
208 if (Log_error_verbosity
>= PGERROR_VERBOSE
)
210 StringInfoData msgbuf
;
212 initStringInfo(&msgbuf
);
214 if (edata
->funcname
&& edata
->filename
)
215 appendStringInfo(&msgbuf
, "%s, %s:%d",
216 edata
->funcname
, edata
->filename
,
218 else if (edata
->filename
)
219 appendStringInfo(&msgbuf
, "%s:%d",
220 edata
->filename
, edata
->lineno
);
221 appendCSVLiteral(&buf
, msgbuf
.data
);
224 appendStringInfoChar(&buf
, ',');
226 /* application name */
227 if (application_name
)
228 appendCSVLiteral(&buf
, application_name
);
230 appendStringInfoChar(&buf
, ',');
233 appendCSVLiteral(&buf
, get_backend_type_for_log());
234 appendStringInfoChar(&buf
, ',');
239 PGPROC
*leader
= MyProc
->lockGroupLeader
;
242 * Show the leader only for active parallel workers. This leaves out
243 * the leader of a parallel group.
245 if (leader
&& leader
->pid
!= MyProcPid
)
246 appendStringInfo(&buf
, "%d", leader
->pid
);
248 appendStringInfoChar(&buf
, ',');
251 appendStringInfo(&buf
, "%lld", (long long) pgstat_get_my_query_id());
253 appendStringInfoChar(&buf
, '\n');
255 /* If in the syslogger process, try to write messages direct to file */
256 if (MyBackendType
== B_LOGGER
)
257 write_syslogger_file(buf
.data
, buf
.len
, LOG_DESTINATION_CSVLOG
);
259 write_pipe_chunks(buf
.data
, buf
.len
, LOG_DESTINATION_CSVLOG
);