af53872e6ec03c0d68f83b86e4b9c9f83320eb6d
[cubemap] / accesslog.cpp
1 #include <stddef.h>
2 #include <stdio.h>
3 #include <time.h>
4 #include <string>
5 #include <vector>
6
7 #include "accesslog.h"
8 #include "client.h"
9 #include "log.h"
10 #include "mutexlock.h"
11 #include "timespec.h"
12
13 using namespace std;
14
15 AccessLogThread::AccessLogThread()
16 {
17         pthread_mutex_init(&mutex, NULL);
18 }
19
20 AccessLogThread::AccessLogThread(const string &filename)
21         : filename(filename) {
22         pthread_mutex_init(&mutex, NULL);
23 }
24
25 void AccessLogThread::write(const ClientStats& client)
26 {
27         {
28                 MutexLock lock(&mutex);
29                 pending_writes.push_back(client);
30         }
31         wakeup();
32 }
33
34 void AccessLogThread::do_work()
35 {
36         // Open the file.
37         if (filename.empty()) {
38                 logfp = NULL;
39         } else {
40                 logfp = fopen(filename.c_str(), "a+");
41                 if (logfp == NULL) {
42                         log_perror(filename.c_str());
43                         // Continue as before.
44                 }
45         }
46
47         while (!should_stop()) {
48                 // Empty the queue.
49                 vector<ClientStats> writes;
50                 {
51                         MutexLock lock(&mutex);
52                         swap(pending_writes, writes);
53                 }
54
55                 if (logfp != NULL) {
56                         // Do the actual writes.
57                         timespec now_monotonic;
58                         timespec now_realtime;
59                         if (clock_gettime(CLOCK_MONOTONIC_COARSE, &now_monotonic) == -1) {
60                                 log_perror("clock_gettime(CLOCK_MONOTONIC_COARSE)");
61                         } else if (clock_gettime(CLOCK_REALTIME, &now_realtime) == -1) {
62                                 log_perror("clock_gettime(CLOCK_REALTIME)");
63                         } else {
64                                 timespec realtime_offset = clock_diff(now_monotonic, now_realtime);
65                                 for (size_t i = 0; i < writes.size(); ++i) {
66                                         timespec connect_time_realtime = clock_add(writes[i].connect_time, realtime_offset);
67                                         timespec time_since_connect = clock_diff(writes[i].connect_time, now_monotonic);
68                                         fprintf(logfp, "%llu %s %s %d %llu %llu %llu \"%s\" \"%s\"\n",
69                                                 (long long unsigned)(connect_time_realtime.tv_sec),
70                                                 writes[i].remote_addr.c_str(),
71                                                 writes[i].url.c_str(),
72                                                 int(time_since_connect.tv_sec),
73                                                 (long long unsigned)(writes[i].bytes_sent),
74                                                 (long long unsigned)(writes[i].bytes_lost),
75                                                 (long long unsigned)(writes[i].num_loss_events),
76                                                 writes[i].referer.c_str(),
77                                                 writes[i].user_agent.c_str());
78                                 }
79                                 fflush(logfp);
80                         }
81                 }
82
83                 // Wait until we are being woken up, either to quit or because
84                 // there is material in pending_writes.
85                 wait_for_wakeup(NULL);
86         }
87
88         if (logfp != NULL) {    
89                 if (fclose(logfp) == EOF) {
90                         log_perror("fclose");
91                 }
92         }
93
94         logfp = NULL;
95 }