Log all finished accesses to an access log.
[cubemap] / accesslog.cpp
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <sys/poll.h>
4 #include <errno.h>
5
6 #include <algorithm>
7 #include <string>
8 #include <vector>
9
10 #include "accesslog.h"
11 #include "client.h"
12 #include "log.h"
13 #include "mutexlock.h"
14
15 using namespace std;
16
17 AccessLogThread::AccessLogThread() {}
18
19 AccessLogThread::AccessLogThread(const string &filename)
20         : filename(filename) {}
21
22 void AccessLogThread::write(const ClientStats& client)
23 {
24         MutexLock lock(&mutex);
25         pending_writes.push_back(client);
26 }
27
28 void AccessLogThread::do_work()
29 {
30         // Open the file.
31         if (filename.empty()) {
32                 logfp = NULL;
33         } else {
34                 logfp = fopen(filename.c_str(), "a+");
35                 if (logfp == NULL) {
36                         log_perror(filename.c_str());
37                         // Continue as before.
38                 }
39         }
40
41         while (!should_stop) {
42                 // Empty the queue.
43                 vector<ClientStats> writes;
44                 {
45                         MutexLock lock(&mutex);
46                         swap(pending_writes, writes);
47                 }
48
49                 if (logfp == NULL) {
50                         continue;
51                 }
52
53                 // Do the actual writes.
54                 time_t now = time(NULL);
55                 for (size_t i = 0; i < writes.size(); ++i) {
56                         fprintf(logfp, "%llu %s %s %d %llu %llu %llu\n",
57                                 (long long unsigned)(writes[i].connect_time),
58                                 writes[i].remote_addr.c_str(),
59                                 writes[i].stream_id.c_str(),
60                                 int(now - writes[i].connect_time),
61                                 (long long unsigned)(writes[i].bytes_sent),
62                                 (long long unsigned)(writes[i].bytes_lost),
63                                 (long long unsigned)(writes[i].num_loss_events));
64                 }
65                 fflush(logfp);
66                 
67                 // Wait until the stop_fd pipe is closed, one second has passed.
68                 // or a spurious signal arrives.
69                 pollfd pfd;
70                 pfd.fd = stop_fd_read;
71                 pfd.events = POLLIN | POLLRDHUP;
72
73                 int nfds = poll(&pfd, 1, 1000);
74                 if (nfds == 0 || (nfds == -1 && errno == EINTR)) {
75                         continue;
76                 }
77                 if (nfds == 1) {
78                         // Should stop.
79                         break;
80                 }
81                 if (nfds == -1) {
82                         log_perror("poll");
83                         usleep(100000);
84                         continue;
85                 }
86         }
87         
88         if (fclose(logfp) == EOF) {
89                 log_perror("fclose");
90         }
91
92         logfp = NULL;
93 }