PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
jsonlog.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * jsonlog.c
4 * JSON logging
5 *
6 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/utils/error/jsonlog.c
12 *
13 *-------------------------------------------------------------------------
14 */
15
16#include "postgres.h"
17
18#include "access/xact.h"
19#include "libpq/libpq-be.h"
20#include "lib/stringinfo.h"
21#include "miscadmin.h"
23#include "storage/lock.h"
24#include "storage/proc.h"
25#include "tcop/tcopprot.h"
27#include "utils/guc.h"
28#include "utils/json.h"
29#include "utils/ps_status.h"
30
31static void appendJSONKeyValueFmt(StringInfo buf, const char *key,
32 bool escape_key,
33 const char *fmt,...) pg_attribute_printf(4, 5);
34
35/*
36 * appendJSONKeyValue
37 *
38 * Append to a StringInfo a comma followed by a JSON key and a value.
39 * The key is always escaped. The value can be escaped optionally, that
40 * is dependent on the data type of the key.
41 */
42static void
43appendJSONKeyValue(StringInfo buf, const char *key, const char *value,
44 bool escape_value)
45{
46 Assert(key != NULL);
47
48 if (value == NULL)
49 return;
50
54
55 if (escape_value)
57 else
59}
60
61
62/*
63 * appendJSONKeyValueFmt
64 *
65 * Evaluate the fmt string and then invoke appendJSONKeyValue() as the
66 * value of the JSON property. Both the key and value will be escaped by
67 * appendJSONKeyValue().
68 */
69static void
71 bool escape_key, const char *fmt,...)
72{
73 int save_errno = errno;
74 size_t len = 128; /* initial assumption about buffer size */
75 char *value;
76
77 for (;;)
78 {
79 va_list args;
80 size_t newlen;
81
82 /* Allocate result buffer */
83 value = (char *) palloc(len);
84
85 /* Try to format the data. */
86 errno = save_errno;
88 newlen = pvsnprintf(value, len, fmt, args);
89 va_end(args);
90
91 if (newlen < len)
92 break; /* success */
93
94 /* Release buffer and loop around to try again with larger len. */
95 pfree(value);
96 len = newlen;
97 }
98
99 appendJSONKeyValue(buf, key, value, escape_key);
100
101 /* Clean up */
102 pfree(value);
103}
104
105/*
106 * Write logs in json format.
107 */
108void
110{
112 char *start_time;
113 char *log_time;
114
115 /* static counter for line numbers */
116 static long log_line_number = 0;
117
118 /* Has the counter been reset in the current process? */
119 static int log_my_pid = 0;
120
121 /*
122 * This is one of the few places where we'd rather not inherit a static
123 * variable's value from the postmaster. But since we will, reset it when
124 * MyProcPid changes.
125 */
126 if (log_my_pid != MyProcPid)
127 {
128 log_line_number = 0;
129 log_my_pid = MyProcPid;
131 }
132 log_line_number++;
133
135
136 /* Initialize string */
138
139 /* timestamp with milliseconds */
140 log_time = get_formatted_log_time();
141
142 /*
143 * First property does not use appendJSONKeyValue as it does not have
144 * comma prefix.
145 */
146 escape_json(&buf, "timestamp");
148 escape_json(&buf, log_time);
149
150 /* username */
151 if (MyProcPort)
152 appendJSONKeyValue(&buf, "user", MyProcPort->user_name, true);
153
154 /* database name */
155 if (MyProcPort)
157
158 /* Process ID */
159 if (MyProcPid != 0)
160 appendJSONKeyValueFmt(&buf, "pid", false, "%d", MyProcPid);
161
162 /* Remote host and port */
164 {
165 appendJSONKeyValue(&buf, "remote_host", MyProcPort->remote_host, true);
166 if (MyProcPort->remote_port && MyProcPort->remote_port[0] != '\0')
167 appendJSONKeyValue(&buf, "remote_port", MyProcPort->remote_port, false);
168 }
169
170 /* Session id */
171 appendJSONKeyValueFmt(&buf, "session_id", true, INT64_HEX_FORMAT ".%x",
173
174 /* Line number */
175 appendJSONKeyValueFmt(&buf, "line_num", false, "%ld", log_line_number);
176
177 /* PS display */
178 if (MyProcPort)
179 {
180 StringInfoData msgbuf;
181 const char *psdisp;
182 int displen;
183
184 initStringInfo(&msgbuf);
185 psdisp = get_ps_display(&displen);
186 appendBinaryStringInfo(&msgbuf, psdisp, displen);
187 appendJSONKeyValue(&buf, "ps", msgbuf.data, true);
188
189 pfree(msgbuf.data);
190 }
191
192 /* session start timestamp */
194 appendJSONKeyValue(&buf, "session_start", start_time, true);
195
196 /* Virtual transaction id */
197 /* keep VXID format in sync with lockfuncs.c */
199 appendJSONKeyValueFmt(&buf, "vxid", true, "%d/%u",
201
202 /* Transaction id */
203 appendJSONKeyValueFmt(&buf, "txid", false, "%u",
205
206 /* Error severity */
207 if (edata->elevel)
208 appendJSONKeyValue(&buf, "error_severity",
209 (char *) error_severity(edata->elevel), true);
210
211 /* SQL state code */
212 if (edata->sqlerrcode)
213 appendJSONKeyValue(&buf, "state_code",
214 unpack_sql_state(edata->sqlerrcode), true);
215
216 /* errmessage */
217 appendJSONKeyValue(&buf, "message", edata->message, true);
218
219 /* errdetail or error_detail log */
220 if (edata->detail_log)
221 appendJSONKeyValue(&buf, "detail", edata->detail_log, true);
222 else
223 appendJSONKeyValue(&buf, "detail", edata->detail, true);
224
225 /* errhint */
226 if (edata->hint)
227 appendJSONKeyValue(&buf, "hint", edata->hint, true);
228
229 /* internal query */
230 if (edata->internalquery)
231 appendJSONKeyValue(&buf, "internal_query", edata->internalquery,
232 true);
233
234 /* if printed internal query, print internal pos too */
235 if (edata->internalpos > 0 && edata->internalquery != NULL)
236 appendJSONKeyValueFmt(&buf, "internal_position", false, "%d",
237 edata->internalpos);
238
239 /* errcontext */
240 if (edata->context && !edata->hide_ctx)
241 appendJSONKeyValue(&buf, "context", edata->context, true);
242
243 /* user query --- only reported if not disabled by the caller */
244 if (check_log_of_query(edata))
245 {
246 appendJSONKeyValue(&buf, "statement", debug_query_string, true);
247 if (edata->cursorpos > 0)
248 appendJSONKeyValueFmt(&buf, "cursor_position", false, "%d",
249 edata->cursorpos);
250 }
251
252 /* file error location */
254 {
255 if (edata->funcname)
256 appendJSONKeyValue(&buf, "func_name", edata->funcname, true);
257 if (edata->filename)
258 {
259 appendJSONKeyValue(&buf, "file_name", edata->filename, true);
260 appendJSONKeyValueFmt(&buf, "file_line_num", false, "%d",
261 edata->lineno);
262 }
263 }
264
265 /* Application name */
266 if (application_name && application_name[0] != '\0')
267 appendJSONKeyValue(&buf, "application_name", application_name, true);
268
269 /* backend type */
270 appendJSONKeyValue(&buf, "backend_type", get_backend_type_for_log(), true);
271
272 /* leader PID */
273 if (MyProc)
274 {
275 PGPROC *leader = MyProc->lockGroupLeader;
276
277 /*
278 * Show the leader only for active parallel workers. This leaves out
279 * the leader of a parallel group.
280 */
281 if (leader && leader->pid != MyProcPid)
282 appendJSONKeyValueFmt(&buf, "leader_pid", false, "%d",
283 leader->pid);
284 }
285
286 /* query id */
287 appendJSONKeyValueFmt(&buf, "query_id", false, "%lld",
288 (long long) pgstat_get_my_query_id());
289
290 /* Finish string */
293
294 /* If in the syslogger process, try to write messages direct to file */
295 if (MyBackendType == B_LOGGER)
297 else
299
300 pfree(buf.data);
301}
uint64 pgstat_get_my_query_id(void)
#define INT64_HEX_FORMAT
Definition: c.h:505
#define Assert(condition)
Definition: c.h:812
#define pg_attribute_printf(f, a)
Definition: c.h:210
bool check_log_of_query(ErrorData *edata)
Definition: elog.c:2731
const char * error_severity(int elevel)
Definition: elog.c:3670
int Log_error_verbosity
Definition: elog.c:108
char * get_formatted_start_time(void)
Definition: elog.c:2707
void write_pipe_chunks(char *data, int len, int dest)
Definition: elog.c:3429
const char * get_backend_type_for_log(void)
Definition: elog.c:2754
char * get_formatted_log_time(void)
Definition: elog.c:2657
char * unpack_sql_state(int sql_state)
Definition: elog.c:3169
void reset_formatted_start_time(void)
Definition: elog.c:2695
@ PGERROR_VERBOSE
Definition: elog.h:482
#define LOG_DESTINATION_JSONLOG
Definition: elog.h:497
int MyProcPid
Definition: globals.c:46
struct Port * MyProcPort
Definition: globals.c:50
pg_time_t MyStartTime
Definition: globals.c:47
char * application_name
Definition: guc_tables.c:543
static struct @161 value
void escape_json(StringInfo buf, const char *str)
Definition: json.c:1602
void write_jsonlog(ErrorData *edata)
Definition: jsonlog.c:109
static void static void appendJSONKeyValue(StringInfo buf, const char *key, const char *value, bool escape_value)
Definition: jsonlog.c:43
static void appendJSONKeyValueFmt(StringInfo buf, const char *key, bool escape_key, const char *fmt,...) pg_attribute_printf(4
Definition: jsonlog.c:70
static void const char * fmt
va_end(args)
va_start(args, fmt)
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc(Size size)
Definition: mcxt.c:1317
@ B_LOGGER
Definition: miscadmin.h:372
BackendType MyBackendType
Definition: miscinit.c:64
const void size_t len
static time_t start_time
Definition: pg_ctl.c:95
static char * buf
Definition: pg_test_fsync.c:72
const char * debug_query_string
Definition: postgres.c:87
#define INVALID_PROC_NUMBER
Definition: procnumber.h:26
const char * get_ps_display(int *displen)
Definition: ps_status.c:532
size_t pvsnprintf(char *buf, size_t len, const char *fmt, va_list args)
Definition: psprintf.c:103
PGPROC * MyProc
Definition: proc.c:66
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:230
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:179
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:191
void initStringInfo(StringInfo str)
Definition: stringinfo.c:56
int internalpos
Definition: elog.h:453
char * context
Definition: elog.h:444
char * internalquery
Definition: elog.h:454
int sqlerrcode
Definition: elog.h:439
const char * filename
Definition: elog.h:434
int elevel
Definition: elog.h:429
char * detail
Definition: elog.h:441
const char * funcname
Definition: elog.h:436
char * message
Definition: elog.h:440
char * detail_log
Definition: elog.h:442
int lineno
Definition: elog.h:435
char * hint
Definition: elog.h:443
bool hide_ctx
Definition: elog.h:433
int cursorpos
Definition: elog.h:452
Definition: proc.h:162
LocalTransactionId lxid
Definition: proc.h:200
struct PGPROC::@123 vxid
ProcNumber procNumber
Definition: proc.h:195
int pid
Definition: proc.h:182
PGPROC * lockGroupLeader
Definition: proc.h:304
char * user_name
Definition: libpq-be.h:152
char * remote_port
Definition: libpq-be.h:144
char * database_name
Definition: libpq-be.h:151
char * remote_host
Definition: libpq-be.h:139
void write_syslogger_file(const char *buffer, int count, int destination)
Definition: syslogger.c:1093
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:440