nbtree: fix read page recheck typo.
[pgsql.git] / src / backend / utils / error / csvlog.c
blobeab8df3fcc3fffa4fc08ffd59716b94040fa870f
1 /*-------------------------------------------------------------------------
3 * csvlog.c
4 * CSV logging
6 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * IDENTIFICATION
11 * src/backend/utils/error/csvlog.c
13 *-------------------------------------------------------------------------
16 #include "postgres.h"
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.
36 static inline void
37 appendCSVLiteral(StringInfo buf, const char *data)
39 const char *p = data;
40 char c;
42 /* avoid confusing an empty string with NULL */
43 if (p == NULL)
44 return;
46 appendStringInfoCharMacro(buf, '"');
47 while ((c = *p++) != '\0')
49 if (c == '"')
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.
62 void
63 write_csvlog(ErrorData *edata)
65 StringInfoData buf;
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
77 * MyProcPid changes.
79 if (log_my_pid != MyProcPid)
81 log_line_number = 0;
82 log_my_pid = MyProcPid;
83 reset_formatted_start_time();
85 log_line_number++;
87 initStringInfo(&buf);
89 /* timestamp with milliseconds */
90 appendStringInfoString(&buf, get_formatted_log_time());
91 appendStringInfoChar(&buf, ',');
93 /* username */
94 if (MyProcPort)
95 appendCSVLiteral(&buf, MyProcPort->user_name);
96 appendStringInfoChar(&buf, ',');
98 /* database name */
99 if (MyProcPort)
100 appendCSVLiteral(&buf, MyProcPort->database_name);
101 appendStringInfoChar(&buf, ',');
103 /* Process id */
104 if (MyProcPid != 0)
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, ',');
122 /* session id */
123 appendStringInfo(&buf, "%" INT64_MODIFIER "x.%x", MyStartTime, MyProcPid);
124 appendStringInfoChar(&buf, ',');
126 /* Line number */
127 appendStringInfo(&buf, "%ld", log_line_number);
128 appendStringInfoChar(&buf, ',');
130 /* PS display */
131 if (MyProcPort)
133 StringInfoData msgbuf;
134 const char *psdisp;
135 int displen;
137 initStringInfo(&msgbuf);
139 psdisp = get_ps_display(&displen);
140 appendBinaryStringInfo(&msgbuf, psdisp, displen);
141 appendCSVLiteral(&buf, msgbuf.data);
143 pfree(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, ',');
157 /* Transaction id */
158 appendStringInfo(&buf, "%u", GetTopTransactionIdIfAny());
159 appendStringInfoChar(&buf, ',');
161 /* Error severity */
162 appendStringInfoString(&buf, _(error_severity(edata->elevel)));
163 appendStringInfoChar(&buf, ',');
165 /* SQL state code */
166 appendStringInfoString(&buf, unpack_sql_state(edata->sqlerrcode));
167 appendStringInfoChar(&buf, ',');
169 /* errmessage */
170 appendCSVLiteral(&buf, edata->message);
171 appendStringInfoChar(&buf, ',');
173 /* errdetail or errdetail_log */
174 if (edata->detail_log)
175 appendCSVLiteral(&buf, edata->detail_log);
176 else
177 appendCSVLiteral(&buf, edata->detail);
178 appendStringInfoChar(&buf, ',');
180 /* errhint */
181 appendCSVLiteral(&buf, edata->hint);
182 appendStringInfoChar(&buf, ',');
184 /* internal query */
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, ',');
193 /* errcontext */
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);
200 if (print_stmt)
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,
217 edata->lineno);
218 else if (edata->filename)
219 appendStringInfo(&msgbuf, "%s:%d",
220 edata->filename, edata->lineno);
221 appendCSVLiteral(&buf, msgbuf.data);
222 pfree(msgbuf.data);
224 appendStringInfoChar(&buf, ',');
226 /* application name */
227 if (application_name)
228 appendCSVLiteral(&buf, application_name);
230 appendStringInfoChar(&buf, ',');
232 /* backend type */
233 appendCSVLiteral(&buf, get_backend_type_for_log());
234 appendStringInfoChar(&buf, ',');
236 /* leader PID */
237 if (MyProc)
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, ',');
250 /* query id */
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);
258 else
259 write_pipe_chunks(buf.data, buf.len, LOG_DESTINATION_CSVLOG);
261 pfree(buf.data);