Factor statistics writing into its own class and file.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Wed, 10 Apr 2013 21:11:00 +0000 (23:11 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Wed, 10 Apr 2013 21:11:00 +0000 (23:11 +0200)
stats.cpp [new file with mode: 0644]
stats.h [new file with mode: 0644]

diff --git a/stats.cpp b/stats.cpp
new file mode 100644 (file)
index 0000000..445bae7
--- /dev/null
+++ b/stats.cpp
@@ -0,0 +1,97 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <pthread.h>
+
+#include "serverpool.h"
+#include "stats.h"
+
+using namespace std;
+
+extern ServerPool *servers;
+
+StatsThread::StatsThread(const std::string &stats_file, int stats_interval)
+       : stats_file(stats_file),
+         stats_interval(stats_interval)
+{
+}
+
+void StatsThread::run()
+{
+       should_stop = false;
+       pthread_create(&worker_thread, NULL, do_work_thunk, this);
+}
+
+void StatsThread::stop()
+{
+       should_stop = true;
+       pthread_kill(worker_thread, SIGHUP);
+       if (pthread_join(worker_thread, NULL) == -1) {
+               perror("pthread_join");
+               exit(1);
+       }
+}
+       
+void *StatsThread::do_work_thunk(void *arg)
+{
+       StatsThread *stats_thread = reinterpret_cast<StatsThread *>(arg);
+       stats_thread->do_work();
+       return NULL;
+}
+
+void StatsThread::do_work()
+{
+       while (!should_stop) {
+               int fd;
+               FILE *fp;
+               time_t now;
+               vector<ClientStats> client_stats;
+
+               // Open a new, temporary file.
+               char *filename = strdup((stats_file + ".new.XXXXXX").c_str());
+               fd = mkostemp(filename, O_WRONLY);
+               if (fd == -1) {
+                       perror(filename);
+                       free(filename);
+                       goto sleep;
+               }
+
+               fp = fdopen(fd, "w");
+               if (fp == NULL) {
+                       perror("fdopen");
+                       close(fd);
+                       unlink(filename);
+                       free(filename);
+                       goto sleep;
+               }
+
+               now = time(NULL);
+               client_stats = servers->get_client_stats();
+               for (size_t i = 0; i < client_stats.size(); ++i) {
+                       fprintf(fp, "%s %s %d %llu\n",
+                               client_stats[i].remote_addr.c_str(),
+                               client_stats[i].stream_id.c_str(),
+                               int(now - client_stats[i].connect_time),
+                               (long long unsigned)(client_stats[i].bytes_sent));
+               }
+               if (fclose(fp) == EOF) {
+                       perror("fclose");
+                       unlink(filename);
+                       free(filename);
+                       goto sleep;
+               }
+               
+               if (rename(filename, stats_file.c_str()) == -1) {
+                       perror("rename");
+                       unlink(filename);
+               }
+
+sleep:
+               int left_to_sleep = stats_interval;
+               do {
+                       left_to_sleep = sleep(left_to_sleep);
+               } while (left_to_sleep > 0 && !should_stop);
+       }
+}
diff --git a/stats.h b/stats.h
new file mode 100644 (file)
index 0000000..c4fb17a
--- /dev/null
+++ b/stats.h
@@ -0,0 +1,29 @@
+#ifndef _STATS_H
+#define _STATS_H 1
+
+#include <pthread.h>
+#include <string>
+
+// A thread that regularly writes out statistics, ie. a list of all connected clients
+// with some information about each.
+
+class StatsThread {
+public:
+       StatsThread(const std::string &stats_file, int stats_interval);
+       void run();
+       void stop();
+
+private:
+       // Recover the this pointer, and call do_work().
+       static void *do_work_thunk(void *arg);
+
+       void do_work();
+
+       std::string stats_file;
+       int stats_interval;
+
+       pthread_t worker_thread;
+       volatile bool should_stop;
+};
+       
+#endif  // !defined(_STATS_H)