/*-------------------------------------------------------------------------
*
* jsonlog . c
* JSON logging
*
* Portions Copyright ( c ) 1996 - 2025 , PostgreSQL Global Development Group
* Portions Copyright ( c ) 1994 , Regents of the University of California
*
*
* IDENTIFICATION
* src / backend / utils / error / jsonlog . c
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
#include "postgres.h"
#include "access/xact.h"
#include "libpq/libpq-be.h"
#include "lib/stringinfo.h"
#include "miscadmin.h"
#include "postmaster/syslogger.h"
#include "storage/lock.h"
#include "storage/proc.h"
#include "tcop/tcopprot.h"
#include "utils/backend_status.h"
#include "utils/guc.h"
#include "utils/json.h"
#include "utils/ps_status.h"
static void appendJSONKeyValueFmt(StringInfo buf, const char *key,
bool escape_key,
const char *fmt,...) pg_attribute_printf(4 , 5 );
/*
* appendJSONKeyValue
*
* Append to a StringInfo a comma followed by a JSON key and a value .
* The key is always escaped . The value can be escaped optionally , that
* is dependent on the data type of the key .
*/
static void
appendJSONKeyValue(StringInfo buf, const char *key, const char *value,
bool escape_value)
{
Assert(key != NULL);
if (value == NULL)
return ;
appendStringInfoChar(buf, ',' );
escape_json(buf, key);
appendStringInfoChar(buf, ':' );
if (escape_value)
escape_json(buf, value);
else
appendStringInfoString(buf, value);
}
/*
* appendJSONKeyValueFmt
*
* Evaluate the fmt string and then invoke appendJSONKeyValue ( ) as the
* value of the JSON property . Both the key and value will be escaped by
* appendJSONKeyValue ( ) .
*/
static void
appendJSONKeyValueFmt(StringInfo buf, const char *key,
bool escape_key, const char *fmt,...)
{
int save_errno = errno;
size_t len = 128 ; /* initial assumption about buffer size */
char *value;
for (;;)
{
va_list args;
size_t newlen;
/* Allocate result buffer */
value = (char *) palloc(len);
/* Try to format the data. */
errno = save_errno;
va_start(args, fmt);
newlen = pvsnprintf(value, len, fmt, args);
va_end(args);
if (newlen < len)
break ; /* success */
/* Release buffer and loop around to try again with larger len. */
pfree(value);
len = newlen;
}
appendJSONKeyValue(buf, key, value, escape_key);
/* Clean up */
pfree(value);
}
/*
* Write logs in json format .
*/
void
write_jsonlog(ErrorData *edata)
{
StringInfoData buf;
char *start_time;
char *log_time;
/* static counter for line numbers */
static long log_line_number = 0 ;
/* Has the counter been reset in the current process? */
static int log_my_pid = 0 ;
/*
* This is one of the few places where we ' d rather not inherit a static
* variable ' s value from the postmaster . But since we will , reset it when
* MyProcPid changes .
*/
if (log_my_pid != MyProcPid)
{
log_line_number = 0 ;
log_my_pid = MyProcPid;
reset_formatted_start_time();
}
log_line_number++;
initStringInfo(&buf);
/* Initialize string */
appendStringInfoChar(&buf, '{' );
/* timestamp with milliseconds */
log_time = get_formatted_log_time();
/*
* First property does not use appendJSONKeyValue as it does not have
* comma prefix .
*/
escape_json(&buf, "timestamp" );
appendStringInfoChar(&buf, ':' );
escape_json(&buf, log_time);
/* username */
if (MyProcPort)
appendJSONKeyValue(&buf, "user" , MyProcPort->user_name, true );
/* database name */
if (MyProcPort)
appendJSONKeyValue(&buf, "dbname" , MyProcPort->database_name, true );
/* Process ID */
if (MyProcPid != 0 )
appendJSONKeyValueFmt(&buf, "pid" , false , "%d" , MyProcPid);
/* Remote host and port */
if (MyProcPort && MyProcPort->remote_host)
{
appendJSONKeyValue(&buf, "remote_host" , MyProcPort->remote_host, true );
if (MyProcPort->remote_port && MyProcPort->remote_port[0 ] != '\0' )
appendJSONKeyValue(&buf, "remote_port" , MyProcPort->remote_port, false );
}
/* Session id */
appendJSONKeyValueFmt(&buf, "session_id" , true , "%" PRIx64 ".%x" ,
MyStartTime, MyProcPid);
/* Line number */
appendJSONKeyValueFmt(&buf, "line_num" , false , "%ld" , log_line_number);
/* PS display */
if (MyProcPort)
{
StringInfoData msgbuf;
const char *psdisp;
int displen;
initStringInfo(&msgbuf);
psdisp = get_ps_display(&displen);
appendBinaryStringInfo(&msgbuf, psdisp, displen);
appendJSONKeyValue(&buf, "ps" , msgbuf.data, true );
pfree(msgbuf.data);
}
/* session start timestamp */
start_time = get_formatted_start_time();
appendJSONKeyValue(&buf, "session_start" , start_time, true );
/* Virtual transaction id */
/* keep VXID format in sync with lockfuncs.c */
if (MyProc != NULL && MyProc->vxid.procNumber != INVALID_PROC_NUMBER)
appendJSONKeyValueFmt(&buf, "vxid" , true , "%d/%u" ,
MyProc->vxid.procNumber, MyProc->vxid.lxid);
/* Transaction id */
appendJSONKeyValueFmt(&buf, "txid" , false , "%u" ,
GetTopTransactionIdIfAny());
/* Error severity */
if (edata->elevel)
appendJSONKeyValue(&buf, "error_severity" ,
error_severity(edata->elevel), true );
/* SQL state code */
if (edata->sqlerrcode)
appendJSONKeyValue(&buf, "state_code" ,
unpack_sql_state(edata->sqlerrcode), true );
/* errmessage */
appendJSONKeyValue(&buf, "message" , edata->message, true );
/* errdetail or error_detail log */
if (edata->detail_log)
appendJSONKeyValue(&buf, "detail" , edata->detail_log, true );
else
appendJSONKeyValue(&buf, "detail" , edata->detail, true );
/* errhint */
if (edata->hint)
appendJSONKeyValue(&buf, "hint" , edata->hint, true );
/* internal query */
if (edata->internalquery)
appendJSONKeyValue(&buf, "internal_query" , edata->internalquery,
true );
/* if printed internal query, print internal pos too */
if (edata->internalpos > 0 && edata->internalquery != NULL)
appendJSONKeyValueFmt(&buf, "internal_position" , false , "%d" ,
edata->internalpos);
/* errcontext */
if (edata->context && !edata->hide_ctx)
appendJSONKeyValue(&buf, "context" , edata->context, true );
/* user query --- only reported if not disabled by the caller */
if (check_log_of_query(edata))
{
appendJSONKeyValue(&buf, "statement" , debug_query_string, true );
if (edata->cursorpos > 0 )
appendJSONKeyValueFmt(&buf, "cursor_position" , false , "%d" ,
edata->cursorpos);
}
/* file error location */
if (Log_error_verbosity >= PGERROR_VERBOSE)
{
if (edata->funcname)
appendJSONKeyValue(&buf, "func_name" , edata->funcname, true );
if (edata->filename)
{
appendJSONKeyValue(&buf, "file_name" , edata->filename, true );
appendJSONKeyValueFmt(&buf, "file_line_num" , false , "%d" ,
edata->lineno);
}
}
/* Application name */
if (application_name && application_name[0 ] != '\0' )
appendJSONKeyValue(&buf, "application_name" , application_name, true );
/* backend type */
appendJSONKeyValue(&buf, "backend_type" , get_backend_type_for_log(), true );
/* leader PID */
if (MyProc)
{
PGPROC *leader = MyProc->lockGroupLeader;
/*
* Show the leader only for active parallel workers . This leaves out
* the leader of a parallel group .
*/
if (leader && leader->pid != MyProcPid)
appendJSONKeyValueFmt(&buf, "leader_pid" , false , "%d" ,
leader->pid);
}
/* query id */
appendJSONKeyValueFmt(&buf, "query_id" , false , "%" PRId64,
pgstat_get_my_query_id());
/* Finish string */
appendStringInfoChar(&buf, '}' );
appendStringInfoChar(&buf, '\n' );
/* If in the syslogger process, try to write messages direct to file */
if (MyBackendType == B_LOGGER)
write_syslogger_file(buf.data, buf.len, LOG_DESTINATION_JSONLOG);
else
write_pipe_chunks(buf.data, buf.len, LOG_DESTINATION_JSONLOG);
pfree(buf.data);
}
Messung V0.5 in Prozent C=92 H=97 G=94
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-08-08)
¤
*© Formatika GbR, Deutschland