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-2022, 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.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/json.h"
31 #include "utils/ps_status.h"
32 
33 static void appendJSONKeyValueFmt(StringInfo buf, const char *key,
34  bool escape_key,
35  const char *fmt,...) pg_attribute_printf(4, 5);
36 
37 /*
38  * appendJSONKeyValue
39  *
40  * Append to a StringInfo a comma followed by a JSON key and a value.
41  * The key is always escaped. The value can be escaped optionally, that
42  * is dependent on the data type of the key.
43  */
44 static void
45 appendJSONKeyValue(StringInfo buf, const char *key, const char *value,
46  bool escape_value)
47 {
48  Assert(key != NULL);
49 
50  if (value == NULL)
51  return;
52 
56 
57  if (escape_value)
59  else
61 }
62 
63 
64 /*
65  * appendJSONKeyValueFmt
66  *
67  * Evaluate the fmt string and then invoke appendJSONKeyValue() as the
68  * value of the JSON property. Both the key and value will be escaped by
69  * appendJSONKeyValue().
70  */
71 static void
73  bool escape_key, const char *fmt,...)
74 {
75  int save_errno = errno;
76  size_t len = 128; /* initial assumption about buffer size */
77  char *value;
78 
79  for (;;)
80  {
81  va_list args;
82  size_t newlen;
83 
84  /* Allocate result buffer */
85  value = (char *) palloc(len);
86 
87  /* Try to format the data. */
88  errno = save_errno;
89  va_start(args, fmt);
90  newlen = pvsnprintf(value, len, fmt, args);
91  va_end(args);
92 
93  if (newlen < len)
94  break; /* success */
95 
96  /* Release buffer and loop around to try again with larger len. */
97  pfree(value);
98  len = newlen;
99  }
100 
101  appendJSONKeyValue(buf, key, value, escape_key);
102 
103  /* Clean up */
104  pfree(value);
105 }
106 
107 /*
108  * Write logs in json format.
109  */
110 void
112 {
114  char *start_time;
115  char *log_time;
116 
117  /* static counter for line numbers */
118  static long log_line_number = 0;
119 
120  /* Has the counter been reset in the current process? */
121  static int log_my_pid = 0;
122 
123  /*
124  * This is one of the few places where we'd rather not inherit a static
125  * variable's value from the postmaster. But since we will, reset it when
126  * MyProcPid changes.
127  */
128  if (log_my_pid != MyProcPid)
129  {
130  log_line_number = 0;
131  log_my_pid = MyProcPid;
133  }
134  log_line_number++;
135 
137 
138  /* Initialize string */
139  appendStringInfoChar(&buf, '{');
140 
141  /* timestamp with milliseconds */
142  log_time = get_formatted_log_time();
143 
144  /*
145  * First property does not use appendJSONKeyValue as it does not have
146  * comma prefix.
147  */
148  escape_json(&buf, "timestamp");
149  appendStringInfoChar(&buf, ':');
150  escape_json(&buf, log_time);
151 
152  /* username */
153  if (MyProcPort)
154  appendJSONKeyValue(&buf, "user", MyProcPort->user_name, true);
155 
156  /* database name */
157  if (MyProcPort)
158  appendJSONKeyValue(&buf, "dbname", MyProcPort->database_name, true);
159 
160  /* Process ID */
161  if (MyProcPid != 0)
162  appendJSONKeyValueFmt(&buf, "pid", false, "%d", MyProcPid);
163 
164  /* Remote host and port */
166  {
167  appendJSONKeyValue(&buf, "remote_host", MyProcPort->remote_host, true);
168  if (MyProcPort->remote_port && MyProcPort->remote_port[0] != '\0')
169  appendJSONKeyValue(&buf, "remote_port", MyProcPort->remote_port, false);
170  }
171 
172  /* Session id */
173  appendJSONKeyValueFmt(&buf, "session_id", true, "%lx.%x",
174  (long) MyStartTime, MyProcPid);
175 
176  /* Line number */
177  appendJSONKeyValueFmt(&buf, "line_num", false, "%ld", log_line_number);
178 
179  /* PS display */
180  if (MyProcPort)
181  {
182  StringInfoData msgbuf;
183  const char *psdisp;
184  int displen;
185 
186  initStringInfo(&msgbuf);
187  psdisp = get_ps_display(&displen);
188  appendBinaryStringInfo(&msgbuf, psdisp, displen);
189  appendJSONKeyValue(&buf, "ps", msgbuf.data, true);
190 
191  pfree(msgbuf.data);
192  }
193 
194  /* session start timestamp */
196  appendJSONKeyValue(&buf, "session_start", start_time, true);
197 
198  /* Virtual transaction id */
199  /* keep VXID format in sync with lockfuncs.c */
200  if (MyProc != NULL && MyProc->backendId != InvalidBackendId)
201  appendJSONKeyValueFmt(&buf, "vxid", true, "%d/%u", MyProc->backendId,
202  MyProc->lxid);
203 
204  /* Transaction id */
205  appendJSONKeyValueFmt(&buf, "txid", false, "%u",
207 
208  /* Error severity */
209  if (edata->elevel)
210  appendJSONKeyValue(&buf, "error_severity",
211  (char *) error_severity(edata->elevel), true);
212 
213  /* SQL state code */
214  if (edata->sqlerrcode)
215  appendJSONKeyValue(&buf, "state_code",
216  unpack_sql_state(edata->sqlerrcode), true);
217 
218  /* errmessage */
219  appendJSONKeyValue(&buf, "message", edata->message, true);
220 
221  /* errdetail or error_detail log */
222  if (edata->detail_log)
223  appendJSONKeyValue(&buf, "detail", edata->detail_log, true);
224  else
225  appendJSONKeyValue(&buf, "detail", edata->detail, true);
226 
227  /* errhint */
228  if (edata->hint)
229  appendJSONKeyValue(&buf, "hint", edata->hint, true);
230 
231  /* internal query */
232  if (edata->internalquery)
233  appendJSONKeyValue(&buf, "internal_query", edata->internalquery,
234  true);
235 
236  /* if printed internal query, print internal pos too */
237  if (edata->internalpos > 0 && edata->internalquery != NULL)
238  appendJSONKeyValueFmt(&buf, "internal_position", false, "%d",
239  edata->internalpos);
240 
241  /* errcontext */
242  if (edata->context && !edata->hide_ctx)
243  appendJSONKeyValue(&buf, "context", edata->context, true);
244 
245  /* user query --- only reported if not disabled by the caller */
246  if (check_log_of_query(edata))
247  {
248  appendJSONKeyValue(&buf, "statement", debug_query_string, true);
249  if (edata->cursorpos > 0)
250  appendJSONKeyValueFmt(&buf, "cursor_position", false, "%d",
251  edata->cursorpos);
252  }
253 
254  /* file error location */
256  {
257  if (edata->funcname)
258  appendJSONKeyValue(&buf, "func_name", edata->funcname, true);
259  if (edata->filename)
260  {
261  appendJSONKeyValue(&buf, "file_name", edata->filename, true);
262  appendJSONKeyValueFmt(&buf, "file_line_num", false, "%d",
263  edata->lineno);
264  }
265  }
266 
267  /* Application name */
268  if (application_name && application_name[0] != '\0')
269  appendJSONKeyValue(&buf, "application_name", application_name, true);
270 
271  /* backend type */
272  appendJSONKeyValue(&buf, "backend_type", get_backend_type_for_log(), true);
273 
274  /* leader PID */
275  if (MyProc)
276  {
277  PGPROC *leader = MyProc->lockGroupLeader;
278 
279  /*
280  * Show the leader only for active parallel workers. This leaves out
281  * the leader of a parallel group.
282  */
283  if (leader && leader->pid != MyProcPid)
284  appendJSONKeyValueFmt(&buf, "leader_pid", false, "%d",
285  leader->pid);
286  }
287 
288  /* query id */
289  appendJSONKeyValueFmt(&buf, "query_id", false, "%lld",
290  (long long) pgstat_get_my_query_id());
291 
292  /* Finish string */
293  appendStringInfoChar(&buf, '}');
294  appendStringInfoChar(&buf, '\n');
295 
296  /* If in the syslogger process, try to write messages direct to file */
297  if (MyBackendType == B_LOGGER)
299  else
301 
302  pfree(buf.data);
303 }
uint64 pgstat_get_my_query_id(void)
#define InvalidBackendId
Definition: backendid.h:23
#define pg_attribute_printf(f, a)
Definition: c.h:164
bool check_log_of_query(ErrorData *edata)
Definition: elog.c:2369
char * get_formatted_log_time(void)
Definition: elog.c:2295
int Log_error_verbosity
Definition: elog.c:109
const char * error_severity(int elevel)
Definition: elog.c:3299
const char * get_backend_type_for_log(void)
Definition: elog.c:2392
void write_pipe_chunks(char *data, int len, int dest)
Definition: elog.c:3061
char * unpack_sql_state(int sql_state)
Definition: elog.c:2798
char * get_formatted_start_time(void)
Definition: elog.c:2345
void reset_formatted_start_time(void)
Definition: elog.c:2333
@ PGERROR_VERBOSE
Definition: elog.h:410
#define LOG_DESTINATION_JSONLOG
Definition: elog.h:425
int MyProcPid
Definition: globals.c:44
struct Port * MyProcPort
Definition: globals.c:47
pg_time_t MyStartTime
Definition: globals.c:45
char * application_name
Definition: guc.c:661
static struct @151 value
void escape_json(StringInfo buf, const char *str)
Definition: json.c:1587
void write_jsonlog(ErrorData *edata)
Definition: jsonlog.c:111
static void static void appendJSONKeyValue(StringInfo buf, const char *key, const char *value, bool escape_value)
Definition: jsonlog.c:45
static void appendJSONKeyValueFmt(StringInfo buf, const char *key, bool escape_key, const char *fmt,...) pg_attribute_printf(4
Definition: jsonlog.c:72
va_end(args)
Assert(fmt[strlen(fmt) - 1] !='\n')
static void const char * fmt
va_start(args, fmt)
void pfree(void *pointer)
Definition: mcxt.c:1175
void * palloc(Size size)
Definition: mcxt.c:1068
@ B_LOGGER
Definition: miscadmin.h:338
BackendType MyBackendType
Definition: miscinit.c:63
const void size_t len
static time_t start_time
Definition: pg_ctl.c:99
static char * buf
Definition: pg_test_fsync.c:67
const char * debug_query_string
Definition: postgres.c:89
const char * get_ps_display(int *displen)
Definition: ps_status.c:430
size_t pvsnprintf(char *buf, size_t len, const char *fmt, va_list args)
Definition: psprintf.c:106
PGPROC * MyProc
Definition: proc.c:68
void appendBinaryStringInfo(StringInfo str, const char *data, int datalen)
Definition: stringinfo.c:227
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
int internalpos
Definition: elog.h:381
char * context
Definition: elog.h:372
char * internalquery
Definition: elog.h:382
int sqlerrcode
Definition: elog.h:367
const char * filename
Definition: elog.h:362
int elevel
Definition: elog.h:357
char * detail
Definition: elog.h:369
const char * funcname
Definition: elog.h:364
char * message
Definition: elog.h:368
char * detail_log
Definition: elog.h:370
int lineno
Definition: elog.h:363
char * hint
Definition: elog.h:371
bool hide_ctx
Definition: elog.h:361
int cursorpos
Definition: elog.h:380
Definition: proc.h:161
LocalTransactionId lxid
Definition: proc.h:182
BackendId backendId
Definition: proc.h:192
int pid
Definition: proc.h:185
PGPROC * lockGroupLeader
Definition: proc.h:290
char * user_name
Definition: libpq-be.h:145
char * remote_port
Definition: libpq-be.h:136
char * database_name
Definition: libpq-be.h:144
char * remote_host
Definition: libpq-be.h:131
void write_syslogger_file(const char *buffer, int count, int destination)
Definition: syslogger.c:1143
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:428