mirror of
https://github.com/postgres/postgres.git
synced 2025-08-09 17:03:00 +03:00
The recent refactoring done in ac7c807
makes this move possible and
simple, as this just moves some code around. This reduces the size of
elog.c by 7%.
Author: Michael Paquier, Sehrope Sarkuni
Reviewed-by: Nathan Bossart
Discussion: https://postgr.es/m/CAH7T-aqswBM6JWe4pDehi1uOiufqe06DJWaU5=X7dDLyqUExHg@mail.gmail.com
simply moves the routines related to csvlog into their own file
265 lines
6.7 KiB
C
265 lines
6.7 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* csvlog.c
|
|
* CSV logging
|
|
*
|
|
* Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of Californi
|
|
*
|
|
*
|
|
* IDENTIFICATION
|
|
* src/backend/utils/error/csvlog.c
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
#include "access/xact.h"
|
|
#include "libpq/libpq.h"
|
|
#include "lib/stringinfo.h"
|
|
#include "miscadmin.h"
|
|
#include "postmaster/bgworker.h"
|
|
#include "postmaster/syslogger.h"
|
|
#include "storage/lock.h"
|
|
#include "storage/proc.h"
|
|
#include "tcop/tcopprot.h"
|
|
#include "utils/backend_status.h"
|
|
#include "utils/elog.h"
|
|
#include "utils/guc.h"
|
|
#include "utils/ps_status.h"
|
|
|
|
|
|
/*
|
|
* append a CSV'd version of a string to a StringInfo
|
|
* We use the PostgreSQL defaults for CSV, i.e. quote = escape = '"'
|
|
* If it's NULL, append nothing.
|
|
*/
|
|
static inline void
|
|
appendCSVLiteral(StringInfo buf, const char *data)
|
|
{
|
|
const char *p = data;
|
|
char c;
|
|
|
|
/* avoid confusing an empty string with NULL */
|
|
if (p == NULL)
|
|
return;
|
|
|
|
appendStringInfoCharMacro(buf, '"');
|
|
while ((c = *p++) != '\0')
|
|
{
|
|
if (c == '"')
|
|
appendStringInfoCharMacro(buf, '"');
|
|
appendStringInfoCharMacro(buf, c);
|
|
}
|
|
appendStringInfoCharMacro(buf, '"');
|
|
}
|
|
|
|
/*
|
|
* write_csvlog -- Generate and write CSV log entry
|
|
*
|
|
* Constructs the error message, depending on the Errordata it gets, in a CSV
|
|
* format which is described in doc/src/sgml/config.sgml.
|
|
*/
|
|
void
|
|
write_csvlog(ErrorData *edata)
|
|
{
|
|
StringInfoData buf;
|
|
bool print_stmt = false;
|
|
|
|
/* static counter for line numbers */
|
|
static long log_line_number = 0;
|
|
|
|
/* has counter been reset in 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);
|
|
|
|
/* timestamp with milliseconds */
|
|
appendStringInfoString(&buf, get_formatted_log_time());
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* username */
|
|
if (MyProcPort)
|
|
appendCSVLiteral(&buf, MyProcPort->user_name);
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* database name */
|
|
if (MyProcPort)
|
|
appendCSVLiteral(&buf, MyProcPort->database_name);
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* Process id */
|
|
if (MyProcPid != 0)
|
|
appendStringInfo(&buf, "%d", MyProcPid);
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* Remote host and port */
|
|
if (MyProcPort && MyProcPort->remote_host)
|
|
{
|
|
appendStringInfoChar(&buf, '"');
|
|
appendStringInfoString(&buf, MyProcPort->remote_host);
|
|
if (MyProcPort->remote_port && MyProcPort->remote_port[0] != '\0')
|
|
{
|
|
appendStringInfoChar(&buf, ':');
|
|
appendStringInfoString(&buf, MyProcPort->remote_port);
|
|
}
|
|
appendStringInfoChar(&buf, '"');
|
|
}
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* session id */
|
|
appendStringInfo(&buf, "%lx.%x", (long) MyStartTime, MyProcPid);
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* Line number */
|
|
appendStringInfo(&buf, "%ld", log_line_number);
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* PS display */
|
|
if (MyProcPort)
|
|
{
|
|
StringInfoData msgbuf;
|
|
const char *psdisp;
|
|
int displen;
|
|
|
|
initStringInfo(&msgbuf);
|
|
|
|
psdisp = get_ps_display(&displen);
|
|
appendBinaryStringInfo(&msgbuf, psdisp, displen);
|
|
appendCSVLiteral(&buf, msgbuf.data);
|
|
|
|
pfree(msgbuf.data);
|
|
}
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* session start timestamp */
|
|
appendStringInfoString(&buf, get_formatted_start_time());
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* Virtual transaction id */
|
|
/* keep VXID format in sync with lockfuncs.c */
|
|
if (MyProc != NULL && MyProc->backendId != InvalidBackendId)
|
|
appendStringInfo(&buf, "%d/%u", MyProc->backendId, MyProc->lxid);
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* Transaction id */
|
|
appendStringInfo(&buf, "%u", GetTopTransactionIdIfAny());
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* Error severity */
|
|
appendStringInfoString(&buf, _(error_severity(edata->elevel)));
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* SQL state code */
|
|
appendStringInfoString(&buf, unpack_sql_state(edata->sqlerrcode));
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* errmessage */
|
|
appendCSVLiteral(&buf, edata->message);
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* errdetail or errdetail_log */
|
|
if (edata->detail_log)
|
|
appendCSVLiteral(&buf, edata->detail_log);
|
|
else
|
|
appendCSVLiteral(&buf, edata->detail);
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* errhint */
|
|
appendCSVLiteral(&buf, edata->hint);
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* internal query */
|
|
appendCSVLiteral(&buf, edata->internalquery);
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* if printed internal query, print internal pos too */
|
|
if (edata->internalpos > 0 && edata->internalquery != NULL)
|
|
appendStringInfo(&buf, "%d", edata->internalpos);
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* errcontext */
|
|
if (!edata->hide_ctx)
|
|
appendCSVLiteral(&buf, edata->context);
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* user query --- only reported if not disabled by the caller */
|
|
print_stmt = check_log_of_query(edata);
|
|
if (print_stmt)
|
|
appendCSVLiteral(&buf, debug_query_string);
|
|
appendStringInfoChar(&buf, ',');
|
|
if (print_stmt && edata->cursorpos > 0)
|
|
appendStringInfo(&buf, "%d", edata->cursorpos);
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* file error location */
|
|
if (Log_error_verbosity >= PGERROR_VERBOSE)
|
|
{
|
|
StringInfoData msgbuf;
|
|
|
|
initStringInfo(&msgbuf);
|
|
|
|
if (edata->funcname && edata->filename)
|
|
appendStringInfo(&msgbuf, "%s, %s:%d",
|
|
edata->funcname, edata->filename,
|
|
edata->lineno);
|
|
else if (edata->filename)
|
|
appendStringInfo(&msgbuf, "%s:%d",
|
|
edata->filename, edata->lineno);
|
|
appendCSVLiteral(&buf, msgbuf.data);
|
|
pfree(msgbuf.data);
|
|
}
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* application name */
|
|
if (application_name)
|
|
appendCSVLiteral(&buf, application_name);
|
|
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* backend type */
|
|
appendCSVLiteral(&buf, get_backend_type_for_log());
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* 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)
|
|
appendStringInfo(&buf, "%d", leader->pid);
|
|
}
|
|
appendStringInfoChar(&buf, ',');
|
|
|
|
/* query id */
|
|
appendStringInfo(&buf, "%lld", (long long) pgstat_get_my_query_id());
|
|
|
|
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_CSVLOG);
|
|
else
|
|
write_pipe_chunks(buf.data, buf.len, LOG_DESTINATION_CSVLOG);
|
|
|
|
pfree(buf.data);
|
|
}
|