|
|
|
@ -47,6 +47,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|
|
|
|
#include "asterisk/config.h"
|
|
|
|
|
#include "asterisk/channel.h"
|
|
|
|
|
#include "asterisk/cdr.h"
|
|
|
|
|
#include "asterisk/cli.h"
|
|
|
|
|
#include "asterisk/module.h"
|
|
|
|
|
|
|
|
|
|
#define DATE_FORMAT "'%Y-%m-%d %T'"
|
|
|
|
@ -56,6 +57,14 @@ static const char config[] = "cdr_pgsql.conf";
|
|
|
|
|
static char *pghostname = NULL, *pgdbname = NULL, *pgdbuser = NULL, *pgpassword = NULL, *pgdbport = NULL, *table = NULL, *encoding = NULL, *tz = NULL;
|
|
|
|
|
static int connected = 0;
|
|
|
|
|
static int maxsize = 512, maxsize2 = 512;
|
|
|
|
|
static time_t connect_time = 0;
|
|
|
|
|
static int totalrecords = 0;
|
|
|
|
|
static int records;
|
|
|
|
|
|
|
|
|
|
static char *handle_cdr_pgsql_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
|
|
|
|
|
static struct ast_cli_entry cdr_pgsql_status_cli[] = {
|
|
|
|
|
AST_CLI_DEFINE(handle_cdr_pgsql_status, "Show connection status of the PostgreSQL CDR driver (cdr_pgsql)"),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
AST_MUTEX_DEFINE_STATIC(pgsql_lock);
|
|
|
|
|
|
|
|
|
@ -99,6 +108,61 @@ static AST_RWLIST_HEAD_STATIC(psql_columns, columns);
|
|
|
|
|
} \
|
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
/*! \brief Handle the CLI command cdr show pgsql status */
|
|
|
|
|
static char *handle_cdr_pgsql_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
|
|
|
|
{
|
|
|
|
|
switch (cmd) {
|
|
|
|
|
case CLI_INIT:
|
|
|
|
|
e->command = "cdr show pgsql status";
|
|
|
|
|
e->usage =
|
|
|
|
|
"Usage: cdr show pgsql status\n"
|
|
|
|
|
" Shows current connection status for cdr_pgsql\n";
|
|
|
|
|
return NULL;
|
|
|
|
|
case CLI_GENERATE:
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (a->argc != 3)
|
|
|
|
|
return CLI_SHOWUSAGE;
|
|
|
|
|
|
|
|
|
|
if (connected) {
|
|
|
|
|
char status[256], status2[100] = "";
|
|
|
|
|
int ctime = time(NULL) - connect_time;
|
|
|
|
|
|
|
|
|
|
if (pgdbport) {
|
|
|
|
|
snprintf(status, 255, "Connected to %s@%s, port %s", pgdbname, pghostname, pgdbport);
|
|
|
|
|
} else {
|
|
|
|
|
snprintf(status, 255, "Connected to %s@%s", pgdbname, pghostname);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pgdbuser && *pgdbuser) {
|
|
|
|
|
snprintf(status2, 99, " with username %s", pgdbuser);
|
|
|
|
|
}
|
|
|
|
|
if (table && *table) {
|
|
|
|
|
snprintf(status2, 99, " using table %s", table);
|
|
|
|
|
}
|
|
|
|
|
if (ctime > 31536000) {
|
|
|
|
|
ast_cli(a->fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 31536000, (ctime % 31536000) / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60);
|
|
|
|
|
} else if (ctime > 86400) {
|
|
|
|
|
ast_cli(a->fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60);
|
|
|
|
|
} else if (ctime > 3600) {
|
|
|
|
|
ast_cli(a->fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 3600, (ctime % 3600) / 60, ctime % 60);
|
|
|
|
|
} else if (ctime > 60) {
|
|
|
|
|
ast_cli(a->fd, "%s%s for %d minutes, %d seconds.\n", status, status2, ctime / 60, ctime % 60);
|
|
|
|
|
} else {
|
|
|
|
|
ast_cli(a->fd, "%s%s for %d seconds.\n", status, status2, ctime);
|
|
|
|
|
}
|
|
|
|
|
if (records == totalrecords) {
|
|
|
|
|
ast_cli(a->fd, " Wrote %d records since last restart.\n", totalrecords);
|
|
|
|
|
} else {
|
|
|
|
|
ast_cli(a->fd, " Wrote %d records since last restart and %d records since last reconnect.\n", totalrecords, records);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ast_cli(a->fd, "Not currently connected to a PgSQL server.\n");
|
|
|
|
|
}
|
|
|
|
|
return CLI_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int pgsql_log(struct ast_cdr *cdr)
|
|
|
|
|
{
|
|
|
|
|
struct ast_tm tm;
|
|
|
|
@ -111,6 +175,8 @@ static int pgsql_log(struct ast_cdr *cdr)
|
|
|
|
|
conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword);
|
|
|
|
|
if (PQstatus(conn) != CONNECTION_BAD) {
|
|
|
|
|
connected = 1;
|
|
|
|
|
connect_time = time(NULL);
|
|
|
|
|
records = 0;
|
|
|
|
|
if (PQsetClientEncoding(conn, encoding)) {
|
|
|
|
|
#ifdef HAVE_PGSQL_pg_encoding_to_char
|
|
|
|
|
ast_log(LOG_WARNING, "Failed to set encoding to '%s'. Encoding set to default '%s'\n", encoding, pg_encoding_to_char(PQclientEncoding(conn)));
|
|
|
|
@ -289,6 +355,8 @@ static int pgsql_log(struct ast_cdr *cdr)
|
|
|
|
|
if (PQstatus(conn) == CONNECTION_OK) {
|
|
|
|
|
ast_log(LOG_ERROR, "Connection reestablished.\n");
|
|
|
|
|
connected = 1;
|
|
|
|
|
connect_time = time(NULL);
|
|
|
|
|
records = 0;
|
|
|
|
|
} else {
|
|
|
|
|
pgerror = PQerrorMessage(conn);
|
|
|
|
|
ast_log(LOG_ERROR, "Unable to reconnect to database server %s. Calls will not be logged!\n", pghostname);
|
|
|
|
@ -312,12 +380,21 @@ static int pgsql_log(struct ast_cdr *cdr)
|
|
|
|
|
if (PQstatus(conn) == CONNECTION_OK) {
|
|
|
|
|
ast_log(LOG_ERROR, "Connection reestablished.\n");
|
|
|
|
|
connected = 1;
|
|
|
|
|
connect_time = time(NULL);
|
|
|
|
|
records = 0;
|
|
|
|
|
PQclear(result);
|
|
|
|
|
result = PQexec(conn, ast_str_buffer(sql));
|
|
|
|
|
if (PQresultStatus(result) != PGRES_COMMAND_OK) {
|
|
|
|
|
pgerror = PQresultErrorMessage(result);
|
|
|
|
|
ast_log(LOG_ERROR, "HARD ERROR! Attempted reconnection failed. DROPPING CALL RECORD!\n");
|
|
|
|
|
ast_log(LOG_ERROR, "Reason: %s\n", pgerror);
|
|
|
|
|
} else {
|
|
|
|
|
/* Second try worked out ok */
|
|
|
|
|
totalrecords++;
|
|
|
|
|
records++;
|
|
|
|
|
ast_mutex_unlock(&pgsql_lock);
|
|
|
|
|
PQclear(result);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ast_mutex_unlock(&pgsql_lock);
|
|
|
|
@ -325,6 +402,9 @@ static int pgsql_log(struct ast_cdr *cdr)
|
|
|
|
|
ast_free(sql);
|
|
|
|
|
ast_free(sql2);
|
|
|
|
|
return -1;
|
|
|
|
|
} else {
|
|
|
|
|
totalrecords++;
|
|
|
|
|
records++;
|
|
|
|
|
}
|
|
|
|
|
PQclear(result);
|
|
|
|
|
ast_free(sql);
|
|
|
|
@ -339,6 +419,7 @@ static int unload_module(void)
|
|
|
|
|
struct columns *current;
|
|
|
|
|
|
|
|
|
|
ast_cdr_unregister(name);
|
|
|
|
|
ast_cli_unregister_multiple(cdr_pgsql_status_cli, ARRAY_LEN(cdr_pgsql_status_cli));
|
|
|
|
|
|
|
|
|
|
PQfinish(conn);
|
|
|
|
|
|
|
|
|
@ -524,6 +605,8 @@ static int config_module(int reload)
|
|
|
|
|
int i, rows, version;
|
|
|
|
|
ast_debug(1, "Successfully connected to PostgreSQL database.\n");
|
|
|
|
|
connected = 1;
|
|
|
|
|
connect_time = time(NULL);
|
|
|
|
|
records = 0;
|
|
|
|
|
if (PQsetClientEncoding(conn, encoding)) {
|
|
|
|
|
#ifdef HAVE_PGSQL_pg_encoding_to_char
|
|
|
|
|
ast_log(LOG_WARNING, "Failed to set encoding to '%s'. Encoding set to default '%s'\n", encoding, pg_encoding_to_char(PQclientEncoding(conn)));
|
|
|
|
@ -641,6 +724,7 @@ static int config_module(int reload)
|
|
|
|
|
|
|
|
|
|
static int load_module(void)
|
|
|
|
|
{
|
|
|
|
|
ast_cli_register_multiple(cdr_pgsql_status_cli, sizeof(cdr_pgsql_status_cli) / sizeof(struct ast_cli_entry));
|
|
|
|
|
return config_module(0) ? AST_MODULE_LOAD_DECLINE : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|