csv.c 5.1 KB

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