Several threads writing to same log file

348 Views Asked by At

I have studied several sources/forum threads/stackoverflow questions, but still can not decide on the correct/best architecture for the software therefore asking for your advice. I will use some pseudocode below.

Simple task - write to log file

volatile FILE* logFP;
pthread_mutex_t logFileMutex = PTHREAD_MUTEX_INITIALIZER;
volatile long logFileSize;

main()
{
    ...
    (log file is being open here in single thread)
    (ensure lock is unlocked)
    ...
    (another threads are started)
    ...
    (threads are terminated)
    (log file closed)
    (exit)
}

void logToFile(char* instr)
{
    pthread_mutex_lock(logFileMutex);
    fwrite(logFP, "some text %s\n", instr);
    fflush(logFP);
    pthread_mutex_unlock(logFileMutex);
}

As far as I understand this function logToFIle() is thread-safe and reentrant, right?

More complicated task - perform log rotation

volatile bool enableAutoLogRotation;

void logToFile(char* instr)
{
    pthread_mutex_lock(logFileMutex);
    // if log file is not open, remove lock and do nothing
    if(logFP == NULL) { pthread_mutex_unlock(logFileMutex); return; }
    if(enableAutoLogRotation && (logFileSize >= SOME_THRESHOLD))
    {
        enableAutoLogRotation = false;
        pthread_mutex_unlock(logFileMutex);
        performLogRotation();
        pthread_mutex_lock(logFileMutex);
        enableAutoLogRotation = true;
    }

    fwrite(logFP, "some text %s\n", instr);
    fflush(logFP);
    logFileSize = ftell(logFP);
    pthread_mutex_unlock(logFileMutex);
}

Explanation: after locking the mutex I check for log rotation enabled enableAutoLogRotation, this flag is reset when log rotation task is in progress. After checking this flag I enable the mutex to ensure if logToFile is called by another thread, it will be able to acquire lock and write its message to the log file. Within performLogRotation(), when there's a file I/O operation (closing, moving contents, opening for append/creating) I also lock the mutex, otherwise it is unlocked. Important to note that performLogRotation() may also call logToFile(), therefore I ensure that mutex lock is removed before calling logToFile().

void performLogRotation()
{
int error;
    ...
    pthread_mutex_lock(logFileMutex);
    fclose(logFP);
    error = remove(logFileName);
    logFP = fopen(logFileName, "a");    // logFP will be NULL on error, logging will be disabled
    pthread_mutex_unlock(logFileMutex);
    if(error < 0) logToFile("remove error");
    ...
}

Does this plan look correct? Anything I miss? Any other better way?

0

There are 0 best solutions below