| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #include "api_v2_contexts.h" |
| 4 | #include "aclk/aclk_capas.h" |
| 5 | #include "database/rrd-metadata.h" |
| 6 | #include "database/rrd-retention.h" |
| 7 | |
| 8 | void build_info_to_json_object(BUFFER *b); |
| 9 | |
| 10 | void buffer_json_agents_v2(BUFFER *wb, struct query_timings *timings, time_t now_s, bool info, bool array, CONTEXTS_OPTIONS options) { |
| 11 | if(!now_s) |
| 12 | now_s = now_realtime_sec(); |
| 13 | |
| 14 | if(array) { |
| 15 | buffer_json_member_add_array(wb, "agents"); |
| 16 | buffer_json_add_array_item_object(wb); |
| 17 | } |
| 18 | else |
| 19 | buffer_json_member_add_object(wb, "agent"); |
| 20 | |
| 21 | buffer_json_member_add_string(wb, "mg", localhost->machine_guid); |
| 22 | buffer_json_member_add_uuid(wb, "nd", localhost->node_id.uuid); |
| 23 | buffer_json_member_add_string(wb, "nm", rrdhost_hostname(localhost)); |
| 24 | buffer_json_member_add_time_t_formatted(wb, "now", now_s, options & CONTEXTS_OPTION_RFC3339); |
| 25 | |
| 26 | if(array) |
| 27 | buffer_json_member_add_uint64(wb, "ai", 0); |
| 28 | |
| 29 | if(info) { |
| 30 | buffer_json_member_add_object(wb, "application"); |
| 31 | build_info_to_json_object(wb); |
| 32 | buffer_json_object_close(wb); // application |
| 33 | |
| 34 | buffer_json_cloud_status(wb, now_s); |
| 35 | |
| 36 | // Get metrics metadata using our reusable function |
| 37 | RRDSTATS_METADATA metadata = rrdstats_metadata_collect(); |
| 38 | |
| 39 | buffer_json_member_add_object(wb, "nodes"); |
| 40 | { |
| 41 | buffer_json_member_add_uint64(wb, "total", metadata.nodes.total); |
| 42 | buffer_json_member_add_uint64(wb, "receiving", metadata.nodes.receiving); |
| 43 | buffer_json_member_add_uint64(wb, "sending", metadata.nodes.sending); |
| 44 | buffer_json_member_add_uint64(wb, "archived", metadata.nodes.archived); |
| 45 | } |
| 46 | buffer_json_object_close(wb); // nodes |
| 47 | |
| 48 | buffer_json_member_add_object(wb, "metrics"); |
| 49 | { |
| 50 | buffer_json_member_add_uint64(wb, "collected", metadata.metrics.collected); |
| 51 | buffer_json_member_add_uint64(wb, "available", metadata.metrics.available); |
| 52 | } |
| 53 | buffer_json_object_close(wb); |
| 54 | |
| 55 | buffer_json_member_add_object(wb, "instances"); |
| 56 | { |
| 57 | buffer_json_member_add_uint64(wb, "collected", metadata.instances.collected); |
| 58 | buffer_json_member_add_uint64(wb, "available", metadata.instances.available); |
| 59 | } |
| 60 | buffer_json_object_close(wb); |
| 61 | |
| 62 | buffer_json_member_add_object(wb, "contexts"); |
| 63 | { |
| 64 | buffer_json_member_add_uint64(wb, "collected", metadata.contexts.collected); |
| 65 | buffer_json_member_add_uint64(wb, "available", metadata.contexts.available); |
| 66 | buffer_json_member_add_uint64(wb, "unique", metadata.contexts.unique); |
| 67 | } |
| 68 | buffer_json_object_close(wb); |
| 69 | |
| 70 | agent_capabilities_to_json(wb, localhost, "capabilities"); |
| 71 | |
| 72 | buffer_json_member_add_object(wb, "api"); |
| 73 | { |
| 74 | buffer_json_member_add_uint64(wb, "version", aclk_get_http_api_version()); |
| 75 | buffer_json_member_add_boolean(wb, "bearer_protection", netdata_is_protected_by_bearer); |
| 76 | } |
| 77 | buffer_json_object_close(wb); // api |
| 78 | |
| 79 | // Get retention information using our new function |
| 80 | RRDSTATS_RETENTION retention = rrdstats_retention_collect(); |
| 81 | |
| 82 | buffer_json_member_add_array(wb, "db_size"); |
| 83 | for (size_t i = 0; i < retention.storage_tiers; i++) { |
| 84 | RRD_STORAGE_TIER *tier_info = &retention.tiers[i]; |
| 85 | if (!tier_info->backend || tier_info->tier != i) |
| 86 | continue; |
| 87 | |
| 88 | buffer_json_add_array_item_object(wb); |
| 89 | buffer_json_member_add_uint64(wb, "tier", tier_info->tier); |
| 90 | buffer_json_member_add_string(wb, "granularity", tier_info->granularity_human); |
| 91 | buffer_json_member_add_uint64(wb, "metrics", tier_info->metrics); |
| 92 | buffer_json_member_add_uint64(wb, "samples", tier_info->samples); |
| 93 | |
| 94 | if(tier_info->disk_used || tier_info->disk_max) { |
| 95 | buffer_json_member_add_uint64(wb, "disk_used", tier_info->disk_used); |
| 96 | buffer_json_member_add_uint64(wb, "disk_max", tier_info->disk_max); |
| 97 | // Format disk_percent to have only 2 decimal places |
| 98 | double rounded_percent = floor(tier_info->disk_percent * 100.0 + 0.5) / 100.0; |
| 99 | buffer_json_member_add_double(wb, "disk_percent", rounded_percent); |
| 100 | } |
| 101 | |
| 102 | if(tier_info->first_time_s < tier_info->last_time_s) { |
| 103 | buffer_json_member_add_time_t_formatted(wb, "from", tier_info->first_time_s, options & CONTEXTS_OPTION_RFC3339); |
| 104 | buffer_json_member_add_time_t_formatted(wb, "to", tier_info->last_time_s, options & CONTEXTS_OPTION_RFC3339); |
| 105 | buffer_json_member_add_time_t(wb, "retention", tier_info->retention); |
| 106 | buffer_json_member_add_string(wb, "retention_human", tier_info->retention_human); |
| 107 | |
| 108 | if(tier_info->disk_used || tier_info->disk_max) { |
| 109 | buffer_json_member_add_time_t(wb, "requested_retention", tier_info->requested_retention); |
| 110 | buffer_json_member_add_string(wb, "requested_retention_human", tier_info->requested_retention_human); |
| 111 | buffer_json_member_add_time_t(wb, "expected_retention", tier_info->expected_retention); |
| 112 | buffer_json_member_add_string(wb, "expected_retention_human", tier_info->expected_retention_human); |
| 113 | } |
| 114 | } |
| 115 | buffer_json_object_close(wb); |
| 116 | } |
| 117 | buffer_json_array_close(wb); // db_size |
| 118 | } |
| 119 | |
| 120 | if(timings) |
| 121 | buffer_json_query_timings(wb, "timings", timings); |
| 122 | |
| 123 | buffer_json_object_close(wb); |
| 124 | |
| 125 | if(array) |
| 126 | buffer_json_array_close(wb); |
| 127 | } |