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