144 lines
3.5 KiB
C++
144 lines
3.5 KiB
C++
#include "log.h"
|
|
#include <cstdlib>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <cassert>
|
|
#include <sstream>
|
|
|
|
Log::Log(const char * fn)
|
|
: log_name(fn), serial(0)
|
|
{
|
|
FILE * fh = fopen(fn, "r");
|
|
if(!fh) {
|
|
fprintf(stderr, "Log: Could not open log file '%s' for reading! Creating an empty log.\n", fn);
|
|
return;
|
|
}
|
|
|
|
LogEntry l;
|
|
while(1 == fread(&l, sizeof(LogEntry), 1, fh))
|
|
entries.push_back(l);
|
|
|
|
serial = l.serial;
|
|
|
|
fclose(fh);
|
|
}
|
|
|
|
uint64_t Log::writeEntry(LogEntry ent)
|
|
{
|
|
FILE * fh = fopen(log_name.c_str(), "a");
|
|
if(!fh) {
|
|
fprintf(stderr, "Log: FATAL: Could not open log file '%s' for append. Aborting.\n", log_name.c_str());
|
|
abort();
|
|
}
|
|
|
|
flockfile(fh);
|
|
|
|
fseek(fh, 0, SEEK_END);
|
|
ent.serial = ++serial;
|
|
if(1 != fwrite(&ent, sizeof(LogEntry), 1, fh)) {
|
|
fprintf(stderr, "Log: FATAL: Could not write entry to log file '%s'. Aborting.\n", log_name.c_str());
|
|
abort();
|
|
}
|
|
fflush(fh);
|
|
|
|
funlockfile(fh);
|
|
fclose(fh);
|
|
|
|
entries.push_back(ent);
|
|
return ent.serial;
|
|
}
|
|
|
|
std::list<LogEntry>::const_iterator Log::begin()
|
|
{
|
|
return entries.begin();
|
|
}
|
|
|
|
std::list<LogEntry>::const_iterator Log::end()
|
|
{
|
|
return entries.end();
|
|
}
|
|
|
|
uint64_t Log::nextSerial()
|
|
{
|
|
return serial + 1;
|
|
}
|
|
|
|
std::string logTypeToString (E_OBJ_TYPE type) {
|
|
switch(type) {
|
|
case ET_TRANS: return "TRANS";
|
|
case ET_HASH: return "HASH";
|
|
case ET_SALE: return "SALE";
|
|
case ET_PRICE: return "PRICE";
|
|
case ET_ADDUPC: return "ADDUPC";
|
|
case ET_REVERT: return "REVERT";
|
|
default: fprintf(stderr, "logTypeToString: unhandled case in switch.\n"); abort();
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
std::string ThingToString (T num) {
|
|
std::stringstream ss;
|
|
ss << num;
|
|
return ss.str();
|
|
}
|
|
|
|
std::vector<std::string> Log::toString()
|
|
{
|
|
assert(sizeof(time_t) == sizeof(uint64_t));
|
|
std::vector<std::string> ans;
|
|
ans.reserve(entries.size());
|
|
std::list<LogEntry>::iterator it;
|
|
for(it = entries.begin(); it != entries.end(); it++) {
|
|
//char* time = new char[64];
|
|
//struct tm* tms = localtime((time_t*)&it->ts);
|
|
//strftime(time, 64, "%c", tms);
|
|
std::string out = ThingToString<uint64_t>(it->ts) + "\t"
|
|
//+ ThingToString<uint64_t> (it->serial) + "\t"
|
|
+ logTypeToString(it->type) + "\t";
|
|
//delete[] time;
|
|
switch(it->type) {
|
|
case ET_TRANS:
|
|
out += ns.get_name(it->Transaction.uid) + "\t"
|
|
+ ThingToString<int32_t>(it->Transaction.delta);
|
|
break;
|
|
case ET_HASH: {
|
|
SHA1Hash h;
|
|
h.set((unsigned char*)it->HashChange.hash);
|
|
out += h.toHex() + "\t"
|
|
+ ns.get_name(it->HashChange.uid) + "\t"
|
|
+ ThingToString<bool>(it->HashChange.add);
|
|
break;
|
|
}
|
|
case ET_SALE:
|
|
out += ThingToString<uint64_t>(it->StockChange.upc) + "\t"
|
|
+ ThingToString<int32_t>(it->StockChange.delta);
|
|
break;
|
|
case ET_PRICE:
|
|
out += ThingToString<uint64_t>(it->PriceChange.upc) + "\t"
|
|
+ ThingToString<int32_t>(it->PriceChange.price);
|
|
break;
|
|
case ET_ADDUPC:
|
|
out += ThingToString<uint64_t>(it->AddUPC.upc) + "\t"
|
|
+ it->AddUPC.name;
|
|
break;
|
|
case ET_REVERT:
|
|
out += ThingToString<uint64_t>(it->Revert.revert_serial);
|
|
break;
|
|
default: fprintf(stderr, "Log: unhandled toString case.\n"); abort();
|
|
}
|
|
|
|
ans.push_back(out);
|
|
}
|
|
return ans;
|
|
}
|
|
|
|
LogEntry Log::newLogEntry(E_OBJ_TYPE type) {
|
|
LogEntry l;
|
|
memset(&l, 0, sizeof(LogEntry));
|
|
l.ts = (uint64_t)time(NULL);
|
|
l.type = type;
|
|
l.serial = nextSerial();
|
|
return l;
|
|
}
|
|
|