master
c 226 lines 8.38 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #define PULSE_INTERNALS 1
4 #include "pulse-http-api.h"
5
6 #define GLOBAL_STATS_RESET_WEB_USEC_MAX 0x01
7
8 static struct web_statistics {
9 bool extended;
10
11 PAD64(int32_t) connected_clients;
12
13 PAD64(uint64_t) web_requests;
14 PAD64(uint64_t) web_usec;
15 PAD64(uint64_t) web_usec_max;
16
17 PAD64(uint64_t) content_size_uncompressed;
18 PAD64(uint64_t) content_size_compressed;
19 } live_stats = { 0 };
20
21 void pulse_web_client_connected(void) {
22 __atomic_fetch_add(&live_stats.connected_clients, 1, __ATOMIC_RELAXED);
23 }
24
25 void pulse_web_client_disconnected(void) {
26 __atomic_fetch_sub(&live_stats.connected_clients, 1, __ATOMIC_RELAXED);
27 }
28
29 void pulse_web_request_completed(uint64_t dt,
30 uint64_t bytes_received __maybe_unused,
31 uint64_t bytes_sent __maybe_unused,
32 uint64_t content_size,
33 uint64_t compressed_content_size) {
34 uint64_t old_web_usec_max = live_stats.web_usec_max;
35 while(dt > old_web_usec_max)
36 __atomic_compare_exchange(&live_stats.web_usec_max, &old_web_usec_max, &dt, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
37
38 __atomic_fetch_add(&live_stats.web_requests, 1, __ATOMIC_RELAXED);
39 __atomic_fetch_add(&live_stats.web_usec, dt, __ATOMIC_RELAXED);
40 // __atomic_fetch_add(&live_stats.bytes_received, bytes_received, __ATOMIC_RELAXED);
41 // __atomic_fetch_add(&live_stats.bytes_sent, bytes_sent, __ATOMIC_RELAXED);
42 __atomic_fetch_add(&live_stats.content_size_uncompressed, content_size, __ATOMIC_RELAXED);
43 __atomic_fetch_add(&live_stats.content_size_compressed, compressed_content_size, __ATOMIC_RELAXED);
44 }
45
46 static inline void pulse_web_copy(struct web_statistics *gs, uint8_t options) {
47 gs->connected_clients = __atomic_load_n(&live_stats.connected_clients, __ATOMIC_RELAXED);
48 gs->web_requests = __atomic_load_n(&live_stats.web_requests, __ATOMIC_RELAXED);
49 gs->web_usec = __atomic_load_n(&live_stats.web_usec, __ATOMIC_RELAXED);
50 gs->web_usec_max = __atomic_load_n(&live_stats.web_usec_max, __ATOMIC_RELAXED);
51 // gs->bytes_received = __atomic_load_n(&live_stats.bytes_received, __ATOMIC_RELAXED);
52 // gs->bytes_sent = __atomic_load_n(&live_stats.bytes_sent, __ATOMIC_RELAXED);
53 gs->content_size_uncompressed = __atomic_load_n(&live_stats.content_size_uncompressed, __ATOMIC_RELAXED);
54 gs->content_size_compressed = __atomic_load_n(&live_stats.content_size_compressed, __ATOMIC_RELAXED);
55
56 if(options & GLOBAL_STATS_RESET_WEB_USEC_MAX) {
57 uint64_t n = 0;
58 __atomic_compare_exchange(&live_stats.web_usec_max, (uint64_t *) &gs->web_usec_max, &n, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
59 }
60 }
61
62 void pulse_web_do(bool extended) {
63 static struct web_statistics gs;
64 pulse_web_copy(&gs, GLOBAL_STATS_RESET_WEB_USEC_MAX);
65
66 // ----------------------------------------------------------------
67
68 {
69 static RRDSET *st_clients = NULL;
70 static RRDDIM *rd_clients = NULL;
71
72 if (unlikely(!st_clients)) {
73 st_clients = rrdset_create_localhost(
74 "netdata"
75 , "clients"
76 , NULL
77 , "HTTP API"
78 , "netdata.http_api_clients"
79 , "Netdata Web API Clients"
80 , "connected clients"
81 , "netdata"
82 , "pulse"
83 , 130200
84 , localhost->rrd_update_every
85 , RRDSET_TYPE_LINE
86 );
87
88 rd_clients = rrddim_add(st_clients, "clients", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
89 }
90
91 rrddim_set_by_pointer(st_clients, rd_clients, gs.connected_clients);
92 rrdset_done(st_clients);
93 }
94
95 // ----------------------------------------------------------------
96
97 {
98 static RRDSET *st_reqs = NULL;
99 static RRDDIM *rd_requests = NULL;
100
101 if (unlikely(!st_reqs)) {
102 st_reqs = rrdset_create_localhost(
103 "netdata"
104 , "requests"
105 , NULL
106 , "HTTP API"
107 , "netdata.http_api_requests"
108 , "Netdata Web API Requests Received"
109 , "requests/s"
110 , "netdata"
111 , "pulse"
112 , 130300
113 , localhost->rrd_update_every
114 , RRDSET_TYPE_LINE
115 );
116
117 rd_requests = rrddim_add(st_reqs, "requests", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
118 }
119
120 rrddim_set_by_pointer(st_reqs, rd_requests, (collected_number) gs.web_requests);
121 rrdset_done(st_reqs);
122 }
123
124 // ----------------------------------------------------------------
125
126 {
127 static unsigned long long old_web_requests = 0, old_web_usec = 0;
128 static collected_number average_response_time = -1;
129
130 static RRDSET *st_duration = NULL;
131 static RRDDIM *rd_average = NULL,
132 *rd_max = NULL;
133
134 if (unlikely(!st_duration)) {
135 st_duration = rrdset_create_localhost(
136 "netdata"
137 , "response_time"
138 , NULL
139 , "HTTP API"
140 , "netdata.http_api_response_time"
141 , "Netdata Web API Response Time"
142 , "milliseconds/request"
143 , "netdata"
144 , "pulse"
145 , 130500
146 , localhost->rrd_update_every
147 , RRDSET_TYPE_LINE
148 );
149
150 rd_average = rrddim_add(st_duration, "average", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
151 rd_max = rrddim_add(st_duration, "max", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
152 }
153
154 uint64_t gweb_usec = gs.web_usec;
155 uint64_t gweb_requests = gs.web_requests;
156
157 uint64_t web_usec = (gweb_usec >= old_web_usec) ? gweb_usec - old_web_usec : 0;
158 uint64_t web_requests = (gweb_requests >= old_web_requests) ? gweb_requests - old_web_requests : 0;
159
160 old_web_usec = gweb_usec;
161 old_web_requests = gweb_requests;
162
163 if (web_requests)
164 average_response_time = (collected_number) (web_usec / web_requests);
165
166 if (unlikely(average_response_time != -1))
167 rrddim_set_by_pointer(st_duration, rd_average, average_response_time);
168 else
169 rrddim_set_by_pointer(st_duration, rd_average, 0);
170
171 rrddim_set_by_pointer(st_duration, rd_max, ((gs.web_usec_max)?(collected_number)gs.web_usec_max:average_response_time));
172 rrdset_done(st_duration);
173 }
174
175 // ----------------------------------------------------------------
176
177 if(!extended) return;
178
179 // ----------------------------------------------------------------
180
181 {
182 static unsigned long long old_content_size = 0, old_compressed_content_size = 0;
183 static collected_number compression_ratio = -1;
184
185 static RRDSET *st_compression = NULL;
186 static RRDDIM *rd_savings = NULL;
187
188 if (unlikely(!st_compression)) {
189 st_compression = rrdset_create_localhost(
190 "netdata"
191 , "compression_ratio"
192 , NULL
193 , "HTTP API"
194 , "netdata.http_api_compression_ratio"
195 , "Netdata Web API Responses Compression Savings Ratio"
196 , "percentage"
197 , "netdata"
198 , "pulse"
199 , 130600
200 , localhost->rrd_update_every
201 , RRDSET_TYPE_LINE
202 );
203
204 rd_savings = rrddim_add(st_compression, "savings", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
205 }
206
207 // since we don't lock here to read the data
208 // read the smaller value first
209 unsigned long long gcompressed_content_size = gs.content_size_compressed;
210 unsigned long long gcontent_size = gs.content_size_uncompressed;
211
212 unsigned long long compressed_content_size = gcompressed_content_size - old_compressed_content_size;
213 unsigned long long content_size = gcontent_size - old_content_size;
214
215 old_compressed_content_size = gcompressed_content_size;
216 old_content_size = gcontent_size;
217
218 if (content_size && content_size >= compressed_content_size)
219 compression_ratio = ((content_size - compressed_content_size) * 100 * 1000) / content_size;
220
221 if (compression_ratio != -1)
222 rrddim_set_by_pointer(st_compression, rd_savings, compression_ratio);
223
224 rrdset_done(st_compression);
225 }
226 }