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