danielhilst

pax_write

Jul 23rd, 2012
133
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 21.10 KB | None | 0 0
  1. /**
  2. * collectd - src/csv.c
  3. * Copyright (C) 2007-2009 Florian octo Forster
  4. * Copyright (C) 2009 Doug MacEachern
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation; only version 2 of the License is applicable.
  9. *
  10. * This program is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program; if not, write to the Free Software Foundation, Inc.,
  17. * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  18. *
  19. * Authors:
  20. * Florian octo Forster <octo at verplant.org>
  21. * Doug MacEachern <[email protected]>
  22. **/
  23.  
  24. #define C_AVL_CREATE_STRCMP() (c_avl_create((int (*)(const void *, const void *))strcmp))
  25.  
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28. #include <fcntl.h>
  29.  
  30. #include "collectd.h"
  31. #include "plugin.h"
  32. #include "common.h"
  33. #include "utils_cache.h"
  34. #include "utils_parse_option.h"
  35. #include "utils_avltree.h"
  36.  
  37. /*
  38. * Private variables
  39. */
  40. /* static const char *config_keys[] = */
  41. /* { */
  42. /* "DataDir", */
  43. /* "FilePrefix", */
  44. /* "StoreRates", */
  45. /* "IncludePlugins", */
  46. /* "IncludeTypes", */
  47. /* }; */
  48. /* static int config_keys_num = STATIC_ARRAY_SIZE (config_keys); */
  49.  
  50.  
  51. /*
  52. * TODO: Implement this kind of options
  53. *
  54. *
  55. *
  56. * <Plugin "pax_write">
  57. * DataDir "/opt/collectd/var/lib/collectd/csv/"
  58. * FilePrefix "data-file"
  59. * StoreRates false
  60. *
  61. * EveryThing yes|no default no
  62. *
  63. *
  64. * <Host "hostname">
  65. * <Plugin "plugin[-plugininstance]/type[-typeinstance]">
  66. * DS "datasources" "datasources" ...
  67. * </Plugin>
  68. *
  69. * <Plugin "plugin[-plugininstance]/type[-typeinstance] /> # All datasources
  70. * </Host>
  71. *
  72. *
  73. * </Plugin>
  74. *
  75. *
  76. */
  77.  
  78.  
  79. static char *datadir = NULL;
  80. static int store_rates = 0;
  81. static c_avl_tree_t *hosts_tree = NULL;
  82. /* static char **include_plugins_keys = NULL; */
  83. /* static char **include_plugins_values = NULL; */
  84. static char *fileprefix = NULL;
  85. /* static char *format = NULL; */
  86.  
  87. static int value_list_to_string (char *buffer, int buffer_len,
  88. const data_set_t *ds, const value_list_t *vl)
  89. {
  90. int offset = 0;
  91. int status;
  92. /* char **keys; */
  93. int i;
  94. gauge_t *rates = NULL;
  95.  
  96. assert (0 == strcmp (ds->type, vl->type));
  97.  
  98.  
  99. /*
  100. * Search plugin on AVL tree and
  101. * return if not found
  102. */
  103. void *tmp;
  104. char **p_types;
  105. if (c_avl_get(include_plugins, vl->plugin, &tmp) != 0)
  106. return -1;
  107.  
  108. p_types = (char **)tmp;
  109. DEBUG ("pax write plugin: pax_write: Plugin %s found on AVL tree", vl->plugin);
  110.  
  111. memset (buffer, '\0', buffer_len);
  112.  
  113.  
  114.  
  115.  
  116.  
  117.  
  118.  
  119. for (i = 0; i < ds->ds_num; i++)
  120. {
  121. int j;
  122. int bit;
  123. for (j = 0, bit = 0; p_types[j]; j++)
  124. {
  125. if (strcmp(p_types[j], ds->ds[i].name) == 0)
  126. {
  127. bit = 1;
  128. break;
  129. }
  130. }
  131.  
  132. if (bit == 0)
  133. {
  134. continue;
  135. }
  136.  
  137. DEBUG("pax write plugin: pax_write: Data source %s found on plugin %s", ds->ds[i].name, vl->plugin);
  138.  
  139. /*
  140. * A new line if we are not on
  141. * first iteration
  142. */
  143. if (i > 0)
  144. {
  145. status = ssnprintf(buffer + offset, buffer_len - offset, "\n");
  146. if ((status < 1) || (status >= buffer_len - offset))
  147. return (-1);
  148.  
  149. offset += status;
  150. }
  151.  
  152.  
  153. /*
  154. * Host
  155. */
  156. status = ssnprintf (buffer + offset, buffer_len - offset,
  157. "%s", vl->host);
  158. if ((status < 1) || (status >= buffer_len - offset))
  159. return (-1);
  160. offset += status;
  161.  
  162. /*
  163. * Plugin Instance
  164. */
  165. if ((strlen (vl->plugin_instance) == 0))
  166. {
  167. status = ssnprintf (buffer + offset, buffer_len - offset,
  168. ",%s", vl->plugin);
  169. }
  170. else
  171. {
  172. status = ssnprintf (buffer + offset, buffer_len - offset,
  173. ",%s-%s", vl->plugin, vl->plugin_instance);
  174. }
  175.  
  176. if ((status < 1) || (status >= buffer_len - offset))
  177. return (-1);
  178. offset += status;
  179.  
  180.  
  181.  
  182. /*
  183. * Type instance
  184. */
  185. if ((strlen (vl->type_instance) == 0))
  186. {
  187. status = ssnprintf (buffer + offset, buffer_len - offset,
  188. ",%s", vl->type);
  189. }
  190. else
  191. {
  192. status = ssnprintf (buffer + offset, buffer_len - offset,
  193. ",%s-%s", vl->type, vl->type_instance);
  194. }
  195.  
  196. if ((status < 1) || (status >= buffer_len - offset))
  197. return (-1);
  198. offset += status;
  199.  
  200.  
  201. /*
  202. * Data source name
  203. */
  204. status = ssnprintf (buffer + offset, buffer_len - offset,
  205. ",%s", ds->ds[i].name);
  206. if ((status < 1) || (status >= buffer_len - offset))
  207. return (-1);
  208. offset += status;
  209.  
  210. /*
  211. * Data source
  212. */
  213. if ((ds->ds[i].type != DS_TYPE_COUNTER)
  214. && (ds->ds[i].type != DS_TYPE_GAUGE)
  215. && (ds->ds[i].type != DS_TYPE_DERIVE)
  216. && (ds->ds[i].type != DS_TYPE_ABSOLUTE))
  217. return (-1);
  218.  
  219. if (ds->ds[i].type == DS_TYPE_GAUGE)
  220. {
  221. status = ssnprintf (buffer + offset, buffer_len - offset,
  222. ",%lf", vl->values[i].gauge);
  223. }
  224. else if (store_rates != 0)
  225. {
  226. if (rates == NULL)
  227. rates = uc_get_rate (ds, vl);
  228. if (rates == NULL)
  229. {
  230. WARNING ("pax plugin: "
  231. "uc_get_rate failed.");
  232. return (-1);
  233. }
  234. status = ssnprintf (buffer + offset,
  235. buffer_len - offset,
  236. ",%lf", rates[i]);
  237. }
  238. else if (ds->ds[i].type == DS_TYPE_COUNTER)
  239. {
  240. status = ssnprintf (buffer + offset,
  241. buffer_len - offset,
  242. ",%llu",
  243. vl->values[i].counter);
  244. }
  245. else if (ds->ds[i].type == DS_TYPE_DERIVE)
  246. {
  247. status = ssnprintf (buffer + offset,
  248. buffer_len - offset,
  249. ",%"PRIi64,
  250. vl->values[i].derive);
  251. }
  252. else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
  253. {
  254. status = ssnprintf (buffer + offset,
  255. buffer_len - offset,
  256. ",%"PRIu64,
  257. vl->values[i].absolute);
  258. }
  259.  
  260. if ((status < 1) || (status >= (buffer_len - offset)))
  261. {
  262. sfree (rates);
  263. return (-1);
  264. }
  265.  
  266. offset += status;
  267.  
  268. /*
  269. * Epoch/Time
  270. */
  271. status = ssnprintf (buffer + offset, buffer_len - offset, ",%.3f",
  272. CDTIME_T_TO_DOUBLE (vl->time));
  273. if ((status < 1) || (status >= buffer_len - offset))
  274. return (-1);
  275. offset += status;
  276. } /* for ds->ds_num */
  277.  
  278. sfree (rates);
  279. return (0);
  280. } /* int value_list_to_string */
  281.  
  282. static int value_list_to_filename (char *buffer, int buffer_len, const char *fileprefix)
  283. {
  284. int status;
  285. int offset = 0;
  286.  
  287.  
  288.  
  289. if (datadir != NULL)
  290. {
  291. status = ssnprintf (buffer, buffer_len,
  292. "%s/", datadir);
  293. if ((status < 1) || (status >= buffer_len))
  294. return (-1);
  295. offset += status;
  296. } else {
  297. ERROR ("pax write plugin: value_list_to_filename: DataDir is NULL at %d", __LINE__);
  298. return (-1);
  299. }
  300.  
  301. assert(fileprefix);
  302. status = ssnprintf (buffer + offset, buffer_len,
  303. "%s", fileprefix);
  304. if ((status < 1) || (status >= buffer_len))
  305. return (-1);
  306. offset += status;
  307.  
  308. time_t now;
  309. struct tm stm;
  310.  
  311. /* TODO: Find a way to minimize the calls to `localtime_r',
  312. * since they are pretty expensive.. */
  313. now = time (NULL);
  314. if (localtime_r (&now, &stm) == NULL)
  315. {
  316. ERROR ("pax plugin: localtime_r failed");
  317. return (1);
  318. }
  319.  
  320. strftime (buffer + offset, buffer_len - offset,
  321. "-%Y-%m-%d", &stm);
  322.  
  323.  
  324. return (0);
  325. } /* int value_list_to_filename */
  326.  
  327.  
  328. static int pax_create_file (const char *filename, const data_set_t *ds)
  329. {
  330. int fd;
  331.  
  332. if (check_create_dir (datadir))
  333. return (-1);
  334.  
  335. fd = creat (filename, S_IRWXU | S_IWUSR | S_IRGRP | S_IROTH);
  336. if (fd == -1)
  337. {
  338. char errbuf[1024];
  339. ERROR ("pax plugin: fopen (%s) failed: %s",
  340. filename,
  341. sstrerror (errno, errbuf, sizeof (errbuf)));
  342. return (-1);
  343. }
  344.  
  345. close (fd);
  346.  
  347. return 0;
  348. } /* int pax_create_file */
  349.  
  350.  
  351. static int pax_config_add_plugin(oconfig_item_t pluginopt, c_avl_tree_t *ptree)
  352. {
  353. int j;
  354. char **datasources = NULL;
  355. char *pname;
  356. assert(ptree);
  357.  
  358. pname = strdup(pluginopt->values[0].values.string);
  359. /* No datasources mean, collect all datasources */
  360. if (pluginopt->children_num == 1)
  361. {
  362. datasources = malloc(sizeof(char *) * pluginopt->children[0].values_num);
  363.  
  364. if (!datasources)
  365. {
  366. int errbuf[1024];
  367. ERROR("pax write plugin: pax_config: Can't allocate memory %s",
  368. sstrerror(errno, errbuf, sizeof(errbuf)));
  369. return (-1);
  370. }
  371.  
  372. for (j = 0; j < pluginopt->children[0].values_num; j++)
  373. {
  374. datasources[j] = strdup(pluginopt->children[0].values[j].values.string);
  375. }
  376. }
  377.  
  378.  
  379. if (pluginopt->children_num == 0)
  380. {
  381.  
  382. int error = c_avl_insert(ptree, pname, datasources);
  383. if (error)
  384. {
  385. ERROR("pax write plugin: pax_config_add_plugin: Can't insert %s at plugin tree", pname);
  386. return (-1);
  387. }
  388. }
  389.  
  390.  
  391.  
  392.  
  393.  
  394.  
  395.  
  396.  
  397.  
  398. static int pax_config_add_host (oconfig_item_t *hostopt)
  399. {
  400. int error;
  401. int i;
  402. char *hostname = strdup(hostopt->values[0].value.string);
  403. c_avl_tree_t *plugin_tree = NULL;
  404.  
  405. if (!hostname)
  406. {
  407. char errbuf[1024];
  408. ERROR("pax write plugin: pax_config_add_host: Can't allocate memory: %s\n",
  409. sstrerror (errno, errbuf,sizeof (errbuf)));
  410. return (-1);
  411. }
  412.  
  413. if (!hosts_tree)
  414. {
  415. hosts_tree = C_AVL_CREATE_STRCMP();
  416. if (!hosts_tree)
  417. {
  418. ERROR("pax write plugin: pax_config: Can't allocate memory for AVL Trees at %d", __LINE__);
  419. return (-1);
  420. }
  421. }
  422.  
  423.  
  424. plugin_tree = C_AVL_CREATE_STRCMP();
  425. if (!plugin_tree)
  426. {
  427. ERROR("pax write plugin: pax_config: Can't allocate memory for AVL Trees at %d", __LINE__);
  428. return (-1);
  429. }
  430.  
  431. for (i = 0; i < hostopt->children_num; i++)
  432. {
  433. oconfig_item_t *pluginopt = hostopt->children + i;
  434.  
  435. if (strcasecmp("Plugin", pluginopt->key) == 0)
  436. {
  437. int error = pax_config_add_plugin(plugin_opt, plugin_tree);
  438. if (error)
  439. return (-1)
  440. }
  441. }
  442.  
  443. error = c_avl_insert(hosts_tree, hostname, plugins_tree);
  444.  
  445. }
  446.  
  447. static int pax_config_complex (oconfig_item_t *ci)
  448. {
  449. int i;
  450.  
  451. include_plugins = c_avl_create((int (*)(const void *, const void *))strcmp);
  452.  
  453. if (!include_plugins)
  454. {
  455. ERROR("pax write plugin: pax_config: Can't allocate memory for AVL Trees at %d", __LINE__);
  456. return (-1);
  457. }
  458.  
  459. for (i = 0; i < ci->children_num; i++)
  460. {
  461. oconfig_item_t *option = ci->children + i;
  462. if (strcasecmp ("DataDir", option->key) == 0)
  463. {
  464. if (datadir != NULL)
  465. free (datadir);
  466.  
  467. datadir = strdup (option->values[0].value.string);
  468. if (datadir != NULL && datadir[strlen(datadir) - 1] != '/')
  469. {
  470. ERROR("pax write plugin: pax_config: Directory path should end with a slash");
  471. free (datadir);
  472. datadir = NULL;
  473. return (-1);
  474. }
  475. DEBUG("pax write plugin: pax_config: DataDir = '%s'", datadir);
  476. }
  477. else if (strcasecmp ("StoreRates", option->key) == 0)
  478. {
  479. if (option->values[0].value.boolean)
  480. store_rates = 1;
  481. else
  482. store_rates = 0;
  483. DEBUG("pax write plugin: pax_config: StoreRates = '%s'", (store_rates ? "true" : "false"));
  484. }
  485. else if (strcasecmp ("FilePrefix", option->key) == 0)
  486. {
  487. if (fileprefix != NULL)
  488. free(fileprefix);
  489.  
  490. fileprefix = strdup(option->values[0].value.string);
  491. DEBUG("pax write plugin: pax_config: FilePrefix = '%s'", fileprefix);
  492. }
  493. else if (strcasecmp ("Host", option->key) == 0)
  494. {
  495. int error = pax_config_add_host(option);
  496. if (error)
  497. {
  498. ERROR("pax write plugin: pax_config: Can't add host %s", option->values[0].value.string);
  499. return (-1);
  500. }
  501. }
  502. /* else if (strcasecmp ("IncludePlugins", option->key) == 0) */
  503. /* { */
  504. /* int j; */
  505. /* include_plugins_keys = malloc(sizeof(char *) * option->children_num); */
  506. /* for (j = 0; j < option->children_num; j++) */
  507. /* { */
  508. /* int k; */
  509. /* oconfig_item_t *plugin_opt = option->children + j; */
  510. /* char **values = malloc(plugin_opt->values_num * sizeof(char *) + 1); */
  511. /* memset(values, '\0', plugin_opt->values_num * sizeof(char *) + 1); */
  512. /* include_plugins_keys[j] = strdup(plugin_opt->key); */
  513. /* /\* DEBUG(">>>>> %s", include_plugins_keys[j]); *\/ */
  514. /* for (k = 0; k < plugin_opt->values_num; k++) */
  515. /* { */
  516. /* /\* DEBUG(">>>>>>>>>>>> %s", plugin_opt->values[k].value.string); *\/ */
  517. /* values[k] = strdup(plugin_opt->values[k].value.string); */
  518. /* } */
  519. /* values[k] = NULL; /\* NULL terminated array *\/ */
  520. /* c_avl_insert(include_plugins, include_plugins_keys[j], values); } */
  521.  
  522. /* } */
  523. else
  524. {
  525. return (-1);
  526. }
  527.  
  528. }
  529. return (0);
  530. } /* int pax_config_complex */
  531.  
  532.  
  533.  
  534. /* static int pax_config (const char *key, const char *value) */
  535. /* { */
  536. /* if (strcasecmp ("DataDir", key) == 0) */
  537. /* { */
  538. /* if (datadir != NULL) */
  539. /* free (datadir); */
  540.  
  541. /* datadir = strdup (value); */
  542. /* if (datadir != NULL && datadir[strlen(datadir) - 1] != '/') */
  543. /* { */
  544. /* ERROR("pax write plugin: pax_config: Directory path should end with a slash"); */
  545. /* free (datadir); */
  546. /* datadir = NULL; */
  547. /* return (-1); */
  548. /* } */
  549. /* DEBUG("pax write plugin: pax_config: DataDir = '%s'", datadir); */
  550. /* } */
  551. /* else if (strcasecmp ("StoreRates", key) == 0) */
  552. /* { */
  553. /* if (IS_TRUE (value)) */
  554. /* store_rates = 1; */
  555. /* else */
  556. /* store_rates = 0; */
  557. /* } */
  558. /* else if (strcasecmp ("FilePrefix", key) == 0) */
  559. /* { */
  560. /* if (fileprefix != NULL) */
  561. /* free(fileprefix); */
  562.  
  563. /* fileprefix = strdup(value); */
  564. /* } */
  565. /* else */
  566. /* { */
  567. /* return (-1); */
  568. /* } */
  569. /* return (0); */
  570. /* } /\* int pax_config *\/ */
  571.  
  572. static int pax_write (const data_set_t *ds, const value_list_t *vl,
  573. user_data_t __attribute__((unused)) *user_data)
  574. {
  575. struct stat statbuf;
  576. char filename[512];
  577. char values[4096];
  578. FILE *pax_fp;
  579. int pax_fd;
  580. struct flock fl;
  581. int status;
  582.  
  583. if (0 != strcmp (ds->type, vl->type)) {
  584. ERROR ("pax plugin: DS type does not match value list type");
  585. return -1;
  586. }
  587.  
  588. if (value_list_to_filename (filename, sizeof (filename), fileprefix) != 0)
  589. return (-1);
  590.  
  591. DEBUG ("pax write plugin: pax_write: filename = %s;", filename);
  592.  
  593. if (value_list_to_string (values, sizeof (values), ds, vl) != 0)
  594. return (-1);
  595.  
  596. if (stat (filename, &statbuf) == -1)
  597. {
  598. if (errno == ENOENT)
  599. {
  600. if (pax_create_file (filename, ds))
  601. return (-1);
  602. }
  603. else
  604. {
  605. char errbuf[1024];
  606. ERROR ("stat(%s) failed: %s", filename,
  607. sstrerror (errno, errbuf,
  608. sizeof (errbuf)));
  609. return (-1);
  610. }
  611. }
  612. else if (!S_ISREG (statbuf.st_mode))
  613. {
  614. ERROR ("stat(%s): Not a regular file!",
  615. filename);
  616. return (-1);
  617. }
  618.  
  619. pax_fp = fopen (filename, "a");
  620. if (pax_fp == NULL)
  621. {
  622. char errbuf[1024];
  623. ERROR ("pax write plugin: fopen (%s) failed: %s", filename,
  624. sstrerror (errno, errbuf, sizeof (errbuf)));
  625. return (-1);
  626. }
  627. pax_fd = fileno (pax_fp);
  628.  
  629. memset (&fl, '\0', sizeof (fl));
  630. fl.l_start = 0;
  631. fl.l_len = 0; /* till end of file */
  632. fl.l_pid = getpid ();
  633. fl.l_type = F_WRLCK;
  634. fl.l_whence = SEEK_SET;
  635.  
  636. status = fcntl (pax_fd, F_SETLK, &fl);
  637. if (status != 0)
  638. {
  639. char errbuf[1024];
  640. ERROR ("pax plugin: flock (%s) failed: %s", filename,
  641. sstrerror (errno, errbuf, sizeof (errbuf)));
  642. fclose (pax_fp);
  643. return (-1);
  644. }
  645.  
  646. fprintf (pax_fp, "%s\n", values);
  647.  
  648. /* The lock is implicitely released. I we don't release it explicitely
  649. * because the `FILE *' may need to flush a cache first */
  650. fclose (pax_fp);
  651.  
  652. return (0);
  653. } /* int pax_write */
  654.  
  655.  
  656. void module_register (void)
  657. {
  658. plugin_register_complex_config ("pax_write", pax_config_complex);
  659. /* plugin_register_config ("pax_write", pax_config, */
  660. /* config_keys, config_keys_num); */
  661. plugin_register_write ("pax_write", pax_write, /* user_data = */ NULL);
  662. } /* void module_register */
Advertisement
Add Comment
Please, Sign In to add comment