Ejemplo n.º 1
0
/*
 * Add all the autogenerated exceptions as subclasses of SPIError
 */
static void
PLy_generate_spi_exceptions(PyObject *mod, PyObject *base)
{
	int			i;

	for (i = 0; exception_map[i].name != NULL; i++)
	{
		bool		found;
		PyObject   *exc;
		PLyExceptionEntry *entry;
		PyObject   *sqlstate;
		PyObject   *dict = PyDict_New();

		if (dict == NULL)
			PLy_elog(ERROR, "could not generate SPI exceptions");

		sqlstate = PyString_FromString(unpack_sql_state(exception_map[i].sqlstate));
		if (sqlstate == NULL)
			PLy_elog(ERROR, "could not generate SPI exceptions");

		PyDict_SetItemString(dict, "sqlstate", sqlstate);
		Py_DECREF(sqlstate);
		exc = PyErr_NewException(exception_map[i].name, base, dict);
		PyModule_AddObject(mod, exception_map[i].classname, exc);
		entry = hash_search(PLy_spi_exceptions, &exception_map[i].sqlstate,
							HASH_ENTER, &found);
		entry->exc = exc;
		Assert(!found);
	}
}
Ejemplo n.º 2
0
/* set attributes of the given exception to details from ErrorData */
void
PLy_exception_set_with_details(PyObject *excclass, ErrorData *edata)
{
	PyObject   *args = NULL;
	PyObject   *error = NULL;

	args = Py_BuildValue("(s)", edata->message);
	if (!args)
		goto failure;

	/* create a new exception with the error message as the parameter */
	error = PyObject_CallObject(excclass, args);
	if (!error)
		goto failure;

	if (!set_string_attr(error, "sqlstate",
						 unpack_sql_state(edata->sqlerrcode)))
		goto failure;

	if (!set_string_attr(error, "detail", edata->detail))
		goto failure;

	if (!set_string_attr(error, "hint", edata->hint))
		goto failure;

	if (!set_string_attr(error, "query", edata->internalquery))
		goto failure;

	if (!set_string_attr(error, "schema_name", edata->schema_name))
		goto failure;

	if (!set_string_attr(error, "table_name", edata->table_name))
		goto failure;

	if (!set_string_attr(error, "column_name", edata->column_name))
		goto failure;

	if (!set_string_attr(error, "datatype_name", edata->datatype_name))
		goto failure;

	if (!set_string_attr(error, "constraint_name", edata->constraint_name))
		goto failure;

	PyErr_SetObject(excclass, error);

	Py_DECREF(args);
	Py_DECREF(error);

	return;

failure:
	Py_XDECREF(args);
	Py_XDECREF(error);

	elog(ERROR, "could not convert error to Python exception");
}
Ejemplo n.º 3
0
/*
 * write_jsonlog
 * Write logs in json format.
 */
