Implementing a fixed-size log file, or a circular buffer on disk

warren picture warren · Nov 24, 2009 · Viewed 13.5k times · Source

I checked this question, but it's not what I'm looking for.

I'm trying to figure out how to cap a log file's size (say, 10MB), and as soon as it's hit, either:

  • start writing to the beginning, rather than appending, or
  • keep appending, but delete the contents from the beginning as I do so

Don't really care about language - as long as it's possible :)


Note: I am aware of the rolling log files approach (hit a target size, rename, and continue logging). I am looking to avoid such a roll.

Answer

wallyk picture wallyk · Nov 24, 2009

If you are implementing both the writer and the reader, then you can do something like this:

struct logentry {
    timestamp  ts;
    char       msg [4000];
};

class logger {
private:
    int write_recordnum;  // next record number to write
    int max_recordnum;  // controls maximum size of file
    FILE    *logfile;

public:
    logger (const char *filename, int max_records)
    {
        max_recordnum = max_records;
        logfile = fopen (filename, "a+");
    }

    void write_next_entry (const char *msg, ...)
    {
        struct logentry ent;
        // format message into entry
        va_list ap;
        va_start (ap, msg);
        vsnprintf (ent.msg, sizeof(ent.msg), msg, ap);
        va_end (ap);
        ent.ts = gettimestamp();

        // position logfile
        if (write_recordnum > max_recordnum)
            write_recordnum = 0;

        fseek (logfile, write_recordnum * sizeof (ent), 0);
        fwrite (&ent, 1, sizeof(ent), logfile);
    }

    bool read_entry (int recnum, char *msg)
    {
        struct logentry ent;
        if (recnum >= max_recordnum)
            return false;
        fseek (logfile, recnum * sizeof (ent), 0);
        fread (&ent, 1, sizeof(ent), logfile);
        strcpy (msg, ent.msg);
        return true;
    }
};

The idea is to manage a circular buffer by explicit fixed-size record numbers. Needed is logic to manage whether record N exists, and to check errors.