* collectd - src/postgresql.c
* Copyright (C) 2008-2012 Sebastian Harl
* Copyright (C) 2009 Florian Forster
- * All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
*
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
*
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
*
* Authors:
* Sebastian Harl <sh at tokkee.org>
- * Florian Forster <octo at verplant.org>
+ * Florian Forster <octo at collectd.org>
**/
/*
*/
#include "collectd.h"
+
#include "common.h"
-#include "configfile.h"
#include "plugin.h"
#include "utils_cache.h"
#include "utils_db_query.h"
#include "utils_complain.h"
-#if HAVE_PTHREAD_H
-# include <pthread.h>
-#endif
-
#include <pg_config_manual.h>
#include <libpq-fe.h>
/* writer "caching" settings */
cdtime_t commit_interval;
cdtime_t next_commit;
+ cdtime_t expire_delay;
char *host;
char *port;
int ref_cnt;
} c_psql_database_t;
-static char *def_queries[] = {
+static const char *const def_queries[] = {
"backends",
"transactions",
"queries",
c_psql_database_t **tmp;
c_psql_database_t *db;
- db = (c_psql_database_t *)malloc (sizeof(*db));
+ db = malloc (sizeof(*db));
if (NULL == db) {
log_err ("Out of memory.");
return NULL;
}
- tmp = (c_psql_database_t **)realloc (databases,
+ tmp = realloc (databases,
(databases_num + 1) * sizeof (*databases));
if (NULL == tmp) {
log_err ("Out of memory.");
db->commit_interval = 0;
db->next_commit = 0;
+ db->expire_delay = 0;
db->database = sstrdup (name);
db->host = NULL;
static void c_psql_database_delete (void *data)
{
- size_t i;
-
c_psql_database_t *db = data;
--db->ref_cnt;
db->conn = NULL;
if (db->q_prep_areas)
- for (i = 0; i < db->queries_num; ++i)
+ for (size_t i = 0; i < db->queries_num; ++i)
udb_query_delete_preparation_area (db->q_prep_areas[i]);
free (db->q_prep_areas);
static PGresult *c_psql_exec_query_params (c_psql_database_t *db,
udb_query_t *q, c_psql_user_data_t *data)
{
- char *params[db->max_params_num];
- char interval[64];
- int i;
+ const char *params[db->max_params_num];
+ char interval[64];
if ((data == NULL) || (data->params_num == 0))
return (c_psql_exec_query_noparams (db, q));
assert (db->max_params_num >= data->params_num);
- for (i = 0; i < data->params_num; ++i) {
+ for (int i = 0; i < data->params_num; ++i) {
switch (data->params[i]) {
case C_PSQL_PARAM_HOST:
params[i] = C_PSQL_IS_UNIX_DOMAIN_SOCKET (db->host)
int rows_num;
int status;
- int row, col;
/* The user data may hold parameter information, but may be NULL. */
data = udb_query_get_user_data (q);
log_err ("calloc failed.");
BAIL_OUT (-1);
}
-
- for (col = 0; col < column_num; ++col) {
+
+ for (int col = 0; col < column_num; ++col) {
/* Pointers returned by `PQfname' are freed by `PQclear' via
* `BAIL_OUT'. */
column_names[col] = PQfname (res, col);
}
if (C_PSQL_IS_UNIX_DOMAIN_SOCKET (db->host)
+ || (0 == strcmp (db->host, "127.0.0.1"))
|| (0 == strcmp (db->host, "localhost")))
host = hostname_g;
else
BAIL_OUT (-1);
}
- for (row = 0; row < rows_num; ++row) {
+ for (int row = 0; row < rows_num; ++row) {
+ int col;
for (col = 0; col < column_num; ++col) {
/* Pointers returned by `PQgetvalue' are freed by `PQclear' via
* `BAIL_OUT'. */
c_psql_database_t *db;
int success = 0;
- int i;
if ((ud == NULL) || (ud->data == NULL)) {
log_err ("c_psql_read: Invalid user data.");
return -1;
}
- for (i = 0; i < db->queries_num; ++i)
+ for (size_t i = 0; i < db->queries_num; ++i)
{
udb_query_preparation_area_t *prep_area;
udb_query_t *q;
char *str_ptr;
size_t str_len;
- int i;
-
str_ptr = string;
str_len = string_len;
- for (i = 0; i < ds->ds_num; ++i) {
+ for (size_t i = 0; i < ds->ds_num; ++i) {
int status = ssnprintf (str_ptr, str_len, ",'%s'", ds->ds[i].name);
if (status < 1)
char *str_ptr;
size_t str_len;
- int i;
-
str_ptr = string;
str_len = string_len;
- for (i = 0; i < ds->ds_num; ++i) {
+ for (size_t i = 0; i < ds->ds_num; ++i) {
int status;
if (store_rates)
gauge_t *rates = NULL;
- int i;
-
str_ptr = string;
str_len = string_len;
- for (i = 0; i < vl->values_len; ++i) {
+ for (size_t i = 0; i < vl->values_len; ++i) {
int status = 0;
if ((ds->ds[i].type != DS_TYPE_GAUGE)
{
c_psql_database_t *db;
- char time_str[32];
+ char time_str[RFC3339NANO_SIZE];
char values_name_str[1024];
char values_type_str[1024];
char values_str[1024];
const char *params[9];
int success = 0;
- int i;
if ((ud == NULL) || (ud->data == NULL)) {
log_err ("c_psql_write: Invalid user data.");
assert (db->database != NULL);
assert (db->writers != NULL);
- if (cdtime_to_iso8601 (time_str, sizeof (time_str), vl->time) == 0) {
- log_err ("c_psql_write: Failed to convert time to ISO 8601 format");
+ if (rfc3339nano (time_str, sizeof (time_str), vl->time) != 0) {
+ log_err ("c_psql_write: Failed to convert time to RFC 3339 format");
return -1;
}
#undef VALUE_OR_NULL
+ if( db->expire_delay > 0 && vl->time < (cdtime() - vl->interval - db->expire_delay) ) {
+ log_info ("c_psql_write: Skipped expired value @ %s - %s/%s-%s/%s-%s/%s",
+ params[0], params[1], params[2], params[3], params[4], params[5], params[6] );
+ return 0;
+ }
+
pthread_mutex_lock (&db->db_lock);
if (0 != c_psql_check_connection (db)) {
&& (db->next_commit == 0))
c_psql_begin (db);
- for (i = 0; i < db->writers_num; ++i) {
+ for (size_t i = 0; i < db->writers_num; ++i) {
c_psql_writer_t *writer;
PGresult *res;
{
c_psql_database_t **dbs = databases;
size_t dbs_num = databases_num;
- size_t i;
if ((ud != NULL) && (ud->data != NULL)) {
dbs = (void *)&ud->data;
dbs_num = 1;
}
- for (i = 0; i < dbs_num; ++i) {
+ for (size_t i = 0; i < dbs_num; ++i) {
c_psql_database_t *db = dbs[i];
/* don't commit if the timeout is larger than the regular commit
static int c_psql_shutdown (void)
{
- size_t i = 0;
-
_Bool had_flush = 0;
plugin_unregister_read_group ("postgresql");
- for (i = 0; i < databases_num; ++i) {
+ for (size_t i = 0; i < databases_num; ++i) {
c_psql_database_t *db = databases[i];
if (db->writers_num > 0) {
data = udb_query_get_user_data (q);
if (NULL == data) {
- data = malloc (sizeof (*data));
+ data = calloc (1, sizeof (*data));
if (NULL == data) {
log_err ("Out of memory.");
return -1;
}
- memset (data, 0, sizeof (*data));
data->params = NULL;
data->params_num = 0;
if (strcasecmp (name, src_writers[i].name) != 0)
continue;
- tmp = (c_psql_writer_t **)realloc (*dst_writers,
+ tmp = realloc (*dst_writers,
sizeof (**dst_writers) * (*dst_writers_num + 1));
if (tmp == NULL) {
log_err ("Out of memory.");
c_psql_writer_t *tmp;
int status = 0;
- int i;
if ((ci->values_num != 1)
|| (ci->values[0].type != OCONFIG_TYPE_STRING)) {
return 1;
}
- tmp = (c_psql_writer_t *)realloc (writers,
+ tmp = realloc (writers,
sizeof (*writers) * (writers_num + 1));
if (tmp == NULL) {
log_err ("Out of memory.");
writer->statement = NULL;
writer->store_rates = 1;
- for (i = 0; i < ci->children_num; ++i) {
+ for (int i = 0; i < ci->children_num; ++i) {
oconfig_item_t *c = ci->children + i;
if (strcasecmp ("Statement", c->key) == 0)
c_psql_database_t *db;
char cb_name[DATA_MAX_NAME_LEN];
- struct timespec cb_interval = { 0, 0 };
- user_data_t ud;
-
static _Bool have_flush = 0;
- int i;
-
if ((1 != ci->values_num)
|| (OCONFIG_TYPE_STRING != ci->values[0].type)) {
log_err ("<Database> expects a single string argument.");
return 1;
}
- memset (&ud, 0, sizeof (ud));
-
db = c_psql_database_new (ci->values[0].value.string);
if (db == NULL)
return -1;
- for (i = 0; i < ci->children_num; ++i) {
+ for (int i = 0; i < ci->children_num; ++i) {
oconfig_item_t *c = ci->children + i;
if (0 == strcasecmp (c->key, "Host"))
cf_util_get_cdtime (c, &db->interval);
else if (strcasecmp ("CommitInterval", c->key) == 0)
cf_util_get_cdtime (c, &db->commit_interval);
+ else if (strcasecmp ("ExpireDelay", c->key) == 0)
+ cf_util_get_cdtime (c, &db->expire_delay);
else
log_warn ("Ignoring unknown config key \"%s\".", c->key);
}
/* If no `Query' options were given, add the default queries.. */
if ((db->queries_num == 0) && (db->writers_num == 0)){
- for (i = 0; i < def_queries_num; i++)
+ for (int i = 0; i < def_queries_num; i++)
udb_query_pick_from_list_by_name (def_queries[i],
queries, queries_num,
&db->queries, &db->queries_num);
}
}
- for (i = 0; (size_t)i < db->queries_num; ++i) {
+ for (int i = 0; (size_t)i < db->queries_num; ++i) {
c_psql_user_data_t *data;
data = udb_query_get_user_data (db->queries[i]);
if ((data != NULL) && (data->params_num > db->max_params_num))
}
}
- ud.data = db;
- ud.free_func = c_psql_database_delete;
-
ssnprintf (cb_name, sizeof (cb_name), "postgresql-%s", db->instance);
- if (db->queries_num > 0) {
- CDTIME_T_TO_TIMESPEC (db->interval, &cb_interval);
+ user_data_t ud = {
+ .data = db,
+ .free_func = c_psql_database_delete
+ };
+ if (db->queries_num > 0) {
++db->ref_cnt;
plugin_register_complex_read ("postgresql", cb_name, c_psql_read,
- /* interval = */ (db->interval > 0) ? &cb_interval : NULL,
- &ud);
+ /* interval = */ db->interval, &ud);
}
if (db->writers_num > 0) {
++db->ref_cnt;
{
static int have_def_config = 0;
- int i;
-
if (0 == have_def_config) {
oconfig_item_t *c;
"any queries - please check your installation.");
}
- for (i = 0; i < ci->children_num; ++i) {
+ for (int i = 0; i < ci->children_num; ++i) {
oconfig_item_t *c = ci->children + i;
if (0 == strcasecmp (c->key, "Query"))