static void
write_jsonlog(ErrorData *edata)
{
	StringInfoData	buf;
	TransactionId	txid = GetTopTransactionIdIfAny();

	initStringInfo(&buf);

	/* Initialize string */
	appendStringInfoChar(&buf, '{');

	/* Timestamp */
	if (log_time[0] == '\0')
		setup_formatted_log_time();
	appendJSONLiteral(&buf, "timestamp", log_time, true);

	/* Username */
	if (MyProcPort)
		appendJSONLiteral(&buf, "user", MyProcPort->user_name, true);

	/* Database name */
	if (MyProcPort)
		appendJSONLiteral(&buf, "dbname", MyProcPort->database_name, true);

	/* Process ID */
	if (MyProcPid != 0)
		appendStringInfo(&buf, "\"pid\":%d,", MyProcPid);

	/* Remote host and port */
	if (MyProcPort && MyProcPort->remote_host)
	{
		appendJSONLiteral(&buf, "remote_host",
						  MyProcPort->remote_host, true);
		if (MyProcPort->remote_port && MyProcPort->remote_port[0] != '\0')
			appendJSONLiteral(&buf, "remote_port",
							  MyProcPort->remote_port, true);
	}

	/* Session id */
	if (MyProcPid != 0)
		appendStringInfo(&buf, "\"session_id\":\"%lx.%x\",",
						 (long) MyStartTime, MyProcPid);

	/* Virtual transaction id */
	/* keep VXID format in sync with lockfuncs.c */
	if (MyProc != NULL && MyProc->backendId != InvalidBackendId)
		appendStringInfo(&buf, "\"vxid\":\"%d/%u\",",
						 MyProc->backendId, MyProc->lxid);

	/* Transaction id */
	if (txid != InvalidTransactionId)
		appendStringInfo(&buf, "\"txid\":%u,", GetTopTransactionIdIfAny());

	/* Error severity */
	appendJSONLiteral(&buf, "error_severity",
					  (char *) error_severity(edata->elevel), true);

	/* SQL state code */
	if (edata->sqlerrcode != ERRCODE_SUCCESSFUL_COMPLETION)
		appendJSONLiteral(&buf, "state_code",
						  unpack_sql_state(edata->sqlerrcode), true);

	/* Error detail or Error detail log */
	if (edata->detail_log)
		appendJSONLiteral(&buf, "detail_log", edata->detail_log, true);
	else if (edata->detail)
		appendJSONLiteral(&buf, "detail", edata->detail, true);

	/* Error hint */
	if (edata->hint)
		appendJSONLiteral(&buf, "hint", edata->hint, true);

	/* Internal query */
	if (edata->internalquery)
		appendJSONLiteral(&buf, "internal_query",
						  edata->internalquery, true);

	/* Error context */
	if (edata->context)
		appendJSONLiteral(&buf, "context", edata->context, true);

	/* 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);
		appendJSONLiteral(&buf, "file_location", msgbuf.data, true);
		pfree(msgbuf.data);
	}

	/* Application name */
	if (application_name && application_name[0] != '\0')
		appendJSONLiteral(&buf, "application_name",
						  application_name, true);

	/* Error message */
	appendJSONLiteral(&buf, "message", edata->message, false);

	/* Finish string */
	appendStringInfoChar(&buf, '}');
	appendStringInfoChar(&buf, '\n');

	/* If in the syslogger process, try to write messages direct to file */
	if (am_syslogger)
		write_syslogger_file(buf.data, buf.len, LOG_DESTINATION_STDERR);
	else
		write_pipe_chunks(buf.data, buf.len);

	/* Cleanup */
	pfree(buf.data);

	/* Continue chain to previous hook */
	if (prev_log_hook)
		(*prev_log_hook) (edata);
}
Ejemplo n.º 4
0
/*
 * redis_log_hook
 * Hook for shipping log events to Redis
 * (based on jsonlog.c)
 */
