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