PostgreSQL Source Code  git master
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"
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/json.h"
29 #include "utils/ps_status.h"
30 
31 static 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  */
42 static void
43 appendJSONKeyValue(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  */
69 static 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;
87  va_start(args, fmt);
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  */
108 void
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 */
137  appendStringInfoChar(&buf, '{');
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");
147  appendStringInfoChar(&buf, ':');
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)
156  appendJSONKeyValue(&buf, "dbname", MyProcPort->database_name, true);
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, "%lx.%x",
172  (long) MyStartTime, MyProcPid);
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 */
198  if (MyProc != NULL && MyProc->vxid.procNumber != INVALID_PROC_NUMBER)
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 */
291  appendStringInfoChar(&buf, '}');
292  appendStringInfoChar(&buf, '\n');
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 Assert(condition)
Definition: c.h:858
#define pg_attribute_printf(f, a)
Definition: c.h:191
bool check_log_of_query(ErrorData *edata)
Definition: elog.c:2695
char * get_formatted_log_time(void)
Definition: elog.c:2621
int Log_error_verbosity
Definition: elog.c:110
const char * error_severity(int elevel)
Definition: elog.c:3634
const char * get_backend_type_for_log(void)
Definition: elog.c:2718
void write_pipe_chunks(char *data, int len, int dest)
Definition: elog.c:3393
char * unpack_sql_state(int sql_state)
Definition: elog.c:3133
char * get_formatted_start_time(void)
Definition: elog.c:2671
void reset_formatted_start_time(void)
Definition: elog.c:2659
@ PGERROR_VERBOSE
Definition: elog.h:481
#define LOG_DESTINATION_JSONLOG
Definition: elog.h:496
int MyProcPid
Definition: globals.c:45
struct Port * MyProcPort
Definition: globals.c:49
pg_time_t MyStartTime
Definition: globals.c:46
char * application_name
Definition: guc_tables.c:545
static struct @155 value
void escape_json(StringInfo buf, const char *str)
Definition: json.c:1549
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:1520
void * palloc(Size size)
Definition: mcxt.c:1316
@ B_LOGGER
Definition: miscadmin.h:367
BackendType MyBackendType
Definition: miscinit.c:63
const void size_t len
static time_t start_time
Definition: pg_ctl.c:94
static char * buf
Definition: pg_test_fsync.c:73
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:530
size_t pvsnprintf(char *buf, size_t len, const char *fmt, va_list args)
Definition: psprintf.c:106
PGPROC * MyProc
Definition: proc.c:66
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:233
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:182
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:194
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
int internalpos
Definition: elog.h:452
char * context
Definition: elog.h:443
char * internalquery
Definition: elog.h:453
int sqlerrcode
Definition: elog.h:438
const char * filename
Definition: elog.h:433
int elevel
Definition: elog.h:428
char * detail
Definition: elog.h:440
const char * funcname
Definition: elog.h:435
char * message
Definition: elog.h:439
char * detail_log
Definition: elog.h:441
int lineno
Definition: elog.h:434
char * hint
Definition: elog.h:442
bool hide_ctx
Definition: elog.h:432
int cursorpos
Definition: elog.h:451
Definition: proc.h:157
LocalTransactionId lxid
Definition: proc.h:196
ProcNumber procNumber
Definition: proc.h:191
int pid
Definition: proc.h:178
PGPROC * lockGroupLeader
Definition: proc.h:300
struct PGPROC::@117 vxid
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:1094
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:438