static void
redis_log_hook(ErrorData *edata)
{
	StringInfoData	buf;
	TransactionId	txid = GetTopTransactionIdIfAny();
	bool		print_stmt = false;
	bool		send_status = false;

	/* static counter for line numbers */
	static long log_line_number = 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 (lastPid != MyProcPid)
	{
		log_line_number = 0;
		lastPid = MyProcPid;
		formatted_start_time[0] = '\0';
		redis_close_connection();
	}

	/*
	 * Check if the log has to be written, if not just exit.
	 */
	if (!is_log_level_output(edata->elevel, Redislog_min_messages))
	{
		goto quickExit;
	}

	log_line_number++;

	initStringInfo(&buf);

	/* Initialize string */
	appendStringInfoChar(&buf, '{');

	/* Timestamp */
	setup_formatted_log_time();
	append_json_literal(&buf, "@timestamp", formatted_log_time, true);

	/* Username */
	if (MyProcPort)
		append_json_literal(&buf, "user_name", MyProcPort->user_name, true);

	/* Database name */
	if (MyProcPort)
		append_json_literal(&buf, "database_name", MyProcPort->database_name, true);

	/* Process ID */
	if (MyProcPid != 0)
		appendStringInfo(&buf, "\"process_id\":%d,", MyProcPid);

	/* Remote host and port */
	if (MyProcPort && MyProcPort->remote_host)
	{
		append_json_literal(&buf, "remote_host",
						  MyProcPort->remote_host, true);
		if (MyProcPort->remote_port && MyProcPort->remote_port[0] != '\0')
			append_json_literal(&buf, "remote_port",
							  MyProcPort->remote_port, true);
	}

	/* Session id */
	if (MyProcPid != 0)
		appendStringInfo(&buf, "\"session_id\":\"%lx.%x\",",
						 (long) MyStartTime, MyProcPid);

	/* Process ID */
	if (MyProcPid != 0)
		appendStringInfo(&buf, "\"session_line_num\":%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);
		append_json_literal(&buf, "command_tag", msgbuf.data, true);

		pfree(msgbuf.data);
	}

	/* session start timestamp */
	if (formatted_start_time[0] == '\0')
		setup_formatted_start_time();
	append_json_literal(&buf, "session_start_time", formatted_start_time, true);

	/* Virtual transaction id */
	/* keep VXID format in sync with lockfuncs.c */
	if (MyProc != NULL && MyProc->backendId != InvalidBackendId)
		appendStringInfo(&buf, "\"virtual_transaction_id\":\"%d/%u\",",
						 MyProc->backendId, MyProc->lxid);

	/* Transaction id */
	if (txid != InvalidTransactionId)
		appendStringInfo(&buf, "\"transaction_id\":%u,", GetTopTransactionIdIfAny());

	/* Error severity */
	append_json_literal(&buf, "error_severity",
					  (char *) error_severity(edata->elevel), true);

	/* SQL state code */
	if (edata->sqlerrcode != ERRCODE_SUCCESSFUL_COMPLETION)
		append_json_literal(&buf, "sql_state_code",
						  unpack_sql_state(edata->sqlerrcode), true);

	/* Error detail or Error detail log */
	if (edata->detail_log)
		append_json_literal(&buf, "detail_log", edata->detail_log, true);
	else if (edata->detail)
		append_json_literal(&buf, "detail", edata->detail, true);

	/* Error hint */
	if (edata->hint)
		append_json_literal(&buf, "hint", edata->hint, true);

	/* Internal query */
	if (edata->internalquery)
		append_json_literal(&buf, "internal_query",
						  edata->internalquery, true);

	/* if printed internal query, print internal pos too */
	if (edata->internalpos > 0 && edata->internalquery != NULL)
		appendStringInfo(&buf, "\"internal_query_pos\":%d,", edata->internalpos);

	/* Error context */
	if (edata->context)
		append_json_literal(&buf, "context", edata->context, true);

	/* user query --- only reported if not disabled by the caller */
	if (is_log_level_output(edata->elevel, Redislog_min_error_statement) &&
		debug_query_string != NULL &&
		!edata->hide_stmt)
		print_stmt = true;
	if (print_stmt)
		append_json_literal(&buf, "query", debug_query_string, true);

	/* user query position -- only reposted if not disabled by the caller */
	if (print_stmt && edata->cursorpos > 0)
		appendStringInfo(&buf, "\"query_pos\":%d,", edata->cursorpos);

	/* 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);
		append_json_literal(&buf, "file_location", msgbuf.data, true);
		pfree(msgbuf.data);
	}

	/* Application name */
	if (application_name && application_name[0] != '\0')
		append_json_literal(&buf, "application_name",
						  application_name, true);

	/* Error message */
	append_json_literal(&buf, "message", edata->message, false);

	/* Finish string */
	appendStringInfoChar(&buf, '}');
	appendStringInfoChar(&buf, '\n');

	/* Send the data to Redis */
	send_status = redis_log_shipper(buf.data, buf.len);

	/* Skip sending the event to the server, if it was correctly
	 * shipped to Redis and if 'ship_to_redis_only' is set to true
	 */
	if (Redislog_ship_to_redis_only && send_status) {
		edata->output_to_server = false;
	}

	/* Cleanup */
	pfree(buf.data);

quickExit:

	/* Continue chain to previous hook */
	if (prev_log_hook)
		(*prev_log_hook) (edata);
}
Ejemplo n.º 5
0
/*
 * write_jsonlog
 * Write logs in json format.
 */
