csv.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "libnetdata/libnetdata.h"
  3. #include "csv.h"
  4. void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, const char *startline, const char *separator, const char *endline, const char *betweenlines, RRDDIM *temp_rd) {
  5. rrdset_check_rdlock(r->st);
  6. //info("RRD2CSV(): %s: BEGIN", r->st->id);
  7. long c, i;
  8. RRDDIM *d;
  9. // print the csv header
  10. for(c = 0, i = 0, d = temp_rd?temp_rd:r->st->dimensions; d && c < r->d ;c++, d = d->next) {
  11. if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
  12. if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
  13. if(!i) {
  14. buffer_strcat(wb, startline);
  15. if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
  16. buffer_strcat(wb, "time");
  17. if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
  18. }
  19. buffer_strcat(wb, separator);
  20. if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
  21. buffer_strcat(wb, d->name);
  22. if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
  23. i++;
  24. }
  25. buffer_strcat(wb, endline);
  26. if(format == DATASOURCE_CSV_MARKDOWN) {
  27. // print the --- line after header
  28. for(c = 0, i = 0, d = temp_rd?temp_rd:r->st->dimensions; d && c < r->d ;c++, d = d->next) {
  29. if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
  30. if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
  31. if(!i) {
  32. buffer_strcat(wb, startline);
  33. if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
  34. buffer_strcat(wb, ":---:");
  35. if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
  36. }
  37. buffer_strcat(wb, separator);
  38. if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
  39. buffer_strcat(wb, ":---:");
  40. if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
  41. i++;
  42. }
  43. buffer_strcat(wb, endline);
  44. }
  45. if(!i) {
  46. // no dimensions present
  47. return;
  48. }
  49. long start = 0, end = rrdr_rows(r), step = 1;
  50. if(!(options & RRDR_OPTION_REVERSED)) {
  51. start = rrdr_rows(r) - 1;
  52. end = -1;
  53. step = -1;
  54. }
  55. // for each line in the array
  56. NETDATA_DOUBLE total = 1;
  57. for(i = start; i != end ;i += step) {
  58. NETDATA_DOUBLE *cn = &r->v[ i * r->d ];
  59. RRDR_VALUE_FLAGS *co = &r->o[ i * r->d ];
  60. buffer_strcat(wb, betweenlines);
  61. buffer_strcat(wb, startline);
  62. time_t now = r->t[i];
  63. if((options & RRDR_OPTION_SECONDS) || (options & RRDR_OPTION_MILLISECONDS)) {
  64. // print the timestamp of the line
  65. buffer_rrd_value(wb, (NETDATA_DOUBLE)now);
  66. // in ms
  67. if(options & RRDR_OPTION_MILLISECONDS) buffer_strcat(wb, "000");
  68. }
  69. else {
  70. // generate the local date time
  71. struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
  72. if(!tm) { error("localtime() failed."); continue; }
  73. buffer_date(wb, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
  74. }
  75. int set_min_max = 0;
  76. if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
  77. total = 0;
  78. for(c = 0, d = temp_rd?temp_rd:r->st->dimensions; d && c < r->d ;c++, d = d->next) {
  79. NETDATA_DOUBLE n = cn[c];
  80. if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
  81. n = -n;
  82. total += n;
  83. }
  84. // prevent a division by zero
  85. if(total == 0) total = 1;
  86. set_min_max = 1;
  87. }
  88. // for each dimension
  89. for(c = 0, d = temp_rd?temp_rd:r->st->dimensions; d && c < r->d ;c++, d = d->next) {
  90. if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
  91. if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
  92. buffer_strcat(wb, separator);
  93. NETDATA_DOUBLE n = cn[c];
  94. if(co[c] & RRDR_VALUE_EMPTY) {
  95. if(options & RRDR_OPTION_NULL2ZERO)
  96. buffer_strcat(wb, "0");
  97. else
  98. buffer_strcat(wb, "null");
  99. }
  100. else {
  101. if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
  102. n = -n;
  103. if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
  104. n = n * 100 / total;
  105. if(unlikely(set_min_max)) {
  106. r->min = r->max = n;
  107. set_min_max = 0;
  108. }
  109. if(n < r->min) r->min = n;
  110. if(n > r->max) r->max = n;
  111. }
  112. buffer_rrd_value(wb, n);
  113. }
  114. }
  115. buffer_strcat(wb, endline);
  116. }
  117. //info("RRD2CSV(): %s: END", r->st->id);
  118. }