Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 409
warren Avatar asked Nov 24 '09 08:11

warren


3 Answers

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.

like image 109
wallyk Avatar answered Sep 27 '22 01:09

wallyk


Why not do rolling logfiles? Does it have to be precisely 10MB? If 10MB is your quota, a common practice would be to write to blah.log, and when it hits, say 1MB, rename file to blah.log.1 and start writing to blah.log. Much simpler, and a very common practice. In fact, in Linux, if you use syslog, it's free.

like image 34
jjthrash Avatar answered Sep 27 '22 01:09

jjthrash


If you are using Log4[j/net] there are options for a rolling log. See the RollingFileAppender. Also, there is an option when specifying the attributes of the log file to set the maximum file size for the log. (Param: MaxFileSize)

like image 20
monksy Avatar answered Sep 25 '22 01:09

monksy