static void
write_jsonlog(ErrorData *edata)
{
	StringInfoData	buf;
	TransactionId	txid = GetTopTransactionIdIfAny();

	/*
	 * Disable logs to server, we don't want duplicate entries in
	 * the server.
	 */
	edata->output_to_server = false;

	/* Determine whether message is enabled for server log output */
	if (!is_log_level_output(edata->elevel, log_min_messages))
		return;

	initStringInfo(&buf);

	/* Initialize string */
	appendStringInfoChar(&buf, '{');

	/* Timestamp */
	setup_formatted_log_time();
	appendJSONLiteral(&buf, "timestamp", formatted_log_time, true);

	/* Username */
	if (MyProcPort && MyProcPort->user_name)
		appendJSONLiteral(&buf, "user", MyProcPort->user_name, true);

	/* Database name */
	if (MyProcPort && MyProcPort->database_name)
		appendJSONLiteral(&buf, "dbname", MyProcPort->database_name, true);

	/* Process ID */
	if (MyProcPid != 0)
		appendStringInfo(&buf, "\"pid\":%d,", MyProcPid);

	/* Remote host and port */
	if (MyProcPort && MyProcPort->remote_host)
	{
		appendJSONLiteral(&buf, "remote_host",
						  MyProcPort->remote_host, true);
		if (MyProcPort->remote_port && MyProcPort->remote_port[0] != '\0')
			appendJSONLiteral(&buf, "remote_port",
							  MyProcPort->remote_port, true);
	}

	/* Session id */
	if (MyProcPid != 0)
		appendStringInfo(&buf, "\"session_id\":\"%lx.%x\",",
						 (long) MyStartTime, MyProcPid);

	/* Virtual transaction id */
	/* keep VXID format in sync with lockfuncs.c */
	if (MyProc != NULL && MyProc->backendId != InvalidBackendId)
		appendStringInfo(&buf, "\"vxid\":\"%d/%u\",",
						 MyProc->backendId, MyProc->lxid);

	/* Transaction id */
	if (txid != InvalidTransactionId)
		appendStringInfo(&buf, "\"txid\":%u,", GetTopTransactionIdIfAny());

	/* Error severity */
	appendJSONLiteral(&buf, "error_severity",
					  (char *) error_severity(edata->elevel), true);

	/* SQL state code */
	if (edata->sqlerrcode != ERRCODE_SUCCESSFUL_COMPLETION)
		appendJSONLiteral(&buf, "state_code",
						  unpack_sql_state(edata->sqlerrcode), true);

	/* Error detail or Error detail log */
	if (edata->detail_log)
		appendJSONLiteral(&buf, "detail_log", edata->detail_log, true);
	else if (edata->detail)
		appendJSONLiteral(&buf, "detail", edata->detail, true);

	/* Error hint */
	if (edata->hint)
		appendJSONLiteral(&buf, "hint", edata->hint, true);

	/* Internal query */
	if (edata->internalquery)
		appendJSONLiteral(&buf, "internal_query",
						  edata->internalquery, true);

	/* Error context */
	if (edata->context)
		appendJSONLiteral(&buf, "context", edata->context, true);

	/* user query --- only reported if not disabled by the caller */
	if (is_log_level_output(edata->elevel, log_min_error_statement) &&
		debug_query_string != NULL &&
		!edata->hide_stmt)
	{
		appendJSONLiteral(&buf, "statement", debug_query_string, true);

		if (edata->cursorpos > 0)
			appendStringInfo(&buf, "\"cursor_position\":%d,",
							 edata->cursorpos);
		else if (edata->internalpos > 0)
			appendStringInfo(&buf, "\"internal_position\":%d,",
							 edata->internalpos);
	}

	/* 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);
		appendJSONLiteral(&buf, "file_location", msgbuf.data, true);
		pfree(msgbuf.data);
	}

	/* Application name */
	if (application_name && application_name[0] != '\0')
		appendJSONLiteral(&buf, "application_name",
						  application_name, true);

	/* Error message */
	appendJSONLiteral(&buf, "message", edata->message, false);

	/* Finish string */
	appendStringInfoChar(&buf, '}');
	appendStringInfoChar(&buf, '\n');

	/* Write to stderr, if enabled */
	if ((Log_destination & LOG_DESTINATION_STDERR) != 0)
	{
		if (Logging_collector && redirection_done && !am_syslogger)
			write_pipe_chunks(buf.data, buf.len);
		else
			write_console(buf.data, buf.len);
	}

	/* If in the syslogger process, try to write messages direct to file */
	if (am_syslogger)
		write_syslogger_file(buf.data, buf.len, LOG_DESTINATION_STDERR);

	/* Cleanup */
	pfree(buf.data);

	/* Continue chain to previous hook */
	if (prev_log_hook)
		(*prev_log_hook) (edata);
}
Ejemplo n.º 6
0
static void
fmtLogMsg(StringInfo dst, ErrorData *edata)
{
	{
		char formattedLogTime[FORMATTED_TS_LEN];

		/* timestamp with milliseconds */
		formatNow(formattedLogTime, sizeof formattedLogTime);

		/*
		 * Always present, non-nullable; don't need to write the N/P
		 * header.
		 */
		appendStringInfoString(dst, formattedLogTime);
		appendStringInfoChar(dst, '\0');
	}

	/* username */
	if (MyProcPort)
		appendStringInfoPtr(dst, MyProcPort->user_name);
	else
		appendStringInfoPtr(dst, NULL);

	/* database name */
	if (MyProcPort)
		appendStringInfoPtr(dst, MyProcPort->database_name);
	else
		appendStringInfoPtr(dst, NULL);

	/* Process id  */
	{
		uint32_t nPid = htobe32(savedPid);

		appendBinaryStringInfo(dst, (void *) &nPid, sizeof nPid);
	}

	/* Remote host and port */
	if (MyProcPort && MyProcPort->remote_host)
	{
		/* 'present' string header, since this string is nullable */
		appendStringInfoChar(dst, 'P');

		appendStringInfoString(dst, MyProcPort->remote_host);
		if (MyProcPort->remote_port && MyProcPort->remote_port[0] != '\0')
		{
			appendStringInfoChar(dst, ':');
			appendStringInfoString(dst, MyProcPort->remote_port);
		}

		appendStringInfoChar(dst, '\0');
	}
	else
		appendStringInfoPtr(dst, NULL);

	/* session id; non-nullable */
	appendStringInfo(dst, "%lx.%x", (long) MyStartTime, MyProcPid);
	appendStringInfoChar(dst, '\0');

	/* Line number */
	{
		uint64_t nSeqNum = htobe64(seqNum);
		appendBinaryStringInfo(dst, (void *) &nSeqNum, sizeof nSeqNum);
	}

	/* PS display */
	if (MyProcPort)
	{
		StringInfoData msgbuf;
		const char *psdisp;
		int			displen;

		initStringInfo(&msgbuf);

		psdisp = get_ps_display(&displen);
		appendBinaryStringInfo(&msgbuf, psdisp, displen);

		appendStringInfoChar(dst, 'P');
		appendStringInfoString(dst, msgbuf.data);
		appendStringInfoChar(dst, '\0');

		pfree(msgbuf.data);
	}
	else
		appendStringInfoPtr(dst, NULL);

	/* session start timestamp */
	if (cachedBackendStartTime[0] == '\0')
	{
		/* Rebuild the cache if it was blown */
		reCacheBackendStartTime();
	}

	/* backend start time; non-nullable string */
	appendStringInfoString(dst, cachedBackendStartTime);
	appendStringInfoChar(dst, '\0');

	/*
	 * Virtual transaction id
	 *
	 * keep VXID format in sync with lockfuncs.c
	 */
	if (MyProc != NULL && MyProc->backendId != InvalidBackendId)
	{
		appendStringInfoChar(dst, 'P');
		appendStringInfo(dst, "%d/%u", MyProc->backendId, MyProc->lxid);
		appendStringInfoChar(dst, '\0');
	}
	else
		appendStringInfoPtr(dst, NULL);

	/*
	 * Transaction id
	 *
	 * This seems to be a mistake both here and in elog.c; in particular, it's
	 * not clear how the epoch would get added here.  However, leave room in
	 * the protocol to fix this later by upcasting.
	 */
	{
		uint64_t nTxid = htobe64((uint64) GetTopTransactionIdIfAny());

		appendBinaryStringInfo(dst, (void *) &nTxid, sizeof nTxid);
	}

	/* Error severity */
	{
		uint32_t nelevel = htobe32(edata->elevel);

		appendBinaryStringInfo(dst, (void *) &nelevel, sizeof nelevel);
	}

	/* SQL state code */
	appendStringInfoPtr(dst, unpack_sql_state(edata->sqlerrcode));

	/* errmessage */
	appendStringInfoPtr(dst, edata->message);

	/* errdetail or errdetail_log */
	if (edata->detail_log)
		appendStringInfoPtr(dst, edata->detail_log);
	else
		appendStringInfoPtr(dst, edata->detail);

	/* errhint */
	appendStringInfoPtr(dst, edata->hint);

	/* internal query */
	appendStringInfoPtr(dst, edata->internalquery);

	/* if printed internal query, print internal pos too */
	if (edata->internalpos > 0 && edata->internalquery != NULL)
	{
		uint32_t ninternalpos = htobe32(edata->internalpos);

		appendBinaryStringInfo(dst, (void *) &ninternalpos,
							   sizeof ninternalpos);
	}
	else
	{
		uint32_t ninternalpos = htobe32(-1);

		appendBinaryStringInfo(dst, (void *) &ninternalpos,
							   sizeof ninternalpos);
	}

	/* errcontext */
	appendStringInfoPtr(dst, edata->context);

	/*
	 * user query --- only reported if not disabled by the caller.
	 *
	 * Also include query position.
	 */
	if (isLogLevelOutput(edata->elevel, log_min_error_statement) &&
		debug_query_string != NULL && !edata->hide_stmt)
	{
		uint32_t nCursorPos = htobe32(edata->cursorpos);

		appendStringInfoPtr(dst, debug_query_string);
		appendBinaryStringInfo(dst, (void *) &nCursorPos, sizeof nCursorPos);
	}
	else
	{
		uint32_t nCursorPos = htobe32(-1);

		appendStringInfoPtr(dst, NULL);
		appendBinaryStringInfo(dst, (void *) &nCursorPos, sizeof nCursorPos);
	}

	/* 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);

		appendStringInfoChar(dst, 'P');
		appendStringInfoString(dst, msgbuf.data);
		appendStringInfoChar(dst, '\0');

		pfree(msgbuf.data);
	}
	else
		appendStringInfoPtr(dst, NULL);

	/* application name */
	appendStringInfoPtr(dst, application_name);
}