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