summaryrefslogtreecommitdiff
path: root/ot_stats.c
diff options
context:
space:
mode:
Diffstat (limited to 'ot_stats.c')
-rw-r--r--ot_stats.c492
1 files changed, 282 insertions, 210 deletions
diff --git a/ot_stats.c b/ot_stats.c
index 6589aef..5f97a2f 100644
--- a/ot_stats.c
+++ b/ot_stats.c
@@ -6,6 +6,7 @@
6/* System */ 6/* System */
7#include <inttypes.h> 7#include <inttypes.h>
8#include <pthread.h> 8#include <pthread.h>
9#include <stdatomic.h>
9#include <stdio.h> 10#include <stdio.h>
10#include <stdlib.h> 11#include <stdlib.h>
11#include <string.h> 12#include <string.h>
@@ -16,15 +17,13 @@
16#include <syslog.h> 17#include <syslog.h>
17#endif 18#endif
18 19
19/* Libowfat */
20#include "io.h"
21
22/* Opentracker */ 20/* Opentracker */
23#include "ot_accesslist.h" 21#include "ot_accesslist.h"
24#include "ot_hex.h" 22#include "ot_hex.h"
25#include "ot_iovec.h" 23#include "ot_iovec.h"
26#include "ot_ip.h" 24#include "ot_ip.h"
27#include "ot_mutex.h" 25#include "ot_mutex.h"
26#include "ot_fmt.h"
28#include "ot_stats.h" 27#include "ot_stats.h"
29#include "trackerlogic.h" 28#include "trackerlogic.h"
30 29
@@ -38,27 +37,58 @@
38static void stats_make(size_t *iovec_entries, struct iovec **iovector, ot_tasktype mode); 37static void stats_make(size_t *iovec_entries, struct iovec **iovector, ot_tasktype mode);
39#define OT_STATS_TMPSIZE 8192 38#define OT_STATS_TMPSIZE 8192
40 39
41/* Clumsy counters... to be rethought */ 40/* Each serving thread keeps its own statistics tally. The list is linked
42static unsigned long long ot_overall_tcp_connections; 41 through intrusive next pointers within the workstruct.
43static unsigned long long ot_overall_udp_connections; 42
44static unsigned long long ot_overall_tcp_successfulannounces; 43 Registration happens once per thread and the adding up once per statistics
45static unsigned long long ot_overall_udp_successfulannounces; 44 request, so this lock is never on anybody's hot path. */
46static unsigned long long ot_overall_tcp_successfulscrapes; 45static struct ot_workstruct *g_counter_contexts;
47static unsigned long long ot_overall_udp_successfulscrapes; 46static ot_counter g_retired[OT_COUNTER_COUNT];
48static unsigned long long ot_overall_udp_connectionidmissmatches; 47static pthread_mutex_t g_counter_mutex = PTHREAD_MUTEX_INITIALIZER;
49static unsigned long long ot_overall_tcp_connects; 48
50static unsigned long long ot_overall_udp_connects; 49void stats_counters_register(struct ot_workstruct *ws) {
51static unsigned long long ot_overall_completed; 50 pthread_mutex_lock(&g_counter_mutex);
52static unsigned long long ot_full_scrape_count; 51 ws->counters_next = g_counter_contexts;
53static unsigned long long ot_full_scrape_request_count; 52 g_counter_contexts = ws;
54static unsigned long long ot_full_scrape_size; 53 pthread_mutex_unlock(&g_counter_mutex);
55static unsigned long long ot_failed_request_counts[CODE_HTTPERROR_COUNT]; 54}
55
56void stats_counters_retire(struct ot_workstruct *ws) {
57 struct ot_workstruct **link;
58 size_t i;
59
60 pthread_mutex_lock(&g_counter_mutex);
61 for (link = &g_counter_contexts; *link; link = &(*link)->counters_next)
62 if (*link == ws) {
63 *link = ws->counters_next;
64 break;
65 }
66
67 /* When retiring a worker thread, collect the counter tally in the global */
68 for (i = 0; i < OT_COUNTER_COUNT; ++i)
69 atomic_fetch_add_explicit(g_retired + i, atomic_load_explicit(ws->counters + i, memory_order_relaxed), memory_order_relaxed);
70 pthread_mutex_unlock(&g_counter_mutex);
71}
72
73/* What every thread has counted so far, added together */
74static void counters_total(unsigned long long *total) {
75 struct ot_workstruct *ws;
76 size_t i;
77
78 pthread_mutex_lock(&g_counter_mutex);
79 for (i = 0; i < OT_COUNTER_COUNT; ++i)
80 total[i] = atomic_load_explicit(g_retired + i, memory_order_relaxed);
81 for (ws = g_counter_contexts; ws; ws = ws->counters_next)
82 for (i = 0; i < OT_COUNTER_COUNT; ++i)
83 total[i] += atomic_load_explicit(ws->counters + i, memory_order_relaxed);
84 pthread_mutex_unlock(&g_counter_mutex);
85}
86
87#define COUNT(index, by) atomic_fetch_add_explicit(ws->counters + (index), (unsigned long long)(by), memory_order_relaxed)
88
56static const char *ot_failed_request_names[] = { 89static const char *ot_failed_request_names[] = {
57 "302 Redirect", "400 Parse Error", "400 Invalid Parameter", "400 Invalid Parameter (compact=0)", "400 Not Modest", 90 "302 Redirect", "400 Parse Error", "400 Invalid Parameter", "400 Invalid Parameter (compact=0)", "400 Not Modest",
58 "402 Payment Required", "403 Access Denied", "404 Not found", "500 Internal Server Error"}; 91 "402 Payment Required", "403 Access Denied", "404 Not found", "500 Internal Server Error"};
59static unsigned long long ot_renewed[OT_PEER_TIMEOUT];
60static unsigned long long ot_overall_sync_count;
61static unsigned long long ot_overall_stall_count;
62 92
63static time_t ot_start_time; 93static time_t ot_start_time;
64 94
@@ -178,8 +208,8 @@ static size_t stats_get_highscore_networks(stats_network_node *node, int depth,
178 ++j; 208 ++j;
179 --j; 209 --j;
180 210
181 memcpy(scores, scores + 1, j * sizeof(*scores)); 211 memmove(scores, scores + 1, j * sizeof(*scores));
182 memcpy(networks, networks + 1, j * sizeof(*networks)); 212 memmove(networks, networks + 1, j * sizeof(*networks));
183 scores[j] = node_score; 213 scores[j] = node_score;
184 memcpy(networks + j, node_value, sizeof(*networks)); 214 memcpy(networks + j, node_value, sizeof(*networks));
185 } 215 }
@@ -187,12 +217,11 @@ static size_t stats_get_highscore_networks(stats_network_node *node, int depth,
187 return score; 217 return score;
188} 218}
189 219
190static size_t stats_return_busy_networks(char *reply, stats_network_node *tree, size_t amount, int limit) { 220static void stats_return_busy_networks(char **reply, const char *reply_end, stats_network_node *tree, size_t amount, int limit) {
191 ot_ip6 networks[amount]; 221 ot_ip6 networks[amount];
192 ot_ip6 node_value; 222 ot_ip6 node_value;
193 size_t scores[amount]; 223 size_t scores[amount];
194 size_t i; 224 size_t i;
195 char *r = reply;
196 225
197 memset(scores, 0, sizeof(scores)); 226 memset(scores, 0, sizeof(scores));
198 memset(networks, 0, sizeof(networks)); 227 memset(networks, 0, sizeof(networks));
@@ -200,24 +229,21 @@ static size_t stats_return_busy_networks(char *reply, stats_network_node *tree,
200 229
201 stats_get_highscore_networks(tree, 0, node_value, scores, networks, amount, limit); 230 stats_get_highscore_networks(tree, 0, node_value, scores, networks, amount, limit);
202 231
203 r += sprintf(r, "Networks, limit /%d:\n", limit + STATS_NETWORK_NODE_BITWIDTH); 232 fmt_append(reply, reply_end, "Networks, limit /%d:\n", limit + STATS_NETWORK_NODE_BITWIDTH);
204 for (i = amount; i > 0; --i) { 233 for (i = amount; i > 0; --i) {
205 if (scores[i - 1]) { 234 if (scores[i - 1]) {
206 r += sprintf(r, "%08zd: ", scores[i - 1]); 235 char ip_readable[64];
207 // #ifdef WANT_V6 236
208 r += ip_format(r, networks[i - 1]); 237 ip_readable[ip_format(ip_readable, networks[i - 1])] = 0;
209 *r++ = '\n'; 238 fmt_append(reply, reply_end, "%08zd: %s\n", scores[i - 1], ip_readable);
210 } 239 }
211 } 240 }
212 *r++ = '\n'; 241 fmt_append(reply, reply_end, "\n");
213
214 return r - reply;
215} 242}
216 243
217static size_t stats_slash24s_txt(char *reply, size_t amount) { 244static void stats_slash24s_txt(char **reply, const char *reply_end, size_t amount) {
218 stats_network_node *slash24s_network_counters_root = NULL; 245 stats_network_node *slash24s_network_counters_root = NULL;
219 char *r = reply; 246 size_t i, bucket, peer_size = OT_PEER_SIZE4;
220 size_t i, bucket, peer_size = OT_PEER_SIZE4;
221 247
222 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) { 248 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) {
223 ot_vector *torrents_list = mutex_bucket_lock(bucket); 249 ot_vector *torrents_list = mutex_bucket_lock(bucket);
@@ -244,35 +270,28 @@ static size_t stats_slash24s_txt(char *reply, size_t amount) {
244 } 270 }
245 mutex_bucket_unlock(bucket, 0); 271 mutex_bucket_unlock(bucket, 0);
246 if (!g_opentracker_running) 272 if (!g_opentracker_running)
247 goto bailout_error; 273 goto done;
248 } 274 }
249 275
250 /* The tree is built. Now analyze */ 276 /* The tree is built. Now analyze */
251 r += stats_return_busy_networks(r, slash24s_network_counters_root, amount, STATS_NETWORK_NODE_MAXDEPTH); 277 stats_return_busy_networks(reply, reply_end, slash24s_network_counters_root, amount, STATS_NETWORK_NODE_MAXDEPTH);
252 r += stats_return_busy_networks(r, slash24s_network_counters_root, amount, STATS_NETWORK_NODE_LIMIT); 278 stats_return_busy_networks(reply, reply_end, slash24s_network_counters_root, amount, STATS_NETWORK_NODE_LIMIT);
253 goto success; 279 goto done;
254 280
255bailout_unlock: 281bailout_unlock:
256 mutex_bucket_unlock(bucket, 0); 282 mutex_bucket_unlock(bucket, 0);
257bailout_error: 283done:
258 r = reply;
259success:
260 stats_shift_down_network_count(&slash24s_network_counters_root, 0, sizeof(int) * 8 - 1); 284 stats_shift_down_network_count(&slash24s_network_counters_root, 0, sizeof(int) * 8 - 1);
261
262 return r - reply;
263} 285}
264 286
265#ifdef WANT_SPOT_WOODPECKER 287#ifdef WANT_SPOT_WOODPECKER
266static stats_network_node *stats_woodpeckers_tree; 288static stats_network_node *stats_woodpeckers_tree;
267static pthread_mutex_t g_woodpeckers_mutex = PTHREAD_MUTEX_INITIALIZER; 289static pthread_mutex_t g_woodpeckers_mutex = PTHREAD_MUTEX_INITIALIZER;
268 290
269static size_t stats_return_woodpeckers(char *reply, int amount) { 291static void stats_return_woodpeckers(char **reply, const char *reply_end, int amount) {
270 char *r = reply;
271
272 pthread_mutex_lock(&g_woodpeckers_mutex); 292 pthread_mutex_lock(&g_woodpeckers_mutex);
273 r += stats_return_busy_networks(r, stats_woodpeckers_tree, amount, STATS_NETWORK_NODE_MAXDEPTH); 293 stats_return_busy_networks(reply, reply_end, stats_woodpeckers_tree, amount, STATS_NETWORK_NODE_MAXDEPTH);
274 pthread_mutex_unlock(&g_woodpeckers_mutex); 294 pthread_mutex_unlock(&g_woodpeckers_mutex);
275 return r - reply;
276} 295}
277#endif 296#endif
278 297
@@ -312,10 +331,10 @@ static inline void stats_insert_into_highscore(size_t val, ot_record* list, size
312 331
313 332
314/* Fetches stats from tracker */ 333/* Fetches stats from tracker */
315size_t stats_top_txt(char *reply, size_t amount) { 334void stats_top_txt(char **reply, const char *reply_end, size_t amount) {
316 size_t j, idx, bucket; 335 size_t j, idx, bucket;
317 ot_record top100s[100], top100c[100], top100l[100]; 336 ot_record top100s[100], top100c[100], top100l[100];
318 char *r = reply, hex_out[42]; 337 char hex_out[42];
319 338
320 if (amount > 100) 339 if (amount > 100)
321 amount = 100; 340 amount = 100;
@@ -326,7 +345,7 @@ size_t stats_top_txt(char *reply, size_t amount) {
326 345
327 /* Iterate over complete torrent list */ 346 /* Iterate over complete torrent list */
328 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) { 347 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) {
329 ot_vector *torrents_list = mutex_bucket_lock(bucket); 348 ot_vector *torrents_list = mutex_bucket_lock(bucket);
330 for (j = 0; j < torrents_list->size; ++j) { 349 for (j = 0; j < torrents_list->size; ++j) {
331 ot_torrent *torrent = (ot_torrent *)(torrents_list->data) + j; 350 ot_torrent *torrent = (ot_torrent *)(torrents_list->data) + j;
332 size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count; 351 size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count;
@@ -339,114 +358,148 @@ size_t stats_top_txt(char *reply, size_t amount) {
339 } 358 }
340 mutex_bucket_unlock(bucket, 0); 359 mutex_bucket_unlock(bucket, 0);
341 if (!g_opentracker_running) 360 if (!g_opentracker_running)
342 return 0; 361 return;
343 } 362 }
344 363
345 r += sprintf(r, "Top %zd torrents by peers:\n", amount); 364 fmt_append(reply, reply_end, "Top %zd torrents by peers:\n", amount);
346 for (idx = 0; idx < amount; ++idx) 365 for (idx = 0; idx < amount; ++idx)
347 if (top100c[idx].val) 366 if (top100c[idx].val)
348 r += sprintf(r, "\t%zd\t%s\n", top100c[idx].val, hex_fromhash(hex_out, top100c[idx].hash)); 367 fmt_append(reply, reply_end, "\t%zd\t%s\n", top100c[idx].val, hex_from_hash(hex_out, top100c[idx].hash));
349 r += sprintf(r, "Top %zd torrents by seeds:\n", amount); 368 fmt_append(reply, reply_end, "Top %zd torrents by seeds:\n", amount);
350 for (idx = 0; idx < amount; ++idx) 369 for (idx = 0; idx < amount; ++idx)
351 if (top100s[idx].val) 370 if (top100s[idx].val)
352 r += sprintf(r, "\t%zd\t%s\n", top100s[idx].val, hex_fromhash(hex_out, top100s[idx].hash)); 371 fmt_append(reply, reply_end, "\t%zd\t%s\n", top100s[idx].val, hex_from_hash(hex_out, top100s[idx].hash));
353 r += sprintf(r, "Top %zd torrents by leechers:\n", amount); 372 fmt_append(reply, reply_end, "Top %zd torrents by leechers:\n", amount);
354 for (idx = 0; idx < amount; ++idx) 373 for (idx = 0; idx < amount; ++idx)
355 if (top100l[idx].val) 374 if (top100l[idx].val)
356 r += sprintf(r, "\t%zd\t%s\n", top100l[idx].val, hex_fromhash(hex_out, top100l[idx].hash)); 375 fmt_append(reply, reply_end, "\t%zd\t%s\n", top100l[idx].val, hex_from_hash(hex_out, top100l[idx].hash));
357
358 return r - reply;
359} 376}
360 377
361static unsigned long events_per_time(unsigned long long events, time_t t) { return events / ((unsigned int)t ? (unsigned int)t : 1); } 378static unsigned long events_per_time(unsigned long long events, time_t t) { return events / ((unsigned int)t ? (unsigned int)t : 1); }
362 379
363static size_t stats_connections_mrtg(char *reply) { 380static void stats_connections_mrtg(char **reply, const char *reply_end) {
364 ot_time t = time(NULL) - ot_start_time; 381 ot_time t = time(NULL) - ot_start_time;
365 return sprintf(reply, "%llu\n%llu\n%i seconds (%i hours)\nopentracker connections, %lu conns/s :: %lu success/s.", 382 unsigned long long total[OT_COUNTER_COUNT];
366 ot_overall_tcp_connections + ot_overall_udp_connections, 383
367 ot_overall_tcp_successfulannounces + ot_overall_udp_successfulannounces + ot_overall_udp_connects, (int)t, (int)(t / 3600), 384 counters_total(total);
368 events_per_time(ot_overall_tcp_connections + ot_overall_udp_connections, t), 385
369 events_per_time(ot_overall_tcp_successfulannounces + ot_overall_udp_successfulannounces + ot_overall_udp_connects, t)); 386 fmt_append(reply, reply_end, "%llu\n%llu\n%i seconds (%i hours)\nopentracker connections, %lu conns/s :: %lu success/s.",
387 total[OT_COUNTER_TCP_CONNECTIONS] + total[OT_COUNTER_UDP_CONNECTIONS],
388 total[OT_COUNTER_TCP_ANNOUNCES] + total[OT_COUNTER_UDP_ANNOUNCES] + total[OT_COUNTER_UDP_CONNECTS], (int)t, (int)(t / 3600),
389 events_per_time(total[OT_COUNTER_TCP_CONNECTIONS] + total[OT_COUNTER_UDP_CONNECTIONS], t),
390 events_per_time(total[OT_COUNTER_TCP_ANNOUNCES] + total[OT_COUNTER_UDP_ANNOUNCES] + total[OT_COUNTER_UDP_CONNECTS], t));
370} 391}
371 392
372static size_t stats_udpconnections_mrtg(char *reply) { 393static void stats_udpconnections_mrtg(char **reply, const char *reply_end) {
373 ot_time t = time(NULL) - ot_start_time; 394 ot_time t = time(NULL) - ot_start_time;
374 return sprintf(reply, "%llu\n%llu\n%i seconds (%i hours)\nopentracker udp4 stats, %lu conns/s :: %lu success/s.", ot_overall_udp_connections, 395 unsigned long long total[OT_COUNTER_COUNT];
375 ot_overall_udp_successfulannounces + ot_overall_udp_connects, (int)t, (int)(t / 3600), events_per_time(ot_overall_udp_connections, t), 396
376 events_per_time(ot_overall_udp_successfulannounces + ot_overall_udp_connects, t)); 397 counters_total(total);
398
399 fmt_append(reply, reply_end, "%llu\n%llu\n%i seconds (%i hours)\nopentracker udp4 stats, %lu conns/s :: %lu success/s.", total[OT_COUNTER_UDP_CONNECTIONS],
400 total[OT_COUNTER_UDP_ANNOUNCES] + total[OT_COUNTER_UDP_CONNECTS], (int)t, (int)(t / 3600),
401 events_per_time(total[OT_COUNTER_UDP_CONNECTIONS], t),
402 events_per_time(total[OT_COUNTER_UDP_ANNOUNCES] + total[OT_COUNTER_UDP_CONNECTS], t));
377} 403}
378 404
379static size_t stats_tcpconnections_mrtg(char *reply) { 405static void stats_tcpconnections_mrtg(char **reply, const char *reply_end) {
380 time_t t = time(NULL) - ot_start_time; 406 time_t t = time(NULL) - ot_start_time;
381 return sprintf(reply, "%llu\n%llu\n%i seconds (%i hours)\nopentracker tcp4 stats, %lu conns/s :: %lu success/s.", ot_overall_tcp_connections, 407 unsigned long long total[OT_COUNTER_COUNT];
382 ot_overall_tcp_successfulannounces, (int)t, (int)(t / 3600), events_per_time(ot_overall_tcp_connections, t), 408
383 events_per_time(ot_overall_tcp_successfulannounces, t)); 409 counters_total(total);
410
411 fmt_append(reply, reply_end, "%llu\n%llu\n%i seconds (%i hours)\nopentracker tcp4 stats, %lu conns/s :: %lu success/s.", total[OT_COUNTER_TCP_CONNECTIONS],
412 total[OT_COUNTER_TCP_ANNOUNCES], (int)t, (int)(t / 3600), events_per_time(total[OT_COUNTER_TCP_CONNECTIONS], t),
413 events_per_time(total[OT_COUNTER_TCP_ANNOUNCES], t));
384} 414}
385 415
386static size_t stats_scrape_mrtg(char *reply) { 416static void stats_scrape_mrtg(char **reply, const char *reply_end) {
387 time_t t = time(NULL) - ot_start_time; 417 time_t t = time(NULL) - ot_start_time;
388 return sprintf(reply, "%llu\n%llu\n%i seconds (%i hours)\nopentracker scrape stats, %lu scrape/s (tcp and udp)", ot_overall_tcp_successfulscrapes, 418 unsigned long long total[OT_COUNTER_COUNT];
389 ot_overall_udp_successfulscrapes, (int)t, (int)(t / 3600), 419
390 events_per_time((ot_overall_tcp_successfulscrapes + ot_overall_udp_successfulscrapes), t)); 420 counters_total(total);
421
422 fmt_append(reply, reply_end, "%llu\n%llu\n%i seconds (%i hours)\nopentracker scrape stats, %lu scrape/s (tcp and udp)",
423 total[OT_COUNTER_TCP_SCRAPES], total[OT_COUNTER_UDP_SCRAPES], (int)t, (int)(t / 3600),
424 events_per_time((total[OT_COUNTER_TCP_SCRAPES] + total[OT_COUNTER_UDP_SCRAPES]), t));
391} 425}
392 426
393static size_t stats_fullscrapes_mrtg(char *reply) { 427static void stats_fullscrapes_mrtg(char **reply, const char *reply_end) {
394 ot_time t = time(NULL) - ot_start_time; 428 ot_time t = time(NULL) - ot_start_time;
395 return sprintf(reply, "%llu\n%llu\n%i seconds (%i hours)\nopentracker full scrape stats, %lu conns/s :: %lu bytes/s.", ot_full_scrape_count * 1000, 429 unsigned long long total[OT_COUNTER_COUNT];
396 ot_full_scrape_size, (int)t, (int)(t / 3600), events_per_time(ot_full_scrape_count, t), events_per_time(ot_full_scrape_size, t)); 430
431 counters_total(total);
432
433 fmt_append(reply, reply_end, "%llu\n%llu\n%i seconds (%i hours)\nopentracker full scrape stats, %lu conns/s :: %lu bytes/s.",
434 total[OT_COUNTER_FULLSCRAPES] * 1000, total[OT_COUNTER_FULLSCRAPE_BYTES], (int)t, (int)(t / 3600),
435 events_per_time(total[OT_COUNTER_FULLSCRAPES], t),
436 events_per_time(total[OT_COUNTER_FULLSCRAPE_BYTES], t));
397} 437}
398 438
399static size_t stats_peers_mrtg(char *reply) { 439static void stats_peers_mrtg(char **reply, const char *reply_end) {
400 torrent_stats stats = {0, 0, 0}; 440 torrent_stats stats = {0, 0, 0};
401 441
402 iterate_all_torrents(torrent_statter, (uintptr_t)&stats); 442 iterate_all_torrents(torrent_statter, (uintptr_t)&stats);
403 443
404 return sprintf(reply, "%llu\n%llu\nopentracker serving %llu torrents\nopentracker", stats.peer_count, stats.seed_count, stats.torrent_count); 444 fmt_append(reply, reply_end, "%llu\n%llu\nopentracker serving %llu torrents\nopentracker", stats.peer_count, stats.seed_count,
445 stats.torrent_count);
405} 446}
406 447
407static size_t stats_torrents_mrtg(char *reply) { 448static void stats_torrents_mrtg(char **reply, const char *reply_end) {
408 size_t torrent_count = mutex_get_torrent_count(); 449 size_t torrent_count = mutex_get_torrent_count();
409 450
410 return sprintf(reply, "%zd\n%zd\nopentracker serving %zd torrents\nopentracker", torrent_count, (size_t)0, torrent_count); 451 fmt_append(reply, reply_end, "%zd\n%zd\nopentracker serving %zd torrents\nopentracker", torrent_count, (size_t)0, torrent_count);
411} 452}
412 453
413static size_t stats_httperrors_txt(char *reply) { 454static void stats_httperrors_txt(char **reply, const char *reply_end) {
414 return sprintf(reply, "302 RED %llu\n400 ... %llu\n400 PAR %llu\n400 COM %llu\n403 IP %llu\n404 INV %llu\n500 SRV %llu\n", ot_failed_request_counts[0], 455 unsigned long long total[OT_COUNTER_COUNT];
415 ot_failed_request_counts[1], ot_failed_request_counts[2], ot_failed_request_counts[3], ot_failed_request_counts[4], 456
416 ot_failed_request_counts[5], ot_failed_request_counts[6]); 457 counters_total(total);
458
459 fmt_append(reply, reply_end, "302 RED %llu\n400 ... %llu\n400 PAR %llu\n400 COM %llu\n403 IP %llu\n404 INV %llu\n500 SRV %llu\n",
460 total[OT_COUNTER_FAILED + 0], total[OT_COUNTER_FAILED + 1], total[OT_COUNTER_FAILED + 2], total[OT_COUNTER_FAILED + 3],
461 total[OT_COUNTER_FAILED + 4], total[OT_COUNTER_FAILED + 5], total[OT_COUNTER_FAILED + 6]);
417} 462}
418 463
419static size_t stats_return_renew_bucket(char *reply) { 464static void stats_return_renew_bucket(char **reply, const char *reply_end) {
420 char *r = reply; 465 unsigned long long total[OT_COUNTER_COUNT];
421 int i; 466
467 counters_total(total);
468
469 int i;
422 470
423 for (i = 0; i < OT_PEER_TIMEOUT; ++i) 471 for (i = 0; i < OT_PEER_TIMEOUT; ++i)
424 r += sprintf(r, "%02i %llu\n", i, ot_renewed[i]); 472 fmt_append(reply, reply_end, "%02i %llu\n", i, total[OT_COUNTER_RENEWED + i]);
425 return r - reply;
426} 473}
427 474
428static size_t stats_return_sync_mrtg(char *reply) { 475static void stats_return_sync_mrtg(char **reply, const char *reply_end) {
429 ot_time t = time(NULL) - ot_start_time; 476 ot_time t = time(NULL) - ot_start_time;
430 return sprintf(reply, "%llu\n%llu\n%i seconds (%i hours)\nopentracker connections, %lu conns/s :: %lu success/s.", ot_overall_sync_count, 0LL, (int)t, 477 unsigned long long total[OT_COUNTER_COUNT];
431 (int)(t / 3600), events_per_time(ot_overall_tcp_connections + ot_overall_udp_connections, t), 478
432 events_per_time(ot_overall_tcp_successfulannounces + ot_overall_udp_successfulannounces + ot_overall_udp_connects, t)); 479 counters_total(total);
480
481 fmt_append(reply, reply_end, "%llu\n%llu\n%i seconds (%i hours)\nopentracker connections, %lu conns/s :: %lu success/s.", total[OT_COUNTER_SYNCS], 0LL,
482 (int)t, (int)(t / 3600), events_per_time(total[OT_COUNTER_TCP_CONNECTIONS] + total[OT_COUNTER_UDP_CONNECTIONS], t),
483 events_per_time(total[OT_COUNTER_TCP_ANNOUNCES] + total[OT_COUNTER_UDP_ANNOUNCES] + total[OT_COUNTER_UDP_CONNECTS], t));
433} 484}
434 485
435static size_t stats_return_completed_mrtg(char *reply) { 486static void stats_return_completed_mrtg(char **reply, const char *reply_end) {
436 ot_time t = time(NULL) - ot_start_time; 487 ot_time t = time(NULL) - ot_start_time;
488 unsigned long long total[OT_COUNTER_COUNT];
489
490 counters_total(total);
437 491
438 return sprintf(reply, "%llu\n%llu\n%i seconds (%i hours)\nopentracker, %lu completed/h.", ot_overall_completed, 0LL, (int)t, (int)(t / 3600), 492
439 events_per_time(ot_overall_completed, t / 3600)); 493 fmt_append(reply, reply_end, "%llu\n%llu\n%i seconds (%i hours)\nopentracker, %lu completed/h.", total[OT_COUNTER_COMPLETED], 0LL, (int)t, (int)(t / 3600),
494 events_per_time(total[OT_COUNTER_COMPLETED], t / 3600));
440} 495}
441 496
442#ifdef WANT_LOG_NUMWANT 497#ifdef WANT_LOG_NUMWANT
443extern unsigned long long numwants[201]; 498extern unsigned long long numwants[201];
444static size_t stats_return_numwants(char *reply) { 499static void stats_return_numwants(char **reply, const char *reply_end) {
445 char *r = reply; 500 int i;
446 int i;
447 for (i = 0; i <= 200; ++i) 501 for (i = 0; i <= 200; ++i)
448 r += sprintf(r, "%03d => %lld\n", i, numwants[i]); 502 fmt_append(reply, reply_end, "%03d => %lld\n", i, numwants[i]);
449 return r - reply;
450} 503}
451#endif 504#endif
452 505
@@ -459,148 +512,162 @@ static void stats_return_fulllog(size_t *iovec_entries, struct iovec **iovector,
459 512
460 while (loglist) { 513 while (loglist) {
461 if (r + (loglist->size + 64) >= re) { 514 if (r + (loglist->size + 64) >= re) {
462 r = iovec_fix_increase_or_free(iovec_entries, iovector, r, 32 * OT_STATS_TMPSIZE); 515 r = iovec_next_chunk(iovec_entries, iovector, r, 32 * OT_STATS_TMPSIZE);
463 if (!r) 516 if (!r)
464 return; 517 return;
465 re = r + 32 * OT_STATS_TMPSIZE; 518 re = r + 32 * OT_STATS_TMPSIZE;
466 } 519 }
467 r += sprintf(r, "%08ld: ", loglist->time); 520 char ip_readable[64];
468 r += ip_format(r, loglist->ip); 521
469 *r++ = '\n'; 522 ip_readable[ip_format(ip_readable, loglist->ip)] = 0;
470 memcpy(r, loglist->data, loglist->size); 523 fmt_append(&r, re, "%08ld: %s\n", loglist->time, ip_readable);
471 r += loglist->size; 524 fmt_bytes(&r, re, loglist->data, loglist->size);
472 *r++ = '\n'; 525 fmt_append(&r, re, "\n*\n\n");
473 *r++ = '*';
474 *r++ = '\n';
475 *r++ = '\n';
476 526
477 llnext = loglist->next; 527 llnext = loglist->next;
478 free(loglist->data); 528 free(loglist->data);
479 free(loglist); 529 free(loglist);
480 loglist = llnext; 530 loglist = llnext;
481 } 531 }
482 iovec_fixlast(iovec_entries, iovector, r); 532 iovec_trim_last(iovec_entries, iovector, r);
483} 533}
484#endif 534#endif
485 535
486static size_t stats_return_everything(char *reply) { 536static void stats_return_everything(char **reply, const char *reply_end) {
537 unsigned long long total[OT_COUNTER_COUNT];
538
539 counters_total(total);
540
487 torrent_stats stats = {0, 0, 0}; 541 torrent_stats stats = {0, 0, 0};
488 int i; 542 int i;
489 char *r = reply;
490 543
491 iterate_all_torrents(torrent_statter, (uintptr_t)&stats); 544 iterate_all_torrents(torrent_statter, (uintptr_t)&stats);
492 545
493 r += sprintf(r, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); 546 fmt_append(reply, reply_end, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
494 r += sprintf(r, "<stats>\n"); 547 fmt_append(reply, reply_end, "<stats>\n");
495 r += sprintf(r, " <tracker_id>%" PRIu32 "</tracker_id>\n", g_tracker_id); 548 fmt_append(reply, reply_end, " <tracker_id>%" PRIu32 "</tracker_id>\n", g_tracker_id);
496 r += sprintf(r, " <version>\n"); 549 fmt_append(reply, reply_end, " <version>\n");
497 r += stats_return_tracker_version(r); 550 stats_return_tracker_version(reply, reply_end);
498 r += sprintf(r, " </version>\n"); 551 fmt_append(reply, reply_end, " </version>\n");
499 r += sprintf(r, " <uptime>%llu</uptime>\n", (unsigned long long)(time(NULL) - ot_start_time)); 552 fmt_append(reply, reply_end, " <uptime>%llu</uptime>\n", (unsigned long long)(time(NULL) - ot_start_time));
500 r += sprintf(r, " <torrents>\n"); 553 fmt_append(reply, reply_end, " <torrents>\n");
501 r += sprintf(r, " <count_mutex>%zd</count_mutex>\n", mutex_get_torrent_count()); 554 fmt_append(reply, reply_end, " <count_mutex>%zd</count_mutex>\n", mutex_get_torrent_count());
502 r += sprintf(r, " <count_iterator>%llu</count_iterator>\n", stats.torrent_count); 555 fmt_append(reply, reply_end, " <count_iterator>%llu</count_iterator>\n", stats.torrent_count);
503 r += sprintf(r, " </torrents>\n"); 556 fmt_append(reply, reply_end, " </torrents>\n");
504 r += sprintf(r, " <peers>\n <count>%llu</count>\n </peers>\n", stats.peer_count); 557 fmt_append(reply, reply_end, " <peers>\n <count>%llu</count>\n </peers>\n", stats.peer_count);
505 r += sprintf(r, " <seeds>\n <count>%llu</count>\n </seeds>\n", stats.seed_count); 558 fmt_append(reply, reply_end, " <seeds>\n <count>%llu</count>\n </seeds>\n", stats.seed_count);
506 r += sprintf(r, " <completed>\n <count>%llu</count>\n </completed>\n", ot_overall_completed); 559 fmt_append(reply, reply_end, " <completed>\n <count>%llu</count>\n </completed>\n", total[OT_COUNTER_COMPLETED]);
507 r += sprintf(r, " <connections>\n"); 560 fmt_append(reply, reply_end, " <connections>\n");
508 r += sprintf(r, " <tcp>\n <accept>%llu</accept>\n <announce>%llu</announce>\n <scrape>%llu</scrape>\n </tcp>\n", 561 fmt_append(reply, reply_end, " <tcp>\n <accept>%llu</accept>\n <announce>%llu</announce>\n <scrape>%llu</scrape>\n </tcp>\n",
509 ot_overall_tcp_connections, ot_overall_tcp_successfulannounces, ot_overall_tcp_successfulscrapes); 562 total[OT_COUNTER_TCP_CONNECTIONS], total[OT_COUNTER_TCP_ANNOUNCES], total[OT_COUNTER_TCP_SCRAPES]);
510 r += sprintf(r, " <udp>\n <overall>%llu</overall>\n <connect>%llu</connect>\n <announce>%llu</announce>\n <scrape>%llu</scrape>\n <missmatch>%llu</missmatch>\n </udp>\n", 563 fmt_append(reply, reply_end, " <udp>\n <overall>%llu</overall>\n <connect>%llu</connect>\n <announce>%llu</announce>\n <scrape>%llu</scrape>\n <missmatch>%llu</missmatch>\n </udp>\n",
511 ot_overall_udp_connections, ot_overall_udp_connects, ot_overall_udp_successfulannounces, ot_overall_udp_successfulscrapes, 564 total[OT_COUNTER_UDP_CONNECTIONS], total[OT_COUNTER_UDP_CONNECTS], total[OT_COUNTER_UDP_ANNOUNCES], total[OT_COUNTER_UDP_SCRAPES],
512 ot_overall_udp_connectionidmissmatches); 565 total[OT_COUNTER_UDP_CONNID_MISSMATCH]);
513 r += sprintf(r, " <livesync>\n <count>%llu</count>\n </livesync>\n", ot_overall_sync_count); 566 fmt_append(reply, reply_end, " <livesync>\n <count>%llu</count>\n </livesync>\n", total[OT_COUNTER_SYNCS]);
514 r += sprintf(r, " </connections>\n"); 567 fmt_append(reply, reply_end, " </connections>\n");
515 r += sprintf(r, " <debug>\n"); 568 fmt_append(reply, reply_end, " <debug>\n");
516 r += sprintf(r, " <renew>\n"); 569 fmt_append(reply, reply_end, " <renew>\n");
517 for (i = 0; i < OT_PEER_TIMEOUT; ++i) 570 for (i = 0; i < OT_PEER_TIMEOUT; ++i)
518 r += sprintf(r, " <count interval=\"%02i\">%llu</count>\n", i, ot_renewed[i]); 571 fmt_append(reply, reply_end, " <count interval=\"%02i\">%llu</count>\n", i, total[OT_COUNTER_RENEWED + i]);
519 r += sprintf(r, " </renew>\n"); 572 fmt_append(reply, reply_end, " </renew>\n");
520 r += sprintf(r, " <http_error>\n"); 573 fmt_append(reply, reply_end, " <http_error>\n");
521 for (i = 0; i < CODE_HTTPERROR_COUNT; ++i) 574 for (i = 0; i < CODE_HTTPERROR_COUNT; ++i)
522 r += sprintf(r, " <count code=\"%s\">%llu</count>\n", ot_failed_request_names[i], ot_failed_request_counts[i]); 575 fmt_append(reply, reply_end, " <count code=\"%s\">%llu</count>\n", ot_failed_request_names[i], total[OT_COUNTER_FAILED + i]);
523 r += sprintf(r, " </http_error>\n"); 576 fmt_append(reply, reply_end, " </http_error>\n");
524 r += sprintf(r, " <mutex_stall>\n <count>%llu</count>\n </mutex_stall>\n", ot_overall_stall_count); 577 fmt_append(reply, reply_end, " <mutex_stall>\n <count>%llu</count>\n </mutex_stall>\n", total[OT_COUNTER_STALLS]);
525 r += sprintf(r, " </debug>\n"); 578 fmt_append(reply, reply_end, " </debug>\n");
526 r += sprintf(r, "</stats>"); 579 fmt_append(reply, reply_end, "</stats>");
527 return r - reply;
528} 580}
529 581
530size_t stats_return_tracker_version(char *reply) { 582void stats_return_tracker_version(char **reply, const char *reply_end) {
531#define QUOTE(name) #name 583#define QUOTE(name) #name
532#define SQUOTE(name) QUOTE(name) 584#define SQUOTE(name) QUOTE(name)
533 return sprintf(reply, "https://erdgeist.org/gitweb/opentracker/commit/?id=" SQUOTE(GIT_VERSION) "\n"); 585 fmt_append(reply, reply_end, "https://erdgeist.org/gitweb/opentracker/commit/?id=" SQUOTE(GIT_VERSION) "\n");
534} 586}
535 587
536size_t return_stats_for_tracker(char *reply, int mode, int format) { 588void return_stats_for_tracker(char **reply, const char *reply_end, int mode, int format) {
537 (void)format; 589 (void)format;
538 switch (mode & TASK_TASK_MASK) { 590 switch (mode & TASK_TASK_MASK) {
539 case TASK_STATS_CONNS: 591 case TASK_STATS_CONNS:
540 return stats_connections_mrtg(reply); 592 stats_connections_mrtg(reply, reply_end);
593 break;
541 case TASK_STATS_SCRAPE: 594 case TASK_STATS_SCRAPE:
542 return stats_scrape_mrtg(reply); 595 stats_scrape_mrtg(reply, reply_end);
596 break;
543 case TASK_STATS_UDP: 597 case TASK_STATS_UDP:
544 return stats_udpconnections_mrtg(reply); 598 stats_udpconnections_mrtg(reply, reply_end);
599 break;
545 case TASK_STATS_TCP: 600 case TASK_STATS_TCP:
546 return stats_tcpconnections_mrtg(reply); 601 stats_tcpconnections_mrtg(reply, reply_end);
602 break;
547 case TASK_STATS_FULLSCRAPE: 603 case TASK_STATS_FULLSCRAPE:
548 return stats_fullscrapes_mrtg(reply); 604 stats_fullscrapes_mrtg(reply, reply_end);
605 break;
549 case TASK_STATS_COMPLETED: 606 case TASK_STATS_COMPLETED:
550 return stats_return_completed_mrtg(reply); 607 stats_return_completed_mrtg(reply, reply_end);
608 break;
551 case TASK_STATS_HTTPERRORS: 609 case TASK_STATS_HTTPERRORS:
552 return stats_httperrors_txt(reply); 610 stats_httperrors_txt(reply, reply_end);
611 break;
553 case TASK_STATS_VERSION: 612 case TASK_STATS_VERSION:
554 return stats_return_tracker_version(reply); 613 stats_return_tracker_version(reply, reply_end);
614 break;
555 case TASK_STATS_RENEW: 615 case TASK_STATS_RENEW:
556 return stats_return_renew_bucket(reply); 616 stats_return_renew_bucket(reply, reply_end);
617 break;
557 case TASK_STATS_SYNCS: 618 case TASK_STATS_SYNCS:
558 return stats_return_sync_mrtg(reply); 619 stats_return_sync_mrtg(reply, reply_end);
620 break;
559#ifdef WANT_LOG_NUMWANT 621#ifdef WANT_LOG_NUMWANT
560 case TASK_STATS_NUMWANTS: 622 case TASK_STATS_NUMWANTS:
561 return stats_return_numwants(reply); 623 stats_return_numwants(reply, reply_end);
624 break;
562#endif 625#endif
563 default: 626 default:
564 return 0; 627 break;
565 } 628 }
566} 629}
567 630
568static void stats_make(size_t *iovec_entries, struct iovec **iovector, ot_tasktype mode) { 631static void stats_make(size_t *iovec_entries, struct iovec **iovector, ot_tasktype mode) {
569 char *r; 632 char *r;
633 const char *r_end;
570 634
571 *iovec_entries = 0; 635 *iovec_entries = 0;
572 *iovector = NULL; 636 *iovector = NULL;
573 if (!(r = iovec_increase(iovec_entries, iovector, OT_STATS_TMPSIZE))) 637 if (!(r = iovec_new_chunk(iovec_entries, iovector, OT_STATS_TMPSIZE)))
574 return; 638 return;
639 r_end = r + OT_STATS_TMPSIZE;
575 640
576 switch (mode & TASK_TASK_MASK) { 641 switch (mode & TASK_TASK_MASK) {
577 case TASK_STATS_TORRENTS: 642 case TASK_STATS_TORRENTS:
578 r += stats_torrents_mrtg(r); 643 stats_torrents_mrtg(&r, r_end);
579 break; 644 break;
580 case TASK_STATS_PEERS: 645 case TASK_STATS_PEERS:
581 r += stats_peers_mrtg(r); 646 stats_peers_mrtg(&r, r_end);
582 break; 647 break;
583 case TASK_STATS_SLASH24S: 648 case TASK_STATS_SLASH24S:
584 r += stats_slash24s_txt(r, 128); 649 stats_slash24s_txt(&r, r_end, 128);
585 break; 650 break;
586 case TASK_STATS_TOP10: 651 case TASK_STATS_TOP10:
587 r += stats_top_txt(r, 10); 652 stats_top_txt(&r, r_end, 10);
588 break; 653 break;
589 case TASK_STATS_TOP100: 654 case TASK_STATS_TOP100:
590 r = iovec_fix_increase_or_free(iovec_entries, iovector, r, 4 * OT_STATS_TMPSIZE); 655 r = iovec_next_chunk(iovec_entries, iovector, r, 4 * OT_STATS_TMPSIZE);
591 if (!r) 656 if (!r)
592 return; 657 return;
593 r += stats_top_txt(r, 100); 658 r_end = r + 4 * OT_STATS_TMPSIZE;
659 stats_top_txt(&r, r_end, 100);
594 break; 660 break;
595 case TASK_STATS_EVERYTHING: 661 case TASK_STATS_EVERYTHING:
596 r = iovec_fix_increase_or_free(iovec_entries, iovector, r, OT_STATS_TMPSIZE + 64 * OT_PEER_TIMEOUT); 662 r = iovec_next_chunk(iovec_entries, iovector, r, OT_STATS_TMPSIZE + 64 * OT_PEER_TIMEOUT);
597 if (!r) 663 if (!r)
598 return; 664 return;
599 r += stats_return_everything(r); 665 r_end = r + OT_STATS_TMPSIZE + 64 * OT_PEER_TIMEOUT;
666 stats_return_everything(&r, r_end);
600 break; 667 break;
601#ifdef WANT_SPOT_WOODPECKER 668#ifdef WANT_SPOT_WOODPECKER
602 case TASK_STATS_WOODPECKERS: 669 case TASK_STATS_WOODPECKERS:
603 r += stats_return_woodpeckers(r, 128); 670 stats_return_woodpeckers(&r, r_end, 128);
604 break; 671 break;
605#endif 672#endif
606#ifdef WANT_FULLLOG_NETWORKS 673#ifdef WANT_FULLLOG_NETWORKS
@@ -612,36 +679,38 @@ static void stats_make(size_t *iovec_entries, struct iovec **iovector, ot_taskty
612 iovec_free(iovec_entries, iovector); 679 iovec_free(iovec_entries, iovector);
613 return; 680 return;
614 } 681 }
615 iovec_fixlast(iovec_entries, iovector, r); 682 iovec_trim_last(iovec_entries, iovector, r);
616} 683}
617 684
618void stats_issue_event(ot_status_event event, PROTO_FLAG proto, uintptr_t event_data) { 685void stats_issue_event(struct ot_workstruct *ws, ot_status_event event, PROTO_FLAG proto, uintptr_t event_data) {
686 if (!ws)
687 return;
688
619 switch (event) { 689 switch (event) {
620 case EVENT_ACCEPT: 690 case EVENT_ACCEPT:
621 if (proto == FLAG_TCP) 691 if (proto == FLAG_TCP)
622 ot_overall_tcp_connections++; 692 COUNT(OT_COUNTER_TCP_CONNECTIONS, 1);
623 else 693 else
624 ot_overall_udp_connections++; 694 COUNT(OT_COUNTER_UDP_CONNECTIONS, 1);
625#ifdef WANT_LOG_NETWORKS 695#ifdef WANT_LOG_NETWORKS
626 stat_increase_network_count(&stats_network_counters_root, 0, event_data); 696 stat_increase_network_count(&stats_network_counters_root, 0, event_data);
627#endif 697#endif
628 break; 698 break;
629 case EVENT_ANNOUNCE: 699 case EVENT_ANNOUNCE:
630 if (proto == FLAG_TCP) 700 if (proto == FLAG_TCP)
631 ot_overall_tcp_successfulannounces++; 701 COUNT(OT_COUNTER_TCP_ANNOUNCES, 1);
632 else 702 else
633 ot_overall_udp_successfulannounces++; 703 COUNT(OT_COUNTER_UDP_ANNOUNCES, 1);
634 break; 704 break;
635 case EVENT_CONNECT: 705 case EVENT_CONNECT:
636 if (proto == FLAG_TCP) 706 if (proto == FLAG_TCP)
637 ot_overall_tcp_connects++; 707 COUNT(OT_COUNTER_TCP_CONNECTS, 1);
638 else 708 else
639 ot_overall_udp_connects++; 709 COUNT(OT_COUNTER_UDP_CONNECTS, 1);
640 break; 710 break;
641 case EVENT_COMPLETED: 711 case EVENT_COMPLETED:
642#ifdef WANT_SYSLOGS 712#ifdef WANT_SYSLOGS
643 if (event_data) { 713 {
644 struct ot_workstruct *ws = (struct ot_workstruct *)event_data;
645 char timestring[64]; 714 char timestring[64];
646 char hash_hex[42], peerid_hex[42], ip_readable[64]; 715 char hash_hex[42], peerid_hex[42], ip_readable[64];
647 struct tm time_now; 716 struct tm time_now;
@@ -651,9 +720,9 @@ void stats_issue_event(ot_status_event event, PROTO_FLAG proto, uintptr_t event_
651 localtime_r(&ttt, &time_now); 720 localtime_r(&ttt, &time_now);
652 strftime(timestring, sizeof(timestring), "%FT%T%z", &time_now); 721 strftime(timestring, sizeof(timestring), "%FT%T%z", &time_now);
653 722
654 hex_fromhash(hash_hex, *ws->hash); 723 hex_from_hash(hash_hex, *ws->hash);
655 if (ws->peer_id) 724 if (ws->peer_id)
656 hex_fromhash(peerid_hex, (uint8_t *)ws->peer_id); 725 hex_from_hash(peerid_hex, (uint8_t *)ws->peer_id);
657 else { 726 else {
658 *peerid_hex = 0; 727 *peerid_hex = 0;
659 } 728 }
@@ -662,47 +731,47 @@ void stats_issue_event(ot_status_event event, PROTO_FLAG proto, uintptr_t event_
662 syslog(LOG_INFO, "time=%s event=completed info_hash=%s peer_id=%s ip=%s", timestring, hash_hex, peerid_hex, ip_readable); 731 syslog(LOG_INFO, "time=%s event=completed info_hash=%s peer_id=%s ip=%s", timestring, hash_hex, peerid_hex, ip_readable);
663 } 732 }
664#endif 733#endif
665 ot_overall_completed++; 734 COUNT(OT_COUNTER_COMPLETED, 1);
666 break; 735 break;
667 case EVENT_SCRAPE: 736 case EVENT_SCRAPE:
668 if (proto == FLAG_TCP) 737 if (proto == FLAG_TCP)
669 ot_overall_tcp_successfulscrapes++; 738 COUNT(OT_COUNTER_TCP_SCRAPES, 1);
670 else 739 else
671 ot_overall_udp_successfulscrapes++; 740 COUNT(OT_COUNTER_UDP_SCRAPES, 1);
672 break; 741 break;
673 case EVENT_FULLSCRAPE: 742 case EVENT_FULLSCRAPE:
674 ot_full_scrape_count++; 743 COUNT(OT_COUNTER_FULLSCRAPES, 1);
675 ot_full_scrape_size += event_data; 744 COUNT(OT_COUNTER_FULLSCRAPE_BYTES, event_data);
676 break; 745 break;
677 case EVENT_FULLSCRAPE_REQUEST: { 746 case EVENT_FULLSCRAPE_REQUEST: {
678 ot_ip6 *ip = (ot_ip6 *)event_data; /* ugly hack to transfer ip to stats */ 747 ot_ip6 *ip = (ot_ip6 *)event_data; /* ugly hack to transfer ip to stats */
679 char _debug[512]; 748 char _debug[512];
680 int off = snprintf(_debug, sizeof(_debug), "[%08d] scrp: ", (unsigned int)(g_now_seconds - ot_start_time) / 60); 749 int off = snprintf(_debug, sizeof(_debug), "[%08d] scrp: ", (unsigned int)(time_now_seconds() - ot_start_time) / 60);
681 off += ip_format(_debug + off, *ip); 750 off += ip_format(_debug + off, *ip);
682 off += snprintf(_debug + off, sizeof(_debug) - off, " - FULL SCRAPE\n"); 751 off += snprintf(_debug + off, sizeof(_debug) - off, " - FULL SCRAPE\n");
683 (void)write(2, _debug, off); 752 (void)write(2, _debug, off);
684 ot_full_scrape_request_count++; 753 COUNT(OT_COUNTER_FULLSCRAPE_REQUESTS, 1);
685 } break; 754 } break;
686 case EVENT_FULLSCRAPE_REQUEST_GZIP: { 755 case EVENT_FULLSCRAPE_REQUEST_GZIP: {
687 ot_ip6 *ip = (ot_ip6 *)event_data; /* ugly hack to transfer ip to stats */ 756 ot_ip6 *ip = (ot_ip6 *)event_data; /* ugly hack to transfer ip to stats */
688 char _debug[512]; 757 char _debug[512];
689 int off = snprintf(_debug, sizeof(_debug), "[%08d] scrp: ", (unsigned int)(g_now_seconds - ot_start_time) / 60); 758 int off = snprintf(_debug, sizeof(_debug), "[%08d] scrp: ", (unsigned int)(time_now_seconds() - ot_start_time) / 60);
690 off += ip_format(_debug + off, *ip); 759 off += ip_format(_debug + off, *ip);
691 off += snprintf(_debug + off, sizeof(_debug) - off, " - FULL SCRAPE\n"); 760 off += snprintf(_debug + off, sizeof(_debug) - off, " - FULL SCRAPE\n");
692 (void)write(2, _debug, off); 761 (void)write(2, _debug, off);
693 ot_full_scrape_request_count++; 762 COUNT(OT_COUNTER_FULLSCRAPE_REQUESTS, 1);
694 } break; 763 } break;
695 case EVENT_FAILED: 764 case EVENT_FAILED:
696 ot_failed_request_counts[event_data]++; 765 COUNT(OT_COUNTER_FAILED + event_data, 1);
697 break; 766 break;
698 case EVENT_RENEW: 767 case EVENT_RENEW:
699 ot_renewed[event_data]++; 768 COUNT(OT_COUNTER_RENEWED + event_data, 1);
700 break; 769 break;
701 case EVENT_SYNC: 770 case EVENT_SYNC:
702 ot_overall_sync_count += event_data; 771 COUNT(OT_COUNTER_SYNCS, event_data);
703 break; 772 break;
704 case EVENT_BUCKET_LOCKED: 773 case EVENT_BUCKET_LOCKED:
705 ot_overall_stall_count++; 774 COUNT(OT_COUNTER_STALLS, 1);
706 break; 775 break;
707#ifdef WANT_SPOT_WOODPECKER 776#ifdef WANT_SPOT_WOODPECKER
708 case EVENT_WOODPECKER: 777 case EVENT_WOODPECKER:
@@ -712,7 +781,7 @@ void stats_issue_event(ot_status_event event, PROTO_FLAG proto, uintptr_t event_
712 break; 781 break;
713#endif 782#endif
714 case EVENT_CONNID_MISSMATCH: 783 case EVENT_CONNID_MISSMATCH:
715 ++ot_overall_udp_connectionidmissmatches; 784 COUNT(OT_COUNTER_UDP_CONNID_MISSMATCH, 1);
716 default: 785 default:
717 break; 786 break;
718 } 787 }
@@ -732,9 +801,11 @@ static void *stats_worker(void *args) {
732 801
733 (void)args; 802 (void)args;
734 803
735 while (1) { 804 while (g_opentracker_running) {
736 ot_tasktype tasktype = TASK_STATS; 805 ot_tasktype tasktype = TASK_STATS;
737 ot_taskid taskid = mutex_workqueue_poptask(&tasktype); 806 ot_taskid taskid = mutex_workqueue_poptask(&tasktype);
807 if (!taskid)
808 break;
738 stats_make(&iovec_entries, &iovector, tasktype); 809 stats_make(&iovec_entries, &iovector, tasktype);
739 if (mutex_workqueue_pushresult(taskid, iovec_entries, iovector)) 810 if (mutex_workqueue_pushresult(taskid, iovec_entries, iovector))
740 iovec_free(&iovec_entries, &iovector); 811 iovec_free(&iovec_entries, &iovector);
@@ -746,10 +817,11 @@ void stats_deliver(int64_t sock, int tasktype) { mutex_workqueue_pushtask(sock,
746 817
747static pthread_t thread_id; 818static pthread_t thread_id;
748void stats_init(void) { 819void stats_init(void) {
749 ot_start_time = g_now_seconds; 820 ot_start_time = time_now_seconds();
750 pthread_create(&thread_id, NULL, stats_worker, NULL); 821 pthread_create(&thread_id, NULL, stats_worker, NULL);
751} 822}
752 823
753void stats_deinit(void) { 824void stats_deinit(void) {
754 pthread_cancel(thread_id); 825 mutex_workqueue_wakeall();
826 pthread_join(thread_id, NULL);
755} 827}